mach_vm_write返回(os/kern) invalid address错误的排查求助
嘿,我来帮你排查下mach_vm_write()返回(os/kern) invalid address的问题,结合你的代码片段,大概率是这几个原因导致的,咱们一个个捋清楚:
你通过base + 0x77777算出的地址看起来数值有效,但它可能落在只读代码段、已释放内存或者未映射的区域里。你可以用mach_vm_region()先检查这个地址的内存属性:
mach_vm_size_t region_size; vm_region_basic_info_data_64_t info; mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; mach_port_t object_name; // 检查address_1所在的内存区域 kret = mach_vm_region(task, &address_1, ®ion_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &info_count, &object_name); if (kret == KERN_SUCCESS) { // 确认区域是否有写入权限 if (!(info.protection & VM_PROT_WRITE)) { // 先修改内存保护属性,添加写权限 kret = mach_vm_protect(task, address_1, sizeof(patch_1), FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); if (kret != KERN_SUCCESS) { // 处理权限修改失败的情况,比如打印错误信息 fprintf(stderr, "Failed to change memory protection: %s\n", mach_error_string(kret)); } } }
记得写完内存后,最好把权限改回原来的状态,避免破坏目标进程的内存稳定性。
虽然task_for_pid()成功拿到了任务端口,但macOS的权限机制很严格:
- 如果目标是系统进程、签名过的App,普通用户权限根本没法写入
- 即使是普通进程,也可能需要root权限或者调试权限才能修改内存
解决办法:
- 先尝试用
sudo运行你的程序,看看是否能解决 - 如果是调试签名App,要么关闭系统完整性保护(SIP),要么给你的程序添加调试 entitlement(用
codesign工具配置)
你调用的get_task_base()返回的基地址真的准确吗?尤其是开启ASLR的情况下,进程的基地址每次启动都会变化,而且如果你的偏移是相对于某个动态库的,那应该用动态库的加载地址,而不是主可执行文件的基地址。
你可以通过lldb附加到目标进程,用image list命令查看实际的基地址,对比你代码里拿到的base值,就能快速验证是不是这里出了问题。
你要写入6字节的数据,得确保address_1到address_1 + 5的所有字节都在同一个有效的内存区域里。比如如果address_1刚好在某个内存页的末尾,那跨页的写入就会失败。用刚才的mach_vm_region()可以检查region_size是否大于等于sizeof(patch_1),以及address_1 + sizeof(patch_1)是否在区域范围内。
在调用mach_vm_write()之前,先把address_1的值打印出来,然后用lldb附加到目标进程,执行memory read 0x你的address_1值,看看这个地址能不能读出内容。如果读都读不了,那肯定写不了,直接就能定位是地址本身的问题。
内容的提问来源于stack exchange,提问作者Ben Stafford

