【问题标题】:Getting base address of dll of specific process using JNA使用JNA获取特定进程的dll基地址
【发布时间】:2021-09-13 17:43:51
【问题描述】:

已更新:在问题的机器人处查看更新


我想得到game.dll 的基地址,它位于war3.exe 进程中。 我正在尝试通过 JNA 库版本 5.9.0 来实现,但没有成功。

我遇到的问题:我无法从 war3.exe 进程中获取 game.dll 模块。 我尝试使用它:

int pid = getProcessId("Warcraft III");
openProcess(PROCESS_ALL_ACCESS, pid);
WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle("game.dll")

但是hMod 的结果是null

我还尝试获取 war3.exe 进程拥有的所有模块。如您所见,它仅包含 5 个模块,并且不包含 game.dll。但是当我通过 Process Explorer 打开 war3.exe 时,我看到的肯定不止 5 个。

使用 Intellij Idea 执行:

取自 Process Explorer:

请分享您的意见和想法,为什么我只能从 IDE 获得 5 个模块。

任何关于如何通过 JNA 获取 game.dll 模块及其基地址的建议将不胜感激。


更新: 根据雷米的回答,我再次尝试使用EnumProcessModules()。 这是我的代码 sn-p:

import com.sun.jna.Pointer;
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 java.util.Arrays;
import java.util.List;

import static com.sun.jna.platform.win32.WinNT.PROCESS_ALL_ACCESS;
import static handler.memory.MemoryHandler.openProcess;

public class MemoryHandler {
    static final User32 user32 = User32.INSTANCE;
    static final Psapi psapi = Psapi.INSTANCE;

    public static void main(String[] args) {
        int pid = getProcessId("Warcraft III");
        HANDLE process = openProcess(PROCESS_ALL_ACCESS, pid);

        HMODULE[] hMods = new HMODULE[1024];
        psapi.EnumProcessModules(process, hMods, hMods.length, new IntByReference(1024));

        List<HMODULE> hModList = Arrays.asList(hMods);
        hModList.forEach(hMod ->
                System.out.println(Pointer.nativeValue(hMod.getPointer())));
    }

    public static int getProcessId(String window) {
        IntByReference pid = new IntByReference(0);
        user32.GetWindowThreadProcessId(user32.FindWindow(null, window), pid);

        return pid.getValue();
    }
}

结果如下:

据我所知,我得到了一些指示。但是我应该如何理解他们中的哪一个与game.dll有关?我假设我应该以某种方式获得模块列表,在那里我可以看到它们的名称和基地址。

此外,如果我将 System.out.println(Pointer.nativeValue(hMod.getPointer()))); 更改为 hModList.forEach(System.out::println);,我会看到以下指针和大量空值(大约 1000 个)。

这些地址是否包含game.dll的地址?

【问题讨论】:

  • 你没有发现它很了不起吗,你不必将进程句柄(同样值得注意的是,你找不到保留它的理由)传递给GetModuleHandle()的调用?

标签: java c++ winapi java-native-interface jna


【解决方案1】:

GetModuleHandle() 只查看调用进程。由于game.dll没有加载到你自己的进程中,所以GetModuleHandle()找不到。

要查找在另一个进程中加载​​的模块,您需要使用:

Kernel32Utils.getModules() 使用CreateToolhelp32Snapshot(TH32CS_SNAPMODULE),因此如果您的 Java 应用程序作为 64 位应用程序运行,那么它将仅枚举 64 位模块。但是war3.exe 在您的屏幕截图中作为 32 位进程运行,因此如果您在 64 位进程中使用CreateToolhelp32Snapshot(),则需要改用TH32CS_SNAPMODULE32

更新:

正如我上面提到的,如果你使用EnumProcessModules() 方法,你可以使用GetModuleFileNameEx() 来确定每个模块的文件名。这样,您就可以找到game.dll 的模块。

更重要的是:

  • 您缺少对每个系统调用所需的错误处理。始终测试失败的返回值。

  • 本身不是错误,但您确实不应该使用openProcess() 请求PROCESS_ALL_ACCESS 权限。仅请求您实际需要的权利,仅此而已。在这种情况下,请改用PROCESS_QUERY_INFORMATION | PROCESS_VM_READ

  • 您不会查看EnumProcessModules() 的第四个参数的输出来了解数组中实际存储了多少模块。

  • EnumProcessModules() 的第 3 和第 4 个参数的输入值是错误的,它们需要用 bytes 表示,而不是 elements

