# Alle Referenzen zu einer Klasse aus Java Bytecode ersetzt, JVM sucht trotzdem diese Klasse



## TheCreeper202 (17. Mrz 2015)

Hallo Java-Forum!

Ich arbeite zurzeit an einem Real-Time Deobfuscator für Minecraft, welcher dort als Main-Class aufgerufen wird und die Main-Class durch einen speziellen ClassLoader lädt und startet. Dieser ClassLoader durchläuft den Bytecode sämtlicher Klassen und deobfuskiert ihn. Die Ausgabe Dateien werden zwischengespeichert und sehen im Bytecode Editor vollkommen korrekt aus. Doch beim Start versucht Java "bsu" zu laden. "bsu" ist der obfuskierte Name für "net.minecraft.client.Minecraft". Eigentlich sind alle Referenzen zu "bsu" auch durch "net.minecraft.client.Minecraft" ersetzt, doch die JVM versucht trotzdem "bsu" zu laden.
Der Fehler, dass "bsu" nicht geladen werden kann tritt in der folgenden Datei in Zeile 41 auf bei "Minecraft.getSystemTime()":

```
package net.minecraft.client.main;

import com.google.gson.GsonBuilder;
import com.mojang.authlib.properties.PropertyMap;
import com.mojang.authlib.properties.PropertyMap.Serializer;
import java.io.File;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.util.List;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.NonOptionArgumentSpec;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Session;

public class Main
{
    private static final String __OBFID = "CL_00001461";

    public static void main(String[] p_main_0_)
    {
        System.setProperty("java.net.preferIPv4Stack", "true");
        OptionParser var1 = new OptionParser();
        var1.allowsUnrecognizedOptions();
        var1.accepts("demo");
        var1.accepts("fullscreen");
        var1.accepts("checkGlErrors");
        ArgumentAcceptingOptionSpec var2 = var1.accepts("server").withRequiredArg();
        ArgumentAcceptingOptionSpec var3 = var1.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(25565), new Integer[0]);
        ArgumentAcceptingOptionSpec var4 = var1.accepts("gameDir").withRequiredArg().ofType(File.class).defaultsTo(new File("."), new File[0]);
        ArgumentAcceptingOptionSpec var5 = var1.accepts("assetsDir").withRequiredArg().ofType(File.class);
        ArgumentAcceptingOptionSpec var6 = var1.accepts("resourcePackDir").withRequiredArg().ofType(File.class);
        ArgumentAcceptingOptionSpec var7 = var1.accepts("proxyHost").withRequiredArg();
        ArgumentAcceptingOptionSpec var8 = var1.accepts("proxyPort").withRequiredArg().defaultsTo("8080", new String[0]).ofType(Integer.class);
        ArgumentAcceptingOptionSpec var9 = var1.accepts("proxyUser").withRequiredArg();
        ArgumentAcceptingOptionSpec var10 = var1.accepts("proxyPass").withRequiredArg();
        ArgumentAcceptingOptionSpec var11 = var1.accepts("username").withRequiredArg().defaultsTo("Player" + Minecraft.getSystemTime() % 1000L, new String[0]);
        ArgumentAcceptingOptionSpec var12 = var1.accepts("uuid").withRequiredArg();
        ArgumentAcceptingOptionSpec var13 = var1.accepts("accessToken").withRequiredArg().required();
        ArgumentAcceptingOptionSpec var14 = var1.accepts("version").withRequiredArg().required();
        ArgumentAcceptingOptionSpec var15 = var1.accepts("width").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(854), new Integer[0]);
        ArgumentAcceptingOptionSpec var16 = var1.accepts("height").withRequiredArg().ofType(Integer.class).defaultsTo(Integer.valueOf(480), new Integer[0]);
        ArgumentAcceptingOptionSpec var17 = var1.accepts("userProperties").withRequiredArg().required();
        ArgumentAcceptingOptionSpec var18 = var1.accepts("assetIndex").withRequiredArg();
        ArgumentAcceptingOptionSpec var19 = var1.accepts("userType").withRequiredArg().defaultsTo("legacy", new String[0]);
        NonOptionArgumentSpec var20 = var1.nonOptions();
        OptionSet var21 = var1.parse(p_main_0_);
        List var22 = var21.valuesOf(var20);

        if (!var22.isEmpty())
        {
            System.out.println("Completely ignored arguments: " + var22);
        }

        String var23 = (String)var21.valueOf(var7);
        Proxy var24 = Proxy.NO_PROXY;

        if (var23 != null)
        {
            try
            {
                var24 = new Proxy(Type.SOCKS, new InetSocketAddress(var23, ((Integer)var21.valueOf(var8)).intValue()));
            }
            catch (Exception var43)
            {
                ;
            }
        }

        final String var25 = (String)var21.valueOf(var9);
        final String var26 = (String)var21.valueOf(var10);

        if (!var24.equals(Proxy.NO_PROXY) && func_110121_a(var25) && func_110121_a(var26))
        {
            Authenticator.setDefault(new Authenticator()
            {
                private static final String __OBFID = "CL_00000828";
                protected PasswordAuthentication getPasswordAuthentication()
                {
                    return new PasswordAuthentication(var25, var26.toCharArray());
                }
            });
        }

        int var27 = ((Integer)var21.valueOf(var15)).intValue();
        int var28 = ((Integer)var21.valueOf(var16)).intValue();
        boolean var29 = var21.has("fullscreen");
        boolean var30 = var21.has("checkGlErrors");
        boolean var31 = var21.has("demo");
        String var32 = (String)var21.valueOf(var14);
        PropertyMap var33 = (PropertyMap)(new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new Serializer()).create().fromJson((String)var21.valueOf(var17), PropertyMap.class);
        File var34 = (File)var21.valueOf(var4);
        File var35 = var21.has(var5) ? (File)var21.valueOf(var5) : new File(var34, "assets/");
        File var36 = var21.has(var6) ? (File)var21.valueOf(var6) : new File(var34, "resourcepacks/");
        String var37 = var21.has(var12) ? (String)var12.value(var21) : (String)var11.value(var21);
        String var38 = var21.has(var18) ? (String)var18.value(var21) : null;
        String var39 = (String)var21.valueOf(var2);
        Integer var40 = (Integer)var21.valueOf(var3);
        Session var41 = new Session((String)var11.value(var21), var37, (String)var13.value(var21), (String)var19.value(var21));
        GameConfiguration var42 = new GameConfiguration(new GameConfiguration.UserInformation(var41, var33, var24), new GameConfiguration.DisplayInformation(var27, var28, var29, var30), new GameConfiguration.FolderInformation(var34, var36, var35, var38), new GameConfiguration.GameInformation(var31, var32), new GameConfiguration.ServerInformation(var39, var40.intValue()));
        Runtime.getRuntime().addShutdownHook(new Thread("Client Shutdown Thread")
        {
            private static final String __OBFID = "CL_00000829";
            public void run()
            {
                Minecraft.stopIntegratedServer();
            }
        });
        Thread.currentThread().setName("Client thread");
        (new Minecraft(var42)).run();
    }

    private static boolean func_110121_a(String p_110121_0_)
    {
        return p_110121_0_ != null && !p_110121_0_.isEmpty();
    }
}
```
Der ClassLoader bekommt folgende anfragen:

