Java Class.forName 和混淆名称,java 找不到类

标签 java class reflection obfuscation deobfuscation

我有 .jar 文件,其名称不常见,混淆后的类如下所示:
nul.goto。 ...\\.. .final. (注意:第一个间隙不是普通空间,而是不间断空间)
我无法通过 Class.forName 获取此类

我用这样的混淆制作了自己的代码版本,即使我在混淆后使用 Class.forName(SomeClass.class.getName()) (这只是要测试的代码),它也不起作用java会抛出找不到这个类的错误。

如何获得这样的类(class)?

最佳答案

所以过了一段时间我决定回到这个,我使用这样的代码进行测试:
pckg.Main:

public static void main(String[] args) {
    Class<ObfuscateMe> obfuscateMeClass = ObfuscateMe.class;
    System.out.println("Class name: `" + obfuscateMeClass + "`");
    try {
        System.out.println("Class.forName: " + Class.forName(obfuscateMeClass.getName()));
    }
    catch (ClassNotFoundException exception) { System.out.println("Can't find class using Class.forName: `" + obfuscateMeClass.getName() + "`"); }
    try {
        System.out.println("ClassLoader.loadClass: " + Main.class.getClassLoader().loadClass(obfuscateMeClass.getName()));
    }
    catch (ClassNotFoundException exception) { System.out.println("Can't find class using ClassLoader.loadClass: `" + obfuscateMeClass.getName() + "`"); }
}

使用 ProGuard 进行混淆:

-injars 'B:\Java\ProGuardTestApp\test.jar'
-outjars 'B:\Java\ProGuardTestApp\testObf.jar'
-dontshrink
-dontoptimize
-classobfuscationdictionary 'B:\Java\ProGuardTestApp\obfs.txt' # contains just one line "final"
-repackageclasses 'nul.goto. ...\\.. .final.'
-ignorewarnings
-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

首先我注意到这在 java 11 中不再是问题:这样的类将无法加载并出现错误:

Error: LinkageError occurred while loading main class pckg.Main
    java.lang.ClassFormatError: Illegal class name "nul/goto/▒///\\// /final//final" in 
class file pckg/Main

但是forNameloadClass之间仍然存在不一致,forName仍然会抛出ClassNotFoundException,但loadClass会抛出ClassFormatError。 OpenJ9 在这两种情况下都会抛出 ClassFormatError

在 java 8 热点上它工作得很好,就像@Holger 在评论中建议的那样,带有 ClassLoader 的版本工作得很好。所以我决定深入挖掘一下,找出原因。 在类加载器中,它只是转到 URLClassLoader 中非常简单的代码:name.replace('.', '/').concat(".class"); 并通过 native 方法 defineClass 从 jar 加载该类,没有任何问题。
但是 Class.forName 直接进入 native 方法并验证类名:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/Class.c

if (VerifyFixClassname(clname) == JNI_TRUE) {
    /* slashes present in clname, use name b4 translation for exception */
    (*env)->GetStringUTFRegion(env, classname, 0, unicode_len, clname);
    JNU_ThrowClassNotFoundException(env, clname);
    goto done;
}

if (!VerifyClassname(clname, JNI_TRUE)) {  /* expects slashed name */
    JNU_ThrowClassNotFoundException(env, clname);
    goto done;
}

因此,所有.都更改为/,然后在VerifyClassname中我们可以找到:

if (slash_okay && ch == '/' && last_ch) {
    if (last_ch == '/') {
        return 0;       /* Don't permit consecutive slashes */
    }
}  

源代码:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/common/check_format.c#l155

这会阻止类加载。

关于Java Class.forName 和混淆名称,java 找不到类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28527196/

相关文章:

c++ 如何将模板应用于模板类的子/友元?

c++ - 使用类指针拆分项目

javascript - TypeScript接口(interface)签名 "(): string"

c# - C#中如何通过反射获取属性值

Java 变压器空元素

java - "Exception in thread "主要 "java.lang.NullPointerException"

java - 理解 [[某些 Java 源代码中引用的 I.class

与类类型的快速类型比较

java - void cv::cvtColor(cv::InputArray Android) 断言失败(scn == 3 || scn == 4)

java - 如何安全地处理 Java 的包装原语