You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ReadProcessMemory读取外部进程字符串并输出至控制台?

问题描述

尝试用ReadProcessMemory读取外部进程的std::string并输出到控制台,但运行后无任何输出。读取目标是外部进程中的varString变量,相关代码如下:

读取进程代码

#include <iostream>
#include <Windows.h>
#include <string>

using namespace std;

wstring astr2wstr(std::string & string_a){
    int length = MultiByteToWideChar(CP_UTF8, 0, string_a.c_str(), -1, NULL, 0);

    wchar_t* temp = new wchar_t[length];
    MultiByteToWideChar(CP_UTF8, 0, string_a.c_str(), -1, temp, length);

    wstring string_w = temp;
    delete[] temp;
    return string_w;
}

int main() {
    DWORD pid;
    cout<<"Enter the PID: ";
    cin>>dec>>pid;
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (hProcess == NULL) {
        cout << "OpenProcess failed. GetLastError = " << dec << GetLastError() << endl;
        system("pause");
        return EXIT_FAILURE;
    }
    uintptr_t Target = 0x7994848;
    string Rec;
    SIZE_T bytesRead = 0;
    ReadProcessMemory(hProcess, (LPCVOID)Target, &Rec, sizeof(Rec), NULL);
    wstring mywstr = astr2wstr(Rec);
    wcout<<mywstr<<endl;
}

目标进程代码

#include <iostream>
#include <String>
#include <Windows.h>
#define CHAR_ARRAY_SIZE 128

using namespace std;

int main(){
    int varInt = 123456;
    string varString = "DefaultString";
    const char arrChar[CHAR_ARRAY_SIZE] = "Long char array right there ->";
    int* ptr2int = &varInt;
    int** ptr2ptr = &ptr2int;
    int*** ptr2ptr2 = &ptr2ptr;
    do{
        cout<<"Process ID: "<<dec<<GetCurrentProcessId()<<endl<<endl;
        cout<<"varInt(0x"<<hex<<(uintptr_t)ptr2int<<") = "<<dec<<varInt<<" "<<endl<<endl;
        wcout<<"varString(0x"<<(uintptr_t)&varString<<") = "<<varString<<" "<<endl<<endl;
        cout<<"arrChar(0x"<<(uintptr_t)&arrChar<<") = "<<arrChar<<" "<<endl<<endl;
        cout<<"ptr2int(0x"<<(uintptr_t)&ptr2int<<") = "<<ptr2int<<" "<<endl<<endl;
        cout<<"ptr2ptr(0x"<<(uintptr_t)&ptr2ptr<<") = "<<ptr2ptr<<" "<<endl<<endl;
        cout<<"ptr2ptr(0x"<<(uintptr_t)&ptr2ptr2<<") = "<<ptr2ptr2<<" "<<endl<<endl;
        cout << "Press ENTER to refresh." << endl;
        getchar();
        cout<<"*==========================================================*"<<endl<<endl;
    } while(true);
    return EXIT_SUCCESS;
}
问题根源

当前代码的核心错误在于对std::string内存结构的误解:

  • std::string不是直接存储字符串内容的字符数组,它是一个容器对象,内部仅包含指向实际字符缓冲区的指针、字符串长度、缓冲区容量等成员变量。
  • 直接读取sizeof(std::string)大小的内存,只能拿到这些成员变量,无法获取字符串的实际内容。
  • 硬编码的Target地址是std::string对象的地址,而非其指向的字符缓冲区地址,且该地址在进程重启或不同运行环境下会失效。
  • 未检查ReadProcessMemory的返回值,无法判断读取操作是否成功。
正确实现步骤

读取外部进程的std::string需要分两步执行(以下以MSVC编译器为例,不同编译器的std::string内部结构可能略有差异):

  1. 读取外部进程中std::string对象的内存,获取它内部的字符缓冲区指针和字符串长度。
  2. 根据拿到的缓冲区指针,从外部进程读取对应长度的字符数据。

修正后的读取代码

#include <iostream>
#include <Windows.h>
#include <string>

using namespace std;

// 模拟MSVC下std::string的内部结构(仅用于读取,禁止直接修改)
struct RemoteString {
    char* _Ptr;       // 指向实际字符缓冲区的指针
    size_t _Mysize;   // 字符串实际长度(不含终止符)
    size_t _Myres;    // 缓冲区容量
};

int main() {
    DWORD pid;
    cout << "Enter the PID: ";
    cin >> dec >> pid;

    // 申请必要的内存读取权限即可,无需全权限
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, pid);
    if (hProcess == NULL) {
        cout << "OpenProcess failed. GetLastError = " << dec << GetLastError() << endl;
        system("pause");
        return EXIT_FAILURE;
    }

    // 从目标进程的输出中复制varString对象的地址
    uintptr_t stringObjAddr;
    cout << "Enter the varString object address (from target process output): ";
    cin >> hex >> stringObjAddr;

    RemoteString remoteStr;
    SIZE_T bytesRead = 0;

    // 第一步:读取std::string对象的内部结构
    if (!ReadProcessMemory(hProcess, (LPCVOID)stringObjAddr, &remoteStr, sizeof(RemoteString), &bytesRead)) {
        cout << "Read string object failed. GetLastError = " << dec << GetLastError() << endl;
        CloseHandle(hProcess);
        system("pause");
        return EXIT_FAILURE;
    }
    if (bytesRead != sizeof(RemoteString)) {
        cout << "Incomplete read for string object" << endl;
        CloseHandle(hProcess);
        system("pause");
        return EXIT_FAILURE;
    }

    // 第二步:读取实际的字符串内容
    string localStr(remoteStr._Mysize + 1, '\0'); // 预留终止符空间
    if (!ReadProcessMemory(hProcess, (LPCVOID)remoteStr._Ptr, &localStr[0], remoteStr._Mysize, &bytesRead)) {
        cout << "Read string content failed. GetLastError = " << dec << GetLastError() << endl;
        CloseHandle(hProcess);
        system("pause");
        return EXIT_FAILURE;
    }
    if (bytesRead != remoteStr._Mysize) {
        cout << "Incomplete read for string content" << endl;
        CloseHandle(hProcess);
        system("pause");
        return EXIT_FAILURE;
    }

    // 输出读取结果
    cout << "Read string: " << localStr << endl;

    CloseHandle(hProcess);
    system("pause");
    return EXIT_SUCCESS;
}

使用说明

  1. 运行目标进程,从输出中复制varString的对象地址(例如varString(0xXXXXXX) = DefaultString中的0xXXXXXX)。
  2. 运行读取进程,输入目标进程的PID和复制的varString对象地址。
  3. 即可获取目标进程中的字符串内容。

内容的提问来源于stack exchange,提问作者Ezra1944

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 09:07:04