Friday, 10 April 2015

Patching ARM Code During Runtime

I always found some boring ways to spend my free time, few months back at the holidays in Israel I got some free time from work so I decided to make a BOT for some Android game (for research only purpose). The game, as almost any large Android game, is written in native c++. The game didn't use any known framework and wrote in plain c++, meaning no symbols and hardcore reversing... I burn all my time in reversing the code (about few megabytes of compiled ARM code, not a simple task). Finally, I reversed all their communication protocol (multiplayer game), in-game messaging mechanism, and got a GDB script which can manually do all the BOT features. I need to make a blog post about reversing this game but maybe somewhere at the future. For now, lets focus on what I did afterward, so I got this gdb script which can do anything I want, but gdb script is no fun.. I mean what happen when you want to show off your work? you can't just say "wait for me to open my gdb in my laptop and attach to the app...." you want some pre-compiled Android APK that does everything.


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:

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:

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

Because of this line

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
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.

No comments:

Post a Comment