【问题标题】:C++: reading memory of another processC++:读取另一个进程的内存
【发布时间】:2013-10-26 11:30:16
【问题描述】:

我想要一个函数,可以让我读取另一个进程的内存。 我在想这样的事情(伪代码):

staticAddress = 0x026E0DC4
processId = GetProcessIdByName(processName)
processHandle = GetProcessHandle(processId)
processBaseAddress = GetBaseAddress(processHandle)
addressToRead = processBaseAddress+staticAddress
readValueAsInt = ReadMemoryInt(processHandle, addressToRead)
readValueAsFloat = ReadMemoryFloat(processHandle, addressToRead)
readValueAsString = ReadMemoryString(processHandle, addressToRead)

这可能吗? 这是我到目前为止得到的:

#include <Windows.h>
#include <conio.h>
#include <tlhelp32.h>
#include <string>
#include <psapi.h>
#pragma comment( lib, "psapi" )

int GetProcessId(char* ProcName) {
    PROCESSENTRY32 pe32;
    HANDLE hSnapshot = NULL;
    pe32.dwSize = sizeof( PROCESSENTRY32 );
    hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

    if( Process32First( hSnapshot, &pe32 ) ) {
        do {
            if( strcmp( pe32.szExeFile, ProcName ) == 0 )
                break;
        } while( Process32Next( hSnapshot, &pe32 ) );
    }

    if( hSnapshot != INVALID_HANDLE_VALUE )
        CloseHandle( hSnapshot );

    return pe32.th32ProcessID;  
}

int GetModuleBase(HANDLE processHandle, string &sModuleName) 
{ 
   HMODULE *hModules; 
   char szBuf[50]; 
   DWORD cModules; 
   DWORD dwBase = -1; 
   //------ 

   EnumProcessModules(processHandle, hModules, 0, &cModules); 
   hModules = new HMODULE[cModules/sizeof(HMODULE)]; 

   if(EnumProcessModules(processHandle, hModules, cModules/sizeof(HMODULE), &cModules)) { 
      for(int i = 0; i < cModules/sizeof(HMODULE); i++) { 
         if(GetModuleBaseName(processHandle, hModules[i], szBuf, sizeof(szBuf))) { 
            if(sModuleName.compare(szBuf) == 0) { 
               dwBase = (DWORD)hModules[i]; 
               break; 
            } 
         } 
      } 
   } 

   delete[] hModules; 

   return dwBase; 
}


int ReadMemoryInt(HANDLE processHandle, LPCVOID address) {
    //LPVOID buffer = ??;
    //SIZE_T size = ??;
    SIZE_T NumberOfBytesToRead = 4; //??
    ReadProcessMemory(processHandle, address, buffer, size, NumberOfBytesToRead)
    return buffer; //??
}

int ReadMemoryFloat(HANDLE processHandle, LPCVOID address) {
    //LPVOID buffer = ??;
    //SIZE_T size = ??;
    SIZE_T NumberOfBytesToRead = 8; //??
    ReadProcessMemory(processHandle, address, buffer, size, NumberOfBytesToRead)
    return buffer; //??
}

int ReadMemoryString(HANDLE processHandle, LPCVOID address) {
    //LPVOID buffer = ??;
    //SIZE_T size = ??;
    SIZE_T NumberOfBytesToRead = 999; //??
    ReadProcessMemory(processHandle, address, buffer, size, NumberOfBytesToRead)
    return buffer; //??
}

