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

求助:使用ReadProcessMemory读取自身进程内存时程序崩溃

Hey,看起来你在做自校验程序时遇到了崩溃问题,第一次用WinAPI踩坑太正常了,我来帮你梳理下可能的原因和解决办法!

首先,排查进程句柄的问题

你怀疑进程句柄hMyProcess有问题,这确实是大概率原因之一。这里要注意两个关键点:

  • 如果你用的是GetCurrentProcess(),它返回的是伪句柄——这个句柄始终指向当前进程,不需要额外打开权限,而且ReadProcessMemory是支持直接使用伪句柄的,但要注意:伪句柄不需要调用CloseHandle()关闭,否则会触发错误!
  • 如果你是用OpenProcess()获取句柄,一定要确保权限参数正确,并且进程ID是自身的。正确的写法应该是:
    DWORD pid = GetCurrentProcessId();
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, pid);
    
    这里PROCESS_VM_READ是必须的权限,少了这个就会导致读取失败甚至崩溃。

其次,确保读取的内存范围有效

直接读取任意内存地址很容易触发访问违规(这就是你程序崩溃的常见原因)。你需要明确自身程序在内存中的有效范围:

  1. 用GetModuleHandle(NULL)获取自身模块的基地址(也就是程序加载到内存的起始地址)。
  2. 用GetModuleInformation()获取模块的大小(SizeOfImage字段),这样你就知道要读取多少字节才不会越界。

正确调用ReadProcessMemory的要点

这个API的参数很容易踩坑,一定要注意:

  • 最后一个参数lpNumberOfBytesRead不能传NULL,必须传一个SIZE_T类型变量的地址,用来接收实际读取的字节数。传NULL会导致未定义行为,直接崩溃都有可能。
  • 缓冲区的大小要足够容纳你要读取的内存,否则会导致缓冲区溢出,同样触发崩溃。
  • 每次调用后都要检查返回值,如果返回FALSE,立刻调用GetLastError()获取错误码——比如ERROR_ACCESS_DENIED是权限问题,ERROR_INVALID_ADDRESS是地址无效,这些错误码能帮你精准定位问题,而不是瞎猜。

完整示例代码

给你一段能正常运行的自校验示例,你可以参考下:

#include <windows.h>
#include <psapi.h>
#include <iostream>

// 链接PSAPI库,否则GetModuleInformation会报错
#pragma comment(lib, "psapi.lib")

int main() {
    // 获取自身进程伪句柄(无需CloseHandle)
    HANDLE hProcess = GetCurrentProcess();
    if (!hProcess) {
        std::cerr << "GetCurrentProcess失败,错误码: " << GetLastError() << std::endl;
        return 1;
    }

    // 获取自身模块信息
    HMODULE hModule = GetModuleHandle(NULL);
    MODULEINFO modInfo{};
    if (!GetModuleInformation(hProcess, hModule, &modInfo, sizeof(modInfo))) {
        std::cerr << "GetModuleInformation失败,错误码: " << GetLastError() << std::endl;
        return 1;
    }

    // 分配足够的缓冲区存储内存数据
    BYTE* pBuffer = new BYTE[modInfo.SizeOfImage];
    if (!pBuffer) {
        std::cerr << "内存分配失败" << std::endl;
        return 1;
    }

    // 读取自身内存
    SIZE_T bytesRead{};
    if (!ReadProcessMemory(hProcess, modInfo.lpBaseOfDll, pBuffer, modInfo.SizeOfImage, &bytesRead)) {
        std::cerr << "ReadProcessMemory失败,错误码: " << GetLastError() << std::endl;
        delete[] pBuffer;
        return 1;
    }

    // 计算简单的校验和(你可以换成MD5/SHA等更安全的算法)
    DWORD checksum = 0;
    for (SIZE_T i = 0; i < bytesRead; ++i) {
        checksum += pBuffer[i];
    }

    std::cout << "程序校验和: 0x" << std::hex << checksum << std::endl;

    // 清理资源
    delete[] pBuffer;
    return 0;
}

常见崩溃原因总结

再帮你归纳下最可能导致你程序挂掉的几个点:

  • 进程句柄无效:比如OpenProcess权限不足、进程ID错误,或者错误关闭了伪句柄。
  • 读取地址无效:没有获取正确的模块基地址和大小,读取了不属于自身程序的内存区域。
  • ReadProcessMemory参数错误:比如lpNumberOfBytesRead传NULL,或者缓冲区大小不够。
  • 内存分配失败:没有检查缓冲区是否分配成功就直接使用。

调试的时候建议用Visual Studio的调试器,崩溃时查看调用栈和错误码,能更快找到问题根源哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:10:50