Java Class.forName 和混淆名称,java 找不到 class
Java Class.forName and obfuscated names, java fail to find class
我有一个 .jar 文件,其中包含不常见的混淆名称,混淆后的 class 看起来像:
nul.goto. ...\.. .final.
(注意:第一个间隙不正常 space,它是不间断的 space)
我无法通过 Class.forName
得到这个 class
我用这样的混淆制作了我自己的代码版本,即使我在混淆后使用 Class.forName(SomeClass.class.getName())
(它只是要测试的代码)它也不起作用 java 会抛出它找不到的错误这个class.
如何获得这样的 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 中的问题:class 那样只会加载失败并出现错误:
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 的版本工作正常。所以我决定深入挖掘一下原因。
在 class 加载器中,它只是进入 URLClassLoader
中非常简单的一段代码: name.replace('.', '/').concat(".class");
并通过本机方法 defineClass
从 jar 中加载 class 没有任何问题.
但是 Class.forName
直接进入本地方法并验证 class name: 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 */
}
}
这会阻止 class 加载。
我有一个 .jar 文件,其中包含不常见的混淆名称,混淆后的 class 看起来像:
nul.goto. ...\.. .final.
(注意:第一个间隙不正常 space,它是不间断的 space)
我无法通过 Class.forName
得到这个 class
我用这样的混淆制作了我自己的代码版本,即使我在混淆后使用 Class.forName(SomeClass.class.getName())
(它只是要测试的代码)它也不起作用 java 会抛出它找不到的错误这个class.
如何获得这样的 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 中的问题:class 那样只会加载失败并出现错误:
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 的版本工作正常。所以我决定深入挖掘一下原因。
在 class 加载器中,它只是进入 URLClassLoader
中非常简单的一段代码: name.replace('.', '/').concat(".class");
并通过本机方法 defineClass
从 jar 中加载 class 没有任何问题.
但是 Class.forName
直接进入本地方法并验证 class name: 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 */
}
}
这会阻止 class 加载。