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

ReadProcessMemory reads all 0s in a process memory

本文关键字:读取 取进程 内存 ReadProcessMemory      更新时间:2024-09-21

我正在尝试编写一个进程内存扫描程序,用于扫描内存中的非零值:

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 %dn", 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无法帮助您。