summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.c26
-rw-r--r--src/jvm/jvm.c36
-rw-r--r--src/libc.c12
-rw-r--r--src/libjvm-android.c10
-rw-r--r--src/libjvm-java.c24
-rw-r--r--src/libpthread.c16
-rw-r--r--src/linker/dlfcn.c49
-rw-r--r--src/linker/linker.c87
-rw-r--r--src/wrapper/wrapper.c70
-rw-r--r--src/wrapper/wrapper.h4
10 files changed, 191 insertions, 143 deletions
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 <dlfcn.h>
#include <err.h>
#include <assert.h>
+#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 <assert.h>
#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 <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdbool.h>
#include <assert.h>
+#include <err.h>
+#include <dlfcn.h>
#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 <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <sys/mman.h>
+
+#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);