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
相关产品推荐
相关产品推荐