根据EnumProcessModules() documentation

cb
lphModule 数组的大小,以字节为单位

lpcbNeeded
将所有模块句柄存储在 lphModule 数组中所需的字节数

...

指定一个大的 HMODULE 值数组是个好主意,因为在您调用 EnumProcessModules 时,很难预测进程中会有多少模块。 要确定lphModule 数组是否太小而无法容纳进程的所有模块句柄,请将lpcbNeeded 中返回的值与cb 中指定的值进行比较。如果lpcbNeeded大于cb,则增加数组的大小并再次调用EnumProcessModules

要确定调用EnumProcessModules 枚举了多少模块,请将lpcbNeeded 参数中的结果值除以sizeof(HMODULE)

【讨论】:

  • 这似乎是common question,我很惊讶没有规范。你认为this 会起作用吗?您愿意在此处扩展您的答案以使其成为规范吗?
  • 我同意丹尼尔的观点。有实际的例子会很棒,因为我看过很多主题,但它们都很老了。
  • 问题已更新,根据 Remy 的回答。
  • 谢谢@RemyLebeau。您对文档中的第 3 和第 4 参数是正确的。但是在 jna-5.9.0 这个方法看起来像: boolean EnumProcessModules(HANDLE hProcess, HMODULE[] lphModule, int cb, IntByReference lpcbNeeded);
  • @Neo 这并没有改变我所说的。您仍然需要为cblpcbNeeded 传递正确的值。 1024 不是任何一个参数的正确值
【解决方案2】:

最后我找到了解决方案,但不是在 Java 或 JNA 中。 我使用 C++ 编写了这段代码,我会像 Java 中的 dll 一样使用它。

这是我的 C++ 代码:

#include <conio.h>
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
using namespace std;

DWORD_PTR GetProcessBaseAddress(DWORD processID)
{
    DWORD_PTR   baseAddress = 0;
    HANDLE      processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
    HMODULE* moduleArray;
    LPBYTE      moduleArrayBytes;
    DWORD       bytesRequired;

    if (processHandle)
    {
        if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
        {
            if (bytesRequired)
            {
                moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);

                if (moduleArrayBytes)
                {
                    unsigned int moduleCount;

                    moduleCount = bytesRequired / sizeof(HMODULE);
                    moduleArray = (HMODULE*)moduleArrayBytes;

                    if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
                    {
                        baseAddress = (DWORD_PTR)moduleArray[0];
                    }

                    LocalFree(moduleArrayBytes);
                }
            }
        }

        CloseHandle(processHandle);
    }

    return baseAddress;
}

DWORD GetProcessId(LPCTSTR ProcessName) // non-conflicting function name
{
    PROCESSENTRY32 pt;
    HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    pt.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hsnap, &pt)) { // must call this first
        do {
            if (!lstrcmpi(pt.szExeFile, ProcessName)) {
                CloseHandle(hsnap);
                return pt.th32ProcessID;
            }
        } while (Process32Next(hsnap, &pt));
    }
    CloseHandle(hsnap); // close handle on failure
    return 0;
}

uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
    uintptr_t modBaseAddr = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
    if (hSnap != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 modEntry;
        modEntry.dwSize = sizeof(modEntry);
        if (Module32First(hSnap, &modEntry))
        {
            do
            {
                if (!_wcsicmp(modEntry.szModule, modName))
                {
                    modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnap, &modEntry));
        }
    }
    CloseHandle(hSnap);
    return modBaseAddr;
}

int main()
{
    DWORD pid = GetProcessId(TEXT("war3.exe"));
    cout << "Process ID of war3.exe: "<< pid << endl;

    DWORD_PTR war3_exe_base_addr = GetProcessBaseAddress(pid);
    cout <<"Base address of war3.exe: "<< war3_exe_base_addr << endl;

    uintptr_t gameDllBaseAddress = GetModuleBaseAddress(pid, TEXT("game.dll"));
    cout <<"Base address of game.dll: " << gameDllBaseAddress << endl;
}

结果是:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    相关资源
    最近更新 更多