簡體   English   中英

ReadProcessMemory 讀取進程中的所有 0 memory

[英]ReadProcessMemory reads all 0s in a process memory

我正在嘗試編寫一個進程 memory 掃描儀,用於掃描 memory 中的非零值:

MEMORY_BASIC_INFORMATION mbi;
char* addr = 0;
dtype readVal = 0;
while (VirtualQueryEx(hProc, addr, &mbi, sizeof(mbi))) {  // HANDLE hProc is defined earlier
  if (mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS) {
        for (int i = 0; i < mbi.RegionSize; i += sizeof(readVal)) {
            BOOL ret = ReadProcessMemory(hProc, (char*) mbi.BaseAddress + i, &readVal, sizeof(readVal), 0);
            printf("ReadProcessMemory returns %d\n", ret); // returns 5 (ERROR_ACCESS_DENIED)
            if (readVal != 0) {
                printf("Found a good value!");
                system("pause");
            }
        }
    }
    addr += mbi.RegionSize;
}

我在chrome.exe上嘗試過,掃描儀發現了大量非零值。 但是,當我在帶有反作弊功能的游戲進程上嘗試它時,它無法工作, ReadProcessMemory在每次調用ReadProcessMemory時都會返回ERROR_ACCESS_DENIED 句柄hProc連接到游戲進程沒有問題,並且找到了正確的 PID。 為什么會這樣?我們如何才能增加繞過反作弊的特權?

根據這個線程,您需要枚舉進程的所有模塊以獲得您感興趣的模塊的有效句柄。然后您可以使用ReadProcessMemory像這樣以管理員身份運行來讀取多級指針:

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <tchar.h>

using namespace std;

DWORD_PTR dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName);
    
int main()
{
    HWND hwnd = FindWindowA(NULL, "Game");
    if (hwnd == NULL)
    {
        cout << "Cannot find window." << endl;
        Sleep(3000);
        exit(-1);
    }
    else
    {
        DWORD procID;
        GetWindowThreadProcessId(hwnd, &procID);
        HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
        DWORD_PTR ModuleBaseAddress = 0;
        ModuleBaseAddress = dwGetModuleBaseAddress(procID, _T("Game.exe"));

        if (procID == NULL)
        {
            cout << "Cannot find process.";
            Sleep(3000);
            exit(-1);
        }
        else {
            while (true)
            {
                DWORD temp;
                ReadProcessMemory(handle, (LPCVOID)(ModuleBaseAddress + 0x43021C), &temp, sizeof(temp), NULL);
                ReadProcessMemory(handle, (LPCVOID)(temp + 0xAC), &temp, sizeof(temp), NULL);
                int curhp;
                ReadProcessMemory(handle, (LPCVOID)(temp + 0x4C), &curhp, sizeof(curhp), NULL);
                cout << "Current HP: "  << curhp << endl;
                Sleep(100);
                system("CLS");
            }
        }
    }
    system("PAUSE");
}

DWORD_PTR dwGetModuleBaseAddress(DWORD dwProcID, TCHAR *szModuleName)
{
    DWORD_PTR dwModuleBaseAddress = 0;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwProcID);
    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 ModuleEntry32;
        ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
        if (Module32First(hSnapshot, &ModuleEntry32))
        {
            do
            {
                if (_tcsicmp(ModuleEntry32.szModule, szModuleName) == 0)
                {
                    dwModuleBaseAddress = (DWORD_PTR)ModuleEntry32.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnapshot, &ModuleEntry32));
        }
        CloseHandle(hSnapshot);
    }
    return dwModuleBaseAddress;
}

更多詳情,您可以從網上查詢。

您的代碼的精簡版本大致執行以下操作:

dtype readVal;
if (readVal != 0) {
    printf("Found a good value!");
    system("pause");
}

有一個(可能)未初始化的值( readVal ),一些代碼的代碼路徑不會改變該值,然后是讀取訪問。 這樣做沒有指定的行為。 因此,它的行為被暗示為未定義的。

要修復您的代碼,您需要進行兩項更改:

  • readVal需要初始化,並在最里面的循環中重置。 盡管不知道readVal是什么數據類型,但不可能知道它是否已初始化。 這留作練習。
  • ReadProcessMemory可能會失敗。 它通過返回FALSE來報告失敗。 您將需要檢查失敗,如果需要擴展錯誤信息,還可以選擇調用GetLastError

為什么會這樣,我們如何繞過反作弊?

我們不知道,因為您決定對重要信息保密(例如目標的具體名稱和版本)。 繞過軟件保護被設計為很困難。 花十年的時間在二進制開發中,你可能已經准備好想出一個方法。 Stack Overflow 無法為您提供幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM