From da200d3ac0204abadd5992820486321970d689b8 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 19 Feb 2018 15:51:56 +0200 Subject: refactoring, fixing and implementing messy commits yay --- Makefile | 40 ++++++++++++----------- src/app.c | 26 ++++++--------- src/jvm/jvm.c | 36 ++++++++++----------- src/libc.c | 12 +++++++ src/libjvm-android.c | 10 ++++++ src/libjvm-java.c | 24 ++++++++++++++ src/libpthread.c | 16 ++++++++++ src/linker/dlfcn.c | 49 ++++++++++------------------- src/linker/linker.c | 87 +++++++-------------------------------------------- src/wrapper/wrapper.c | 70 +++++++++++++++++++++++++++++++++++++++++ src/wrapper/wrapper.h | 4 +++ 11 files changed, 212 insertions(+), 162 deletions(-) create mode 100644 src/wrapper/wrapper.c create mode 100644 src/wrapper/wrapper.h diff --git a/Makefile b/Makefile index 8597504..1ba8563 100644 --- a/Makefile +++ b/Makefile @@ -14,14 +14,11 @@ override CPPFLAGS += -Isrc bins = app all: $(bins) runtime/libc.so runtime/libandroid.so runtime/liblog.so -%.o: %.c - $(COMPILE.c) $^ -o $@ +%.a: + $(LINK.c) -c $(filter %.c,$^) -o $@ %.so: - $(LINK.c) -shared $(filter %.c,$^) $(LDLIBS) -o $@ - -%.a: - $(AR) rvs $@ $^ + $(LINK.c) -shared $(filter %.c %.a,$^) $(LDLIBS) -o $@ $(bins): %: $(LINK.c) $(filter %.c %.a,$^) $(LDLIBS) -o $@ @@ -29,29 +26,34 @@ $(bins): %: runtime: mkdir -p $@ -runtime/libc.so: private CFLAGS += -D_GNU_SOURCE +wrapper.a: private CPPFLAGS += -D_GNU_SOURCE -DANDROID_X86_LINKER +wrapper.a: src/wrapper/wrapper.c +jvm.a: private CPPFLAGS += -D_GNU_SOURCE +jvm.a: private CFLAGS += -Wno-unused-variable -Wno-pedantic +jvm.a: wrapper.a src/jvm/jvm.c + +runtime/libdl.so: private CPPFLAGS += -D_GNU_SOURCE -DANDROID_X86_LINKER -DLINKER_DEBUG=1 +runtime/libdl.so: private CFLAGS += -Wno-pedantic -Wno-variadic-macros -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast +runtime/libdl.so: runtime wrapper.a src/linker/dlfcn.c src/linker/linker.c src/linker/linker_environ.c src/linker/rt.c src/linker/strlcpy.c +runtime/libc.so: private CPPFLAGS += -D_GNU_SOURCE +runtime/libc.so: private LDLIBS += `pkg-config --libs libbsd` runtime/libc.so: runtime src/libc.c -runtime/libpthread.so: private CFLAGS += -D_GNU_SOURCE +runtime/libpthread.so: private CPPFLAGS += -D_GNU_SOURCE runtime/libpthread.so: private LDLIBS += -lpthread runtime/libpthread.so: runtime src/libpthread.c runtime/libandroid.so: private LDLIBS += `pkg-config --libs glfw3` runtime/libandroid.so: runtime src/libandroid.c runtime/liblog.so: runtime src/liblog.c -native: runtime/libc.so runtime/libpthread.so runtime/libandroid.so runtime/liblog.so +native: runtime/libdl.so runtime/libc.so runtime/libpthread.so runtime/libandroid.so runtime/liblog.so +runtime/libjvm-java.so: private CPPFLAGS += -D_GNU_SOURCE runtime/libjvm-java.so: runtime src/libjvm-java.c runtime/libjvm-android.so: runtime src/libjvm-android.c java: runtime/libjvm-java.so runtime/libjvm-android.so -linker.a: CFLAGS += -D_GNU_SOURCE -DANDROID_X86_LINKER -DLINKER_DEBUG=1 -linker.a: CFLAGS += -Wno-pedantic -Wno-variadic-macros -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -linker.a: src/linker/dlfcn.o src/linker/linker.o src/linker/linker_environ.o src/linker/rt.o src/linker/strlcpy.o -jvm.a: CFLAGS += -D_GNU_SOURCE -jvm.a: CFLAGS += -Wno-unused-variable -Wno-pedantic -jvm.a: src/jvm/jvm.o - -app: private LDLIBS += -ldl -Wl,-rpath,runtime -app: src/app.c linker.a native jvm.a java +app: private LDLIBS += -ldl -Wl,-rpath,runtime runtime/libdl.so runtime/libpthread.so +app: private LDLIBS += runtime/libjvm-java.so runtime/libjvm-android.so +app: wrapper.a src/app.c native jvm.a java install-bin: $(bins) install -Dm755 $^ -t "$(DESTDIR)$(PREFIX)$(BINDIR)" @@ -59,7 +61,7 @@ install-bin: $(bins) install: install-bin clean: - $(RM) $(bins) *.a src/linker/*.o src/jvm/*.o + $(RM) $(bins) *.a $(RM) -r runtime .PHONY: all clean install diff --git a/src/app.c b/src/app.c index 9a0d07e..c80430b 100644 --- a/src/app.c +++ b/src/app.c @@ -4,38 +4,28 @@ #include #include #include +#include "linker/dlfcn.h" #include "jvm/jvm.h" -extern void *apkenv_android_dlopen(const char*, int); -extern void *apkenv_android_dlclose(void*); -extern const char *apkenv_android_dlerror(void); -extern void *apkenv_android_dlsym(void*, const char*); -extern void apkenv_parse_library_path(const char *path, char *delim); - int main(int argc, const char *argv[]) { if (argc < 2) errx(EXIT_FAILURE, "usage: so-file"); - printf("loading runtime\n"); - if (!dlopen("libpthread.so", RTLD_NOW | RTLD_GLOBAL) || - !dlopen("libjvm-java.so", RTLD_NOW | RTLD_GLOBAL) || - !dlopen("libjvm-android.so", RTLD_NOW | RTLD_GLOBAL)) - errx(EXIT_FAILURE, "%s", dlerror()); - printf("loading module: %s\n", argv[1]); { + // FIXME: when bionic linker is rewritten it will just use system search path char path[4096]; snprintf(path, sizeof(path), "%s", argv[1]); - apkenv_parse_library_path(dirname(path), ";"); + dl_parse_library_path(dirname(path), ";"); } { void *handle; - if (!(handle = apkenv_android_dlopen(argv[1], RTLD_NOW | RTLD_LOCAL))) - errx(EXIT_FAILURE, "dlopen failed: %s", apkenv_android_dlerror()); + if (!(handle = bionic_dlopen(argv[1], RTLD_NOW | RTLD_LOCAL))) + errx(EXIT_FAILURE, "dlopen failed: %s", bionic_dlerror()); printf("trying JNI_OnLoad from: %s\n", argv[1]); @@ -43,7 +33,7 @@ main(int argc, const char *argv[]) jvm_init(&jvm); const jobject context = jvm.native.AllocObject(&jvm.env, jvm.native.FindClass(&jvm.env, "android/content/Context")); - void* (*JNI_OnLoad)(void*, void*) = apkenv_android_dlsym(handle, "JNI_OnLoad"); + void* (*JNI_OnLoad)(void*, void*) = bionic_dlsym(handle, "JNI_OnLoad"); assert(JNI_OnLoad); JNI_OnLoad(&jvm.vm, NULL); @@ -64,10 +54,12 @@ main(int argc, const char *argv[]) native_file(&jvm.env, context, jvm.native.NewStringUTF(&jvm.env, "./file.apk")); native_done(&jvm.env, context); native_recreate_gfx_state(&jvm.env, context, context); + puts("ASD"); native_render(&jvm.env, (jobject)1); + puts("LOL"); printf("unloading module: %s\n", argv[1]); - apkenv_android_dlclose(handle); + bionic_dlclose(handle); jvm_release(&jvm); } diff --git a/src/jvm/jvm.c b/src/jvm/jvm.c index 72529df..bae1a51 100644 --- a/src/jvm/jvm.c +++ b/src/jvm/jvm.c @@ -6,12 +6,11 @@ #include #include "dlfcn.h" #include "jvm.h" +#include "wrapper/wrapper.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #define container_of(ptr, type, member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member))) -extern void* create_wrapper(const char *const symbol, void *function); - static inline char* ccopy(const char *str, const size_t len, const bool null_terminate) { @@ -107,7 +106,7 @@ jvm_object_release(struct jvm_object *o) assert(o->type < JVM_OBJECT_LAST); - if (destructor) + if (destructor[o->type]) destructor[o->type](o); *o = (struct jvm_object){0}; @@ -502,7 +501,7 @@ JNIEnv_CallObjectMethodV(JNIEnv *p0, jobject p1, jmethodID p2, va_list p3) assert(p0 && p1 && p2); char symbol[255]; jvm_form_symbol(jnienv_get_jvm(p0), p2, symbol, sizeof(symbol)); - jobject (*fun)(JNIEnv*, jobject, va_list) = create_wrapper(symbol, dlsym(RTLD_DEFAULT, symbol)); + jobject (*fun)(JNIEnv*, jobject, va_list) = wrapper_create(symbol, dlsym(RTLD_DEFAULT, symbol)); return fun(p0, p1, p3); } @@ -530,10 +529,10 @@ static jboolean JNIEnv_CallBooleanMethodV(JNIEnv* p0, jobject p1, jmethodID p2, va_list p3) { assert(p0 && p1 && p2); - struct jvm *jvm = jnienv_get_jvm(p0); - struct jvm_method *method = &jvm_get_object(jvm, p2)->method; - printf("%s::%s\n", jvm_get_object(jvm, method->klass)->klass.name.data, method->name.data); - return 0; + char symbol[255]; + jvm_form_symbol(jnienv_get_jvm(p0), p2, symbol, sizeof(symbol)); + jboolean (*fun)(JNIEnv*, jobject, va_list) = wrapper_create(symbol, dlsym(RTLD_DEFAULT, symbol)); + return fun(p0, p1, p3); } static jboolean @@ -650,10 +649,10 @@ static jint JNIEnv_CallIntMethodV(JNIEnv* p0, jobject p1, jmethodID p2, va_list p3) { assert(p0 && p1 && p2); - struct jvm *jvm = jnienv_get_jvm(p0); - struct jvm_method *method = &jvm_get_object(jvm, p2)->method; - printf("%s::%s\n", jvm_get_object(jvm, method->klass)->klass.name.data, method->name.data); - return 0; + char symbol[255]; + jvm_form_symbol(jnienv_get_jvm(p0), p2, symbol, sizeof(symbol)); + jint (*fun)(JNIEnv*, jobject, va_list) = wrapper_create(symbol, dlsym(RTLD_DEFAULT, symbol)); + return fun(p0, p1, p3); } static jint @@ -771,7 +770,7 @@ JNIEnv_CallVoidMethodV(JNIEnv* p0, jobject p1, jmethodID p2, va_list p3) assert(p0 && p1 && p2); char symbol[255]; jvm_form_symbol(jnienv_get_jvm(p0), p2, symbol, sizeof(symbol)); - void (*fun)(JNIEnv*, jobject, va_list) = create_wrapper(symbol, dlsym(RTLD_DEFAULT, symbol)); + void (*fun)(JNIEnv*, jobject, va_list) = wrapper_create(symbol, dlsym(RTLD_DEFAULT, symbol)); fun(p0, p1, p3); } @@ -1477,9 +1476,10 @@ static void JNIEnv_CallStaticVoidMethodV(JNIEnv* p0, jclass p1, jmethodID p2, va_list p3) { assert(p0 && p1 && p2); - struct jvm *jvm = jnienv_get_jvm(p0); - struct jvm_method *method = &jvm_get_object(jvm, p2)->method; - printf("%s::%s\n", jvm_get_object(jvm, method->klass)->klass.name.data, method->name.data); + char symbol[255]; + jvm_form_symbol(jnienv_get_jvm(p0), p2, symbol, sizeof(symbol)); + void (*fun)(JNIEnv*, jobject, va_list) = wrapper_create(symbol, dlsym(RTLD_DEFAULT, symbol)); + fun(p0, p1, p3); } static void @@ -2075,7 +2075,7 @@ JNIEnv_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf) assert(env && string && utf); } -#define WRAP(x) create_wrapper(#x, x) +#define WRAP(x) wrapper_create(#x, x) static void env_init(JNIEnv *env, struct JNINativeInterface *native) @@ -2368,7 +2368,7 @@ jvm_get_native_method(struct jvm *jvm, const char *klass, const char *method) for (size_t i = 0; i < ARRAY_SIZE(jvm->methods) && jvm->methods[i].function; ++i) { if (!strcmp(jvm_get_object(jvm, jvm->methods[i].method.klass)->klass.name.data, klass) && !strcmp(jvm->methods[i].method.name.data, method)) - return create_wrapper(method, jvm->methods[i].function); + return wrapper_create(method, jvm->methods[i].function); } return NULL; } diff --git a/src/libc.c b/src/libc.c index f83395b..80be0f2 100644 --- a/src/libc.c +++ b/src/libc.c @@ -22,6 +22,18 @@ gettid(void) return syscall(SYS_gettid); } +int +tgkill(int tgid, int tid, int sig) +{ + return syscall(SYS_tgkill, tgid, tid, sig); +} + +int +tkill(int tid, int sig) +{ + return syscall(SYS_tkill, tid, sig); +} + #include "libc-sha1.h" // Stuff needed for runtime compatibility, but not neccessary for linking diff --git a/src/libjvm-android.c b/src/libjvm-android.c index d9fff44..fd4e7d5 100644 --- a/src/libjvm-android.c +++ b/src/libjvm-android.c @@ -21,6 +21,16 @@ android_content_Context_getSharedPreferences(JNIEnv *env, jobject object, va_lis return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "android/content/SharedPreferences")))); } +jint +android_content_SharedPreferences_getInt(JNIEnv *env, jobject object, va_list args) +{ + assert(env && object); + jstring str = va_arg(args, jstring); + printf("%s::%d\n", (*env)->GetStringUTFChars(env, str, NULL), va_arg(args, jint)); + va_end(args); + return 0; +} + jobject android_content_SharedPreferences_edit(JNIEnv *env, jobject object, va_list args) { diff --git a/src/libjvm-java.c b/src/libjvm-java.c index 25e93c0..ed2b6ce 100644 --- a/src/libjvm-java.c +++ b/src/libjvm-java.c @@ -1,8 +1,23 @@ +#include #include #include +#include #include +#include +#include #include "jvm/jni.h" +void +java_lang_System_load(JNIEnv *env, jobject object, va_list args) +{ + assert(env && object); + const char *lib = (*env)->GetStringUTFChars(env, va_arg(args, jstring), NULL); + va_end(args); + printf("%s\n", lib); + // FIXME: should handle loading properly + // bionic_dlopen(lib, RTLD_NOW | RTLD_GLOBAL); +} + jclass java_lang_Object_getClass(JNIEnv *env, jobject object, va_list args) { @@ -22,6 +37,8 @@ jobject java_lang_ClassLoader_findLibrary(JNIEnv *env, jobject object, va_list args) { assert(env && object); + // XXX: according to docs should return absolute path, but relative is more convenient for us. + // fix if breaks anything because of this. char lib[255]; snprintf(lib, sizeof(lib), "lib%s.so", (*env)->GetStringUTFChars(env, va_arg(args, jstring), NULL)); va_end(args); @@ -44,3 +61,10 @@ java_util_Set_iterator(JNIEnv *env, jobject object, va_list args) static jobject sv; return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/util/Iterator")))); } + +jboolean +java_util_Iterator_hasNext(JNIEnv *env, jobject object, va_list args) +{ + assert(env && object); + return false; +} diff --git a/src/libpthread.c b/src/libpthread.c index b09a0ba..3136632 100644 --- a/src/libpthread.c +++ b/src/libpthread.c @@ -73,6 +73,22 @@ is_mapped(void *mem, const size_t sz) return !mincore(mem, sz, vec); } +void +bionic___pthread_cleanup_push(void *c, void *routine, void *arg) +{ +} + +void +bionic___pthread_cleanup_pop(void *c, int execute) +{ +} + +int +bionic_pthread_cond_timedwait_relative_np(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *reltime) +{ + return 0; +} + int bionic_pthread_cond_timedwait_monotonic_np(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *abstime) { diff --git a/src/linker/dlfcn.c b/src/linker/dlfcn.c index 3f76e92..a044094 100644 --- a/src/linker/dlfcn.c +++ b/src/linker/dlfcn.c @@ -21,12 +21,7 @@ #include "linker.h" #include "linker_format.h" -/* for apkenv_get_hooked_symbol */ -// #include "../compat/hooks.h" - -/* for create_wrapper */ -// #include "../debug/wrappers.h" - +#include "wrapper/wrapper.h" #include "linker_debug.h" #ifdef APKENV_DEBUG @@ -66,7 +61,7 @@ static void set_dlerror(int err) dl_err_str = (const char *)&dl_err_buf[0]; } -void *apkenv_android_dlopen(const char *filename, int flag) +void *bionic_dlopen(const char *filename, int flag) { soinfo *ret; @@ -83,18 +78,7 @@ void *apkenv_android_dlopen(const char *filename, int flag) return ret; } -static void *apkenv_android_dlopen_wrap(const char *filename, int flag) -{ -#if 0 - void *ret = get_builtin_lib_handle(filename); - if (ret) - return ret; -#endif - - return apkenv_android_dlopen(filename, flag); -} - -const char *apkenv_android_dlerror(void) +const char *bionic_dlerror(void) { const char *tmp = dl_err_str; dl_err_str = NULL; @@ -105,7 +89,7 @@ enum { WRAPPER_DYNHOOK, }; -void *apkenv_android_dlsym(void *handle, const char *symbol) +void *bionic_dlsym(void *handle, const char *symbol) { soinfo *found; Elf32_Sym *sym; @@ -159,7 +143,7 @@ void *apkenv_android_dlsym(void *handle, const char *symbol) if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { unsigned ret = sym->st_value + found->base; pthread_mutex_unlock(&apkenv_dl_lock); - return create_wrapper((char*)symbol, (void*)ret, WRAPPER_DYNHOOK); + return wrapper_create((char*)symbol, (void*)ret); } set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); @@ -173,7 +157,7 @@ err: return 0; } -int apkenv_android_dladdr(const void *addr, Dl_info *info) +int bionic_dladdr(const void *addr, Dl_info *info) { int ret = 0; @@ -204,7 +188,7 @@ int apkenv_android_dladdr(const void *addr, Dl_info *info) return ret; } -int apkenv_android_dlclose(void *handle) +int bionic_dlclose(void *handle) { #if 0 if (is_builtin_lib_handle(handle)) @@ -224,7 +208,7 @@ int apkenv_android_dlclose(void *handle) #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" -_Unwind_Ptr apkenv_android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); +_Unwind_Ptr bionic_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); #elif defined(ANDROID_X86_LINKER) // 0000000 00011111 111112 22222222 2333333 3333444444444455 @@ -232,8 +216,7 @@ _Unwind_Ptr apkenv_android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); #define ANDROID_LIBDL_STRTAB \ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" int -apkenv_android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), - void *data); +bionic_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), void *data); #else #error Unsupported architecture. Only ARM and x86 are presently supported. @@ -289,41 +272,41 @@ construct(void) .st_name = sizeof(ANDROID_LIBDL_STRTAB) - 1, }, { .st_name = 0, // starting index of the name in apkenv_libdl_info.strtab - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dlopen_wrap, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dlopen, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, { .st_name = 7, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dlclose, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dlclose, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, { .st_name = 15, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dlsym, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dlsym, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, { .st_name = 21, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dlerror, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dlerror, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, { .st_name = 29, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dladdr, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dladdr, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, #ifdef ANDROID_ARM_LINKER { .st_name = 36, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dl_unwind_find_exidx, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dl_unwind_find_exidx, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, #elif defined(ANDROID_X86_LINKER) { .st_name = 36, - .st_value = (Elf32_Addr)(uintptr_t)apkenv_android_dl_iterate_phdr, + .st_value = (Elf32_Addr)(uintptr_t)bionic_dl_iterate_phdr, .st_info = STB_GLOBAL << 4, .st_shndx = 1, }, diff --git a/src/linker/linker.c b/src/linker/linker.c index 09ebf8f..e5e1095 100644 --- a/src/linker/linker.c +++ b/src/linker/linker.c @@ -54,10 +54,7 @@ #include "strlcpy.h" -/* for apkenv_get_hooked_symbol */ -// #include "../compat/hooks.h" -/* for create_wrapper */ -// #include "../debug/wrappers.h" +#include "wrapper/wrapper.h" #include "linker.h" #include "linker_debug.h" @@ -163,50 +160,6 @@ enum { WRAPPER_ARM_INJECTION, }; -static char* (*__cxa_demangle)(const char *mangled_name, char *output_buffer, size_t *length, int *status); - -static void -trace(const char *const symbol) -{ - if (__cxa_demangle) { - // >If output_buffer is not long enough, it is expanded using realloc - // Holy fuck gcc what the fuck? Guess we don't use stack then, thanks - int status; - char *demangled; - if ((demangled = __cxa_demangle(symbol, NULL, NULL, &status))) { - printf("trace: %s\n", demangled); - free(demangled); // so pointless... - return; - } - } - - printf("trace: %s\n", symbol); -} - -__asm__( - "wrapper_start: nop\n" - "wrapper_symbol: pushl $0xFAFBFCFD\n" - "wrapper_trace: movl $0xFAFBFCFD, %eax\ncall *%eax\npop %eax\n" - "wrapper_call: movl $0xFAFBFCFD, %eax\njmp *%eax\n" - "wrapper_end: nop\n" -); - -extern char wrapper_start, wrapper_symbol, wrapper_trace, wrapper_call, wrapper_end; - -void* -create_wrapper(const char *const symbol, void *function, int wrapper_type) -{ - const size_t sz = &wrapper_end - &wrapper_start; - unsigned char *fun = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - assert(fun != MAP_FAILED); - memcpy(fun, &wrapper_start, sz); - memcpy(fun + (&wrapper_symbol - &wrapper_start) + 1, &symbol, sizeof(symbol)); - memcpy(fun + (&wrapper_trace - &wrapper_start) + 1, (uintptr_t[]){ (uintptr_t)trace }, sizeof(uintptr_t)); - memcpy(fun + (&wrapper_call - &wrapper_start) + 1, &function, sizeof(function)); - mprotect(fun, sz, PROT_READ | PROT_EXEC); - return fun; -} - /* * This function is an empty stub where GDB locates a breakpoint to get notified * about linker activity. @@ -388,19 +341,6 @@ static void apkenv_free_info(soinfo *si) apkenv_freelist = si; } -static const char *apkenv_addr_to_name(unsigned addr) -{ - soinfo *si; - - for(si = apkenv_solist; si != 0; si = si->next){ - if((addr >= si->base) && (addr < (si->base + si->size))) { - return si->name; - } - } - - return ""; -} - /* For a given PC, find the .so that it belongs to. * Returns the base address of the .ARM.exidx section * for that .so, and the number of 8-byte entries @@ -411,7 +351,7 @@ static const char *apkenv_addr_to_name(unsigned addr) * This function is exposed via dlfcn.c and libdl.so. */ #ifdef ANDROID_ARM_LINKER -_Unwind_Ptr apkenv_android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) +_Unwind_Ptr bionic_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) { soinfo *si; unsigned addr = (unsigned)pc; @@ -428,7 +368,7 @@ _Unwind_Ptr apkenv_android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) /* Here, we only have to provide a callback to iterate across all the * loaded libraries. gcc_eh does the rest. */ int -apkenv_android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), +bionic_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), void *data) { soinfo *si; @@ -1427,7 +1367,7 @@ static int apkenv_reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) if (!strcmp(sym_name, "dl_iterate_phdr")) { // FIXME: hack, move to libc.so - sym_addr = apkenv_android_dl_iterate_phdr; + sym_addr = bionic_dl_iterate_phdr; } else if ((sym_addr = dlsym(RTLD_DEFAULT, wrap_sym_name))) { LINKER_DEBUG_PRINTF("%s hooked symbol %s to %x\n", si->name, wrap_sym_name, sym_addr); } else if ((sym_addr = dlsym(RTLD_DEFAULT, sym_name))) { @@ -1444,7 +1384,7 @@ static int apkenv_reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) } if(sym_addr != 0) { - sym_addr = (unsigned)create_wrapper(sym_name, (void*)sym_addr, WRAPPER_UNHOOKED); + sym_addr = (unsigned)wrapper_create(sym_name, (void*)sym_addr); } else if(s == NULL) { /* We only allow an undefined symbol if this is a weak @@ -1515,7 +1455,7 @@ static int apkenv_reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) sym_addr = (unsigned)(s->st_value + base); LINKER_DEBUG_PRINTF("%s symbol (from %s) %s to %x\n", si->name, apkenv_last_library_used, sym_name, sym_addr); if(ELF32_ST_TYPE(s->st_info) == STT_FUNC) { - sym_addr = (unsigned)create_wrapper(sym_name, (void*)sym_addr, WRAPPER_UNHOOKED); + sym_addr = (unsigned)wrapper_create(sym_name, (void*)sym_addr); } } @@ -1834,7 +1774,7 @@ static void apkenv_wrap_function(void *sym_addr, char *sym_name, int is_thumb, s { DEBUG("HOOKING INTERNAL (ARM) FUNCTION %s@%x (in %s) TO: %x\n",sym_name,sym_addr,si->name,hook); ((int32_t*)sym_addr)[0] = 0xe51ff004; // ldr pc, [pc, -#4] (load the hooks address into pc) - ((int32_t*)sym_addr)[1] = (uint32_t)create_wrapper(sym_name, hook, WRAPPER_LATEHOOK); + ((int32_t*)sym_addr)[1] = (uint32_t)wrapper_create(sym_name, hook); __clear_cache((int32_t*)sym_addr, (int32_t*)sym_addr + 2); } @@ -1850,7 +1790,7 @@ static void apkenv_wrap_function(void *sym_addr, char *sym_name, int is_thumb, s ((int16_t*)sym_addr)[4] = 0xBC01; /* pop {r0} */ ((int16_t*)sym_addr)[5] = 0x4760; /* bx ip */ - void *wrp = create_wrapper(sym_name, hook, WRAPPER_LATEHOOK); + void *wrp = wrapper_create(sym_name, hook); // store the hooks address ((int16_t*)sym_addr)[6] = (uint32_t)wrp & 0x0000FFFF; @@ -1867,7 +1807,7 @@ static void apkenv_wrap_function(void *sym_addr, char *sym_name, int is_thumb, s { DEBUG("CREATING ARM WRAPPER FOR: %s@%x (in %s)\n", sym_name, (unsigned)sym_addr, si->name); - create_wrapper(sym_name, sym_addr, WRAPPER_ARM_INJECTION); + wrapper_create(sym_name, sym_addr); } // TODO: this will fail if the first 2-5 instructions do something pc related // (this DOES happen very often) @@ -1875,7 +1815,7 @@ static void apkenv_wrap_function(void *sym_addr, char *sym_name, int is_thumb, s { DEBUG("CREATING THUMB WRAPPER FOR: %s@%x (in %s)\n",sym_name, (unsigned)sym_addr,si->name); - create_wrapper(sym_name, sym_addr, WRAPPER_THUMB_INJECTION); + wrapper_create(sym_name, sym_addr); } } @@ -2133,9 +2073,6 @@ static int apkenv_link_image(soinfo *si, unsigned wr_offset) lsi = apkenv_find_library(si->strtab + d[1]); if (!lsi && dlopen(si->strtab + d[1], RTLD_NOW | RTLD_GLOBAL)) { DEBUG("Loaded %s with glibc dlopen\n", si->strtab + d[1]); - - if (!__cxa_demangle) - __cxa_demangle = dlsym(RTLD_DEFAULT, "__cxa_demangle"); } #endif if(lsi == 0) { @@ -2234,7 +2171,7 @@ fail: return -1; } -void apkenv_parse_library_path(const char *path, char *delim) +void dl_parse_library_path(const char *path, char *delim) { size_t len; char *apkenv_ldpaths_bufp = apkenv_ldpaths_buf; @@ -2428,7 +2365,7 @@ sanitize: /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */ if (ldpath_env) - apkenv_parse_library_path(ldpath_env, ":"); + dl_parse_library_path(ldpath_env, ":"); if (ldpreload_env) { apkenv_parse_apkenv_preloads(ldpreload_env, " :"); diff --git a/src/wrapper/wrapper.c b/src/wrapper/wrapper.c new file mode 100644 index 0000000..5ed0943 --- /dev/null +++ b/src/wrapper/wrapper.c @@ -0,0 +1,70 @@ +#include "wrapper.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ANDROID_X86_LINKER +__asm__( + "wrapper_start: nop\n" + "wrapper_symbol: pushl $0xFAFBFCFD\n" + "wrapper_trace: movl $0xFAFBFCFD, %eax\ncall *%eax\npop %eax\n" + "wrapper_call: movl $0xFAFBFCFD, %eax\njmp *%eax\n" + "wrapper_end: nop\n" +); +# define WRAPPER_TRACE +#else +# warning "no wrapper asm for this platform, function tracing is not available" +#endif + +#ifdef WRAPPER_TRACE +extern char wrapper_start, wrapper_symbol, wrapper_trace, wrapper_call, wrapper_end; +static char* (*__cxa_demangle)(const char *mangled_name, char *output_buffer, size_t *length, int *status); + +static void +trace(const char *const symbol) +{ + if (__cxa_demangle) { + // >If output_buffer is not long enough, it is expanded using realloc + // Holy fuck gcc what the fuck? Guess we don't use stack then, thanks + int status; + char *demangled; + if ((demangled = __cxa_demangle(symbol, NULL, NULL, &status))) { + printf("trace: %s\n", demangled); + free(demangled); // so pointless... + return; + } + } + + printf("trace: %s\n", symbol); +} +#endif + +void* +wrapper_create(const char *const symbol, void *function) +{ +#ifdef WRAPPER_TRACE + if (!__cxa_demangle) + __cxa_demangle = dlsym(RTLD_DEFAULT, "__cxa_demangle"); + + const size_t sz = &wrapper_end - &wrapper_start; + unsigned char *fun = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(fun != MAP_FAILED); + memcpy(fun, &wrapper_start, sz); +#ifdef ANDROID_X86_LINKER + memcpy(fun + (&wrapper_symbol - &wrapper_start) + 1, &symbol, sizeof(symbol)); + memcpy(fun + (&wrapper_trace - &wrapper_start) + 1, (uintptr_t[]){ (uintptr_t)trace }, sizeof(uintptr_t)); + memcpy(fun + (&wrapper_call - &wrapper_start) + 1, &function, sizeof(function)); +#else +# error "should not happen" +#endif + mprotect(fun, sz, PROT_READ | PROT_EXEC); + return fun; +#else + return function; +#endif +} diff --git a/src/wrapper/wrapper.h b/src/wrapper/wrapper.h new file mode 100644 index 0000000..c75ef33 --- /dev/null +++ b/src/wrapper/wrapper.h @@ -0,0 +1,4 @@ +#pragma once + +void* +wrapper_create(const char *const symbol, void *function); -- cgit v1.2.3