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

mach_vm_write()调用失败求助:mach_vm_protect()成功仍报KERN_INVALID_ADDRESS

解决Rosetta进程mach_vm_protect成功但mach_vm_write返回KERN_INVALID_ADDRESS的问题

可能的原因及对应解决方案

1. 内存保护操作未按页粒度执行

Mach的内存保护是按页粒度生效的,你当前只针对4字节范围调用mach_vm_protect,内核可能并未实际修改该地址所在页的权限。

修复代码:先计算目标地址所在页的起始地址,对整个页执行保护修改:

#include <mach/mach_vm.h>

char bytes[] = {"\x03\x68\xF6\x3C\x03\x3C\x80\x3D\x02\x38\x80\x3D"};
vm_address_t nop_addr = find_bytes_in_rosetta(task, bytes, 12);
char nop[] = {"\x1f\x20\x03\xd5"};
printf("%p\n", nop_addr);

// 计算目标地址所在页的起始地址
vm_size_t page_size = vm_page_size;
vm_address_t target_addr = nop_addr + 4;
vm_address_t page_start = target_addr & ~(page_size - 1);

// 对整个页设置可写权限并启用写时复制
kern_return_t prot_ret = mach_vm_protect(task, page_start, page_size, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY);
printf("mach_vm_protect ret: %d\n", prot_ret);

// 执行写入
kern_return_t write_ret = mach_vm_write(task, target_addr, (vm_address_t)nop, 4);
printf("mach_vm_write ret: %d\n", write_ret);

2. 目标内存区域受特殊保护(Rosetta/SIP限制)

Rosetta作为Apple的转译层,其进程内存可能带有额外的内核级防护,即使mach_vm_protect返回成功,内核也可能阻止实际写入。此外,系统完整性保护(SIP)会限制对系统进程内存的修改。

排查步骤:

  • 用vm_region_recurse_64查看目标地址的内存属性,确认实际权限:
    vm_address_t region_addr = target_addr;
    vm_size_t region_size;
    vm_region_submap_info_64 info;
    mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
    kern_return_t region_ret = mach_vm_region_recurse_64(task, &region_addr, &region_size, &info, &info_count);
    if (region_ret == KERN_SUCCESS) {
        printf("Region protection: 0x%x\n", info.protection);
        printf("Max protection: 0x%x\n", info.max_protection);
        printf("Region flags: 0x%x\n", info.user_tag);
    }
    
    如果max_protection不包含VM_PROT_WRITE,说明该区域无法被修改。
  • 临时关闭SIP(仅用于测试):重启Mac进入恢复模式,执行csrutil disable,重启后再测试写入。测试完成后记得用csrutil enable重新开启SIP。

3. Task Port权限不足

确保你通过task_for_pid获取的目标进程task port拥有足够权限:

  • 必须以root用户运行程序,或者拥有调试目标进程的权限(比如通过lldb附加过目标进程)。

4. 尝试替代写入方式

如果直接mach_vm_write仍失败,可以尝试先在目标进程分配可写内存,写入数据后再复制到目标地址:

// 在目标进程分配内存
vm_address_t temp_addr;
kern_return_t alloc_ret = mach_vm_allocate(task, &temp_addr, 4, VM_FLAGS_ANYWHERE);
if (alloc_ret == KERN_SUCCESS) {
    // 写入临时内存
    mach_vm_write(task, temp_addr, (vm_address_t)nop, 4);
    // 复制到目标地址
    mach_vm_copy(task, temp_addr, 4, target_addr);
    // 释放临时内存
    mach_vm_deallocate(task, temp_addr, 4);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:25:21