Android Native API Hooking With Library Injection and ELF Introspection.



This post can be considered both the part 2 of the previous “Dynamically inject a shared library into a running process on Android/ARM“ and a proof of concept of the same, namely what can be done with library injection on Android.

TL;DR

I’ve updated the source code of the arminject project on github adding a library that once injected into a process will hook its open API and print some logs to the logcat, the make test command will basically start a new Chrome browser process, use the injector discussed in the previous post to inject libhook.so into it and wait for its logs to appear, an example output could be like:

@ Attaching to process com.android.chrome ...
@ Injecting library /data/local/tmp/libhook.so into process 8511.
@ Calling dlopen in target process ...
@ dlopen returned 0xb5202dc4

I/LIBHOOK ( 8511): [8511] open('/data/data/com.android.chrome/app_chrome/.com.google.Chrome.gJY5h4', 194)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/data/data/com.android.chrome/shared_prefs/com.android.chrome_preferences.xml', 577)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/data/data/com.android.chrome/files/android_ticl_service_state.bin', 0)
I/LIBHOOK ( 8511): [8511] open('/data/data/com.android.chrome/files/ticl_storage.bin', 0)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/data/data/com.android.chrome/files/android_ticl_service_state.bin', 577)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
I/LIBHOOK ( 8511): [8511] open('/dev/ashmem', 2)
...
...

Hooking System Functions

As I basically wrote everywhere in the source to avoid any kind of misunderstanding, the libhook.so code is almost totally based on Andrey Petrov‘s blog post “Android hacking: hooking system functions used by Dalvik“, although I had to modify and fix its original version since it didn’t work ( page align errors, memory protection faults and so forth ).

The main concept is quite simple yet neat, once the library is injected inside the target process, its constructor will be executed.
A constructor function is declared like this:

lang-c
1
2
3
__attribute__((constructor)) somefunction() {
// something
}

This means that “somefunction” will be executed as soon as the library is loaded.

This allowed me to exploit Petrov’s code at runtime and patch the process relocation table, an ELF structure that holds the addressess of system functions used by the program.
The logic steps to do this are:

  • Get the base pointer of the module using dlopen.
  • Given its pointer, lookup the symbol ( open in our case ) inside its (sym|str)tab.
  • Search the symbol inside the reloc table by index.
  • Backup its original address and finally patch it with our own hook function address.

Once the hook function is called, it will log its parameters and then call the original function we previously backupped:

lang-c
1
2
3
4
5
int hook_open(const char *pathname, int flags) {
HOOKLOG( "[%d] open('%s', %d)", getpid(), pathname, flags );

return __open( pathname, flags );
}

Obviously this method can be applied to any kind of function, even Dalvik high level native API.

Enjoy :)