From 6da9db8376aefd6c93aa781963129ccc9fe9cd77 Mon Sep 17 00:00:00 2001 From: haolianfu Date: Sat, 12 Jun 2021 02:02:39 +0800 Subject: [PATCH 1/2] Fixed the crash on iOS 15 perfectly: changing vm prot according to whether having VM_PROT_WRITE rather than being const seg. --- fishhook.c | 67 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/fishhook.c b/fishhook.c index 026a5c0..54b5c9e 100644 --- a/fishhook.c +++ b/fishhook.c @@ -81,12 +81,12 @@ static int prepend_rebindings(struct rebindings_entry **rebindings_head, return 0; } -static vm_prot_t get_protection(void *sectionStart) { +static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { mach_port_t task = mach_task_self(); vm_size_t size = 0; - vm_address_t address = (vm_address_t)sectionStart; + vm_address_t address = (vm_address_t)addr; memory_object_name_t object; -#if __LP64__ +#ifdef __LP64__ mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; vm_region_basic_info_data_64_t info; kern_return_t info_ret = vm_region_64( @@ -97,25 +97,54 @@ static vm_prot_t get_protection(void *sectionStart) { kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); #endif if (info_ret == KERN_SUCCESS) { - return info.protection; - } else { - return VM_PROT_READ; + if (prot != NULL) + *prot = info.protection; + + if (max_prot != NULL) + *max_prot = info.max_protection; + + return 0; } + + return -1; } + static void perform_rebinding_with_section(struct rebindings_entry *rebindings, section_t *section, intptr_t slide, nlist_t *symtab, char *strtab, uint32_t *indirect_symtab) { - const bool isDataConst = strcmp(section->segname, SEG_DATA_CONST) == 0; uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); - vm_prot_t oldProtection = VM_PROT_READ; - if (isDataConst) { - oldProtection = get_protection(rebindings); - mprotect(indirect_symbol_bindings, section->size, PROT_READ | PROT_WRITE); + vm_prot_t prot; + vm_prot_t max_prot; + uintptr_t prot_addr; + + if (get_protection(indirect_symbol_bindings, &prot, &max_prot) < 0) + return; + + if ((prot & VM_PROT_WRITE) == 0) { + kern_return_t err; + + prot_addr = (uintptr_t)indirect_symbol_bindings; + /** + * if this segment does not have the 'write' permission, + * then add it. + * -- Lianfu Hao(@agora.io) Jun 11th, 2021 + **/ + err = vm_protect (mach_task_self (), prot_addr, section->size, false, prot | VM_PROT_WRITE | VM_PROT_COPY); + if (err != 0) { + /** + * Once we failed to change the vm protection, we + * MUST NOT continue the following write actions! + * iOS 15 has corrected the const segments prot. + * -- Lianfu Hao(@agora.io) Jun 11th, 2021 + **/ + return; + } } + for (uint i = 0; i < section->size / sizeof(void *); i++) { uint32_t symtab_index = indirect_symbol_indices[i]; if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || @@ -142,19 +171,9 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings, } symbol_loop:; } - if (isDataConst) { - int protection = 0; - if (oldProtection & VM_PROT_READ) { - protection |= PROT_READ; - } - if (oldProtection & VM_PROT_WRITE) { - protection |= PROT_WRITE; - } - if (oldProtection & VM_PROT_EXECUTE) { - protection |= PROT_EXEC; - } - mprotect(indirect_symbol_bindings, section->size, protection); - } + + if ((prot & VM_PROT_WRITE) == 0) + vm_protect (mach_task_self (), prot_addr, section->size, true, max_prot); } static void rebind_symbols_for_image(struct rebindings_entry *rebindings, From 31e51827675cbdee0a8ed2533d1dd700ea4c8306 Mon Sep 17 00:00:00 2001 From: haolianfu Date: Fri, 18 Jun 2021 23:06:43 +0800 Subject: [PATCH 2/2] Moved the vm protection modifying codes inside the condition to reduce the changing scope. --- fishhook.c | 58 ++++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/fishhook.c b/fishhook.c index 54b5c9e..fb41e8e 100644 --- a/fishhook.c +++ b/fishhook.c @@ -81,6 +81,7 @@ static int prepend_rebindings(struct rebindings_entry **rebindings_head, return 0; } +#if 0 static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { mach_port_t task = mach_task_self(); vm_size_t size = 0; @@ -108,6 +109,7 @@ static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { return -1; } +#endif static void perform_rebinding_with_section(struct rebindings_entry *rebindings, section_t *section, @@ -117,33 +119,6 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings, uint32_t *indirect_symtab) { uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); - vm_prot_t prot; - vm_prot_t max_prot; - uintptr_t prot_addr; - - if (get_protection(indirect_symbol_bindings, &prot, &max_prot) < 0) - return; - - if ((prot & VM_PROT_WRITE) == 0) { - kern_return_t err; - - prot_addr = (uintptr_t)indirect_symbol_bindings; - /** - * if this segment does not have the 'write' permission, - * then add it. - * -- Lianfu Hao(@agora.io) Jun 11th, 2021 - **/ - err = vm_protect (mach_task_self (), prot_addr, section->size, false, prot | VM_PROT_WRITE | VM_PROT_COPY); - if (err != 0) { - /** - * Once we failed to change the vm protection, we - * MUST NOT continue the following write actions! - * iOS 15 has corrected the const segments prot. - * -- Lianfu Hao(@agora.io) Jun 11th, 2021 - **/ - return; - } - } for (uint i = 0; i < section->size / sizeof(void *); i++) { uint32_t symtab_index = indirect_symbol_indices[i]; @@ -157,13 +132,29 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings, struct rebindings_entry *cur = rebindings; while (cur) { for (uint j = 0; j < cur->rebindings_nel; j++) { - if (symbol_name_longer_than_1 && - strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { - if (cur->rebindings[j].replaced != NULL && - indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { + if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { + kern_return_t err; + + if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; + + /** + * 1. Moved the vm protection modifying codes to here to reduce the + * changing scope. + * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region + * API on some iOS/Mac reports mismatch vm protection attributes. + * -- Lianfu Hao Jun 16th, 2021 + **/ + err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); + if (err == KERN_SUCCESS) { + /** + * Once we failed to change the vm protection, we + * MUST NOT continue the following write actions! + * iOS 15 has corrected the const segments prot. + * -- Lionfore Hao Jun 11th, 2021 + **/ + indirect_symbol_bindings[i] = cur->rebindings[j].replacement; } - indirect_symbol_bindings[i] = cur->rebindings[j].replacement; goto symbol_loop; } } @@ -171,9 +162,6 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings, } symbol_loop:; } - - if ((prot & VM_PROT_WRITE) == 0) - vm_protect (mach_task_self (), prot_addr, section->size, true, max_prot); } static void rebind_symbols_for_image(struct rebindings_entry *rebindings,