获取进程的基地址

18

我想要访问进程的某个地址,但首先需要获取进程的基地址。我正在使用一个工具来查看是否正确操作。该工具显示我需要以下内容:"app.exe"+0x011F9B08 = 0x119F8300

我以为可以通过 OpenProcess() 获取进程的基地址,但返回结果是 0x0000005c。我不认为这是正确的?至少不是我需要的。

我认为我需要的基地址是:0x119F8300 - 0x011F9B08 = 0x107FE7F8 <-- base?

这是我的代码:

hWindow = FindWindow(NULL, lpWindowName);
if(hWindow)
{
    GetWindowThreadProcessId(hWindow, &dwProcId);
    if(dwProcId != 0)
    {
            // hProcHandle -> 0x0000005c
            hProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcId);
    }
    else
    {
        return 0;
    }
}

我如何获取已打开进程的基地址?


4
“进程的基址”具体指什么? - NPE
4
或许你需要了解一下虚拟内存 - Fred Larson
你是否正在尝试读取另一个正在运行的进程的内存,并需要知道该进程在虚拟地址空间中映射图像的基址? - Peter Ruderman
@PeterRuderman 这就是我的意思。 - Vivendi
1
你不能直接访问另一个进程的内存。你必须使用ReadProcessMemory()。它的hProcess参数可以是从OpenProcess()获取的HANDLE。它的lpBaseAddress参数是相对于被访问的进程的,所以你不需要计算它,如果你知道它是什么,就硬编码它,例如:hProcess = OpenProcess(...); ReadProcessMemory(hProcess, (void*)0x011F9B08, ...); - Remy Lebeau
2个回答

20

如果你想获取另一个进程地址空间中的虚拟地址,可以按以下步骤进行:

  1. 使用OpenProcess打开该进程--如果成功,则返回值是指向该进程的句柄,这只是内核用于识别内核对象的不透明标记。它的确切整数值(在您的情况下为0x5c)对用户空间程序没有任何意义,除了将其与其他句柄和无效句柄区分开来。
  2. 调用GetProcessImageFileName获取进程的主可执行模块的名称。
  3. 使用EnumProcessModules枚举目标进程中所有模块的列表。
  4. 对于每个模块,调用GetModuleFileNameEx获取文件名,并将其与可执行文件的文件名进行比较。
  5. 当您找到可执行模块时,请调用GetModuleInformation获取可执行文件的原始入口点。

这将给您虚拟地址,但由于它未映射到当前进程的地址空间中,所以您可以做的事情有限。


4
据推测,接下来可能会使用ReadProcessMemory等函数进行跟进。此外,我不认为调用GetModuleInformation是必要的,模块基址和HMODULE是相同的。 - Peter Ruderman
3
@Peter:是的,这是必要的——基地址和HMODULE是相同的,但模块的入口点(调用WinMain()DllMain()的CRT启动函数)与基地址不同。 - Adam Rosenfield
1
没错,如果是这种情况,调用GetModuleInformation()肯定很方便(尽管OP没有要求入口点)。 - Peter Ruderman
但是如何找到基址? - VityaSchel

11

我想对@Adam Rosenfield的回答进行一些详细说明。我将以英雄联盟为例。


为了打开进程(获取句柄),我们需要它的PID(进程ID)。我们可以通过窗口句柄(HWND)来实现,因为通常已知窗口的标题。
//You will need to change this the name of the window of the foreign process
HWND WindowHandle = FindWindow(nullptr, L"League of Legends (TM) Client");
DWORD PID;
GetWindowThreadProcessId(WindowHandle, &PID);
PVOID hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, PID);

现在我们能够获取进程的句柄,让我们继续。

HMODULE Module = GetModule();
DWORD BaseAddress = (DWORD)Module;

GetModule函数

HMODULE GetModule()
{
    HMODULE hMods[1024];
    HANDLE pHandle = GetHandle();
    DWORD cbNeeded;
    unsigned int i;

    if (EnumProcessModules(pHandle, hMods, sizeof(hMods), &cbNeeded))
        {
        for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
        {
            TCHAR szModName[MAX_PATH];
            if (GetModuleFileNameEx(pHandle, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
            {
                wstring wstrModName = szModName;
                //you will need to change this to the name of the exe of the foreign process
                wstring wstrModContain = L"League of Legends.exe"; 
                if (wstrModName.find(wstrModContain) != string::npos)
                {
                    CloseHandle(pHandle);
                    return hMods[i];
                }
            }
        }
    }
    return nullptr;
}

就我个人而言,我喜欢编写两个单独的函数,一个用于获取句柄,另一个用于获取模块。

这样我们就成功地获取了外部进程的基地址。


5
有人为了不必再写第100次而复制粘贴,但要小心,因为他在找到句柄后会不明原因地关闭它。同样令人困惑的是,如果失败了,他不会关闭句柄。 - TrisT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接