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

mach_vm_read返回非预期数据:地址正确却读出动态垃圾值求助

问题描述

以下是用于读取内存的C语言函数:

unsigned char* read_memory(void *address, mach_msg_type_number_t count) {
    int kr = 0;
    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_COPY);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    unsigned char *buffer = malloc(count);
    if (buffer == NULL) {
        RDErrorLog("malloc() failed");
        return NULL;
    }

    mach_msg_type_number_t actualCount = count;
    kr = mach_vm_read(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, (vm_offset_t *) buffer, &actualCount);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_read() failed with error: 0x%x", kr);
        free(buffer);
        return NULL;
    }

    if (actualCount != count) {
        RDErrorLog("mach_vm_read() failed due to invalid count");
        free(buffer);
        return NULL;
    }

    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    if (kr != KERN_SUCCESS) {
        free(buffer);
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    return buffer;
}

对应的Objective-C调用代码:

intptr_t baseAddress;
[self.baseAddress getValue:&baseAddress];

NSLog(@"baseAddress: 0x%lX", baseAddress);

intptr_t targetAddress = baseAddress + 0x10035A90C;

unsigned char *buffer = read_memory((void *)targetAddress, 8);
if (buffer == NULL) {
    NSLog(@"read memory failed");
    return;
}

NSLog(@"print at %lX", targetAddress - baseAddress);

char *s = (char *)malloc(sizeof(char) * 3 * 8);
for (size_t i = 0; i < 8; i++) {
    sprintf(s + i * 3, "%02X ", buffer[i]);
}

NSLog(@"%s", s);

free(s);
free(buffer);

已确认目标地址正确,且使用相同地址调用mach_vm_write功能正常,但mach_vm_read读出的是垃圾值,每次运行结果不同,该地址应存储静态字节,求问题原因及解决方法。


问题原因与解决方案

核心问题

mach_vm_read的第四个参数data要求传入指向vm_offset_t变量的指针,内核会将读取到的内存的内核映射地址写入该变量,而非直接将内存内容拷贝到用户态缓冲区。你当前直接把malloc出来的用户缓冲区强转成(vm_offset_t *)传入,导致内核把内存映射地址写入了缓冲区,而非目标内存的实际内容,这就是出现随机垃圾值的原因。

解决方法

修改read_memory函数,使用vm_offset_t接收内核返回的映射地址,将内容拷贝到用户缓冲区后释放内核映射的内存:

unsigned char* read_memory(void *address, mach_msg_type_number_t count) {
    int kr = 0;
    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_COPY);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    unsigned char *buffer = malloc(count);
    if (buffer == NULL) {
        RDErrorLog("malloc() failed");
        return NULL;
    }

    mach_msg_type_number_t actualCount = count;
    vm_offset_t kernel_buffer = 0;
    kr = mach_vm_read(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, &kernel_buffer, &actualCount);
    if (kr != KERN_SUCCESS) {
        RDErrorLog("mach_vm_read() failed with error: 0x%x", kr);
        free(buffer);
        return NULL;
    }

    if (actualCount != count) {
        RDErrorLog("mach_vm_read() failed due to invalid count");
        mach_vm_deallocate(mach_task_self(), kernel_buffer, actualCount);
        free(buffer);
        return NULL;
    }

    // 拷贝内核映射的内存内容到用户缓冲区
    memcpy(buffer, (void*)kernel_buffer, count);
    // 释放内核分配的映射内存
    mach_vm_deallocate(mach_task_self(), kernel_buffer, count);

    kr = mach_vm_protect(mach_task_self(), (mach_vm_address_t) address, (mach_vm_size_t) count, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
    if (kr != KERN_SUCCESS) {
        free(buffer);
        RDErrorLog("mach_vm_protect() failed with error: 0x%x", kr);
        return NULL;
    }

    return buffer;
}

补充说明

  • mach_vm_read由内核分配内存存储读取内容,返回该内存的内核地址,用户必须调用mach_vm_deallocate释放这块内存,避免内存泄漏。
  • 恢复目标内存权限的步骤保留,防止破坏原有内存的权限属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 14:15:08