You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 13:39:01