我有 .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
但是forName
和loadClass
之间仍然存在不一致,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 */
}
}
这会阻止类加载。
关于Java Class.forName 和混淆名称,java 找不到类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28527196/