编辑:似乎有些不同,请先阅读Edit2。
如何加载具有与查找名称不同的二进制名称的类?
我知道Java规范不允许这样做,但我面前有一个应用程序以某种方式完成它。
我有一个专有的服务器(运行JVM的Windows exe),创建它的公司不再存在。自从我最终遇到一个错误后,我开始提取类来修复它并同时将其移动到Linux。这些课程是混淆的,但这并不困扰我。
我操纵他们的顶级类加载器在调用defineClass
后转储每个类文件(它从加密存档中加载类)。在那里我看到它查找并定义了一个类P.x但是转储的类文件包含一个二进制名称为P.X的类(不匹配)(还有一些名为P.X $ Y的内部类,因此它们匹配二进制名称)。案例不匹配应在NoClassDefFoundError
中抛出defineClass()
,但由于我在defineClass()
之后直接转储该类,因此它显然没有。
在我理解之前,我有点害怕继续。因为它们可能包含一些陷阱,比如以后必须加载和检查的类。因此,如果我继续而不详细了解其工作原理,服务器可能会返回错误的结果。
从他们打包JVM的方式来看,我认为他们没有操纵JVM。从查看OpenJDK代码这样的东西是在C ++部分,所以他们不能只是替换一些类文件来实现它。
我只能想到3种不破解JVM的方法:
java.lang.ClassLoader
并将传入的名称设置为null
这样只有二进制名才重要。但这会起作用吗?ClassFileTransformer
。但这会起作用吗?我没有发现他们做的线索2)或3)。而且我不知道这些是如何工作的,因为代码会查找P.x,所以即使P.X会被加载,所以不确定这些会有用。
有人知道如何做到这一点吗?他们在Windows上使用32位JRE Hotspot 1.6.0_01-b06混合模式。
法律声明:在我的国家,我明显被允许修复我付了很多钱并且不再受支持的软件。
EDIT1:
我现在将我的小样本注入其代码中。它以NoClassDefFoundError
失败,因此它们不会操纵JVM或java.lang.ClassLoader,因此不会在全局范围内完成此测试。
EDIT2:
它可能是文件系统,但是在评论中建议的另一种方式(我覆盖文件)
由于我现在可以附加一个调试器,我看到了一些奇怪的东西:进入byte[]
的{{1}}包含正确的二进制名称。
如果存在P / x和P / X,我会覆盖一个,因为Windows FS不区分大小写。卫生署。如果我确定是这样的话会回来的。
答案 0 :(得分:1)
也许他们绕过了正常的Classloader#defineClass实现并改为使用sun.misc.Unsafe#defineClass?
答案 1 :(得分:0)
问题是Windows文件系统不区分大小写(但不是因为加载了类似注释中建议的类,而是因为我编写了文件转储)。
我用他们的名字写出了这些类,但由于P.x和P.X存在,我确实用P.X覆盖了P.x.
所以它只是在寻找我,好像是从文件P.x加载P.X,因为在我的转储文件中,由于该错误,P.x是P.X类。
谢谢大家,抱歉。