```
<Zu ladende Klasse> -> <Datei, die der ClassLoader läd>
net.minecraft.client.main.Main -> net/minecraft/client/main/Main.class
joptsimple.OptionSpec -> joptsimple/OptionSpec.class
net.minecraft.client.main.Main$1 -> cbl.class
net.minecraft.client.main.Main$2 -> cbm.class
joptsimple.OptionParser -> joptsimple/OptionParser.class
joptsimple.OptionDeclarer -> joptsimple/OptionDeclarer.class
joptsimple.AbstractOptionSpec -> joptsimple/AbstractOptionSpec.class
joptsimple.OptionDescriptor -> joptsimple/OptionDescriptor.class
joptsimple.AlternativeLongOptionSpec -> joptsimple/AlternativeLongOptionSpec.class
joptsimple.ArgumentAcceptingOptionSpec -> joptsimple/ArgumentAcceptingOptionSpec.class
joptsimple.OptionException -> joptsimple/OptionException.class
joptsimple.UnconfiguredOptionException -> joptsimple/UnconfiguredOptionException.class
joptsimple.MissingRequiredOptionException -> joptsimple/MissingRequiredOptionException.class
joptsimple.NonOptionArgumentSpec -> joptsimple/NonOptionArgumentSpec.class
joptsimple.HelpFormatter -> joptsimple/HelpFormatter.class
joptsimple.BuiltinHelpFormatter -> joptsimple/BuiltinHelpFormatter.class
joptsimple.internal.Rows -> joptsimple/internal/Rows.class
joptsimple.internal.AbbreviationMap -> joptsimple/internal/AbbreviationMap.class
joptsimple.OptionParserState -> joptsimple/OptionParserState.class
joptsimple.OptionParserState$1 -> joptsimple/OptionParserState$1.class
joptsimple.OptionParserState$2 -> joptsimple/OptionParserState$2.class
joptsimple.UnrecognizedOptionException -> joptsimple/UnrecognizedOptionException.class
joptsimple.ValueConversionException -> joptsimple/ValueConversionException.class
joptsimple.internal.ReflectionException -> joptsimple/internal/ReflectionException.class
joptsimple.OptionArgumentConversionException -> joptsimple/OptionArgumentConversionException.class
joptsimple.ParserRules -> joptsimple/ParserRules.class
joptsimple.IllegalOptionSpecificationException -> joptsimple/IllegalOptionSpecificationException.class
joptsimple.OptionSpecBuilder -> joptsimple/OptionSpecBuilder.class
joptsimple.NoArgumentOptionSpec -> joptsimple/NoArgumentOptionSpec.class
joptsimple.OptionalArgumentOptionSpec -> joptsimple/OptionalArgumentOptionSpec.class
joptsimple.RequiredArgumentOptionSpec -> joptsimple/RequiredArgumentOptionSpec.class
joptsimple.OptionMissingRequiredArgumentException -> joptsimple/OptionMissingRequiredArgumentException.class
joptsimple.internal.Reflection -> joptsimple/internal/Reflection.class
joptsimple.ValueConverter -> joptsimple/ValueConverter.class
joptsimple.internal.Classes -> joptsimple/internal/Classes.class
joptsimple.internal.MethodInvokingValueConverter -> joptsimple/internal/MethodInvokingValueConverter.class
joptsimple.internal.Objects -> joptsimple/internal/Objects.class
joptsimple.internal.ConstructorInvokingValueConverter -> joptsimple/internal/ConstructorInvokingValueConverter.class
net.minecraft.client.Minecraft -> bsu.class
net.minecraft.util.IThreadListener -> vn.class
net.minecraft.profiler.IPlayerUsage -> wd.class
bsu -> bsu.class
```
Dort sieht man, dass der ClassLoader nach "bsu" angefragt wird. Wie kann das sein und wie kann ich das lösen?

