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

时间:2014-10-26 11:28:09

标签: 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;
}

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

任何想法如何获得64位应用程序的基地址或让这个脚本运行?

由于

3 个答案:

答案 0 :(得分:2)

您的代码永远不会成功,因为您正在谈论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;
}

答案 1 :(得分:1)

正如大卫所暗示的那样,这句话是错误的:

dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;

因为您正在将64位指针(在64位应用程序上)转换为DWORD截断值(来自调试器的屏幕截图,64位应用程序打开64位进程)

enter image description here

你应该选择指针类型(DWORD_PTR也适用于便携式解决方案。)

答案 2 :(得分:-1)

基于@Nostromoo给出的示例的控制台应用程序示例

应该在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;
}