Unpacking Odin Minecraft Anticheat

Edit: This JAR was protected with the Paramorphism Java obfuscator by Anthony Som.

Edit #2: Removed JAR link at request of the author.

While this JAR wasn’t too hard to poke around in and figure out what is going on, I found this one of the more unique obfuscations I have seen in attempting to prevent Java reverse-engineering.

In this image, we can see the JAR has duplicated entries. I later found out after attempting to use my own Java obfuscator, Radon, to deobfuscate the JAR using my shrinker transformers, the entry duplication results in the fake classes being written to the JAR instead of the correct ones. Additionally, I found the JAR uses null bytes (‘\u0000’ or ‘\x00’) as well which is a trick used to fool around with non-Java archivers.

To counter this, I quickly wrote an unpacker to filter out the fake classes and rename the JAR resources (which turn out to be encrypted classes) to something easier to access. Shield your eyes if you don’t like cancer code.

package me.itzsomebody.jarfixer;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.LdcInsnNode;

public class Main {
    public static void main(String[] args) {
        try {
            File input = new File("input.jar");
            File output = new File("output.jar");
            ZipFile zipFile = new ZipFile(input);
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(output));
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            LinkedList<ClassNode> classNodes = new LinkedList<>();
            HashMap<String, String> resourceNameMap = new HashMap<>();

            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();
                if (!zipEntry.isDirectory()) {
                    if (zipEntry.getName().endsWith(".class")) {
                        try {
                            ClassNode classNode = new ClassNode();
                            ClassReader cr = new ClassReader(zipFile.getInputStream(zipEntry));
                            cr.accept(classNode, 0);
                            classNodes.add(classNode);
                        } catch (Throwable t) {
                            String newName = UUID.randomUUID().toString() + ".encryptedclass";
                            resourceNameMap.put(zipEntry.getName(), newName);
                            zipEntry.setCompressedSize(-1);
                            zos.putNextEntry(new ZipEntry(newName));
                            zos.write(toByteArray(zipFile.getInputStream(zipEntry)));
                        }
                    } else {
                        zipEntry.setCompressedSize(-1);
                        zos.putNextEntry(zipEntry);
                        zos.write(toByteArray(zipFile.getInputStream(zipEntry)));
                    }
                }
            }

            classNodes.stream().filter(Main::isValidClassNode).forEach(classNode -> {
                classNode.methods.stream().filter(methodNode -> methodNode.instructions != null && methodNode.instructions.size() > 0).forEach(methodNode -> {
                    for (AbstractInsnNode insn : methodNode.instructions.toArray()) {
                        if (insn instanceof LdcInsnNode) {
                            LdcInsnNode ldc = (LdcInsnNode) insn;

                            if (ldc.cst instanceof String) {
                                String mappedName = resourceNameMap.get(ldc.cst);

                                if (mappedName != null) {
                                    ldc.cst = mappedName;
                                }
                            }
                        }
                    }
                });

                try {
                    ClassWriter cw = new ClassWriter(0);
                    classNode.accept(cw);
                    ZipEntry zipEntry = new ZipEntry(classNode.name + ".class");
                    zipEntry.setCompressedSize(-1);
                    zos.putNextEntry(zipEntry);
                    zos.write(cw.toByteArray());
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            });

            zos.close();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static boolean isValidClassNode(ClassNode classNode) {
        if (classNode.fields != null) {
            for (FieldNode fieldNode : classNode.fields) {
                if (fieldNode.desc.contains("GIVE UP")) {
                    return false;
                }
            }
        }

        return true;
    }

    private static byte[] toByteArray(InputStream in) {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            while (in.available() > 0) {
                int data = in.read(buffer);
                out.write(buffer, 0, data);
            }

            in.close();
            out.close();
            return out.toByteArray();
        } catch (IOException ioe) {
            ioe.printStackTrace();
            throw new RuntimeException();
        }
    }
}

Once I had done this, I was able to use my obfuscator to strip the “GIVE UP” spam embedded in annotations out and change the class names into something easier to read than various unicode and null bytes.

A really interesting class I found extended ClassLoader (there are actually two).

At that point, I realized that the invalid classes in the JAR were encrypted classes. So I whipped out my class-dumping java agent and attached it to a Spigot server running the plugin.

