def lookup_svc_insn(debugger, startAddr, endAddr): command_script = '@import Foundation;\n' command_script += 'uint64_t text_start = {};uint64_t text_end = {};\n'.format( startAddr, endAddr) command_script += r''' NSMutableString* retStr = [NSMutableString string]; uint8_t * p = (uint8_t*)text_start; int size = text_end - text_start; char* ret = (char *)malloc(sizeof(char)); for(int i = 0; i < size ;i++ ){ /* mov x16, #0x1a -> 0xd2800350 svc #0x80 -> 0xd4001001 */ if (*((uint32_t*)p) == 0xd4001001) { [retStr appendString:@" "]; [retStr appendString:(id)[@((uint64_t)p) stringValue]]; } p++; } retStr ''' retStr = exeScript(debugger, command_script) return utils.hex_int_in_str(retStr)
def get_address_info_by_address(debugger, address): command_script = 'void * targetAddr = (void*)' + address + ';' command_script += r''' NSMutableString* retStr = [NSMutableString string]; typedef struct dl_info { const char *dli_fname; /* Pathname of shared object */ void *dli_fbase; /* Base address of shared object */ const char *dli_sname; /* Name of nearest symbol */ void *dli_saddr; /* Address of nearest symbol */ } Dl_info; Dl_info dl_info; dladdr(targetAddr, &dl_info); char* module_path = (char*)dl_info.dli_fname; uintptr_t module_base = (uintptr_t)dl_info.dli_fbase; char* symbol_name = (char*)dl_info.dli_sname; uintptr_t symbol_addr = (uintptr_t)dl_info.dli_saddr; [retStr appendString:@"Module path: "]; [retStr appendString:@(module_path)]; [retStr appendString:@"\nModule base: "]; [retStr appendString:(id)[@(module_base) stringValue]]; long slide = 0; NSString* targetModulePath = @(module_path); uint32_t count = (uint32_t)_dyld_image_count(); for(uint32_t i = 0; i < count; i++){ char* curModuleName_cstr = (char*)_dyld_get_image_name(i); slide = (long)_dyld_get_image_vmaddr_slide(i); uintptr_t baseAddr = (uintptr_t)_dyld_get_image_header(i); NSString* curModuleName = @(curModuleName_cstr); if([curModuleName isEqualToString:targetModulePath]) { [retStr appendString:@"\nModule slide: "]; [retStr appendString:(id)[@(slide) stringValue]]; break; } } [retStr appendString:@"\ntarget addr: "]; [retStr appendString:(id)[@((uintptr_t)targetAddr) stringValue]]; uintptr_t target_file_addr = (uintptr_t)((uint64_t)targetAddr - slide); [retStr appendString:@"\nFile addr: "]; [retStr appendString:(id)[@(target_file_addr) stringValue]]; [retStr appendString:@"\nSymbol name: "]; [retStr appendString:@(symbol_name)]; [retStr appendString:@"\nSymbol addr: "]; [retStr appendString:(id)[@(symbol_addr) stringValue]]; retStr ''' retStr = utils.exe_script(debugger, command_script) return utils.hex_int_in_str(retStr)
def get_func_info_by_name(debugger, funcName): command_script = 'const char * func_name = "' + funcName + '";' command_script += r''' NSMutableString* retStr = [NSMutableString string]; #define RTLD_LAZY 0x1 #define RTLD_NOW 0x2 #define RTLD_LOCAL 0x4 #define RTLD_GLOBAL 0x8 typedef struct dl_info { const char *dli_fname; /* Pathname of shared object */ void *dli_fbase; /* Base address of shared object */ const char *dli_sname; /* Name of nearest symbol */ void *dli_saddr; /* Address of nearest symbol */ } Dl_info; Dl_info dl_info; void* handle = (void*)dlopen(0, RTLD_GLOBAL | RTLD_NOW); void* target_ptr = (void*)dlsym(handle, func_name); if(target_ptr){ uintptr_t target_addr = (uintptr_t)target_ptr; dladdr(target_ptr, &dl_info); char* module_path = (char*)dl_info.dli_fname; uintptr_t module_base = (uintptr_t)dl_info.dli_fbase; char* symbol_name = (char*)dl_info.dli_sname; uintptr_t symbol_addr = (uintptr_t)dl_info.dli_saddr; [retStr appendString:@"Func name: "]; [retStr appendString:@((char*)func_name)]; [retStr appendString:@"\nFunc addr: "]; [retStr appendString:(id)[@(target_addr) stringValue]]; [retStr appendString:@"\nModule Path: "]; [retStr appendString:@(module_path)]; [retStr appendString:@"\nModule base: "]; [retStr appendString:(id)[@(module_base) stringValue]]; [retStr appendString:@"\nSymbol name: "]; [retStr appendString:@(symbol_name)]; [retStr appendString:@"\nSymbol addr: "]; [retStr appendString:(id)[@(symbol_addr) stringValue]]; }else{ [retStr appendString:@"[-] dlsym not found symbol:"]; [retStr appendString:@((char*)func_name)]; } retStr ''' retStr = utils.exe_script(debugger, command_script) return utils.hex_int_in_str(retStr)
def get_module_info_by_name(debugger, moduleName): command_script = '@import Foundation;NSString* moduleName = @"' + moduleName + '";' command_script += r''' NSMutableString* retStr = [NSMutableString string]; uint32_t count = (uint32_t)_dyld_image_count(); for(uint32_t i = 0; i < count; i++){ char* curModuleName_cstr = (char*)_dyld_get_image_name(i); long slide = (long)_dyld_get_image_vmaddr_slide(i); uintptr_t baseAddr = (uintptr_t)_dyld_get_image_header(i); NSString* curModuleName = @(curModuleName_cstr); if([curModuleName containsString:moduleName]) { [retStr appendString:@"\n=======\nModule Path : "]; [retStr appendString:@(curModuleName_cstr)]; [retStr appendString:@"\nModule Silde: "]; [retStr appendString:(id)[@(slide) stringValue]]; [retStr appendString:@"\nModule base : "]; [retStr appendString:(id)[@(baseAddr) stringValue]]; } } retStr ''' retStr = utils.exe_script(debugger, command_script) if "error" in retStr: utils.ELOG("something error in OC script # " + retStr.strip()) utils.ILOG("so use command to get info") ret = utils.exe_cmd(debugger, "im li -o -f") pattern = ".*" + moduleName.replace("\"", "") match = re.search(pattern, ret) # TODO: more strict if match: found = match.group(0) else: utils.ELOG("not found image:" + moduleName) return return found return utils.hex_int_in_str(retStr)
def patch_ptrace(debugger): command_script = '' command_script += r''' NSMutableString* retStr = [NSMutableString string]; #define PAGE_SIZE 0x0000000000004000 #define PAGE_MASK 0x0000000000003fff #define RTLD_LAZY 0x1 #define RTLD_NOW 0x2 #define RTLD_LOCAL 0x4 #define RTLD_GLOBAL 0x8 #define VM_PROT_READ ((vm_prot_t) 0x01) #define VM_PROT_WRITE ((vm_prot_t) 0x02) #define VM_PROT_EXECUTE ((vm_prot_t) 0x04) #define PROT_NONE 0x00 /* [MC2] no permissions */ #define PROT_READ 0x01 /* [MC2] pages can be read */ #define PROT_WRITE 0x02 /* [MC2] pages can be written */ #define PROT_EXEC 0x04 /* [MC2] pages can be executed */ #define MAP_SHARED 0x0001 #define MAP_ANON 0x1000 #define KERN_SUCCESS 0 typedef unsigned int mach_port_t; typedef int kern_return_t; typedef unsigned int vm_inherit_t; typedef mach_port_t task_t; typedef int vm_prot_t; typedef unsigned long uintptr_t; typedef uintptr_t vm_offset_t; typedef vm_offset_t vm_address_t; typedef uint64_t mach_vm_address_t; typedef int boolean_t; typedef int vm_behavior_t; typedef uint32_t vm32_object_id_t; typedef uintptr_t vm_size_t; typedef int *vm_region_recurse_info_t; typedef unsigned long long memory_object_offset_t; struct vm_region_submap_short_info_64 { vm_prot_t protection; /* present access protection */ vm_prot_t max_protection; /* max avail through vm_prot */ vm_inherit_t inheritance;/* behavior of map/obj on fork */ memory_object_offset_t offset; /* offset into object/map */ unsigned int user_tag; /* user tag on map entry */ unsigned int ref_count; /* obj/map mappers, etc */ unsigned short shadow_depth; /* only for obj */ unsigned char external_pager; /* only for obj */ unsigned char share_mode; /* see enumeration */ boolean_t is_submap; /* submap vs obj */ vm_behavior_t behavior; /* access behavior hint */ vm32_object_id_t object_id; /* obj/map name, not a handle */ unsigned short user_wired_count; }; typedef unsigned int __darwin_natural_t; typedef __darwin_natural_t natural_t; typedef natural_t mach_msg_type_number_t; typedef struct vm_region_submap_short_info_64 vm_region_submap_short_info_data_64_t; #define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 \ ((mach_msg_type_number_t) \ (sizeof (vm_region_submap_short_info_data_64_t) / sizeof (natural_t))) #define VM_FLAGS_OVERWRITE 0x4000 /* delete any existing mappings first */ typedef int __int32_t; typedef __int32_t __darwin_pid_t; typedef __darwin_pid_t pid_t; // init value kern_return_t kret; task_t self_task = (task_t)mach_task_self(); /* Set platform binary flag */ #define FLAG_PLATFORMIZE (1 << 1) // platformize_me // https://github.com/pwn20wndstuff/Undecimus/issues/112 /* void* handle = (void*)dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY); if (!handle){ [retStr appendString:@"[-] /usr/lib/libjailbreak.dylib dlopen failed!\n"]; return; } // Reset errors (const char *)dlerror(); typedef void (*fix_entitle_prt_t)(pid_t pid, uint32_t what); fix_entitle_prt_t ptr = (fix_entitle_prt_t)dlsym(handle, "jb_oneshot_entitle_now"); const char *dlsym_error = (const char *)dlerror(); if (dlsym_error) return; ptr((pid_t)getpid(), FLAG_PLATFORMIZE); [retStr appendString:@"\n[+] platformize me success!"]; */ // get target address and page void* handle = (void*)dlopen(0, RTLD_GLOBAL | RTLD_NOW); uintptr_t target_ptr = (uintptr_t)dlsym(handle, "ptrace"); unsigned long page_start = (unsigned long) (target_ptr) & ~PAGE_MASK; unsigned long patch_offset = (unsigned long)target_ptr - page_start; [retStr appendString:@"\n[*] ptrace target address: "]; [retStr appendString:(id)[@((uintptr_t)target_ptr) stringValue]] [retStr appendString:@" and offset: "]; [retStr appendString:(id)[@((uintptr_t)patch_offset) stringValue]] [retStr appendString:@"\n"]; // map new page for patch void *new_page = (void *)mmap(NULL, PAGE_SIZE, 0x1 | 0x2, 0x1000 | 0x0001, -1, 0); if (!new_page ){ [retStr appendString:@"[-] mmap failed!\n"]; return; } [retStr appendString:@"[*] mmap new page: "]; [retStr appendString:(id)[@((uintptr_t)new_page) stringValue]] [retStr appendString:@" success. \n"]; kret = (kern_return_t)vm_copy(self_task, (unsigned long)page_start, PAGE_SIZE, (vm_address_t) new_page); if (kret != KERN_SUCCESS){ [retStr appendString:@"[-] vm_copy faild!\n"]; return; } [retStr appendString:@"[+] vm_copy target to new page.\n"]; // start patch uint8_t patch_ret_ins_data[4] = {0xc0, 0x03, 0x5f, 0xd6}; // ret /* kret = (kern_return_t)mach_vm_write(self_task, (vm_address_t)((unsigned long)new_page+patch_offset), (vm_offset_t)patch_ret_ins_data, 4); if (kret != KERN_SUCCESS){ [retStr appendString:@"[-] patch data mach_vm_write faild!\n"]; return; } */ // use memcpy to replace mach_vm_write memcpy((void *)((unsigned long)new_page+patch_offset), patch_ret_ins_data, 4); [retStr appendString:@"[+] patch ret[0xc0 0x03 0x5f 0xd6] with memcpy\n"]; // set back to r-x (int)mprotect(new_page, PAGE_SIZE, PROT_READ | PROT_EXEC); [retStr appendString:@"[*] set new page back to r-x success!\n"]; // remap vm_prot_t prot; vm_inherit_t inherit; // get page info vm_address_t region = (vm_address_t) page_start; vm_size_t region_len = 0; struct vm_region_submap_short_info_64 vm_info; mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; natural_t max_depth = 99999; kret = (kern_return_t)vm_region_recurse_64(self_task, ®ion, ®ion_len, &max_depth, (vm_region_recurse_info_t) &vm_info, &info_count); if (kret != KERN_SUCCESS){ [retStr appendString:@"[-] vm_region_recurse_64 faild!\n"]; return; } prot = vm_info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC); inherit = vm_info.inheritance; [retStr appendString:@"[*] get page info done.\n"]; vm_prot_t c; vm_prot_t m; mach_vm_address_t target = (mach_vm_address_t)page_start; kret = (kern_return_t)mach_vm_remap(self_task, &target, PAGE_SIZE, 0, VM_FLAGS_OVERWRITE, self_task, (mach_vm_address_t) new_page, true, &c, &m, inherit); if (kret != KERN_SUCCESS){ [retStr appendString:@"[-] remap mach_vm_remap faild!\n"]; return; } [retStr appendString:@"[+] remap to target success!\n"]; // clear cache void* clear_start_ = (void*)(page_start + patch_offset); sys_icache_invalidate (clear_start_, 4); sys_dcache_flush (clear_start_, 4); [retStr appendString:@"[*] clear cache success!\n"]; [retStr appendString:@"[+] all done! happy debug~"]; retStr ''' retStr = exeScript(debugger, command_script) return utils.hex_int_in_str(retStr)
def xia0Hook(debugger, svcAddr): command_script = '@import Foundation;\n' command_script += 'uint64_t target_addr = {};\n'.format(svcAddr) command_script += r''' NSMutableString* retStr = [NSMutableString string]; #define PAGE_SIZE 0x0000000000004000 #define PAGE_MASK 0x0000000000003fff #define VM_PROT_READ ((vm_prot_t) 0x01) #define VM_PROT_WRITE ((vm_prot_t) 0x02) #define VM_PROT_EXECUTE ((vm_prot_t) 0x04) #define PROT_NONE 0x00 /* [MC2] no permissions */ #define PROT_READ 0x01 /* [MC2] pages can be read */ #define PROT_WRITE 0x02 /* [MC2] pages can be written */ #define PROT_EXEC 0x04 /* [MC2] pages can be executed */ #define MAP_SHARED 0x0001 #define MAP_ANON 0x1000 #define KERN_SUCCESS 0 int len = (int)sysconf(_SC_PAGESIZE); [retStr appendString:@"len= "]; [retStr appendString:(id)[@(len) stringValue]]; [retStr appendString:@"\n"]; // 1. get target address page and patch offset unsigned long page_start = (unsigned long) (target_addr) & ~PAGE_MASK; unsigned long patch_offset = (unsigned long)target_addr - page_start; // 2. map new page for patch void *new_page = (void *)mmap(NULL, PAGE_SIZE, 0x1 | 0x2, 0x1000 | 0x0001, -1, 0); [retStr appendString:@"new_page= "]; [retStr appendString:(id)[@((uint64_t)new_page) stringValue]]; [retStr appendString:@"\n"]; // 3.copy target 4 ins to new page int copy_size = 4*4; void* copy_from_addr = ( void*)(target_addr - copy_size); memcpy((void *)(new_page), copy_from_addr, copy_size); uint64_t orig_svc_addr = (uint64_t)target_addr; uint64_t orig_svc_next_addr = (uint64_t)(target_addr+1*4); // just check x16 /* cmp x16, #0x1a b.ne loc_not_ptrace_svc_jmp ldr x17, #0x8 br x17 orig_svc_next_addr_1 orig_svc_next_addr_2 ldr x17, #0x8 br x17 orig_svc_addr_1 orig_svc_addr_2 */ //uint8_t check_jmp_data[] = {0x1f, 0x6a, 0x00, 0xf1,0xa1, 0x00, 0x00, 0x54,0x51, 0x00, 0x00, 0x58, 0x20, 0x02, 0x1f, 0xd6, (uint8_t)((orig_svc_next_addr&0xff)), (uint8_t)((orig_svc_next_addr>>8*1)&0xff), (uint8_t)((orig_svc_next_addr>>8*2)&0xff), (uint8_t)((orig_svc_next_addr>>8*3)&0xff), (uint8_t)((orig_svc_next_addr>>8*4)&0xff), (uint8_t)((orig_svc_next_addr>>8*5)&0xff), (uint8_t)((orig_svc_next_addr>>8*6)&0xff), (uint8_t)((orig_svc_next_addr>>8*7)&0xff), 0x51, 0x00, 0x00, 0x58, 0x20, 0x02, 0x1f, 0xd6, (uint8_t)((orig_svc_addr&0xff)), (uint8_t)((orig_svc_addr>>8*1)&0xff), (uint8_t)((orig_svc_addr>>8*2)&0xff), (uint8_t)((orig_svc_addr>>8*3)&0xff), (uint8_t)((orig_svc_addr>>8*4)&0xff), (uint8_t)((orig_svc_addr>>8*5)&0xff), (uint8_t)((orig_svc_addr>>8*6)&0xff), (uint8_t)((orig_svc_addr>>8*7)&0xff)}; //int check_jmp_data_size = 10*4; // new check x16 and x0 /* new check syscall() cmp x16, #0x1a b.ne loc_next_syscall_check_jmp 0xa1, 0x00, 0x00, 0x54 ldr x17, #0x8 <------ loc_ptrace_handle_jmp br x17 orig_svc_next_addr_1 orig_svc_next_addr_2 cmp x16, #0x0 <------- loc_next_syscall_check_jmp b.ne loc_not_ptrace_jmp 0x61, 0x00, 0x00, 0x54 cmp x0, #0x1a b.e loc_ptrace_handle_jmp 0x20, 0xff, 0xff, 0x54 ldr x17, #0x8 <------- loc_not_ptrace_jmp br x17 orig_svc_addr_1 orig_svc_addr_2 */ uint8_t check_jmp_data[] = {0x1f, 0x6a, 0x00, 0xf1, \ 0xa1, 0x00, 0x00, 0x54, \ 0x51, 0x00, 0x00, 0x58, \ 0x20, 0x02, 0x1f, 0xd6, \ (uint8_t)((orig_svc_next_addr&0xff)), (uint8_t)((orig_svc_next_addr>>8*1)&0xff), (uint8_t)((orig_svc_next_addr>>8*2)&0xff), (uint8_t)((orig_svc_next_addr>>8*3)&0xff), (uint8_t)((orig_svc_next_addr>>8*4)&0xff), (uint8_t)((orig_svc_next_addr>>8*5)&0xff), (uint8_t)((orig_svc_next_addr>>8*6)&0xff), (uint8_t)((orig_svc_next_addr>>8*7)&0xff), \ 0x1f, 0x02, 0x00, 0xf1, \ 0x61, 0x00, 0x00, 0x54, \ 0x1f, 0x68, 0x00, 0xf1, \ 0x20, 0xff, 0xff, 0x54, \ 0x51, 0x00, 0x00, 0x58, \ 0x20, 0x02, 0x1f, 0xd6, \ (uint8_t)((orig_svc_addr&0xff)), (uint8_t)((orig_svc_addr>>8*1)&0xff), (uint8_t)((orig_svc_addr>>8*2)&0xff), (uint8_t)((orig_svc_addr>>8*3)&0xff), (uint8_t)((orig_svc_addr>>8*4)&0xff), (uint8_t)((orig_svc_addr>>8*5)&0xff), (uint8_t)((orig_svc_addr>>8*6)&0xff), (uint8_t)((orig_svc_addr>>8*7)&0xff)}; int check_jmp_data_size = 14*4; memcpy((void *)((uint64_t)new_page+4*4), (void*)check_jmp_data, check_jmp_data_size); // 4.patch target address to jmp hook code void* patch_addr = copy_from_addr; uint64_t new_p = (uint64_t)new_page; /* ldr x16, #0x8 br x16 hook_code_addr_1 hook_code_addr_2 */ uint8_t patch_data[] = {0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x1f, 0xd6, (uint8_t)(new_p&0xff), (uint8_t)((new_p>>8*1)&0xff), (uint8_t)((new_p>>8*2)&0xff), (uint8_t)((new_p>>8*3)&0xff), (uint8_t)((new_p>>8*4)&0xff), (uint8_t)((new_p>>8*5)&0xff), (uint8_t)((new_p>>8*6)&0xff), (uint8_t)((new_p>>8*7)&0xff)}; int patch_data_size = 4*4; // =====================================================patch code============================================= typedef bool (*patch_code_t)(void* patch_addr, uint8_t* patch_data, int patch_data_size); patch_code_t patch_code = [](void* patch_addr, uint8_t* patch_data, int patch_data_size) -> bool { #define PAGE_SIZE 0x0000000000004000 #define PAGE_MASK 0x0000000000003fff #define RTLD_LAZY 0x1 #define RTLD_NOW 0x2 #define RTLD_LOCAL 0x4 #define RTLD_GLOBAL 0x8 #define VM_PROT_READ ((vm_prot_t) 0x01) #define VM_PROT_WRITE ((vm_prot_t) 0x02) #define VM_PROT_EXECUTE ((vm_prot_t) 0x04) #define PROT_NONE 0x00 /* [MC2] no permissions */ #define PROT_READ 0x01 /* [MC2] pages can be read */ #define PROT_WRITE 0x02 /* [MC2] pages can be written */ #define PROT_EXEC 0x04 /* [MC2] pages can be executed */ #define MAP_SHARED 0x0001 #define MAP_ANON 0x1000 #define KERN_SUCCESS 0 typedef unsigned int mach_port_t; typedef int kern_return_t; typedef unsigned int vm_inherit_t; typedef mach_port_t task_t; typedef int vm_prot_t; typedef unsigned long uintptr_t; typedef uintptr_t vm_offset_t; typedef vm_offset_t vm_address_t; typedef uint64_t mach_vm_address_t; typedef int boolean_t; typedef int vm_behavior_t; typedef uint32_t vm32_object_id_t; typedef uintptr_t vm_size_t; typedef int *vm_region_recurse_info_t; typedef unsigned long long memory_object_offset_t; struct vm_region_submap_short_info_64 { vm_prot_t protection; /* present access protection */ vm_prot_t max_protection; /* max avail through vm_prot */ vm_inherit_t inheritance;/* behavior of map/obj on fork */ memory_object_offset_t offset; /* offset into object/map */ unsigned int user_tag; /* user tag on map entry */ unsigned int ref_count; /* obj/map mappers, etc */ unsigned short shadow_depth; /* only for obj */ unsigned char external_pager; /* only for obj */ unsigned char share_mode; /* see enumeration */ boolean_t is_submap; /* submap vs obj */ vm_behavior_t behavior; /* access behavior hint */ vm32_object_id_t object_id; /* obj/map name, not a handle */ unsigned short user_wired_count; }; typedef unsigned int __darwin_natural_t; typedef __darwin_natural_t natural_t; typedef natural_t mach_msg_type_number_t; typedef struct vm_region_submap_short_info_64 vm_region_submap_short_info_data_64_t; #define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 \ ((mach_msg_type_number_t) \ (sizeof (vm_region_submap_short_info_data_64_t) / sizeof (natural_t))) #define VM_FLAGS_OVERWRITE 0x4000 /* delete any existing mappings first */ typedef int __int32_t; typedef __int32_t __darwin_pid_t; typedef __darwin_pid_t pid_t; // init value kern_return_t kret; task_t self_task = (task_t)mach_task_self(); /* Set platform binary flag */ #define FLAG_PLATFORMIZE (1 << 1) // platformize_me // https://github.com/pwn20wndstuff/Undecimus/issues/112 /* void* handle = (void*)dlopen("/usr/lib/libjailbreak.dylib", RTLD_LAZY); if (!handle){ //[retStr appendString:@"[-] /usr/lib/libjailbreak.dylib dlopen failed!\n"]; return false; } // Reset errors (const char *)dlerror(); typedef void (*fix_entitle_prt_t)(pid_t pid, uint32_t what); fix_entitle_prt_t ptr = (fix_entitle_prt_t)dlsym(handle, "jb_oneshot_entitle_now"); const char *dlsym_error = (const char *)dlerror(); if (dlsym_error) return; ptr((pid_t)getpid(), FLAG_PLATFORMIZE); //[retStr appendString:@"\n[+] platformize me success!"]; */ void* target_addr = patch_addr; // 1. get target address page and patch offset unsigned long page_start = (unsigned long) (target_addr) & ~PAGE_MASK; unsigned long patch_offset = (unsigned long)target_addr - page_start; // map new page for patch void *new_page = (void *)mmap(NULL, PAGE_SIZE, 0x1 | 0x2, 0x1000 | 0x0001, -1, 0); if (!new_page ){ //[retStr appendString:@"[-] mmap failed!\n"]; return false; } kret = (kern_return_t)vm_copy(self_task, (unsigned long)page_start, PAGE_SIZE, (vm_address_t) new_page); if (kret != KERN_SUCCESS){ //[retStr appendString:@"[-] vm_copy faild!\n"]; return false; } // 4. start patch /* nop -> {0x1f, 0x20, 0x03, 0xd5} ret -> {0xc0, 0x03, 0x5f, 0xd6} */ // char patch_ins_data[4] = {0x1f, 0x20, 0x03, 0xd5}; // mach_vm_write(task_self, (vm_address_t)(new+patch_offset), patch_ret_ins_data, 4); memcpy((void *)((uint64_t)new_page+patch_offset), patch_data, patch_data_size); //[retStr appendString:@"[+] patch ret[0xc0 0x03 0x5f 0xd6] with memcpy\n"]; // set back to r-x (int)mprotect(new_page, PAGE_SIZE, PROT_READ | PROT_EXEC); //[retStr appendString:@"[*] set new page back to r-x success!\n"]; // remap vm_prot_t prot; vm_inherit_t inherit; // get page info vm_address_t region = (vm_address_t) page_start; vm_size_t region_len = 0; struct vm_region_submap_short_info_64 vm_info; mach_msg_type_number_t info_count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; natural_t max_depth = 99999; kret = (kern_return_t)vm_region_recurse_64(self_task, ®ion, ®ion_len, &max_depth, (vm_region_recurse_info_t) &vm_info, &info_count); if (kret != KERN_SUCCESS){ //[retStr appendString:@"[-] vm_region_recurse_64 faild!\n"]; return false; } prot = vm_info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC); inherit = vm_info.inheritance; //[retStr appendString:@"[*] get page info done.\n"]; vm_prot_t c; vm_prot_t m; mach_vm_address_t target = (mach_vm_address_t)page_start; kret = (kern_return_t)mach_vm_remap(self_task, &target, PAGE_SIZE, 0, VM_FLAGS_OVERWRITE, self_task, (mach_vm_address_t) new_page, true, &c, &m, inherit); if (kret != KERN_SUCCESS){ //[retStr appendString:@"[-] remap mach_vm_remap faild!\n"]; return false; } //[retStr appendString:@"[+] remap to target success!\n"]; // clear cache void* clear_start_ = (void*)(page_start + patch_offset); sys_icache_invalidate (clear_start_, 4); sys_dcache_flush (clear_start_, 4); return true; }; // =====================================================patch code============================================= patch_code(patch_addr, patch_data, patch_data_size); // 5. set new page to r-x mprotect(new_page, len, PROT_READ | PROT_EXEC); retStr ''' retStr = exeScript(debugger, command_script) return utils.hex_int_in_str(retStr)
def get_text_segment(debugger): command_script = '@import Foundation;' command_script += r''' //NSMutableString* retStr = [NSMutableString string]; #define MH_MAGIC_64 0xfeedfacf #define LC_SEGMENT_64 0x19 typedef int integer_t; typedef integer_t cpu_type_t; typedef integer_t cpu_subtype_t; typedef integer_t cpu_threadtype_t; struct mach_header_64 { uint32_t magic; /* mach magic number identifier */ cpu_type_t cputype; /* cpu specifier */ cpu_subtype_t cpusubtype; /* machine specifier */ uint32_t filetype; /* type of file */ uint32_t ncmds; /* number of load commands */ uint32_t sizeofcmds; /* the size of all the load commands */ uint32_t flags; /* flags */ uint32_t reserved; /* reserved */ }; struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ }; typedef int vm_prot_t; struct segment_command_64 { /* for 64-bit architectures */ uint32_t cmd; /* LC_SEGMENT_64 */ uint32_t cmdsize; /* includes sizeof section_64 structs */ char segname[16]; /* segment name */ uint64_t vmaddr; /* memory address of this segment */ uint64_t vmsize; /* memory size of this segment */ uint64_t fileoff; /* file offset of this segment */ uint64_t filesize; /* amount to map from the file */ vm_prot_t maxprot; /* maximum VM protection */ vm_prot_t initprot; /* initial VM protection */ uint32_t nsects; /* number of sections in segment */ uint32_t flags; /* flags */ }; struct section_64 { /* for 64-bit architectures */ char sectname[16]; /* name of this section */ char segname[16]; /* segment this section goes in */ uint64_t addr; /* memory address of this section */ uint64_t size; /* size in bytes of this section */ uint32_t offset; /* file offset of this section */ uint32_t align; /* section alignment (power of 2) */ uint32_t reloff; /* file offset of relocation entries */ uint32_t nreloc; /* number of relocation entries */ uint32_t flags; /* flags (section type and attributes)*/ uint32_t reserved1; /* reserved (for offset or index) */ uint32_t reserved2; /* reserved (for count or sizeof) */ uint32_t reserved3; /* reserved */ }; int x_offset = 0; struct mach_header_64* header = (struct mach_header_64*)_dyld_get_image_header(0); if(header->magic != MH_MAGIC_64) { return ; } x_offset = sizeof(struct mach_header_64); int ncmds = header->ncmds; uint64_t textStart = 0; uint64_t textEnd = 0; while(ncmds--) { /* go through all load command to find __TEXT segment*/ struct load_command * lcp = (struct load_command *)((uint8_t*)header + x_offset); x_offset += lcp->cmdsize; if(lcp->cmd == LC_SEGMENT_64) { struct segment_command_64 * curSegment = (struct segment_command_64 *)lcp; struct section_64* curSection = (struct section_64*)((uint8_t*)curSegment + sizeof(struct segment_command_64)); // check current section of segment is __TEXT? if(!strcmp(curSection->segname, "__TEXT") && !strcmp(curSection->sectname, "__text")){ uint64_t memAddr = curSection->addr; textStart = memAddr + (uint64_t)_dyld_get_image_vmaddr_slide(0); textEnd = textStart + curSection->size; /* [retStr appendString:@" "]; [retStr appendString:(id)[@(textStart) stringValue]]; [retStr appendString:@" , "]; [retStr appendString:(id)[@(textEnd) stringValue]]; */ break; } } } char ret[50]; char textStartAddrStr[20]; sprintf(textStartAddrStr, "0x%016lx", textStart); char textEndAddrStr[20]; sprintf(textEndAddrStr, "0x%016lx", textEnd); char* splitStr = ","; strcpy(ret,textStartAddrStr); strcat(ret,splitStr); strcat(ret,textEndAddrStr); ret ''' retStr = exeScript(debugger, command_script) return utils.hex_int_in_str(retStr)
def get_macho_mod_init_first_func(debugger): command_script = '@import Foundation;' command_script += r''' //NSMutableString* retStr = [NSMutableString string]; #define MH_MAGIC_64 0xfeedfacf #define LC_SEGMENT_64 0x19 typedef int integer_t; typedef integer_t cpu_type_t; typedef integer_t cpu_subtype_t; typedef integer_t cpu_threadtype_t; struct mach_header_64 { uint32_t magic; /* mach magic number identifier */ cpu_type_t cputype; /* cpu specifier */ cpu_subtype_t cpusubtype; /* machine specifier */ uint32_t filetype; /* type of file */ uint32_t ncmds; /* number of load commands */ uint32_t sizeofcmds; /* the size of all the load commands */ uint32_t flags; /* flags */ uint32_t reserved; /* reserved */ }; struct load_command { uint32_t cmd; /* type of load command */ uint32_t cmdsize; /* total size of command in bytes */ }; typedef int vm_prot_t; struct segment_command_64 { /* for 64-bit architectures */ uint32_t cmd; /* LC_SEGMENT_64 */ uint32_t cmdsize; /* includes sizeof section_64 structs */ char segname[16]; /* segment name */ uint64_t vmaddr; /* memory address of this segment */ uint64_t vmsize; /* memory size of this segment */ uint64_t fileoff; /* file offset of this segment */ uint64_t filesize; /* amount to map from the file */ vm_prot_t maxprot; /* maximum VM protection */ vm_prot_t initprot; /* initial VM protection */ uint32_t nsects; /* number of sections in segment */ uint32_t flags; /* flags */ }; struct section_64 { /* for 64-bit architectures */ char sectname[16]; /* name of this section */ char segname[16]; /* segment this section goes in */ uint64_t addr; /* memory address of this section */ uint64_t size; /* size in bytes of this section */ uint32_t offset; /* file offset of this section */ uint32_t align; /* section alignment (power of 2) */ uint32_t reloff; /* file offset of relocation entries */ uint32_t nreloc; /* number of relocation entries */ uint32_t flags; /* flags (section type and attributes)*/ uint32_t reserved1; /* reserved (for offset or index) */ uint32_t reserved2; /* reserved (for count or sizeof) */ uint32_t reserved3; /* reserved */ }; int x_offset = 0; struct mach_header_64* header = (struct mach_header_64*)_dyld_get_image_header(0); if(header->magic != MH_MAGIC_64) { return ; } x_offset = sizeof(struct mach_header_64); int ncmds = header->ncmds; uint64_t modInitFirstAddr = 0; char* secName; while(ncmds--) { /* go through all load command to find __TEXT segment*/ struct load_command * lcp = (struct load_command *)((uint8_t*)header + x_offset); x_offset += lcp->cmdsize; if(lcp->cmd == LC_SEGMENT_64) { struct segment_command_64 * curSegment = (struct segment_command_64 *)lcp; struct section_64* curSection = (struct section_64*)((uint8_t*)curSegment + sizeof(struct segment_command_64)); if(!strcmp(curSection->segname, "__DATA")){ for (int i = 0; i < curSegment->nsects; i++) { if (!strcmp(curSection->sectname, "__mod_init_func")) { uint64_t memAddr = curSection->addr; uint64_t modInitAddrArr = memAddr + (uint64_t)_dyld_get_image_vmaddr_slide(0); modInitFirstAddr = *((uint64_t*)modInitAddrArr) break; } curSection = (struct section_64*)((uint8_t*)curSection + sizeof(struct section_64)); } break; } } } char ret[50]; sprintf(ret, "0x%016lx", modInitFirstAddr); ret ''' retStr = utils.exe_script(debugger, command_script) return utils.hex_int_in_str(retStr)
def choose(debugger, classname): command_script = 'NSString * className = @"' + classname + '";' command_script += r''' // define #define KERN_SUCCESS 0 // typedef typedef unsigned long uintptr_t; #define MALLOC_PTR_IN_USE_RANGE_TYPE 1 typedef int kern_return_t; typedef unsigned int mach_port_t; typedef mach_port_t task_t; typedef uintptr_t vm_offset_t; typedef vm_offset_t vm_address_t; typedef uintptr_t vm_size_t; typedef struct { vm_address_t address; vm_size_t size; } vm_range_t; typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory); typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size); typedef struct malloc_introspection_t { kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */ } malloc_introspection_t; typedef struct _malloc_zone_t { void *reserved1; void *reserved2; size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); void *(*malloc)(struct _malloc_zone_t *zone, size_t size); void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); void *(*valloc)(struct _malloc_zone_t *zone, size_t size); void (*free)(struct _malloc_zone_t *zone, void *ptr); void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); void (*destroy)(struct _malloc_zone_t *zone); const char *zone_name; unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); struct malloc_introspection_t *introspect; unsigned version; void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size); void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size); size_t (*pressure_relief)(struct _malloc_zone_t *zone, size_t goal); } malloc_zone_t; struct XZChoice { NSMutableArray * query_; // std::set<Class> query_; NSMutableArray * result_; // std::set<id> result_; }; struct XZObjectStruct { Class isa_; }; // function memory_reader_t memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t { *local_memory = (void*) remote_address; return KERN_SUCCESS; }; // function copy_class_list: get the class list typedef Class * (*copy_class_list_t)(size_t &size); copy_class_list_t copy_class_list = [](size_t &size) -> Class *{ size = (size_t)objc_getClassList(NULL, 0); Class * data = (Class *)(malloc(sizeof(Class) * size)); for (;;) { size_t writ = (size_t)objc_getClassList(data, (int)size); if (writ <= size) { size = writ; return data; } Class * copy = (Class *)(realloc(data, sizeof(Class) * writ)); if (copy == NULL) { free(data); return NULL; } data = copy; size = writ; } } // function void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) typedef void (*choose__t)(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count); choose__t choose_ = [](task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) -> void { XZChoice * choiz = (struct XZChoice *)(baton); for (unsigned i = 0; i < count; ++i) { vm_range_t &range = ranges[i]; void * data = (void *)(range.address); size_t size = range.size; if (size < sizeof(XZObjectStruct)) continue; uintptr_t * pointers = (uintptr_t *)(data); #ifdef __arm64__ struct objc_class * isa = (struct objc_class *)(pointers[0] & 0x1fffffff8); #else struct objc_class * isa = (struct objc_class *)(pointers[0]); #endif //uint64_t p = (uint64_t)isa; //[choiz->result_ addObject:[@(p) stringValue]]; size_t needed; for(unsigned i=0; i < [choiz->query_ count]; i++){ struct objc_class * result = (struct objc_class *)[choiz->query_ objectAtIndex:i]; uint64_t result_intv = (uint64_t)result; uint64_t isa_intv = (uint64_t)isa; uint64_t data_intv = (uint64_t)data; if(result_intv == isa_intv){ /* NSMutableString* tmpStr = [NSMutableString string]; [tmpStr appendString:@"isa:"]; [tmpStr appendString:[@(isa_intv) stringValue]]; [tmpStr appendString:@"query:"]; [tmpStr appendString:[@(result_intv) stringValue]]; [tmpStr appendString:@"object:"]; [tmpStr appendString:[@(data_intv) stringValue]]; [choiz->result_ addObject:tmpStr]; continue; */ size_t boundary = 496; #ifdef __LP64__ boundary *= 2; #endif needed = (size_t)class_getInstanceSize((Class)result)); if ((needed <= boundary && (needed + 15) / 16 * 16 != size) || (needed > boundary && (needed + 511) / 512 * 512 != size)){ continue; } [choiz->result_ addObject:(id)data]; } } } } XZChoice choice; choice.query_ = (NSMutableArray*)[NSMutableArray array]; choice.result_ = (NSMutableArray*)[NSMutableArray array]; Class _class = NSClassFromString(className); size_t number; Class * classes = copy_class_list(number); for (size_t i = 0; i != number; ++i) { for (Class current = classes[i]; current != Nil; current = (Class)class_getSuperclass(current)) { if (current == _class) { [choice.query_ addObject:classes[i]]; break; } } } free(classes); vm_address_t *zones = 0; unsigned int num_zones = 0; task_t task = 0; kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones); for (unsigned i = 0; i != num_zones; ++i) { const malloc_zone_t * zone = (const malloc_zone_t *)(zones[i]); if (zone == NULL || zone->introspect == NULL) continue; zone->introspect->enumerator((task_t)mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], task_peek, choose_); } NSArray* choosed = choice.result_; NSMutableString* retStr = [NSMutableString string]; unsigned choosedSize = [choosed count]; if(choosedSize == 0){ [retStr appendString:@"Not found any object of class: "]; [retStr appendString:className]; }else{ uint64_t objAdrr = (uint64_t)choosed; [retStr appendString:@"====>xia0LLDB NSArray Address: "]; [retStr appendString:[@(objAdrr) stringValue]]; [retStr appendString:@"\tsize: "]; [retStr appendString:[@(choosedSize) stringValue]]; [retStr appendString:@"\n"]; [retStr appendString:@"| | | | | | | | | | | | | | | | | | | | \n"]; [retStr appendString:@"V V V V V V V V V V V V V V V V V V V V \n"]; for (unsigned i = 0; i != [choosed count]; ++i) { if([(NSObject*)([choosed objectAtIndex:i]) isKindOfClass:[NSString class]]){ [retStr appendString: @"Now not support print the NSString, You can po it by yourself like below:"]; [retStr appendString:@"\n1. p/x "]; [retStr appendString:[@(objAdrr) stringValue]]; [retStr appendString:@"\n2. po (NSArray*)above_hex_address_vaule : print the NSArray contain NSString"]; [retStr appendString:@"\n3. po [(NSArray*)above_hex_address_vaule objectAtIndex:0] : print first NSString"]; break; }else{ uint64_t objAdrr = (uint64_t)[choosed objectAtIndex:i]; [retStr appendString:@"======>xia0LLDB Object Address: "]; [retStr appendString:[@(objAdrr) stringValue]]; [retStr appendString:@"\n"]; [retStr appendString:[(NSObject*)([choosed objectAtIndex:i]) description]]; } [retStr appendString:@"\n"]; } } retStr ''' retStr = utils.exe_script(debugger, command_script) return colorme.attr_str(utils.hex_int_in_str(retStr), 'green')