Created
June 24, 2023 08:41
-
-
Save wh1te4ever/d43970844c99a7bab89c5975a5cb6afa to your computer and use it in GitHub Desktop.
Revisions
-
wh1te4ever created this gist
Jun 24, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,297 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <mach/mach.h> #include <mach/vm_map.h> #include <mach-o/loader.h> #include <mach-o/dyld_images.h> #include <fcntl.h> #define PATH_MAX 1024 kern_return_t mach_vm_read_overwrite(vm_map_t, mach_vm_address_t, mach_vm_size_t, mach_vm_address_t, mach_vm_size_t *); kern_return_t mach_vm_region(vm_map_read_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t *infoCnt, mach_port_t *object_name); kern_return_t find_main_binary(pid_t pid, mach_vm_address_t *main_address) { vm_map_t targetTask = 0; kern_return_t kr = 0; if (task_for_pid(mach_task_self(), pid, &targetTask)) { printf("[-] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n"); return KERN_FAILURE; } vm_address_t iter = 0; while (1) { struct mach_header mh = {0}; vm_address_t addr = iter; vm_size_t lsize = 0; uint32_t depth; mach_vm_size_t bytes_read = 0; struct vm_region_submap_info_64 info; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; if (vm_region_recurse_64(targetTask, &addr, &lsize, &depth, (vm_region_info_t)&info, &count)) { break; } kr = mach_vm_read_overwrite(targetTask, (mach_vm_address_t)addr, (mach_vm_size_t)sizeof(struct mach_header), (mach_vm_address_t)&mh, &bytes_read); if (kr == KERN_SUCCESS && bytes_read == sizeof(struct mach_header)) { /* only one image with MH_EXECUTE filetype */ if ( (mh.magic == MH_MAGIC || mh.magic == MH_MAGIC_64) && mh.filetype == MH_EXECUTE) { *main_address = addr; break; } } iter = addr + lsize; } return KERN_SUCCESS; } static kern_return_t readmem(mach_vm_offset_t *buffer, mach_vm_address_t address, mach_vm_size_t size, pid_t pid, vm_region_basic_info_data_64_t *info) { // get task for pid vm_map_t port; kern_return_t kr; if (task_for_pid(mach_task_self(), pid, &port)) { fprintf(stderr, "[ERROR] Can't execute task_for_pid! Do you have the right permissions/entitlements?\n"); return KERN_FAILURE; } mach_msg_type_number_t info_cnt = sizeof (vm_region_basic_info_data_64_t); mach_port_t object_name; mach_vm_size_t size_info; mach_vm_address_t address_info = address; kr = mach_vm_region(port, &address_info, &size_info, VM_REGION_BASIC_INFO_64, (vm_region_info_t)info, &info_cnt, &object_name); if (kr) { fprintf(stderr, "[ERROR] mach_vm_region failed with error %d\n", (int)kr); return KERN_FAILURE; } /* read memory - vm_read_overwrite because we supply the buffer */ mach_vm_size_t nread; kr = mach_vm_read_overwrite(port, address, size, (mach_vm_address_t)buffer, &nread); if (kr) { fprintf(stderr, "[ERROR] vm_read failed! %d\n", kr); return KERN_FAILURE; } else if (nread != size) { fprintf(stderr, "[ERROR] vm_read failed! requested size: 0x%llx read: 0x%llx\n", size, nread); return KERN_FAILURE; } return KERN_SUCCESS; } int64_t get_image_size(mach_vm_address_t address, pid_t pid, uint64_t *vmaddr_slide) { vm_region_basic_info_data_64_t region_info = {0}; // allocate a buffer to read the header info // NOTE: this is not exactly correct since the 64bit version has an extra 4 bytes // but this will work for this purpose so no need for more complexity! struct mach_header header = {0}; if (readmem((mach_vm_offset_t*)&header, address, sizeof(struct mach_header), pid, ®ion_info)) { printf("Can't read header!\n"); return -1; } if (header.magic != MH_MAGIC && header.magic != MH_MAGIC_64) { printf("[ERROR] Target is not a mach-o binary!\n"); return -1; } int64_t imagefilesize = -1; /* read the load commands */ uint8_t *loadcmds = (uint8_t*)malloc(header.sizeofcmds); uint16_t mach_header_size = sizeof(struct mach_header); if (header.magic == MH_MAGIC_64) { mach_header_size = sizeof(struct mach_header_64); } if (readmem((mach_vm_offset_t*)loadcmds, address+mach_header_size, header.sizeofcmds, pid, ®ion_info)) { printf("Can't read load commands\n"); free(loadcmds); return -1; } /* process and retrieve address and size of linkedit */ uint8_t *loadCmdAddress = 0; loadCmdAddress = (uint8_t*)loadcmds; struct load_command *loadCommand = NULL; struct segment_command *segCmd = NULL; struct segment_command_64 *segCmd64 = NULL; for (uint32_t i = 0; i < header.ncmds; i++) { loadCommand = (struct load_command*)loadCmdAddress; if (loadCommand->cmd == LC_SEGMENT) { segCmd = (struct segment_command*)loadCmdAddress; if (strncmp(segCmd->segname, "__PAGEZERO", 16) != 0) { if (strncmp(segCmd->segname, "__TEXT", 16) == 0) { *vmaddr_slide = address - segCmd->vmaddr; } imagefilesize += segCmd->filesize; } } else if (loadCommand->cmd == LC_SEGMENT_64) { segCmd64 = (struct segment_command_64*)loadCmdAddress; if (strncmp(segCmd64->segname, "__PAGEZERO", 16) != 0) { if (strncmp(segCmd64->segname, "__TEXT", 16) == 0) { *vmaddr_slide = address - segCmd64->vmaddr; } imagefilesize += segCmd64->filesize; } } // advance to next command loadCmdAddress += loadCommand->cmdsize; } free(loadcmds); return imagefilesize; } kern_return_t dump_binary(mach_vm_address_t address, pid_t pid, uint8_t *buffer, uint64_t aslr_slide, char* segment_name, int *segment_size) { vm_region_basic_info_data_64_t region_info = {0}; // allocate a buffer to read the header info // NOTE: this is not exactly correct since the 64bit version has an extra 4 bytes // but this will work for this purpose so no need for more complexity! struct mach_header header = {0}; if (readmem((mach_vm_offset_t*)&header, address, sizeof(struct mach_header), pid, ®ion_info)) { printf("Can't read header!\n"); return KERN_FAILURE; } if (header.magic != MH_MAGIC && header.magic != MH_MAGIC_64) { printf("[ERROR] Target is not a mach-o binary!\n"); return KERN_FAILURE; } // read the header info to find the LINKEDIT uint8_t *loadcmds = (uint8_t*)malloc(header.sizeofcmds); uint16_t mach_header_size = sizeof(struct mach_header); if (header.magic == MH_MAGIC_64) { mach_header_size = sizeof(struct mach_header_64); } // retrieve the load commands if (readmem((mach_vm_offset_t*)loadcmds, address+mach_header_size, header.sizeofcmds, pid, ®ion_info)) { printf("Can't read load commands\n"); free(loadcmds); loadcmds = NULL; return KERN_FAILURE; } // process and retrieve address and size of linkedit uint8_t *loadCmdAddress = 0; loadCmdAddress = (uint8_t*)loadcmds; struct load_command *loadCommand = NULL; struct segment_command *segCmd = NULL; struct segment_command_64 *segCmd64 = NULL; for (uint32_t i = 0; i < header.ncmds; i++) { loadCommand = (struct load_command*)loadCmdAddress; if (loadCommand->cmd == LC_SEGMENT) { segCmd = (struct segment_command*)loadCmdAddress; // printf("LC_SEGMENT segCmd->segname: %s\n", segCmd->segname); } else if (loadCommand->cmd == LC_SEGMENT_64) { segCmd64 = (struct segment_command_64*)loadCmdAddress; // printf("LC_SEGMENT_64 segCmd->segname: %s\n", segCmd64->segname); if(strcmp(segCmd64->segname, segment_name) == 0) { // buffer += segCmd64->filesize; printf("[+] Found %s at 0x%llx with size 0x%llx\n", segCmd64->segname, segCmd64->vmaddr+aslr_slide, segCmd64->filesize); readmem((mach_vm_offset_t*)buffer, segCmd64->vmaddr+aslr_slide, segCmd64->filesize, pid, ®ion_info); *segment_size = segCmd64->filesize; } } loadCmdAddress += loadCommand->cmdsize; } free(loadcmds); loadcmds = NULL; return KERN_SUCCESS; } int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <pid>\n", argv[0]); return 1; } pid_t targetPID = atoi(argv[1]); mach_vm_address_t mainAddress = 0; if (find_main_binary(targetPID, &mainAddress)) { printf("[-] Failed to find main binary address!"); return 1; } uint64_t aslr_slide = 0; uint64_t imagesize = 0; if ( (imagesize = get_image_size(mainAddress, targetPID, &aslr_slide)) == 0 ) { printf("[ERROR] Got image file size equal to 0!\n"); return 1; } printf("[+] image size: 0x%llx, aslr_slide: 0x%llx\n", imagesize, aslr_slide); uint8_t *readbuffer = (uint8_t*)malloc(imagesize); printf("[i] buffer allocated: %p, size: 0x%llx\n", readbuffer, imagesize); int segment_size = 0; if (dump_binary(mainAddress, targetPID, readbuffer, aslr_slide, "__LINKEDIT", &segment_size)) { printf("Failed to dump memory of __LINKEDIT segment!\n"); free(readbuffer); return 1; } char* filename = "/tmp/app_linkedit.bin"; remove(filename); int fd=open(filename, O_CREAT|O_RDWR|O_TRUNC, 0666); write(fd, readbuffer, segment_size); close(fd); if (dump_binary(mainAddress, targetPID, readbuffer, aslr_slide, "__DATA", &segment_size)) { printf("Failed to dump memory of __DATA segment!\n"); free(readbuffer); return 1; } filename = "/tmp/app_data.bin"; remove(filename); fd=open(filename, O_CREAT|O_RDWR|O_TRUNC, 0666); write(fd, readbuffer, segment_size); close(fd); free(readbuffer); return 0; }