简体   繁体   English

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

[英]C++ Get Module Base Address for 64bit Application

I have been playing around with memory reading/editing recently and have run into a problem which I think is due to the 64bit application, I have also tried to compile under 64bit. 我最近一直在进行内存读取/编辑,遇到了我认为是由于64位应用程序引起的问题,我也尝试在64位下进行编译。 I had no problem with this script using with 32bit apps, however when I try this on Solitaire it fails to get the base address, which then fails to workout the correct offsets ect. 我将此脚本与32位应用程序一起使用时没有问题,但是当我在Solitaire上尝试该脚本时,它无法获取基地址,从而无法正确执行偏移量等。 Here is the script: 这是脚本:

#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;
}

The problem may be that the function I use uses MODULE32, however I have tried other functions (that uses EnumModules) which still fails to return address. 问题可能是我使用的函数使用MODULE32,但是我尝试了其他函数(使用EnumModules),但这些函数仍无法返回地址。

Any ideas how to get base address of 64bit application or to get this script working? 有什么想法如何获取64位应用程序的基址或如何使此脚本工作?

Thanks 谢谢

Well your code is never going to work successfully because you are talking about 64 bits but you are using DWORD for base address! 好吧,您的代码永远不会成功运行,因为您正在谈论64位,但是您正在使用DWORD作为基址! Solitare might have a 32 bit address but you cannot guarantee that and you should never assume it. Solitare 可能具有32位地址,但是您不能保证该地址,并且永远不要假定它。

This function works. 此功能有效。 It requires only the process ID of the process in question, and it assume you want the base address of that process. 它仅需要相关进程的进程ID,并假定您需要该进程的基址。 ie not one of its DLLs. 即不是它的DLL之一。 If you don't want the owning process then you need to iterate through moduleArray using something like for (int i=0; i<moduleCount; i++ ) { // do something with moduleArray[i] } and then check the module file name. 如果你不想拥有的进程,那么你需要通过迭代moduleArray使用类似for (int i=0; i<moduleCount; i++ ) { // do something with moduleArray[i] }然后检查模块文件名。

If you only want the starting process (the executable) you can just make an assumption that it's the first element in the array. 如果只需要启动过程(可执行文件),则可以假设它是数组中的第一个元素。

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;
}

As hinted by David this line is wrong: 正如David所暗示的,这一行是错误的:

dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;

since you're casting a 64-bit pointer (on a 64-bit application) to a DWORD truncating the value (screenshot from the debugger, 64 bit app opening a 64 bit process) 因为您正在将64位指针(在64位应用程序上)强制转换为截断该值的DWORD (调试器的屏幕快照,所以64位应用程序会打开一个64位进程)

在此处输入图片说明

You should go for a pointer type ( DWORD_PTR could also work for a portable solution). 您应该使用指针类型( DWORD_PTR也可以用于便携式解决方案)。

Sample console-application based on the examples given by @Nostromoo 基于@Nostromoo给出的示例的示例控制台应用程序

Should work on x86/x64 应该在x86 / x64上工作

#include "stdafx.h"
#include <windows.h>
#include <psapi.h>
#include <vector>

#define MODULE_NAME L"TestModule"
#define WINDOW_NAME L"TestConsole"

bool GetBaseModuleInfo(MODULEINFO* baseModuleInfo);
HMODULE GetProcessBaseAddressFromProcessHandle(HANDLE processHandle);
bool EnumProcessModulesPlattform(HANDLE processHandle, HMODULE* lphModule, DWORD cb, LPDWORD bytesRequired);
DWORD GetProcessIdentifier(const wchar_t* windowName);

int main()
{
    SetConsoleTitle(WINDOW_NAME);

    // Wait for the title to be set otherwise the window might not be found.
    Sleep(200);

    MODULEINFO baseModuleInfo;
    bool success = GetBaseModuleInfo(&baseModuleInfo);

    if (success == false) {
        wprintf(MODULE_NAME L"main() - GetBaseModuleInfo() failed.\n");
        std::getchar();
        return 1;
    }

        wchar_t buffer[2000];
#ifdef _WIN64
        swprintf_s(buffer, sizeof(buffer) / sizeof(*buffer), MODULE_NAME L"main() - baseAddress: '%llX' size: '%lX'\n", baseModuleInfo.lpBaseOfDll, baseModuleInfo.SizeOfImage);
#elif _WIN32
        swprintf_s(buffer, sizeof(buffer) / sizeof(*buffer), MODULE_NAME L"main() - baseAddress: '%lX' size: '%lX'\n", baseModuleInfo.lpBaseOfDll, baseModuleInfo.SizeOfImage);
#endif
        wprintf(buffer);

    std::getchar();
    return 0;
}

