C++ 只读取进程范围内的内存地址

C++ read memory addresses within process range only

所以我一直在尝试使用 C++ 进行内存读取,我认为一个很酷的项目是读取进程正在使用的所有地址(类似于 Cheat Engine 的工作方式)。

我从阅读开始

Link1:

Link2: Read memory of 64bit process address

Link3: http://www.cplusplus.com/forum/general/42132/

我还在 youtube 上观看了一个教程,他在其中解释了进程(游戏)如何使用地址。 Link 到 youtube 视频: https://www.youtube.com/watch?v=wiX5LmdD5yk

这导致我制定了三种不同的方法:

DWORD GetProcId(const wchar_t* procName) {
    DWORD pid = 0;
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(hSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 procEntry;
        procEntry.dwSize = sizeof(procEntry);
        if(Process32First(hSnap, &procEntry)) {
            do {
                if(!_wcsicmp(procEntry.szExeFile, procName)) {
                    pid = procEntry.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnap, &procEntry));
        }
    }
    CloseHandle(hSnap);
    return pid;
}

此方法是获取进程 ID,我也可以通过在任务管理器中找到相同的 PID(稍后为我提供相同的基地址)手动键入该进程 ID。

uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName) {
    uintptr_t modBaseAddr = 0;
//I use 0x10 instead of TH32CS_SNAPMODULE32 since it didnt work and according to documentation 
// this is the value it should have.
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | 0x10, 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;
}

此方法(我假设)将 return 进程的基地址。例如,在我的代码中,我试图找到 discord.exe 进程的基地址。当 discord.exe 不是 运行 时,我得到 0,当它是 运行 时,我得到一个地址(我认为这是正确的基地址,如果我错了请纠正我)。

还有我的main方法:

int main() {
    DWORD procId = GetProcId(L"Discord.exe");
    uintptr_t moduleBase = GetModuleBaseAddress(procId, L"Discord.exe");

    HANDLE hProcess = 0;
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);

    uintptr_t dynamicPtrBaseAddr = moduleBase;

    std::cout << "Dynamic: " << dynamicPtrBaseAddr << std::endl;

    int value = 0;
    int arr [10000] = {};
    for (int i = 0; i < 100000; i++) {
        ReadProcessMemory(hProcess, (BYTE*)dynamicPtrBaseAddr, &value, sizeof(value),0);
        dynamicPtrBaseAddr += 1;
        arr[i] = value;
    }
}

我尝试将所有 100000 个地址的所有值放入一个数组中。

所以我的问题是:

我用 g++ main.cpp -o test -lpsapi -DUNICODE (MinGW) 编译。

您必须 运行 作为管理员并且您必须编译为与目标进程相同的位数。

您不应该一次读取 1 个字节,尤其是在外部 hack 中。

您应该使用 VirtualQueryEx() 来正确循环遍历正确的内存区域:

    DWORD procid = GetProcId("ac_client.exe");

    unsigned char* addr = 0;

    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procid);

    MEMORY_BASIC_INFORMATION mbi;

    while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi)))
    {
        if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS && mbi.Protect != PAGE_GUARD)
        {
            std::cout << "base : 0x" << std::hex << mbi.BaseAddress << " end : 0x" << std::hex << (uintptr_t)mbi.BaseAddress + mbi.RegionSize << "\n";
        }
        addr += mbi.RegionSize;
    }

这确保您只读取正确的内存。接下来,您将一次性将每个区域到达本地缓冲区,这将显着提高速度,因为您不会有为每个字节调用 API 的开销。

您看起来像是在尝试进行模式扫描。您可以在找到您所关注的原始教程的同一位置找到我们的模式扫描教程。