From e15d1e8d6f090b4a42a826af10ade7bece0fe2d4 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 26 Jun 2023 15:14:15 +0700 Subject: [PATCH] run initializers in the correct order - Objective-C load methods must be called first - Constructors are called after - All constructors arguments are passed correctly --- research/custom_loader/b.cc | 166 ++++++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 66 deletions(-) diff --git a/research/custom_loader/b.cc b/research/custom_loader/b.cc index 585f4a2..435e7cd 100644 --- a/research/custom_loader/b.cc +++ b/research/custom_loader/b.cc @@ -656,6 +656,38 @@ int hook_printf(const char *format, ...) { return status; } +typedef void *(*readClass_t)(void *, bool, bool); +typedef void *(*realizeClassWithoutSwift_t)(void *, void*); +typedef void *(*remapClass_t)(void *); +typedef void *(*load_method_t)(void*, void*); +typedef void *(*sel_lookUpByName_t)(const char*); +typedef void (*addClassTableEntry_t)(void *); +typedef void (*schedule_class_load_t)(void *); + +typedef void *(*objc_autoreleasePoolPush_t)(); +typedef void (*objc_autoreleasePoolPop_t)(void *); + +struct custom_initializer_t { + // used for Objective-C load methods + uint64_t* loadable_classes; + uint32_t* loadable_classes_used; + sel_lookUpByName_t sel_lookUpByName; + objc_autoreleasePoolPush_t objc_autoreleasePoolPush; + objc_autoreleasePoolPop_t objc_autoreleasePoolPop; + remapClass_t remapClass; + schedule_class_load_t schedule_class_load; + uint64_t* cls; + size_t ncls; + // used for constructors + void* programvars; + uint64_t* constructors; + size_t nconstructors; +}; + +// global variable for PoC +struct custom_initializer_t* custom_initializer_i; + + struct ProgramVars { void *mh; // mach_header or mach_header64 int *NXArgcPtr; @@ -701,6 +733,10 @@ bruh(int argc, const char *const argv[], const char *const envp[], // (we do not remove them for **our lib**) // - malloc // - free + custom_initializer_i = (custom_initializer_t*)malloc(sizeof(custom_initializer_t)); + custom_initializer_i->programvars = (void*)vars; + custom_initializer_i->cls = 0; + custom_initializer_i->constructors = 0; fix(cache); for (int i = 0; i < cache.size; i++) { @@ -779,6 +815,7 @@ void build_cache(struct libcache& cache, void* main) { } } + void fix_objc(struct libcache_item* libfixing, struct libcache& cache); void fix_initializer(struct libcache_item* libfixing, struct libcache& cache); void fix(struct libcache& cache) { @@ -942,77 +979,64 @@ void fix(struct libcache& cache) { fix_initializer(libfixing, cache); } - -typedef void *(*readClass_t)(void *, bool, bool); -typedef void *(*realizeClassWithoutSwift_t)(void *, void*); -typedef void *(*remapClass_t)(void *); -typedef void *(*load_method_t)(void*, void*); -typedef void *(*sel_lookUpByName_t)(const char*); -typedef void (*addClassTableEntry_t)(void *); -typedef void (*schedule_class_load_t)(void *); - -typedef void *(*objc_autoreleasePoolPush_t)(); -typedef void (*objc_autoreleasePoolPop_t)(void *); - -struct custom_initializer_t { - uint64_t* loadable_classes; - uint32_t* loadable_classes_used; - sel_lookUpByName_t sel_lookUpByName; - objc_autoreleasePoolPush_t objc_autoreleasePoolPush; - objc_autoreleasePoolPop_t objc_autoreleasePoolPop; - remapClass_t remapClass; - schedule_class_load_t schedule_class_load; - uint64_t* cls; - size_t ncls; -}; - -// global variable for PoC -struct custom_initializer_t* custom_initializer_i; - void volatile -custom_initializer(int argc, const char *const argv[], const char *const envp[], - const char *const apple[], const struct ProgramVars *vars) { +custom_initializer(int argc, const char *const argv[], const char *const envp[], const char *const apple[]) { printf("run custom initializers %p\n", custom_initializer_i); - // return; - uint64_t* loadable_classes = custom_initializer_i->loadable_classes; - uint32_t* loadable_classes_used = custom_initializer_i->loadable_classes_used; - sel_lookUpByName_t sel_lookUpByName = custom_initializer_i->sel_lookUpByName; - objc_autoreleasePoolPop_t objc_autoreleasePoolPop = custom_initializer_i->objc_autoreleasePoolPop; - objc_autoreleasePoolPush_t objc_autoreleasePoolPush = custom_initializer_i->objc_autoreleasePoolPush; - remapClass_t remapClass = custom_initializer_i->remapClass; - schedule_class_load_t schedule_class_load = custom_initializer_i->schedule_class_load; - for (int i = 0; i < custom_initializer_i->ncls; i++) { - void* cls0 = (void*)custom_initializer_i->cls[i]; - void* cls = remapClass(cls0); - if (!cls) continue; - schedule_class_load(cls); + if (custom_initializer_i->cls != 0) { + // for Objective-C load + uint64_t* loadable_classes = custom_initializer_i->loadable_classes; + uint32_t* loadable_classes_used = custom_initializer_i->loadable_classes_used; + sel_lookUpByName_t sel_lookUpByName = custom_initializer_i->sel_lookUpByName; + objc_autoreleasePoolPop_t objc_autoreleasePoolPop = custom_initializer_i->objc_autoreleasePoolPop; + objc_autoreleasePoolPush_t objc_autoreleasePoolPush = custom_initializer_i->objc_autoreleasePoolPush; + remapClass_t remapClass = custom_initializer_i->remapClass; + schedule_class_load_t schedule_class_load = custom_initializer_i->schedule_class_load; + + for (int i = 0; i < custom_initializer_i->ncls; i++) { + void* cls0 = (void*)custom_initializer_i->cls[i]; + void* cls = remapClass(cls0); + if (!cls) continue; + schedule_class_load(cls); + } + + printf("loadable_classes %llx %x\n", *loadable_classes, *loadable_classes_used); + + struct loadable_class_t { + void* cls; + void* method; + }; + struct loadable_class_t *classes = (struct loadable_class_t*)*loadable_classes; + int used = *loadable_classes_used; + *loadable_classes = 0; + // *loadable_classes_allocated = 0; + *loadable_classes_used = 0; + void* sel = sel_lookUpByName("load"); + // Call all +loads for the detached list. + void* pool = objc_autoreleasePoolPush(); + for (int i = 0; i < used; i++) { + void* cls = classes[i].cls; + load_method_t load_method = (load_method_t)classes[i].method; + printf("call load of class %p %p\n", cls, load_method); + if (!cls) continue; + (load_method)(cls, sel); + } + // Destroy the detached list. + if (classes) free(classes); + objc_autoreleasePoolPop(pool); } - printf("loadable_classes %llx %x\n", *loadable_classes, *loadable_classes_used); - - struct loadable_class_t { - void* cls; - void* method; - }; - struct loadable_class_t *classes = (struct loadable_class_t*)*loadable_classes; - int used = *loadable_classes_used; - *loadable_classes = 0; - // *loadable_classes_allocated = 0; - *loadable_classes_used = 0; - void* sel = sel_lookUpByName("load"); - // Call all +loads for the detached list. - void* pool = objc_autoreleasePoolPush(); - for (int i = 0; i < used; i++) { - void* cls = classes[i].cls; - load_method_t load_method = (load_method_t)classes[i].method; - printf("call load of class %p %p\n", cls, load_method); - if (!cls) continue; - (load_method)(cls, sel); + // for constructors + if (custom_initializer_i->constructors) { + typedef void *(*constructors_t)(int, void*, void*, void*, void*); + uint32_t nconst = custom_initializer_i->nconstructors; + for (int i = 0; i < nconst; i++) { + constructors_t cons = (constructors_t)custom_initializer_i->constructors[i]; + printf("call initializer at %p\n", cons); + cons(argc, (void*)argv, (void*)envp, (void*)apple, custom_initializer_i->programvars); + } + free(custom_initializer_i->constructors); } - // Destroy the detached list. - if (classes) free(classes); - objc_autoreleasePoolPop(pool); free(custom_initializer_i); } @@ -1119,7 +1143,6 @@ void fix_objc(struct libcache_item* libfixing, struct libcache& cache) { printf("build nonlazy class at (%llx)%p\n", data_ptr[ptr_i], cls); } - custom_initializer_i = (custom_initializer_t*)malloc(sizeof(custom_initializer_t)); custom_initializer_i->sel_lookUpByName = sel_lookUpByName; custom_initializer_i->loadable_classes = loadable_classes; custom_initializer_i->loadable_classes_used = loadable_classes_used; @@ -1248,6 +1271,17 @@ void fix_initializer(struct libcache_item* libfixing, struct libcache& cache) { uint32_t *data_ptr = (uint32_t*)(addr + slide); printf("found initializer at %p\n", data_ptr); + + custom_initializer_i->nconstructors = size / 4; + custom_initializer_i->constructors = (uint64_t*)malloc(sizeof(uint64_t) * size/4); + for (int j = 0; j < size / 4; j++) { + custom_initializer_i->constructors[j] = (uint64_t)header + data_ptr[j]; + printf("registered initializer at %llx\n", custom_initializer_i->constructors[j]); + } + } + if (custom_strcmp(secname, "__mod_init_func") == 0) { + // TODO: EHEHE + printf("initializer encoded in __mod_init_func is not supported\n"); } sections_ptr += 16 * 2 + 8 * 2 + 4 * 8; }