bool GetBaseModuleInfo(MODULEINFO* baseModuleInfo)
{
    DWORD processID = GetProcessIdentifier(WINDOW_NAME);
    if (processID == NULL) {
        wprintf(MODULE_NAME L"GetBaseModuleInfo() - GetProcessIdentifier() returned NULL.\n");
        return false;
    }

    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
    if (processHandle == NULL) {
        wprintf(MODULE_NAME L"GetBaseModuleInfo() - OpenProcess() returned NULL.\n");
        return false;
    }

    HMODULE baseAddress = GetProcessBaseAddressFromProcessHandle(processHandle);
    if (baseAddress == NULL) {
        wprintf(MODULE_NAME L"GetBaseModuleInfo() - GetProcessBaseAddressFromProcessHandle() returned NULL.\n");
        return false;
    }

    bool resultGMI = GetModuleInformation(processHandle, baseAddress, baseModuleInfo, sizeof(*baseModuleInfo));
    // NOTE: GetModuleInformation doesn't fail even if the baseAddress is wrong. Maybe it uses the nearest module?
    if (resultGMI == false) {
        wprintf(MODULE_NAME L"GetBaseModuleInfo() - GetModuleInformation() failed.\n");
        return false;
    }

    CloseHandle(processHandle);

    return true;
}

HMODULE GetProcessBaseAddressFromProcessHandle(HANDLE processHandle)
{
    DWORD bytesRequired;
    if (EnumProcessModulesPlattform(processHandle, NULL, 0, &bytesRequired) == false) {
        wprintf(MODULE_NAME L"GetProcessBaseAddressFromProcessHandle() - EnumProcessModules() error.\n");
        return NULL;
    }

    if (bytesRequired == NULL) {
        wprintf(MODULE_NAME L"GetProcessBaseAddressFromProcessHandle() - EnumProcessModules() returned 0 bytesRequired.\n");
        return NULL;
    }

    unsigned int moduleCount = bytesRequired / sizeof(HMODULE);

    std::vector<HMODULE> hModules(moduleCount, 0);
    if (EnumProcessModulesPlattform(processHandle, &hModules[0], bytesRequired, &bytesRequired) == false) {
        wprintf(MODULE_NAME L"GetProcessBaseAddressFromProcessHandle() - EnumProcessModules(moduleArray) error.\n");
        return NULL;
    }

    // The first item is always the baseModule.
    HMODULE baseAddress = hModules[0];
    return baseAddress;
}

bool EnumProcessModulesPlattform(HANDLE processHandle, HMODULE* lphModule, DWORD cb, LPDWORD bytesRequired)
{
#ifdef _WIN64
    bool returnValue = EnumProcessModulesEx(processHandle, lphModule, cb, bytesRequired, LIST_MODULES_64BIT);
#elif _WIN32
    bool returnValue = EnumProcessModulesEx(processHandle, lphModule, cb, bytesRequired, LIST_MODULES_32BIT);
#endif

    DWORD lastError = GetLastError();
    if (lastError != 0) {
        wprintf(MODULE_NAME L"EnumProcessModulesPlattform() - lastError != 0 EnumProcessModulesEx().\n");
        return false;
    }

    return returnValue;
}

DWORD GetProcessIdentifier(const wchar_t* windowName)
{
    HWND windowHandle = FindWindow(NULL, windowName);
    if (windowHandle == NULL) {
        wprintf(MODULE_NAME L"GetProcessIdentifier() - Could not find hwnd of '%s'.\n", windowName);
        return NULL;
    }

    DWORD processID;
    GetWindowThreadProcessId(windowHandle, &processID);
    return processID;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM