首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用JNA获取特定进程的dll基址

使用JNA获取特定进程的dll基址
EN

Stack Overflow用户
提问于 2021-09-13 17:43:51
回答 2查看 367关注 0票数 0

更新的:参见问题机器人上的更新

我想获得game.dll的基址,它位于war3.exe进程中。我正试图通过JNA库5.9.0版本来完成这一任务,但没有成功。

我面临的问题是:我无法从war3.exe进程中获取game.dll模块。我试着用:

代码语言:javascript
运行
复制
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打开war3.exe时,我看到的绝对超过5个。

与Intellij:一起执行

从Process获取的

请分享你的观点和想法,为什么我只从IDE得到5个模块。

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

更新:根据雷米的回答,我又尝试了一次EnumProcessModules()。下面是我的代码片段:

代码语言:javascript
运行
复制
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的地址?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-18 18:51:57

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

以下是我的C++代码:

代码语言:javascript
运行
复制
#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;
}

结果是:

票数 0
EN

Stack Overflow用户

发布于 2021-09-13 20:19:38

GetModuleHandle()只在调用过程中查看。因为game.dll没有加载到您自己的进程中,所以GetModuleHandle()找不到它。

要查找在另一个进程中加载的模块,您需要使用以下两种方法:

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

更新:

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

更重要的是:

  • 每个系统调用都缺少所需的错误处理。始终测试失败的返回值。
  • 这本身并不是一个错误,但您确实不应该用openProcess()请求openProcess()权限。只要求你真正需要的权利,不再。在本例中,使用PROCESS_QUERY_INFORMATION | PROCESS_VM_READ代替。
  • 您不需要查看EnumProcessModules()的第四个参数的输出来了解实际存储在数组中的模块数量。
  • EnumProcessModules()的第3和第4个参数的输入值是错误的,它们需要用字节表示,而不是以元素表示。

根据文档

cb lphModule数组的大小,(以字节为单位)lpcbNeeded数组中存储所有模块句柄所需的字节数。 ..。 指定大量的HMODULE值是个好主意,因为很难预测在调用EnumProcessModules时流程中会有多少个模块。若要确定lphModule lpcbNeeded 数组是否太小,无法容纳进程的所有模块句柄,请将lpcbNeeded中返回的值与 cb**.中指定的值进行比较。如果** lpcbNeeded 大于 cb**,,则增加数组的大小并再次调用** EnumProcessModules 。 确定调用EnumProcessModules**,所枚举的模块数量的除以 sizeof(HMODULE).在** lpcbNeeded 参数中的结果值

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69167015

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档