Java 类加载器:如何使用不同于查找名称的二进制名称加载 class?

Java Classloader: How to load class with binary name different from looked up name?

编辑:好像有点不一样,先读一下Edit2。

如何加载二进制名称与查找名称不同的 class?

我知道 Java 规范不允许这样做,但我面前有一个应用程序以某种方式做到了这一点。

我有一个专有服务器(Windows 运行 JVM 的 exe),创建它的公司已不存在。因为我终于遇到了一个错误,所以我开始提取 classes 来修复它,同时将它移动到 Linux。 classes 被混淆了,但这不是困扰我的问题。

我操纵他们的顶级类加载器在他们调用 defineClass 后转储每个 class 文件(它从加密存档加载 classes)。在那里我看到它寻找并定义了一个 class P.x 但是转储的 class 文件包含一个 class 二进制名称 P.X (大小写不匹配)(有内部 classes 命名为 P.X$Y,因此它们匹配二进制名称)。大小写不匹配应该在 defineClass() 中抛出 NoClassDefFoundError,但由于我直接在 defineClass() 之后转储了 class,所以显然不会。

在我理解之前,我有点不敢继续。因为他们可能包含了一些陷阱,比如 classes 不能加载并稍后检查。因此,如果我只是继续而不详细了解其工作原理,服务器可能会 return 错误结果。

从他们打包 JVM 的方式来看,我认为他们没有操纵 JVM。从 OpenJDK 代码来看,这些东西在 C++ 部分,所以他们不能仅仅替换一些 class 文件来实现它。

在不破解JVM的情况下,我只能想到3种方法:

  1. 我希望它可能是一些秘密的 VM arg,但到目前为止我什么也没发现:https://web.archive.org/web/20100130070337/http://www.md.pp.ru/~eu/jdk6options.html
  2. 替换java.lang.ClassLoader并将传入的名称设置为空 所以只有二进制名称很重要。但这真的有用吗?
  3. 以某种方式使用 ClassFileTransformer。但这真的有用吗?

我没有找到他们做 2) 或 3) 的线索。而且我不知道这些是如何工作的,因为代码会查找 P.x 所以即使 P.X 会被加载,所以不确定这些是否有帮助。

有人知道如何做到这一点吗?他们在 Windows.

上使用 32 位 JRE Hotspot 1.6.0_01-b06,混合模式

法律说明:在我的国家,我被明确允许修复一个我花了很多钱买的软件,但它不再受支持。

编辑 1:
我现在将做同样事情的我的小样本注入到他们的代码中。它失败并显示 NoClassDefFoundError,因此他们不会操纵 JVM 或 java.lang.ClassLoader,因此不会在全局范围内完成此测试。

编辑2:
它可能是文件系统,但正如评论中所建议的那样(我覆盖文件)。
因为我现在可以附加调试器,所以我看到了一些奇怪的东西:进入 defineClass()byte[] 包含正确的二进制名称。
如果 P/x 和 P/X 存在,我会覆盖一个,因为 Windows FS 不区分大小写。呵呵。如果我确定是这样的话,我会回来的。

也许他们绕过了正常的 Classloader#defineClass 实现并使用 sun.misc.Unsafe#defineClass 代替?

问题是 Windows 文件系统不区分大小写(但不是因为像评论中建议的那样加载 classes,而是因为我写了文件转储)。

我把class的名字写出来了,但是因为P.x和P.X存在,所以我用P.X覆盖了P.x。

所以它只寻找我,好像它正在从文件 P.x 加载 P.X,因为在我转储的文件中 P.x 是 class P.X因为那个错误。

谢谢大家,抱歉。