Hier sieht man auch nochmal einen Ausschnitt aus dem Bytecode von der deobfuskierten Main.class:

```
aload_1
ldc "username"
invokevirtual joptsimple/OptionParser/accepts(Ljava/lang/String;)Ljoptsimple/OptionSpecBuilder;
invokevirtual joptsimple/OptionSpecBuilder/withRequiredArg()Ljoptsimple/ArgumentAcceptingOptionSpec;
new java/lang/StringBuilder
dup
ldc "Player"
invokespecial java/lang/StringBuilder/<init>(Ljava/lang/String;)V
invokestatic net/minecraft/client/Minecraft/getSystemTime()J
ldc2_w 1000
lrem
invokevirtual java/lang/StringBuilder/append(J)Ljava/lang/StringBuilder;
invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;
iconst_0
anewarray java/lang/String
invokevirtual joptsimple/ArgumentAcceptingOptionSpec/defaultsTo(Ljava/lang/Object;[Ljava/lang/Object;)Ljoptsimple/ArgumentAcceptingOptionSpec;
astore 11
```

Danke im Voraus!

Liebe Grüße,
Roman


----------



## TheCreeper202 (20. Mrz 2015)

Ich hatte vergessen im Local Variable Table die Referenzen zu ändern. Jetzt habe ich das folgende Problem:

Ich habe dies in meinem RemappingHelper:

```
if (mn.maxLocals > 0 && (mn.localVariables == null
		|| mn.localVariables.size() < mn.maxLocals)) {
	throw new RuntimeException("Data corruption: " +
		cn.name + "." + mn.name + mn.desc);
}
if (mn.localVariables != null) {
	for (Object obj2 : mn.localVariables) {
		LocalVariableNode lvn = (LocalVariableNode) obj2;
		lvn.desc = remapDesc(remapper, lvn.desc);
	}
}
```
Aber dabei kommt der folgende Error:

```
Caused by: java.lang.RuntimeException: Data corruption: net/minecraft/client/main/Main$1.<init>(Ljava/lang/String;Ljava/lang/String;)V
	at cbop.hook.launcher.RemappingHelper.remapClass(RemappingHelper.java:127)
	at cbop.hook.launcher.LaunchClassLoader.runTransformers(LaunchClassLoader.java:287)
	at cbop.hook.launcher.LaunchClassLoader.findClass(LaunchClassLoader.java:202)
	... 9 more
```
Ich versteh es einfach nicht :'(


----------