int main()
{
    //read an integer from "Program.exe"+0x05D8A3C4
    int address = 0x05D8A3C4;
    char* processName = "Program.exe";
    int processId = GetProcessId(processName);
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
    int processBaseAddress = GetModuleBase(processHandle, (string)"Program.exe";
    LPCVOID actualAddress = processBaseAddress+address;
    int readValue = ReadMemory(processHandle, actualAddress);
    std::cout << readValue << std::endl;
    CloseHandle(processHandle);
    return 0;
}

正如您从代码中的问号看到的那样,我真的不确定 ReadProcessMemory 的“缓冲区”和“大小”参数。如果有人能帮我解决这个问题,我将不胜感激。

【问题讨论】:

  • 这么多问号!问题是什么?
  • 问题在代码下方。 “你能帮我完成代码,解释我的错误并引导我朝着正确的方向前进吗?”
  • OP 不知道内存中的内存布局、字节序和指针/值。请有礼貌。 @OP:AFAIK 这可以让你努力工作。
  • 听起来您在 C++ 概念方面存在一些基本问题,例如如何将指针传递给变量。在尝试处理如此复杂的事情之前,您可能应该更熟悉 C++。 (此外,进程没有基地址。模块有基地址。一个进程包含许多模块。)
  • @RaymondChen:其实并不是特别复杂。例如。在我知道数组是什么之前,我编写了这样做的程序。

标签: c++ winapi memory


【解决方案1】:

这是您的 ReadMemoryInt() 函数的示例:

int ReadMemoryInt(HANDLE processHandle, LPCVOID address) {
    int buffer = 0;
    SIZE_T NumberOfBytesToRead = sizeof(buffer); //this is equal to 4
    SIZE_T NumberOfBytesActuallyRead;
    BOOL err = ReadProcessMemory(processHandle, address, &buffer, NumberOfBytesToRead, &NumberOfBytesActuallyRead);
    if (err || NumberOfBytesActuallyRead != NumberOfBytesToRead)
      /*an error occured*/ ;
    return buffer; 
}

&amp; 表示传递变量的地址而不是其值。

而在ReadMemoryString() 中,您无法知道需要读取的实际大小,您可以读取一个大块(大小 999)或读取许多小块,直到得到一个包含 \0 的块。

如果你想知道它是否有效,你可以在调试器中启动它,看看是否返回了你期望的值。

【讨论】:

  • 谢谢,我刚测试过,它应该返回 500 时返回 0。:( 250kb.de/u/131026/j/xh4b0Wap0bTC.jpg pastebin.com/vp2fk8TU
  • 检查GetLastError 返回的内容。当 winapi 函数失败时,您应该始终检查它。您使用的是 Windows 7 吗?然后您可能需要调整您的权限(请参阅 cmets 中的 PriviledgeCheck 函数)
  • 我在 Windows 8 上,GetLastError() 返回 299:ERROR_PARTIAL_COPY(仅完成了 ReadProcessMemory 或 WriteProcessMemory 请求的一部分。)我将检查 previledge 功能。谢谢。
  • 等等,我并没有真正阅读您的评论。您删除了 SetPrivilege?那当然是不设置权限了……msdn里面有个SetPrivilege example
  • 多么奇怪。 GetLastError 在 ReadProcessMemory 之后直接返回什么?你在 OpenProcess 之前调用 SetPrivilege?
【解决方案2】:

https://github.com/T-vK/Memory-Hacking-Class
是一个非常简单的类,可以完成所有这些甚至更多。
以下是它支持的所有方法的列表:

GetProcessId()
GetModuleBase()
SetPrivilege()
GetDebugPrivileges()
ReadInt()
GetPointerAddress()
ReadPointerInt()
ReadFloat()
ReadPointerFloat()
ReadText()
ReadPointerText()

示例用法:

#include "Memory.hpp"
using std::string;

int main() {
    char* TARGET_PROCESS_NAME = "League of Legends.exe";

    int GAME_VERSION_MODULE_OFFSET = 0x2A1D738; // [Base address of 'League of Legends.exe']+0x2A1D738 (address of a string containing a version number)

    Memory Memory;
    Memory.GetDebugPrivileges();
    int processId = Memory.GetProcessId(TARGET_PROCESS_NAME);
    HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);

    int baseAddress = Memory.GetModuleBase(processHandle, (string)TARGET_PROCESS_NAME);

    int gameVersionAddress = baseAddress + GAME_VERSION_MODULE_OFFSET;

    string gameVersion = Memory.ReadText(processHandle, gameVersionAddress);

    std::cout << "Game version: " << gameVersionAddress << std::endl;

    cin.get();
    return 0;
}

如果你想知道,是的,我是作者。

【讨论】:

  • 在游戏黑客或其他领域我不明白的一件事是,作弊如何将偏移量硬编码?我的意思是操作系统总是在游戏进程开始时在内存中加载一个随机块并且地址应该总是不同的?
  • 进程的基地址总是不同的。偏移量只是相对于基地址,因此永远不会改变(除非游戏已更新然后运行新代码)。
  • 2020 年的那一刻,您意识到 2017 年您回答了您在 2013 年提出的问题。
  • @Forivin 你怎么做才能找到你试图读取的进程的最后地址?
  • 最后一个地址是什么意思?通常,我使用 Cheat Engine、OllyDbg 和 Ida Pro 等工具来查找地址,然后将其追溯到模块以获取(例如)多级指针。如果您以前没有这样做过或不太了解组装,Cheat Engine 的指针扫描仪对初学者非常友好。然后就是使用我提供的代码了。
猜你喜欢
  • 2020-03-24
  • 1970-01-01
  • 2012-12-17
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多