连接到已在运行的JVM

8
有没有一种方法可以附加到已经运行的JVM?
例如,在JNI中,您可以使用JNI_CreateJavaVM创建一个VM并运行一个jar文件,并检查其所有类。
但是,如果该jar文件已经在运行中,我找不到一种方式来附加到其JVM并与其类通信或获取其env指针。
另一个问题是,如果该jar文件加载了我的本地库(.dll),并且我想在.dll内部创建一个JVM,我也无法这样做。也不能够附加到该jar文件的当前JVM,除非该jar文件调用我的函数。
以下是Java端的示例:
class Foo
{
    static {loadLibrary("Foo")}
}

在 C++ 方面:

void Foo()
{
    //CreateJVM
    //Attach to the current process..
    //Call function from the jar that loaded me.
}

如果没有jar文件先调用Foo,就无法完成此操作。

有什么想法吗?是否没有办法获取当前JVM或者连接到它或外部JVM实例?


这是为Windows还是Linux或其他操作系统?您使用哪个C调试器/集成开发环境? - cup
我可能遗漏了一些东西,但是你不能只是打开调试端口并附加到它吗?在调试器中暂停虚拟机并期望一切? - WeMakeSoftware
我正在使用Codeblocks,且我的操作系统是Windows。我不确定您所说的打开调试器并点击暂停是什么意思。 - Brandon
@CantChooseUsernames 如果你成功使用了我的答案,请告诉我。它可以正常工作。 - manuell
2个回答

16

是的,你可以。

1) 注入DLL到托管JVM的进程中(例如,java.exe, 或 javaw.exe, 或 iexplore.exe)。一种常见的注入技术是使用SetWindowsHookEx

2) 在DLL中,使用GetModuleHandle获取jvm.dll的模块句柄

3) 使用GetProcAddress获取JNI_GetCreatedJavaVMs函数的地址

4) 调用该函数,在成功时,使用JavaVM结构中的AttachCurrentThread函数指针将线程附加到第一个找到的JVM上。

5) 完成。

有用的链接: 调用API


是的!这个可行 :D 我没有使用 SetWindowsHook。相反,我只是使用了 CreateThreadLoadLibrary 的组合来进行注入。尽管如此,它能够工作 =) 我很高兴! - Brandon
@CantChooseUsernames 祝你编程愉快!(注意JNI内存泄漏问题 :-) - manuell
@CantChooseUsernames 顺便提一下:使用 SetWindowsHookEx 函数时,你可以选择附加到“GUI”线程。这可能很重要。 - manuell

1

不行。JNI仅支持两种模式:

  • 你的非Java程序创建JVM。
  • 你的Java程序调用本地方法。

如果你需要在其他情况下进行通信,你需要使用其他机制。Web服务是一种直接的方法。


2
你可以将一个动态链接库注入到一个正在运行的Java进程中,并附加到JVM。请参见我的答案。在Windows上运行良好。 - manuell
同样适用于Linux,当然会有一些小差异。 - uglibubla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接