[XX:XX:XX INFO]: [OdinAnticheat] Enabling OdinAnticheat v1.0.3
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/á/á as classes/5708111e-d6fd-462c-bd3d-4fc25fba327a.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/á/á/? as classes/fb04070e-ded3-41df-a012-e57fe453e2a6.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ?/?/?/??/?/ ? as classes/96a7ce2c-5315-4e18-89c5-1532818d3b9d.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ?/?/?/??/?/ ?i as classes/8264e641-d75b-4a6f-b38f-16f3d9d08726.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ?/?/?/??/?/  as classes/f64e2544-d4a7-4910-a0e6-02cf4f614d60.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/163512c7-c080-4acd-86b8-4c6e0d33b8b7.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/á/á/? as classes/ace7239b-e416-4fb3-b7d7-f4b0ae0e3536.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/á/á/á as classes/103e165f-fbfb-4044-b276-c7036a4abcbd.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/?? as classes/44c720d9-7974-4c8c-b6df-11e03d8b0cd8.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ? as classes/762a693f-c9cc-40e8-958a-20528943c487.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ?i as classes/ba7327b1-5493-408c-be40-6d2808bf064d.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/  as classes/d3799634-9337-4327-ab31-d2603d681510.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/13b68d25-a228-48d9-aad5-78eba6e9a413.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/?/á as classes/8ab83229-a92a-4d39-8f55-598a0d1944b7.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/á/á as classes/a9b816c6-1654-4f40-b422-bf339344053d.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/? as classes/828f1125-d671-49d7-b625-cce36a3ddbc5.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/á as classes/118e1f0e-37bc-46b7-97ba-c0eb9086c884.class
[XX:XX:XX INFO]: [ClassDumper] Dumping  á/á/á/?/á/? as classes/8c9dad1e-f94f-4b7a-8b4f-6cc073fa851f.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ? as classes/74c05083-f04d-4a7d-9bf9-22c7bfe30e25.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ?i as classes/1c87935f-3c59-4ede-9fa7-6d4edbc2ff15.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/677ce288-6496-43a8-aba0-31ced1fea203.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ? as classes/4fd6d167-50ae-4d3b-9e30-47da8eb5375e.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ?i as classes/d594ae9b-ab3c-4599-a773-be8159ca8c73.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/a42db563-35dd-48bd-a8e5-68eb6eb407a8.class
[XX:XX:XX INFO]: Server permissions file permissions.yml is empty, ignoring it
[XX:XX:XX INFO]: Done (2.407s)! For help, type "help" or "?"
[XX:XX:XX INFO]: UUID of player ItzSomebody is 44cd61b5-6c09-34dd-9add-3db42c4ff6da
[XX:XX:XX INFO]: ItzSomebody[/127.0.0.1:55549] logged in with entity id 35 at ([world]1399.5, 4.0, -224.5)
[XX:XX:XX INFO]: <ItzSomebody> odin
[XX:XX:XX INFO]: ItzSomebody issued server command: /odinb
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ? as classes/b45bf833-25f6-451d-8962-fc62c02e8d3a.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ?i as classes/ed52e40f-b870-4855-80be-0823963a8b4d.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/771d2f88-9365-43d4-a246-aa5ec52f35de.class
[XX:XX:XX INFO]: ItzSomebody issued server command: /odin
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ?? as classes/1fe206bf-6c43-49aa-8298-288468459a8e.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ??/ ?/??/?/??/ ??i as classes/f4526b07-a02c-4c23-92dc-ef9483ca3910.class
[XX:XX:XX INFO]: [ClassDumper] Dumping ? as classes/552bec71-8b9f-4480-aef8-549e9d2bcb97.class
[XX:XX:XX ERROR]: null
org.bukkit.command.CommandException: Unhandled exception executing command 'odin' in plugin OdinAnticheat v1.0.3
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[REMOVED FROM PUBLIC VIEW]
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) ~[REMOVED FROM PUBLIC VIEW]
        at org.bukkit.craftbukkit.v1_8_R3.CraftServer.dispatchCommand(CraftServer.java:641) ~[REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.PlayerConnection.handleCommand(PlayerConnection.java:1162) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:997) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:45) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:1) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [REMOVED FROM PUBLIC VIEW]
        at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:1.8.0_131]
        at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_131]
        at net.minecraft.server.v1_8_R3.SystemUtils.a(SourceFile:44) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:715) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [REMOVED FROM PUBLIC VIEW]
        at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [REMOVED FROM PUBLIC VIEW]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_131]
Caused by: java.lang.NoSuchMethodError: org.bukkit.command.CommandSender.spigot()Lorg/bukkit/command/CommandSender$Spigot;
        at  á.á.á.?.?.á.á(Unknown Source) ~[?:?]
        at  á.á.á.?.?.á.onCommand(Unknown Source) ~[?:?]
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[REMOVED FROM PUBLIC VIEW]
        ... 15 more

According to this, we want to take a look at the dumped classes which originally had a name of “?”. The way I was able to determine this was to figure out which classes invoked the custom ClassLoader classes. For example:

