情况
你好,我有两个问题。
情况是我正在编写 Windows 的 Java API,它还提供用于将代码注入(inject)进程然后操作目标的工具。我已经实现了注入(inject)部分,例如将一个 jar 注入(inject)另一个 jar。此时我的 jar 被调用(而目标已经在运行时)并在完整的静态上下文中启动。
目标与问题
从这里我有两个目标:
- 我想与目标对象互动,因此我需要引用资料。对于许多对象来说,这已经成为可能,因为它们提供对其实例的静态访问。例如,awt.Frames#getFrames() 提供对所有创建的 Frame 对象的访问。但是,如果有可能在堆上访问任意对象,那就太棒了。类似于“Heap#getAllObjectInstances()”。
- 给定一个对象实例,我想连接到该对象的任意函数。例如,每当 BufferStrategy#show() 被调用时,我希望它首先调用另一个方法。
所以我总结存在的问题如下:
- 如何从静态上下文中获取任意对象引用?
- 如何连接到任意函数?
备注
到目前为止我做了什么,评论和想法:
- JDI(Java 调试器接口(interface))通过 VirtualMachine#allClasses() -> ReferenceType#instances(0) 提供了这样的方法。但是 JDI 需要使用额外的调试参数启动目标 JVM,这我没有选择。可以深入到低级并使用内存工具分析堆,但我希望有人知道一种更高级的方法。使用 Windows API 对我来说是一个选择,因为我熟悉 JNA/JNI,但我不知道这样的工具。
- 最后的办法是对 C 代码使用 IAT Hook ,这是一种非常底层的方法,我想避免这种情况。正如我可以假设此时有一个对象引用,Reflection API 是否提供了一种方法来更改对象方法?或者至少简单地提供一个 Hook 机制?
请注意,更改目标代码对我来说当然不是一个选项。而且它已经在运行时,因此 ByteCode-Manipulation 也可以是一个选项。
场景
这会派上用场的场景:
目标是作为 jar 部署的游戏。它使用 BufferStrategy 类以 Double-Buffer-Strategy 呈现。它使用 BufferStrategy#show() 显示图像。我们将我们的 jar 注入(inject)游戏中,并喜欢绘制带有附加信息的叠加层。为此,我们获得对使用过的 BufferStrategy 的引用,并连接到它的 show 方法。以便它每次被调用时都调用我们的 drawOverlay 方法,然后我们返回到原始的 show-method。
最佳答案
您需要的是 JVMTI 代理 - 一个使用 JVM Tool Interface 的 native 库.
可以使用 Attach API 将代理动态附加到正在运行的 VM .
参见 VirtualMachine.loadAgentPath .
要获取给定类的所有实例,请使用 JVMTI IterateOverInstancesOfClass功能。
查看related question了解详情。要拦截外部类的方法,您需要 JVMTI RetransformClasses应用程序接口(interface)。同样可以通过使用 Java 级别的检测 API 来实现,参见 Instrumentation.retransformClasses .
JVMTI级方法拦截的例子引用Oracle JDK demos and samples包中的demo/jvmti/mtrace
使用像 Byte Buddy 这样的字节码操作库,Java 级别的检测会更容易。 .
关于Java:方法 Hook 和查找对象实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38042962/