C++ 获取 64 位应用程序的模块基地址

use*_*103 2 c++ winapi visual-c++

我最近一直在玩内存读取/编辑,遇到了一个问题,我认为这是由于 64 位应用程序引起的,我也尝试在 64 位下编译。我在 32 位应用程序中使用此脚本没有任何问题,但是当我在 Solitaire 上尝试此操作时,它无法获取基地址,从而无法计算出正确的偏移量等。这是脚本:

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
using namespace std;

DWORD dwGetModuleBaseAddress(DWORD dwProcessID, TCHAR *lpszModuleName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
    DWORD dwModuleBaseAddress = 0;
    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 ModuleEntry32 = { 0 };
        ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
        if (Module32First(hSnapshot, &ModuleEntry32))
        {
            do
            {
                if (_tcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
                {
                    dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnapshot, &ModuleEntry32));
        }
        CloseHandle(hSnapshot);
    }
    return dwModuleBaseAddress;
}

int main()
{
    DWORD address = 0xBAFA8;
    HWND hwnd = FindWindow(0, L"Solitaire");
    DWORD pid;
    int data = 0;
    int newData = 0;
    if (hwnd)
    {
        GetWindowThreadProcessId(hwnd, &pid);
        HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
        if (phandle)
        {
            DWORD base = dwGetModuleBaseAddress(pid, L"Solitaire.exe");
            cout << "Base: " << (void*)base << endl;

            ReadProcessMemory(phandle, (LPCVOID)(base + address), &data, sizeof(data), 0);
        }
        else {
            cout << "Couldnt get handle" << endl;
        }

    }
    else {
        cout << "Couldn't find window" << endl;
    }
    cin.get();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

问题可能是我使用的函数使用 MODULE32,但是我尝试了其他函数(使用 EnumModules),但仍然无法返回地址。

有什么想法如何获取 64 位应用程序的基地址或让此脚本工作吗?

谢谢

小智 6

那么你的代码永远不会成功工作,因为你谈论的是 64 位,但你使用 DWORD 作为基地址!Solitare可能有一个 32 位地址,但你不能保证这一点,而且你永远不应该假设它。

这个功能有效。它只需要相关进程的进程 ID,并且假设您需要该进程的基地址。即不是它的 DLL 之一。如果您不想要拥有进程,那么您需要moduleArray使用类似的方法进行迭代for (int i=0; i<moduleCount; i++ ) { // do something with moduleArray[i] },然后检查模块文件名。

如果您只想要启动进程(可执行文件),您可以假设它是数组中的第一个元素。

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;
}
Run Code Online (Sandbox Code Playgroud)