public static Object mgZZ = (new TerL(Xepw.class.getClassLoader(), "e0ab771d-65ea-4675-afe6-594ee752a95c.encryptedclass", 95608)).IkWb("?").newInstance();

According to this, we want the classes called “?”. This turned out to be successful and I was able to determine how the entire plugin worked. Here are a couple of samples

public class ? implements \u2061.\u2062.\u200b.\u200f\u200e.\u2063.\u0000\u200bi {
    public ?()
    {
        super();
    }
    
    public org.bukkit.Server \u200b(org.bukkit.plugin.java.JavaPlugin a)
    {
        return a.getServer();
    }
    
    public String \u200c(org.bukkit.event.player.PlayerCommandPreprocessEvent a)
    {
        return a.getMessage();
    }
    
    public boolean \u200d(String s, String s0)
    {
        return s.equalsIgnoreCase(s0);
    }
    
    public void \u200f\u200e(org.bukkit.event.player.PlayerCommandPreprocessEvent a, boolean b)
    {
        a.setCancelled(b);
    }
    
    public java.util.regex.Pattern \u2060(String s, int i)
    {
        return java.util.regex.Pattern.compile(s, i);
    }
    
    public java.util.regex.Matcher \u2061(java.util.regex.Pattern a, CharSequence a0)
    {
        return a.matcher(a0);
    }
    
    public boolean \u2062(java.util.regex.Matcher a)
    {
        return a.find();
    }
    
    public String \u2063(java.util.regex.Matcher a, int i)
    {
        return a.group(i);
    }
    
    public java.util.regex.Pattern \u2064(String s)
    {
        return java.util.regex.Pattern.compile(s);
    }
    
    public int \ufeff(java.util.regex.Matcher a, int i)
    {
        return a.start(i);
    }
    
    public int \u200b\u00a0(java.util.regex.Matcher a, int i)
    {
        return a.end(i);
    }
    
    public String \u200b\u200b(String s, int i, int i0)
    {
        return s.substring(i, i0);
    }
    
    public int \u200b\u200c(java.util.Random a, int i)
    {
        return a.nextInt(i);
    }
    
    public org.bukkit.scheduler.BukkitScheduler \u200b\u200d()
    {
        return org.bukkit.Bukkit.getScheduler();
    }
    
    public org.bukkit.event.entity.EntityDamageEvent$DamageCause \u200b\u200f\u200e(org.bukkit.event.entity.EntityDamageEvent a)
    {
        return a.getCause();
    }
    
    public boolean \u200b\u2060(java.util.HashMap a, Object a0)
    {
        return a.containsKey(a0);
    }
    
    public long \u200b\u2061()
    {
        return System.currentTimeMillis();
    }
    
    public Object \u200b\u2062(java.util.HashMap a, Object a0)
    {
        return a.get(a0);
    }
    
    public Object \u200b\u2063(java.util.HashMap a, Object a0, Object a1)
    {
        return a.put(a0, a1);
    }
    
    public Object \u200b\u2064(java.util.Optional a)
    {
        return a.get();
    }
    
    public org.bukkit.Location \u200b\ufeff(org.bukkit.Location a, double d, double d0, double d1)
    {
        return a.subtract(d, d0, d1);
    }
    
    public org.bukkit.block.Block \u200c\u00a0(org.bukkit.Location a)
    {
        return a.getBlock();
    }
    
    public boolean \u200c\u200b(String s, String s0)
    {
        return s.endsWith(s0);
    }
    
    public Integer \u200c\u200c(int i)
    {
        return Integer.valueOf(i);
    }
    
    public Object \u200c\u200d(java.util.HashMap a, Object a0, Object a1)
    {
        return a.getOrDefault(a0, a1);
    }
    
    public int \u200c\u200f\u200e(Integer a)
    {
        return a.intValue();
    }
    
    public Object \u200c\u2060(java.util.HashMap a, Object a0)
    {
        return a.remove(a0);
    }
    
    public org.bukkit.Location \u200c\u2061(org.bukkit.event.player.PlayerMoveEvent a)
    {
        return a.getFrom();
    }
    
    public org.bukkit.Location \u200c\u2062(org.bukkit.event.player.PlayerMoveEvent a)
    {
        return a.getTo();
    }
    
    public double \u200c\u2063(org.bukkit.Location a, org.bukkit.Location a0)
    {
        return a.distance(a0);
    }
    
    public double \u200c\u2064(org.bukkit.Location a)
    {
        return a.getY();
    }
    
    public int \u200c\ufeff(org.bukkit.potion.PotionEffect a)
    {
        return a.getAmplifier();
    }
    
    public boolean \u200d\u00a0(String s, CharSequence a)
    {
        return s.contains(a);
    }
    
