使用JNA获取war3.exe进程内game.dll模块基地址的相关问题咨询
问题根因说明
- 你最初调用
GetModuleHandle返回null是因为这个API的作用域是当前调用进程,你是在Java进程内调用它,拿的是Java进程加载的game.dll,自然不存在,返回null。 - 枚举模块只能拿到5个、看不到
game.dll的核心原因是进程位数不匹配:如果你的Java程序运行的JDK位数(32/64位)和War3进程的位数不一致,跨位数调用EnumProcessModules只能枚举到少量系统级公共模块,目标进程的业务模块都会看不到。 - 你现在代码输出大量null的原因是你创建了长度为1024的模块数组,但实际返回的有效模块数量远小于1024,超出实际数量的位置都是null值。你没有正确读取
EnumProcessModules输出的实际模块数参数导致的。
解决方案
第一步:对齐进程位数
先确认你的Warcraft III进程是32位还是64位,下载对应位数的JDK运行你的代码,保证两者位数一致,否则无法正常枚举模块。
第二步:修正代码,实现模块名匹配
你需要调用Psapi.INSTANCE.GetModuleBaseName方法,传入进程句柄和每个模块句柄,获取模块名称,和game.dll做匹配即可拿到对应的基地址。修正后的代码示例如下:
import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.Psapi; import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinDef.HMODULE; import com.sun.jna.platform.win32.WinNT.HANDLE; import com.sun.jna.ptr.IntByReference; import static com.sun.jna.platform.win32.WinNT.PROCESS_QUERY_INFORMATION; import static com.sun.jna.platform.win32.WinNT.PROCESS_VM_READ; public class MemoryHandler { static final User32 user32 = User32.INSTANCE; static final Psapi psapi = Psapi.INSTANCE; static final Kernel32 kernel32 = Kernel32.INSTANCE; public static void main(String[] args) { int pid = getProcessId("Warcraft III"); // 枚举模块不需要PROCESS_ALL_ACCESS,用更小的权限即可,避免权限不足问题 HANDLE process = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if (process == null) { System.out.println("打开进程失败,错误码:" + kernel32.GetLastError()); return; } HMODULE[] hMods = new HMODULE[1024]; IntByReference lpcbNeeded = new IntByReference(); // 传入空的lpcbNeeded接收实际返回的模块字节数 if (!psapi.EnumProcessModules(process, hMods, hMods.length * Native.getNativeSize(HMODULE.class), lpcbNeeded)) { System.out.println("枚举模块失败,错误码:" + kernel32.GetLastError()); kernel32.CloseHandle(process); return; } // 计算实际有效模块数量 int moduleCount = lpcbNeeded.getValue() / Native.getNativeSize(HMODULE.class); char[] moduleNameBuf = new char[256]; Long gameDllBase = null; for (int i = 0; i < moduleCount; i++) { HMODULE hMod = hMods[i]; // 获取模块名称 psapi.GetModuleBaseName(process, hMod, moduleNameBuf, moduleNameBuf.length); String moduleName = Native.toString(moduleNameBuf); if ("game.dll".equalsIgnoreCase(moduleName)) { // 模块基地址就是HMODULE的指针值 gameDllBase = Pointer.nativeValue(hMod.getPointer()); System.out.printf("找到game.dll,基地址:0x%x%n", gameDllBase); break; } } if (gameDllBase == null) { System.out.println("未找到game.dll模块,请确认进程位数匹配且进程已正确加载该模块"); } // 记得关闭进程句柄,避免资源泄漏 kernel32.CloseHandle(process); } public static int getProcessId(String windowName) { IntByReference pid = new IntByReference(0); user32.GetWindowThreadProcessId(user32.FindWindow(null, windowName), pid); return pid.getValue(); } }
额外说明
- 如果对齐位数后还是拿不到完整模块,可尝试使用
EnumProcessModulesEx方法,传入LIST_MODULES_ALL参数枚举所有类型的模块。 - 优先用
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ权限,不要用PROCESS_ALL_ACCESS,高权限会被系统安全策略拦截,反而容易打开进程失败。
内容的提问来源于stack exchange,提问作者Neo
相关产品推荐
相关产品推荐

