微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ReadProcessMemory 读取进程内存中的所有 0

如何解决ReadProcessMemory 读取进程内存中的所有 0

我正在尝试编写一个进程内存扫描器来扫描内存中的非零值:

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 在每次调用 ERROR_ACCESS_DENIED 时都返回 ReadProcessMemory。句柄 hProc 附加到游戏进程没有问题,并且找到了正确的 PID。为什么会这样?我们如何才能增加绕过反作弊的特权?

解决方法

根据这个thread,你需要enumerate all modules for a process来获取你感兴趣的模块的有效句柄。然后你可以像这样以管理员身份运行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),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 无法为您提供帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。