    public org.bukkit.Location \u200d\u200b(org.bukkit.Location a, double d, double d0, double d1)
    {
        return a.add(d, d0, d1);
    }
    
    public boolean \u200d\u200c(org.bukkit.Material a)
    {
        return a.isSolid();
    }
    
    public Long \u200d\u200d(long j)
    {
        return Long.valueOf(j);
    }
    
    public long \u200d\u200f\u200e(Long a)
    {
        return a.longValue();
    }
    
    public org.bukkit.Material \u200d\u2060(org.bukkit.inventory.ItemStack a)
    {
        return a.getType();
    }
    
    public void \u200d\u2061(org.bukkit.event.player.PlayerMoveEvent a, boolean b)
    {
        a.setCancelled(b);
    }
    
    public double \u200d\u2062(org.bukkit.Location a)
    {
        return a.getX();
    }
    
    public double \u200d\u2063(double d, double d0)
    {
        return Math.pow(d, d0);
    }
    
    public double \u200d\u2064(org.bukkit.Location a)
    {
        return a.getZ();
    }
    
    public double \u200d\ufeff(double d)
    {
        return Math.sqrt(d);
    }
    
    public void \u200f\u200e\u00a0(java.util.HashMap a)
    {
        a.clear();
    }
    
    public java.util.Collection \u200f\u200e\u200b()
    {
        return org.bukkit.Bukkit.getOnlinePlayers();
    }
    
    public org.bukkit.configuration.file.FileConfiguration \u200f\u200e\u200c(org.bukkit.plugin.java.JavaPlugin a)
    {
        return a.getConfig();
    }
    
    public java.io.File \u200f\u200e\u200d(org.bukkit.plugin.java.JavaPlugin a)
    {
        return a.getDataFolder();
    }
    
    public boolean \u200f\u200e\u200f\u200e(java.io.File a)
    {
        return a.exists();
    }
    
    public Boolean \u200f\u200e\u2060(boolean b)
    {
        return Boolean.valueOf(b);
    }
    
    public Double \u200f\u200e\u2061(double d)
    {
        return Double.valueOf(d);
    }
    
    public org.bukkit.configuration.file.FileConfigurationOptions \u200f\u200e\u2062(org.bukkit.configuration.file.FileConfiguration a)
    {
        return a.options();
    }
    
    public org.bukkit.configuration.file.FileConfigurationOptions \u200f\u200e\u2063(org.bukkit.configuration.file.FileConfigurationOptions a, boolean b)
    {
        return a.copyDefaults(b);
    }
    
    public void \u200f\u200e\u2064(org.bukkit.plugin.java.JavaPlugin a)
    {
        a.saveConfig();
    }
    
    public void \u200f\u200e\ufeff(java.io.PrintStream a, String s)
    {
        a.println(s);
    }
    
    public void \u2060\u00a0(org.bukkit.plugin.java.JavaPlugin a)
    {
        a.reloadConfig();
    }
    
    public net.md_5.bungee.api.chat.ComponentBuilder \u2060\u200b(net.md_5.bungee.api.chat.ComponentBuilder a, String s)
    {
        return a.append(s);
    }
    
    public net.md_5.bungee.api.chat.ComponentBuilder \u2060\u200c(net.md_5.bungee.api.chat.ComponentBuilder a, net.md_5.bungee.api.ChatColor a0)
    {
        return a.color(a0);
    }
    
    public net.md_5.bungee.api.chat.ComponentBuilder \u2060\u200d(net.md_5.bungee.api.chat.ComponentBuilder a, net.md_5.bungee.api.chat.ClickEvent a0)
    {
        return a.event(a0);
    }
    
    public StringBuilder \u2060\u200f\u200e(StringBuilder a, int i)
    {
        return a.append(i);
    }
    
    public StringBuilder \u2060\u2060(StringBuilder a, String s)
    {
        return a.append(s);
    }
    
    public String \u2060\u2061(StringBuilder a)
    {
        return a.toString();
    }
    
    public net.md_5.bungee.api.chat.BaseComponent[] \u2060\u2062(net.md_5.bungee.api.chat.ComponentBuilder a)
    {
        return a.create();
    }
    
    public net.md_5.bungee.api.chat.ComponentBuilder \u2060\u2063(net.md_5.bungee.api.chat.ComponentBuilder a, net.md_5.bungee.api.chat.HoverEvent a0)
    {
        return a.event(a0);
    }
    
    public void \u2060\u2064(org.bukkit.entity.Player$Spigot a, net.md_5.bungee.api.chat.BaseComponent[] a0)
    {
        a.sendMessage(a0);
    }
    
    public void \u2060\ufeff(org.bukkit.event.server.ServerCommandEvent a, boolean b)
    {
        a.setCancelled(b);
    }
    
    public org.bukkit.entity.Entity \u2061\u00a0(org.bukkit.event.entity.EntityDamageByEntityEvent a)
    {
        return a.getDamager();
    }
    
    public org.bukkit.event.entity.EntityDamageEvent$DamageCause[] \u2061\u200b()
    {
        return org.bukkit.event.entity.EntityDamageEvent$DamageCause.values();
    }
    
    public void \u2061\u200c(org.bukkit.command.CommandSender$Spigot a, net.md_5.bungee.api.chat.BaseComponent[] a0)
    {
        a.sendMessage(a0);
    }
    
    public net.md_5.bungee.api.chat.ComponentBuilder \u2061\u200d(net.md_5.bungee.api.chat.ComponentBuilder a, net.md_5.bungee.api.chat.BaseComponent[] a0)
    {
        return a.append(a0);
    }
    
    public String \u2061\u200f\u200e(org.bukkit.event.player.AsyncPlayerChatEvent a)
    {
        return a.getMessage();
    }
    
    public boolean \u2061\u2060(org.bukkit.event.player.AsyncPlayerChatEvent a)
    {
        return a.isCancelled();
    }
    
    public StringBuilder \u2061\u2061(StringBuilder a, Object a0)
    {
        return a.append(a0);
    }
    
    public void \u2061\u2062(org.bukkit.event.player.AsyncPlayerChatEvent a, boolean b)
    {
        a.setCancelled(b);
    }
    
    public org.bukkit.command.PluginCommand \u2061\u2063(org.bukkit.plugin.java.JavaPlugin a, String s)
    {
        return a.getCommand(s);
    }
    
    public void \u2061\u2064(org.bukkit.command.PluginCommand a, org.bukkit.command.CommandExecutor a0)
    {
        a.setExecutor(a0);
    }
}
public class ? implements \u200f\u200e.\u0000\u200d.\u200f\u200e.\u2061.\u200f\u200e.\u0000\u200bi {
    private String \u200b;
    private String \u200c;
    private String \u200d;
    private String \u200f\u200e;
    private String \u2060;
    private String \u2061;
    private String \u2062;
    private String \u2063;
    private String \u2064;
    private String \ufeff;
    private String \u200b\u00a0;
    private String \u200b\u200b;
    private String \u200b\u200c;
    private String \u200b\u200d;
    private String \u200b\u200f\u200e;
    private String \u200b\u2060;
    
    public ?()
    {
        super();
    }
    
    public String \u200b()
    {
        String s = this.\u200b;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)47).append((char)105).append((char)108).append((char)105).append((char)107).append((char)101).append((char)99).append((char)104).append((char)101).append((char)101).append((char)116).append((char)111).append((char)115).toString();
        this.\u200b = s0;
        return s0;
    }
    
    public String \u200c()
    {
        String s = this.\u200c;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)115).append((char)97).append((char)109).append((char)101).toString();
        this.\u200c = s0;
        return s0;
    }
    
    public String \u200d()
    {
        String s = this.\u200d;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)46).append((char)109).append((char)111).append((char)118).append((char)101).append((char)109).append((char)101).append((char)110).append((char)116).toString();
        this.\u200d = s0;
        return s0;
    }
    
    public String \u200f\u200e()
    {
        String s = this.\u200f\u200e;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)65).append((char)73).append((char)82).toString();
        this.\u200f\u200e = s0;
        return s0;
    }
    
    public String \u2060()
    {
        String s = this.\u2060;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)116).append((char)105).append((char)109).append((char)101).append((char)114).toString();
        this.\u2060 = s0;
        return s0;
    }
    
    public String \u2061()
    {
        String s = this.\u2061;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)73).append((char)67).append((char)69).toString();
        this.\u2061 = s0;
        return s0;
    }
    
    public String \u2062()
    {
        String s = this.\u2062;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)83).append((char)84).append((char)65).append((char)73).append((char)82).toString();
        this.\u2062 = s0;
        return s0;
    }
    
    public String \u2063()
    {
        String s = this.\u2063;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)83).append((char)76).append((char)65).append((char)66).toString();
        this.\u2063 = s0;
        return s0;
    }
    
    public String \u2064()
    {
        String s = this.\u2064;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)115).append((char)110).append((char)101).append((char)97).append((char)107).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString();
        this.\u2064 = s0;
        return s0;
    }
    
    public String \ufeff()
    {
        String s = this.\ufeff;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).append((char)45).append((char)97).toString();
        this.\ufeff = s0;
        return s0;
    }
    
    public String \u200b\u00a0()
    {
        String s = this.\u200b\u00a0;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)115).append((char)116).append((char)101).append((char)112).toString();
        this.\u200b\u00a0 = s0;
        return s0;
    }
    
    public String \u200b\u200b()
    {
        String s = this.\u200b\u200b;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)106).append((char)101).append((char)115).append((char)117).append((char)115).toString();
        this.\u200b\u200b = s0;
        return s0;
    }
    
    public String \u200b\u200c()
    {
        String s = this.\u200b\u200c;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)102).append((char)108).append((char)121).append((char)45).append((char)97).toString();
        this.\u200b\u200c = s0;
        return s0;
    }
    
    public String \u200b\u200d()
    {
        String s = this.\u200b\u200d;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)102).append((char)108).append((char)121).append((char)45).append((char)98).toString();
        this.\u200b\u200d = s0;
        return s0;
    }
    
    public String \u200b\u200f\u200e()
    {
        String s = this.\u200b\u200f\u200e;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)102).append((char)108).append((char)121).append((char)45).append((char)99).toString();
        this.\u200b\u200f\u200e = s0;
        return s0;
    }
    
    public String \u200b\u2060()
    {
        String s = this.\u200b\u2060;
        if (s != null)
        {
            return s;
        }
        String s0 = new StringBuilder().append((char)105).append((char)110).append((char)115).append((char)97).append((char)110).append((char)101).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString();
        this.\u200b\u2060 = s0;
        return s0;
    }
}

