To do so, you have several options:
1) Using APKTool and Smali patching the app Java wrapper and creating a new process in the app context. The process will Ptrace the app original process and hook the required addresses. The downside in this method is that creating new process in android as java is not supported, meaning android can close your process anytime without any relationship to the app original process.
2) Same as above, but the new process that will be created will be GDB compiled specifically for Android. The pros is that I can take my GDB scripts as is and use them without any work. This method got my attention because I need zero work on the scripts I already have. The only debugger available for android is the NDK gdbserver, not gdb istself. The NDK project, written by google, is open-source, so you can look at what changes google made to the gdbserver and apply them to the main gdb project. This porting of gdb to android proven too complicated for me so I give up on this method.
3) Patching the Smali code to load another shared library that you wrote to the dalvik vm. The library will mprotect the selected pages in memory that you want to patch, and patch the ARM code as you like.
As the title suggested, I took the third option.
Using APKTool, patching the smali code to load my share library:
This code should be wrapped in try..catch, my solution was to search where the app load their library and add this code below.
When the dalvik load our library the function
Now we know where our app code is and we can mprotect the page:
In the future I want to integrate this to APKTool and make a feature of native hook. The code will search the main activity and add the Smali code that load the library automatically to an app.
1) Using APKTool and Smali patching the app Java wrapper and creating a new process in the app context. The process will Ptrace the app original process and hook the required addresses. The downside in this method is that creating new process in android as java is not supported, meaning android can close your process anytime without any relationship to the app original process.
2) Same as above, but the new process that will be created will be GDB compiled specifically for Android. The pros is that I can take my GDB scripts as is and use them without any work. This method got my attention because I need zero work on the scripts I already have. The only debugger available for android is the NDK gdbserver, not gdb istself. The NDK project, written by google, is open-source, so you can look at what changes google made to the gdbserver and apply them to the main gdb project. This porting of gdb to android proven too complicated for me so I give up on this method.
3) Patching the Smali code to load another shared library that you wrote to the dalvik vm. The library will mprotect the selected pages in memory that you want to patch, and patch the ARM code as you like.
As the title suggested, I took the third option.
Using APKTool, patching the smali code to load my share library:
const-string v0, "somelib" invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
This code should be wrapped in try..catch, my solution was to search where the app load their library and add this code below.
When the dalvik load our library the function
jint JNI_OnLoad(JavaVM* aVm, void* aReserved)
is called. JNI_OnLoad is our main function.
Android uses ASLR, and you can't shut it down without replacing the kernel, at least in my phone. We need to patch the game library, but the address is changing. We load the original library using dlopen and we get the original library dynamic address.
handle = dlopen("game_lib.so", RTLD_LAZY); addr = dlsym()...
Now we know where our app code is and we can mprotect the page:
void protectPage(int addr) { int mf=addr; int page_s = ~(PAGE_SIZE-1); mf=mf & page_s; int res = mprotect(mf, getpagesize(), PROT_WRITE | PROT_READ | PROT_EXEC); __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Mprotect res: %d", res); }
Thats the easy part, now patching. For this part I wanted to use some already working code, something like Microsoft Detours, found is this github project:
https://github.com/crmulliner/adbi
This code patches the start of a function, and jump to address you give it. This code got a bug:
Because of this linehttps://github.com/crmulliner/adbi
This code patches the start of a function, and jump to address you give it. This code got a bug:
h->jumpt[1] = 0xb4; h->jumpt[0] = 0x30; // push {r4,r5} h->jumpt[3] = 0xa5; h->jumpt[2] = 0x03; // add r5, pc, #12 h->jumpt[5] = 0x68; h->jumpt[4] = 0x2d; // ldr r5, [r5] h->jumpt[7] = 0xb0; h->jumpt[6] = 0x02; // add sp,sp,#8 h->jumpt[9] = 0xb4; h->jumpt[8] = 0x20; // push {r5} h->jumpt[11] = 0xb0; h->jumpt[10] = 0x81; // sub sp,sp,#4 h->jumpt[13] = 0xbd; h->jumpt[12] = 0x20; // pop {r5, pc} h->jumpt[15] = 0x46; h->jumpt[14] = 0xaf; // mov pc, r5 ; just to pad to 4 byte boundary
h->jumpt[1] = 0xb4; h->jumpt[0] = 0x30; // push {r4,r5}
The app will crash. It will cause the r4 register to duplicate itself to r5 at the end of the run. I started to write this post, but faced the problem few months back and now someone made a pull request, maybe by the time I will publish this the code will be already fixed.The solution? pushing r5 twice:
h->jumpt[1] = 0xb4; h->jumpt[0] = 0x20; // push {r5} h->jumpt[3] = 0xb4; h->jumpt[2] = 0x20; // push {r5}Instead of the previous:
h->jumpt[1] = 0xb4; h->jumpt[0] = 0x30; // push {r4,r5}
Also, hook_direct did not support THUMB mode, added it.
My adbi fork:
https://github.com/smulikHakipod/adbi
No comments:
Post a Comment