Cedric’s Cruft

  • Blog
  • Tools
Browse: Home > Intercepting Android native library calls

Intercepting Android native library calls

Edit: at the time of writing, not many details could be disclosed as part of a responsible disclosure policy. The application in question was BlackBerry Messenger (com.bbm). BlackBerry did not respond to our findings. The full report is now available (unrevised version, including typos, mistakes, etc.).

As part of a uni project, we’ve been busy reverse engineering an Android application. Amongst the things we investigated were the following:

  • SSL checks, using signature based static analysis of the Java bytecode
  • MitM and decryption/modifying of streams

 
The APK contains quite some calls to native libraries. The developers decided to include some libraries that can be found on every Android system as well, suggesting that they might not trust the ones that are delivered with stock Android, and decided to compile their own version. The application core is mostly contained in a shared object as well, which makes it painful to get a quick overview of what is going on inside. We don’t have sources, so have to rely on static and dynamic analysis of the ARM binary.

During disassembly, we noticed a particular text file being written to the data folder with AES-256-CBC encryption. The encryption relies on a few functions in the OpenSSL EVP library, which provides a high-level interface to cryptographic functions, of which they used EVP_BytesToKey and EVP_EncryptUpdate amongst others. A quick google shows that they based this mostly on an example implementation. How do we capture/intercept those calls and log them?

Our first approach was to attach a remote debugger to the process with GDB (or IDA Pro if you prefer and have loads of money) and put breakpoints on the parts where encryption is being used. This worked, but we wanted a more permanent solution.

Is it possible to use LD_PRELOAD’s on Android? Yes it is, we can preload shared objects on Android just like we can on other Linux systems. (Though you may not want to attempt this on Android <= 4.0). The apitrace project is a nice example of a project that uses a very similar technique to trace OpenGL, Direct3D, and other graphics APIs.

The great thing about LD_PRELOAD is that it can intercept hardcoded paths in the binary thanks to the load order. We created a shared object for ARM/Android, which we could then preload:

Function override
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <openssl/evp.h>
#include <android/log.h>
 
int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md, const unsigned char *salt, const unsigned char *data, int datal, int count, unsigned char *key,unsigned char *iv)
{
    int (*new_evp_bytestokey)(const EVP_CIPHER *type,const EVP_MD *md, const unsigned char *salt, const unsigned char *data, int datal, int count, unsigned char *key,unsigned char *iv);
    new_evp_bytestokey = dlsym(RTLD_NEXT, "EVP_BytesToKey");
 
    __android_log_print(ANDROID_LOG_DEBUG, "SSLOverride", "Salt: {%d,%d}, Key: %s, Count: %d\n", *(unsigned int*)salt, *(unsigned int*)(salt+4), data, count);
 
    return new_evp_bytestokey(type, md, salt, data, datal, count, key, iv);
}
 
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
{
    int (*new_evp_encryptupdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
    new_evp_encryptupdate = dlsym(RTLD_NEXT, "EVP_EncryptUpdate");
 
    __android_log_print(ANDROID_LOG_DEBUG, "SSLOverride", "Plaintext: %s \n", in);
 
    return new_evp_encryptupdate(ctx, out, outl, in, inl);
}

This will catch the function calls, print the arguments, then pass the call on to the original function.
Compile the C file with your favorite NDK toolchain and linked with -llog (this one has been compiled with API level 14):

1
2
3
4
$ ../android-toolchain/bin/arm-linux-androideabi-gcc -shared -o libsslover.so sslover.c -I /home/cedric/toolchain/openssl-1.0.1e/include/ -llog
 
$ file libsslover.so
libsslover.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, not stripped

We then push the shared object to the Android device and preload it into the Dalvik VM by setting the wrap property for the application. You might need root for some of these commands (or remount with read-write permissions):

1
2
$ adb push libsslover.so /data/libsslover.so
$ setprop wrap.com.xyz.yourapp LD_PRELOAD=/data/libsslover.so

Then start the application as you normally would from the launcher, and watch logcat closely:

adb logcat
1
2
3
4
5
6
$ adb logcat | grep --line-buffered -i SSLOver
 
D/SSLOverride(27373): Salt: {87611,13275}, Key: sUp3r1337h4x0rK3Y, Count: 5
D/SSLOverride(27373): Plaintext: userid cedric:13487965
D/SSLOverride(27373):
D/SSLOverride(27373): Plaintext: pass helterskelterinasummerswelter

We’ve got plaintext being spit out in our terminal right before it gets encrypted!

Reverse engineering the HITB binary 100 CTF challenge
Comments: 5
  1. mittorn
    2138 days ago

    It says "could not set property"

    ReplyCancel
  2. Pipas
    1832 days ago

    Hey dude, congrats on this great workaround.
    I was trying something very simillar however it seems not all versions of android allow you to use LD_PRELOAD.
    Can you explain which version of android were you using?
    Or did you have some extra settings to enforce the LD_PRELOAD?

    Thanks

    ReplyCancel
  3. cedric
    1832 days ago

    I did not have any additional settings. I've found out about a far more robust solution though: Frida. You run the frida-server binary as root on your Android device, and the client then allows you to hook any function at runtime.

    ReplyCancel
  4. Nils
    1698 days ago

    Is it possible to use above method on newer Android versions using ART VM? So far I'm get some sort of libc error always and the app is not starting anymore.

    ReplyCancel
  5. Igor Ganapolsky
    1532 days ago

    This is really interesting. Does IDA Pro not do de-obfuscation sufficiently? I mean, if people are paying $5000.00 bucks for it, they'd expect it to be foolproof and without fail...

    ReplyCancel

Leave a Reply to Igor Ganapolsky Cancel reply

cedric

Uncategorized

Android, ARM, Dalvik, debugging, decompile, disassemble, gdb, LD_PRELOAD, loader, native libraries, shared object, SSL, wrap, Zygote

2598 days ago

63,300
Recent Posts
  • Tracing API calls in Burp with Frida
  • SANS Holiday Hack Challenge 2015 writeup
  • SECCON 2015 – Reverse engineering Android APK 2 – 400 writeup
  • WordPress < 4.1.2 Stored XSS vulnerability
  • Reverse engineering the HITB binary 100 CTF challenge
Recent Comments
  • Tech En bref : une faille critique découverte dans WordPress | KANO on WordPress < 4.1.2 Stored XSS vulnerability
  • New Security Flaw Allows Attackers to Hijack WordPress Sites – My WordPress Website on WordPress < 4.1.2 Stored XSS vulnerability
  • Millions at risk with Critical WordPress Zero-day Vulnerability on WordPress < 4.1.2 Stored XSS vulnerability
  • h4niz on Tracing API calls in Burp with Frida
  • Millions at risk with Critical Wordpress Zero-day Vulnerability | MageShield | Secure & simple magento maintenance on WordPress < 4.1.2 Stored XSS vulnerability
Archives
  • January 2017
  • January 2016
  • December 2015
  • April 2015
  • June 2014
  • December 2013
© 2013-2017 Cedric Van Bockhaven