From: Jay Freeman (saurik) <saurik@saurik.com> Date: Sat, 22 Jun 2013 23:27:19 +0000 (-0700) Subject: Find all remote symbols via dyld_all_image_infos. X-Git-Tag: v0.9.500%b1~54 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/38ae783db781810a19b3103bb55c81ea70e7d952 Find all remote symbols via dyld_all_image_infos. --- diff --git a/Baton.hpp b/Baton.hpp index e2f96e4..8607893 100644 --- a/Baton.hpp +++ b/Baton.hpp @@ -24,15 +24,7 @@ #include <sys/types.h> struct Baton { - void (*__pthread_set_self)(pthread_t); - int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); - - mach_port_t (*mach_thread_self)(); - kern_return_t (*thread_terminate)(thread_act_t); - - char *(*dlerror)(); - void *(*dlsym)(void *, const char *); - + mach_vm_address_t dyld; pid_t pid; char library[]; }; diff --git a/Mach/Inject.cpp b/Mach/Inject.cpp index 64414e7..a6dcf9f 100644 --- a/Mach/Inject.cpp +++ b/Mach/Inject.cpp @@ -33,8 +33,6 @@ #include "Pooling.hpp" #include "Trampoline.t.hpp" -extern "C" void __pthread_set_self(pthread_t); - void InjectLibrary(pid_t pid) { const char *library(CY_LIBRARY); @@ -46,35 +44,32 @@ void InjectLibrary(pid_t pid) { uint8_t *local(pool.malloc<uint8_t>(depth)); Baton *baton(reinterpret_cast<Baton *>(local)); - baton->__pthread_set_self = &__pthread_set_self; - baton->pthread_create = &pthread_create; - - baton->mach_thread_self = &mach_thread_self; - baton->thread_terminate = &thread_terminate; - - baton->dlerror = &dlerror; - baton->dlsym = &dlsym; - baton->pid = getpid(); memcpy(baton->library, library, length); - vm_size_t size(depth + Stack_); - mach_port_t self(mach_task_self()), task; _krncall(task_for_pid(self, pid, &task)); + mach_msg_type_number_t count; + + task_dyld_info info; + count = TASK_DYLD_INFO_COUNT; + _krncall(task_info(task, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&info), &count)); + _assert(count == TASK_DYLD_INFO_COUNT); + _assert(info.all_image_info_addr != 0); + baton->dyld = info.all_image_info_addr; + + vm_size_t size(depth + Stack_); vm_address_t stack; _krncall(vm_allocate(task, &stack, size, true)); - vm_address_t data(stack + Stack_); + vm_address_t data(stack + Stack_); _krncall(vm_write(task, data, reinterpret_cast<vm_address_t>(baton), depth)); thread_act_t thread; _krncall(thread_create(task, &thread)); thread_state_flavor_t flavor; - mach_msg_type_number_t count; - #if defined (__i386__) || defined(__x86_64__) x86_thread_state_t state; flavor = x86_THREAD_STATE; diff --git a/Trampoline.t.cpp b/Trampoline.t.cpp index 73baa3a..aff0296 100644 --- a/Trampoline.t.cpp +++ b/Trampoline.t.cpp @@ -22,14 +22,132 @@ #define _PTHREAD_ATTR_T #include <pthread_internals.h> +#include <mach-o/dyld.h> +#include <mach-o/dyld_images.h> +#include <mach-o/loader.h> + +extern "C" { +#include <mach-o/nlist.h> +} + #include "Standard.hpp" #include "Baton.hpp" +static void $bzero(void *data, size_t size) { + char *bytes(reinterpret_cast<char *>(data)); + for (size_t i(0); i != size; ++i) + bytes[i] = 0; +} + +static int $strcmp(const char *lhs, const char *rhs) { + while (*lhs == *rhs) { + if (*lhs == '\0') + return 0; + ++lhs, ++rhs; + } return *lhs < *rhs ? -1 : 1; +} + +#ifdef __LP64__ +typedef struct mach_header_64 mach_header_xx; +typedef struct nlist_64 nlist_xx; +typedef struct segment_command_64 segment_command_xx; + +static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64; +static const uint32_t MH_MAGIC_XX = MH_MAGIC_64; +#else +typedef struct mach_header mach_header_xx; +typedef struct nlist nlist_xx; +typedef struct segment_command segment_command_xx; + +static const uint32_t LC_SEGMENT_XX = LC_SEGMENT; +static const uint32_t MH_MAGIC_XX = MH_MAGIC; +#endif + +#define forlc(command, mach, lc, type) \ + if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \ + if (const struct load_command *lcp = load_commands) \ + for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \ + if ( \ + lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \ + reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \ + ) \ + return NULL; \ + else if (lcp->cmd != lc) \ + continue; \ + else if (lcp->cmdsize < sizeof(type)) \ + return NULL; \ + else if (const type *command = reinterpret_cast<const type *>(lcp)) + +static void *Symbol(struct dyld_all_image_infos *infos, const char *library, const char *name) { + const dyld_image_info *info(NULL); + for (uint32_t i(0); i != infos->infoArrayCount; ++i) + if ($strcmp(infos->infoArray[i].imageFilePath, library) == 0) + info = &infos->infoArray[i]; + if (info == NULL) + return NULL; + + const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info->imageLoadAddress)); + if (mach->magic != MH_MAGIC_XX) + return NULL; + + const struct symtab_command *stp(NULL); + forlc (command, mach, LC_SYMTAB, struct symtab_command) + stp = command; + if (stp == NULL) + return NULL; + + size_t slide(_not(size_t)); + const nlist_xx *symbols(NULL); + const char *strings(NULL); + + forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) { + if (segment->fileoff == 0) + slide = reinterpret_cast<size_t>(mach) - segment->vmaddr; + if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize) + symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide); + if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize) + strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide); + } + + if (slide == _not(size_t) || symbols == NULL || strings == NULL) + return NULL; + + for (size_t i(0); i != stp->nsyms; ++i) { + const nlist_xx *symbol(&symbols[i]); + if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0) + continue; + + const char *nambuf(strings + symbol->n_un.n_strx); + if ($strcmp(name, nambuf) != 0) + continue; + + uintptr_t value(symbol->n_value); + if (value == 0) + continue; + + value += slide; + return reinterpret_cast<void *>(value); + } + + return NULL; +} + +struct Dynamic { + char *(*dlerror)(); + void *(*dlsym)(void *, const char *); +}; + template <typename Type_> -static _finline void dlset(Baton *baton, Type_ &function, const char *name, void *handle = RTLD_DEFAULT) { - function = reinterpret_cast<Type_>(baton->dlsym(handle, name)); +static _finline void dlset(Dynamic *dynamic, Type_ &function, const char *name, void *handle = RTLD_DEFAULT) { + function = reinterpret_cast<Type_>(dynamic->dlsym(handle, name)); if (function == NULL) - baton->dlerror(); + dynamic->dlerror(); +} + +template <typename Type_> +static _finline void cyset(Baton *baton, Type_ &function, const char *name, const char *library) { + struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld)); + function = reinterpret_cast<Type_>(Symbol(infos, library, name)); } // XXX: where you find this needs to be relative to CoreFoundation (or something) @@ -40,36 +158,40 @@ static _finline void dlset(Baton *baton, Type_ &function, const char *name, void void *Routine(void *arg) { Baton *baton(reinterpret_cast<Baton *>(arg)); + Dynamic dynamic; + cyset(baton, dynamic.dlerror, "_dlerror", "/usr/lib/system/libdyld.dylib"); + cyset(baton, dynamic.dlsym, "_dlsym", "/usr/lib/system/libdyld.dylib"); + int (*pthread_detach)(pthread_t); - dlset(baton, pthread_detach, "pthread_detach"); + dlset(&dynamic, pthread_detach, "pthread_detach"); pthread_t (*pthread_self)(); - dlset(baton, pthread_self, "pthread_self"); + dlset(&dynamic, pthread_self, "pthread_self"); pthread_detach(pthread_self()); void *(*dlopen)(const char *, int); - dlset(baton, dlopen, "dlopen"); + dlset(&dynamic, dlopen, "dlopen"); - if (baton->dlsym(RTLD_DEFAULT, "JSEvaluateScript") == NULL) + if (dynamic.dlsym(RTLD_DEFAULT, "JSEvaluateScript") == NULL) dlopen(Framework(JavaScriptCore), RTLD_GLOBAL | RTLD_LAZY); void *(*objc_getClass)(const char *); - dlset(baton, objc_getClass, "objc_getClass"); + dlset(&dynamic, objc_getClass, "objc_getClass"); if (objc_getClass("WebUndefined") == NULL) dlopen(Framework(WebKit), RTLD_GLOBAL | RTLD_LAZY); void *handle(dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL)); if (handle == NULL) { - baton->dlerror(); + dynamic.dlerror(); return NULL; } void (*CYHandleServer)(pid_t); - dlset(baton, CYHandleServer, "CYHandleServer", handle); + dlset(&dynamic, CYHandleServer, "CYHandleServer", handle); if (CYHandleServer == NULL) { - baton->dlerror(); + dynamic.dlerror(); return NULL; } @@ -77,31 +199,27 @@ void *Routine(void *arg) { return NULL; } -static void $bzero(void *data, size_t size) { - char *bytes(reinterpret_cast<char *>(data)); - for (size_t i(0); i != size; ++i) - bytes[i] = 0; -} - extern "C" void Start(Baton *baton) { struct _pthread self; $bzero(&self, sizeof(self)); - // this code comes from _pthread_set_self + void (*$__pthread_set_self)(pthread_t); + cyset(baton, $__pthread_set_self, "___pthread_set_self", "/usr/lib/system/libsystem_c.dylib"); + self.tsd[0] = &self; - baton->__pthread_set_self(&self); + $__pthread_set_self(&self); - //int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); - //dlset(baton, pthread_create, "pthread_create"); + int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); + cyset(baton, $pthread_create, "_pthread_create", "/usr/lib/system/libsystem_c.dylib"); pthread_t thread; - baton->pthread_create(&thread, NULL, &Routine, baton); + $pthread_create(&thread, NULL, &Routine, baton); - //mach_port_t (*mach_thread_self)(); - //dlset(baton, mach_thread_self, "mach_thread_self"); + mach_port_t (*$mach_thread_self)(); + cyset(baton, $mach_thread_self, "_mach_thread_self", "/usr/lib/system/libsystem_kernel.dylib"); - //kern_return_t (*thread_terminate)(thread_act_t); - //dlset(baton, thread_terminate, "thread_terminate"); + kern_return_t (*$thread_terminate)(thread_act_t); + cyset(baton, $thread_terminate, "_thread_terminate", "/usr/lib/system/libsystem_kernel.dylib"); - baton->thread_terminate(baton->mach_thread_self()); + $thread_terminate($mach_thread_self()); }