关于将JAR/Class转换为DLL并注入禁用Attach与Agent的运行中Java程序的技术咨询
Great question—this is a super tricky scenario when the standard Attach/Agent APIs are off-limits, especially for games like Minecraft where those mechanisms might be blocked or restricted. Let’s dive into alternative approaches beyond the j2d tool you mentioned:
Native Code Injection with JVM Internal Hooks
This is likely the same category as the Thanatos DLL you referenced. The core idea is to inject a custom native DLL into the target Java process, then leverage undocumented JVM internal functions to load your JAR/class files, bypassing the official Attach API.
- How it works: You’ll need to reverse-engineer the target JVM’s (e.g., HotSpot for Minecraft) memory layout to find critical pointers like
JNIEnvor the globalJVMinstance. Once you have access to these, you can call JNI functions directly:- Use
DefineClassto load raw class bytecode into the target class loader. - Use reflection (via JNI) to invoke
URLClassLoader.addURLto load an entire JAR file (you can even load the JAR from memory if needed).
- Use
- Caveat: This is highly version-dependent—each JVM update can change internal structures, so your code will only work for specific JVM versions (like Minecraft 1.12.2’s bundled JVM).
Memory Editing & Bytecode Patching
For advanced use cases, you can directly modify the target Java process’s memory to inject code or add new classes.
- How it works:
- Use a memory scanner (or custom tool) to locate the JVM’s metaspace (where class definitions are stored).
- Patch existing class bytecode (e.g., replace a method’s code with your own) or insert entirely new class structures into the metaspace.
- Trigger the JVM to reload the modified class (though this can be risky and may cause crashes if done incorrectly).
- Caveat: This is extremely fragile and requires deep knowledge of JVM memory internals. It’s rarely used for production-grade injection, but common in game modding scenarios.
Custom Class Loader Injection via Native Code
This approach combines native injection with Java’s built-in class loading system for more reliability:
- How it works:
- Inject your native DLL into the Java process and obtain a valid
JNIEnvpointer. - Use JNI to reflectively instantiate a custom
URLClassLoader(or extend the target app’s existing class loader). - Use reflection to call the protected
addURLmethod on the class loader, pointing it to your JAR file (or an in-memory JAR buffer). - Load your target classes via this class loader, which will execute them in the context of the running Java app.
- Inject your native DLL into the Java process and obtain a valid
- Advantage: This leverages Java’s official class loading mechanisms, making it more stable than raw memory editing.
JVMTI Agent Injection (Without Attach API)
JVMTI is usually loaded via the Attach API or command-line arguments, but you can manually load a JVMTI agent DLL directly into the process:
- How it works:
- Inject your DLL into the Java process, then locate the JVM instance pointer (e.g.,
gHotSpotVMin HotSpot). - Load your JVMTI agent DLL using
LoadLibrary, then retrieve the address of theAgent_OnLoadorAgent_OnAttachfunction. - Call that function directly, passing the JVM instance and necessary arguments to initialize JVMTI.
- Use JVMTI’s official APIs like
RedefineClassesorDefineClassto inject your bytecode.
- Inject your DLL into the Java process, then locate the JVM instance pointer (e.g.,
- Caveat: Like the first approach, this requires knowing the JVM’s internal structure to find the JVM instance pointer.
A Note on Thanatos & j2d
Tools like Thanatos and j2d are essentially pre-built implementations of the native hook approach. They’re tailored to specific JVM versions (like Minecraft 1.12.2’s JVM) and hide the low-level reverse-engineering work from users. The lack of public documentation is because they rely on undocumented JVM internals, which Oracle/OpenJDK don’t support and may change without warning.
If you’re looking to build something similar, start by reverse-engineering the exact JVM version your target app uses—study its memory layout, find the JNIEnv and JVM pointers, and experiment with calling JNI functions directly from your injected DLL.
内容的提问来源于stack exchange,提问作者志成zhi_cheng

