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

使用ReadProcessMemory读跨进程指针触发STATUS_ACCESS_VIOLATION异常

Windows平台使用ReadProcessMemory解引用跨进程读取指针触发STATUS_ACCESS_VIOLATION异常

问题描述

我正在练习使用Windows平台ReadProcessMemory API实现跨进程内存读取,当前实现目标分为两步:

  • 读取目标进程中指定指针变量本身存储的地址值
  • 基于第一步读到的地址,进一步读取该地址指向的实际整数值

目前第一步读取指针自身值的逻辑已经可以正常运行,但每次执行第二步解引用操作、读取指针指向地址存储的数值时,程序都会抛出Exception: STATUS_ACCESS_VIOLATION异常。我尝试过用= new int;的方式预先初始化接收指针值的变量,异常仍然没有解决。

本次测试涉及的材料清单:

  • 被读取的目标测试程序源码dummy.cpp:包含多级测试指针、循环打印内存地址的逻辑
  • 实现内存读取逻辑的程序源码reader.cpp
  • 程序运行截图
  • 异常触发后生成的CORE转储日志

所有程序均使用MinGW工具链编译,源码内所有代码、技术标识未做修改。

根因排查与修复方案

STATUS_ACCESS_VIOLATION本质是内存访问违规,按以下优先级排查即可定位问题:

  1. 直接在本地进程解引用跨进程指针
    这是使用ReadProcessMemory的最典型新手错误:第一步读到的指针值属于目标进程的虚拟地址空间,不是当前reader程序进程内的有效地址。如果直接写*read_ptr这类本地解引用代码,相当于在自身进程地址空间访问未分配、无权限的地址,必然触发访问违规。
    你之前用= new int;初始化本地变量的操作完全无效,因为new分配的是reader进程自身的内存,和目标进程地址空间完全隔离,不可能解决跨进程访问的问题。

    核心规则:跨进程场景下永远不要直接解引用从目标进程读到的指针值,所有对目标进程内存的访问都必须调用ReadProcessMemory,将目标进程的地址作为lpBaseAddress参数传入。
    两步读取的正确写法参考:

    // hProcess为已打开的、持有PROCESS_VM_READ权限的目标进程句柄
    intptr_t* target_ptr_addr = (intptr_t*)0x12345678; // 目标进程中指针变量自身的地址
    intptr_t ptr_stored_addr = 0; // 存储第一步读到的、指针指向的目标进程地址
    int actual_int_value = 0; // 存储最终读取到的整数值
    SIZE_T bytes_read = 0;
    
    // 第一步:读取指针变量本身存储的地址值
    BOOL read_ptr_ret = ReadProcessMemory(
        hProcess,
        target_ptr_addr,
        &ptr_stored_addr,
        sizeof(ptr_stored_addr),
        &bytes_read
    );
    if (!read_ptr_ret || bytes_read != sizeof(ptr_stored_addr)) {
        // 增加错误处理,比如调用GetLastError()打印错误码
        return -1;
    }
    
    // 第二步:读取指针指向地址的整数值,注意第二个参数传入第一步读到的目标进程地址
    BOOL read_value_ret = ReadProcessMemory(
        hProcess,
        (LPCVOID)ptr_stored_addr,
        &actual_int_value,
        sizeof(actual_int_value),
        &bytes_read
    );
    if (!read_value_ret || bytes_read != sizeof(actual_int_value)) {
        // 增加错误处理
        return -1;
    }
    
  2. 进程架构不匹配导致指针截断
    如果目标进程和reader程序的编译架构不统一(比如目标是64位程序、指针占8字节,reader编译为32位程序、指针占4字节),第一步读取指针值时会发生截断,拿到的是残缺的非法地址,传入ReadProcessMemory自然触发访问违规。
    排查方式:打开任务管理器确认目标进程是否带有*32后缀,编译两个程序时统一添加架构参数:64位编译加-m64,32位编译加-m32,同时用intptr_t类型存储地址值,避免指针长度不匹配。
  3. 进程句柄权限不足
    调用OpenProcess打开目标进程时如果没有传入PROCESS_VM_READ权限,ReadProcessMemory会调用失败,如果没有检查返回值直接使用未初始化的地址做后续读取,也会触发访问违规。打开进程的正确写法参考:
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, target_pid);
    if (hProcess == NULL) {
        // 处理打开失败逻辑,比如权限不足、PID不存在
        return -1;
    }
    
  4. 硬编码地址受ASLR影响失效
    如果硬编码了上次运行时拿到的指针变量地址,Windows的ASLR(地址空间随机化)机制会让程序每次加载的基址发生变化,硬编码的地址在下次运行时大概率是非法地址,需要每次运行时先获取目标进程模块基址,再通过固定偏移计算指针变量的真实地址。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:06:21