如何通过ReadProcessMemory跨进程读取std::string?(int类型读取正常但字符串读取失败)
std::string with ReadProcessMemory Fails (And How to Fix It) Ah, I see the issue here—reading a std::string across processes isn't as straightforward as reading a raw int, and your current code is hitting a classic pitfall with how C++ strings are stored under the hood. Let's break this down:
The Root Cause
Unlike an int (a simple value stored directly in memory), a std::string is a complex container object. It doesn't hold the actual string characters in its own memory space. Instead, it stores:
- A pointer to a separate heap buffer where the real characters live
- Metadata like the string's length and capacity
When you use ReadProcessMemory to read directly into your local std::string (&JoJo_string), you're only copying the pointer and metadata from the target process's std::string object. That pointer is only valid in the target process's address space—when your local process tries to use it, it's accessing invalid memory, which causes the crash or error you're seeing.
The Fix: Read the String in Two Steps
To correctly read a std::string from another process, you need to:
- Read the target
std::stringobject's metadata (pointer to characters and string length) - Use that metadata to read the actual character data from the target process's heap
Here's a revised Programm_B that implements this (note: this assumes both processes use the same compiler/architecture—e.g., 64-bit MSVC, since std::string layout varies between compilers):
#include <iostream> #include <string> #include <cstdlib> #include <windows.h> int main() { int id; std::cout << "Enter target process ID: "; std::cin >> id; DWORD ProcessId = id; // Open target process with read access HANDLE ProcessHandle = OpenProcess(PROCESS_VM_READ, FALSE, ProcessId); if (!ProcessHandle) { std::cout << "Process is not found...\n"; return 0; } std::string addr_str; std::cout << "Enter std::string address (hex): "; std::cin >> addr_str; uintptr_t string_addr = std::strtoull(addr_str.c_str(), NULL, 16); // Step 1: Read target std::string's metadata (matches MSVC layout) struct RemoteStringMetadata { char* data_ptr; size_t length; size_t capacity; }; RemoteStringMetadata meta; if (!ReadProcessMemory(ProcessHandle, (LPVOID)string_addr, &meta, sizeof(meta), NULL)) { std::cout << "Failed to read string metadata\n"; CloseHandle(ProcessHandle); return 0; } // Step 2: Read actual character data from target's heap std::string local_string; local_string.resize(meta.length); // Allocate space for characters if (!ReadProcessMemory(ProcessHandle, (LPVOID)meta.data_ptr, &local_string[0], meta.length, NULL)) { std::cout << "Failed to read string data\n"; CloseHandle(ProcessHandle); return 0; } std::cout << "Read string: " << local_string << std::endl; CloseHandle(ProcessHandle); return 0; }
Critical Notes
- Compiler Consistency: The
RemoteStringMetadatastruct depends on your compiler'sstd::stringimplementation. For GCC/Clang, you'll need to adjust the struct to match their internal layout (they use a union for short-string optimization). - Short-String Optimization (SSO): Even if the target string uses SSO (stored directly in the
std::stringobject), this code still works—meta.data_ptrwill point to the object's internal buffer, andReadProcessMemorywill correctly read that buffer from the target process's address space. - Error Handling: Always check the return values of
ReadProcessMemoryandOpenProcessto catch issues like insufficient permissions or invalid addresses.
内容的提问来源于stack exchange,提问作者St_rt_la