Then, after stuffing all the string generation code into one class, we are rewarded with all of the strings.

import java.util.ArrayList;

public class RandomJava {
    public static final ClassLoader classLoader = RandomJava.class.getClassLoader();

    public static void main(String[] args) {
        ArrayList<String> strings = new ArrayList<String>() {
            {
                add("" + (char) 105 + (char) 110 + (char) 115 + (char) 97 + (char) 110 + (char) 101 + (char) 95 + (char) 114 + (char) 101 + (char) 97 + (char) 99 + (char) 104);
                add("" + (char) 111 + (char) 100 + (char) 105 + (char) 110 + (char) 46 + (char) 99 + (char) 111 + (char) 109 + (char) 109 + (char) 97 + (char) 110 + (char) 100);
                add("" + (char) 47 + (char) 111 + (char) 100 + (char) 105 + (char) 110 + (char) 32 + (char) 118 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110);
                add("" + (char) 47 + (char) 111 + (char) 100 + (char) 105 + (char) 110 + (char) 32 + (char) 118 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110);
                add("" + (char) 47 + (char) 111 + (char) 100 + (char) 105 + (char) 110 + (char) 32 + (char) 104 + (char) 101 + (char) 108 + (char) 112);
                add("" + (char) 118 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110);
                add("" + (char) 86 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110 + (char) 58 + (char) 32);
                add("" + (char) 49 + (char) 46 + (char) 48 + (char) 46 + (char) 51);
                add("" + (char) 89 + (char) 111 + (char) 117 + (char) 32 + (char) 100 + (char) 111 + (char) 32 + (char) 110 + (char) 111 + (char) 116 + (char) 32 + (char) 104 + (char) 97 + (char) 118 + (char) 101 + (char) 32 + (char) 112 + (char) 101 + (char) 114 + (char) 109 + (char) 105 + (char) 115 + (char) 115 + (char) 105 + (char) 111 + (char) 110 + (char) 32 + (char) 116 + (char) 111 + (char) 32 + (char) 117 + (char) 115 + (char) 101 + (char) 32 + (char) 116 + (char) 104 + (char) 105 + (char) 115 + (char) 32 + (char) 99 + (char) 111 + (char) 109 + (char) 109 + (char) 97 + (char) 110 + (char) 100 + (char) 46);
                add("" + (char) 104 + (char) 101 + (char) 108 + (char) 112);
                add("" + (char) 47 + (char) 104 + (char) 101 + (char) 108 + (char) 112);
                add("" + (char) 32 + (char) 76 + (char) 105 + (char) 115 + (char) 116 + (char) 115 + (char) 32 + (char) 99 + (char) 111 + (char) 109 + (char) 109 + (char) 97 + (char) 110 + (char) 100 + (char) 115 + (char) 10);
                add("" + (char) 47 + (char) 118 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110);
                add("" + (char) 32 + (char) 68 + (char) 105 + (char) 115 + (char) 112 + (char) 108 + (char) 97 + (char) 121 + (char) 115 + (char) 32 + (char) 118 + (char) 101 + (char) 114 + (char) 115 + (char) 105 + (char) 111 + (char) 110 + (char) 10);
                add("" + (char) 47 + (char) 114 + (char) 101 + (char) 108 + (char) 111 + (char) 97 + (char) 100);
                add("" + (char) 32 + (char) 82 + (char) 101 + (char) 108 + (char) 111 + (char) 97 + (char) 100 + (char) 115 + (char) 32 + (char) 99 + (char) 111 + (char) 110 + (char) 102 + (char) 105 + (char) 103 + (char) 117 + (char) 114 + (char) 97 + (char) 116 + (char) 105 + (char) 111 + (char) 110);
                add("" + (char) 114 + (char) 101 + (char) 108 + (char) 111 + (char) 97 + (char) 100);

                add(new StringBuilder().append((char) 47).append((char) 105).append((char) 108).append((char) 105).append((char) 107).append((char) 101).append((char) 99).append((char) 104).append((char) 101).append((char) 101).append((char) 116).append((char) 111).append((char) 115).toString());
                add(new StringBuilder().append((char) 115).append((char) 97).append((char) 109).append((char) 101).toString());
                add(new StringBuilder().append((char) 111).append((char) 100).append((char) 105).append((char) 110).append((char) 46).append((char) 99).append((char) 104).append((char) 101).append((char) 99).append((char) 107).append((char) 46).append((char) 109).append((char) 111).append((char) 118).append((char) 101).append((char) 109).append((char) 101).append((char) 110).append((char) 116).toString());
                add(new StringBuilder().append((char) 65).append((char) 73).append((char) 82).toString());
                add(new StringBuilder().append((char) 116).append((char) 105).append((char) 109).append((char) 101).append((char) 114).toString());
                add(new StringBuilder().append((char) 73).append((char) 67).append((char) 69).toString());
                add(new StringBuilder().append((char) 83).append((char) 84).append((char) 65).append((char) 73).append((char) 82).toString());
                add(new StringBuilder().append((char) 83).append((char) 76).append((char) 65).append((char) 66).toString());
                add(new StringBuilder().append((char) 115).append((char) 110).append((char) 101).append((char) 97).append((char) 107).append((char) 45).append((char) 115).append((char) 112).append((char) 101).append((char) 101).append((char) 100).toString());
                add(new StringBuilder().append((char) 115).append((char) 112).append((char) 101).append((char) 101).append((char) 100).append((char) 45).append((char) 97).toString());
                add(new StringBuilder().append((char) 115).append((char) 116).append((char) 101).append((char) 112).toString());
                add(new StringBuilder().append((char) 106).append((char) 101).append((char) 115).append((char) 117).append((char) 115).toString());
                add(new StringBuilder().append((char) 102).append((char) 108).append((char) 121).append((char) 45).append((char) 97).toString());
                add(new StringBuilder().append((char) 102).append((char) 108).append((char) 121).append((char) 45).append((char) 98).toString());
                add(new StringBuilder().append((char) 102).append((char) 108).append((char) 121).append((char) 45).append((char) 99).toString());
                add(new StringBuilder().append((char) 105).append((char) 110).append((char) 115).append((char) 97).append((char) 110).append((char) 101).append((char) 45).append((char) 115).append((char) 112).append((char) 101).append((char) 101).append((char) 100).toString());

                add(new StringBuilder().append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).append((char)45).append((char)98).toString());
                add(new StringBuilder().append((char)110).append((char)111).append((char)102).append((char)97).append((char)108).append((char)108).toString());
                add(new StringBuilder().append((char)115).append((char)119).append((char)105).append((char)109).append((char)109).append((char)105).append((char)110).append((char)103).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)101).append((char)108).append((char)121).append((char)116).append((char)114).append((char)97).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)104).append((char)111).append((char)114).append((char)115).append((char)101).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)104).append((char)111).append((char)114).append((char)115).append((char)101).append((char)45).append((char)102).append((char)108).append((char)121).toString());
                add(new StringBuilder().append((char)98).append((char)111).append((char)97).append((char)116).append((char)45).append((char)115).append((char)112).append((char)101).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)98).append((char)111).append((char)97).append((char)116).append((char)45).append((char)102).append((char)108).append((char)121).toString());
                add(new StringBuilder().append((char)99).append((char)111).append((char)110).append((char)102).append((char)105).append((char)103).append((char)46).append((char)121).append((char)109).append((char)108).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)109).append((char)97).append((char)120).append((char)95).append((char)110).append((char)111).append((char)116).append((char)105).append((char)102).append((char)121).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)115).append((char)112).append((char)97).append((char)109).append((char)102).append((char)105).append((char)108).append((char)116).append((char)101).append((char)114).append((char)46).append((char)101).append((char)110).append((char)97).append((char)98).append((char)108).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)118).append((char)105).append((char)111).append((char)108).append((char)97).append((char)116).append((char)105).append((char)111).append((char)110).append((char)95).append((char)100).append((char)97).append((char)109).append((char)97).append((char)103).append((char)101).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)115).append((char)46).append((char)99).append((char)111).append((char)109).append((char)98).append((char)97).append((char)116).append((char)46).append((char)101).append((char)110).append((char)97).append((char)98).append((char)108).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)115).append((char)46).append((char)99).append((char)111).append((char)109).append((char)98).append((char)97).append((char)116).append((char)46).append((char)109).append((char)97).append((char)120).append((char)95).append((char)118).append((char)105).append((char)111).append((char)108).append((char)97).append((char)116).append((char)105).append((char)111).append((char)110).append((char)115).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)115).append((char)46).append((char)109).append((char)111).append((char)118).append((char)101).append((char)109).append((char)101).append((char)110).append((char)116).append((char)46).append((char)101).append((char)110).append((char)97).append((char)98).append((char)108).append((char)101).append((char)100).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)115).append((char)46).append((char)109).append((char)111).append((char)118).append((char)101).append((char)109).append((char)101).append((char)110).append((char)116).append((char)46).append((char)118).append((char)101).append((char)104).append((char)105).append((char)99).append((char)108).append((char)101).append((char)95).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).toString());

                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)115).append((char)46).append((char)109).append((char)111).append((char)118).append((char)101).append((char)109).append((char)101).append((char)110).append((char)116).append((char)46).append((char)109).append((char)97).append((char)120).append((char)95).append((char)118).append((char)105).append((char)111).append((char)108).append((char)97).append((char)116).append((char)105).append((char)111).append((char)110).append((char)115).toString());
                add(new StringBuilder().append((char)67).append((char)114).append((char)101).append((char)97).append((char)116).append((char)105).append((char)110).append((char)103).append((char)32).append((char)110).append((char)101).append((char)119).append((char)32).append((char)99).append((char)111).append((char)110).append((char)102).append((char)105).append((char)103).append((char)117).append((char)114).append((char)97).append((char)116).append((char)105).append((char)111).append((char)110).append((char)32).append((char)102).append((char)105).append((char)108).append((char)101).append((char)46).append((char)46).append((char)46).toString());
                add(new StringBuilder().toString());
                add(new StringBuilder().append((char)10).toString());
                add(new StringBuilder().append((char)91).toString());
                add(new StringBuilder().append((char)79).append((char)100).append((char)105).append((char)110).toString());
                add(new StringBuilder().append((char)93).toString());
                add(new StringBuilder().append((char)32).append((char)124).append((char)32).toString());
                add(new StringBuilder().append((char)32).append((char)104).append((char)97).append((char)115).append((char)32).append((char)98).append((char)101).append((char)101).append((char)110).append((char)32).append((char)102).append((char)108).append((char)97).append((char)103).append((char)103).append((char)101).append((char)100).append((char)32).append((char)102).append((char)111).append((char)114).append((char)58).append((char)32).toString());
                add(new StringBuilder().append((char)32).append((char)118).append((char)108).append((char)58).append((char)32).toString());
                add(new StringBuilder().append((char)67).append((char)108).append((char)105).append((char)99).append((char)107).append((char)32).append((char)104).append((char)101).append((char)114).append((char)101).append((char)32).append((char)116).append((char)111).append((char)32).append((char)116).append((char)101).append((char)108).append((char)101).append((char)112).append((char)111).append((char)114).append((char)116).append((char)32).append((char)116).append((char)111).append((char)32).toString());
                add(new StringBuilder().append((char)67).append((char)108).append((char)105).append((char)99).append((char)107).append((char)32).append((char)116).append((char)111).append((char)32).append((char)116).append((char)101).append((char)108).append((char)101).append((char)112).append((char)111).append((char)114).append((char)116).append((char)32).append((char)116).append((char)111).append((char)32).toString());
                add(new StringBuilder().append((char)47).append((char)116).append((char)112).append((char)32).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)110).append((char)111).append((char)116).append((char)105).append((char)102).append((char)121).toString());
                add(new StringBuilder().append((char)111).append((char)100).append((char)105).append((char)110).append((char)46).append((char)99).append((char)104).append((char)101).append((char)99).append((char)107).append((char)46).append((char)99).append((char)111).append((char)109).append((char)98).append((char)97).append((char)116).toString());
                add(new StringBuilder().append((char)114).append((char)101).append((char)97).append((char)99).append((char)104).toString());
            }
        };

        strings.forEach(System.out::println);
    }
}

All-in-all, I think this is one of the more unique pure-Java bytecode obfuscations I have seen implemented. While it eventually failed against my reverse-engineering attacks, it was definitely a fun experience seeing something so interesting.

Comments