Debugging Android apps without source: native methods

  • Tutorial

What is this article about


In two previous articles, I talked about how to debug Android applications without Java source code and some features of installing breakpoints . If the dear reader has not yet read these articles, I highly recommend starting with them, and only then reading this article.

It just so happened that so far I talked exclusively about debugging Dalvik bytecode and did not say a word about debugging native methods. But it is in native methods that the most delicious is often hidden - cunning defenses, interesting malware features, zero-day vulnerabilities. Therefore, today I am concise, without "water", I will tell you how to debug native methods without source code in C / C ++ (well, or whatever, dear reader, they are written there).

To benefit from my story you need to be a little “in the subject”. In particular, it is desirable that the reader
  • understood the syntax of Smali , could write its own code in .smali files, and could distinguish declarations and calls of native methods from ordinary methods, knew how to recompile .apk files using Apktool ;
  • Imagine what Java Native Interface (JNI) is and how it works ;
  • I knew for what the methods System.load (...) and System.loadLibrary (...) were used , how they work in Android, and by the arguments of these methods in Smali code I could independently determine in which .so libraries the JNI functions are located corresponding to those or other native methods;
  • knew how to find these JNI functions in .so libraries;
  • at least at the initial level, knew the ARM assembler (the article assumes that debugging will be performed on a device with ARM architecture or on an emulator that emulates this architecture);
  • had some experience with gdb and gdbserver ;

That's probably all the knowledge and skills that the reader will need. Let's move on to the tools.

Instruments


Today we need:
  • gdb and gdbserver for ARM from the latest version of Android NDK . Installation is described here .
  • A utility adbfrom the latest version of the Android SDK . Installation is described here .
  • If debugging is on a real Android device, it needs root privileges.

Let's move on to the preparation.

Training


It is assumed that the reader is experienced enough to independently carry out the following preparatory steps:
  • Disassemble the .apk application file using Apktool, examine the files in a subdirectory папка/куда/дизассемблировали/приложение/smaliand find out:
    • what native methods are called from Dalvik bytecode;
    • in which .so library the functions corresponding to these JNI methods are located;

  • Remove this .so library from the subdirectory папка/куда/дизассемблировали/приложение/libor from the device on which debugging will be performed, examine it and find out what the JNI functions are called that correspond to certain native methods called from the Dalvik bytecode.
  • Rebuild the .apk application using Apktool with open source tools -dand drive them to debugging in NetBeans as described in this article of mine .
  • Make sure that debugging in NetBeans stops after calls System.loadLibrary(...)or System.load(...)that load .so with the JNI functions of interest to us, but before the first call of any of the native methods. You can use the trick I wrote about here .
  • Push gdbserver to the device or emulator on which we are debugging.

Now that all the preparations are completed, you can proceed to debugging.

Debugging


The idea is to drive our application directly under two debuggers: under the debugger built into NetBeans - to debug Dalvik bytecode, and under gdb - solely to debug calls to native methods. It sounds a little strange, but in practice it works for itself. Although not always, see the next section, Pitfalls.

So, if the reader has completed all the preparatory steps from the previous “Preparation” section, then now he has probably run a rebuilt application on his device or emulator, NetBeans is open on the computer and debugging is located somewhere after the call System.load(...)or System.loadLibrary(...), but even before the first call to the native method. And the reader is already aware in which library which JNI functions correspond to which native methods. This is where we will begin.

Next is a step-by-step instruction. It was written for Windows, but I think it will work for Linux and MacOS. Please follow the instructions exactly:
  1. From a command prompt, abd shellopen the ADB console of your device or emulator. Find the PID of your application process using the command psin the ADB console. In the same console, run the command:
    gdbserver :5039 --attach %PID%
    where %PID%is the PID of the process of your application. In response, gdbserver should output something like:
    Attached; pid = %PID%
    Listening on port 5039
    From now on, debugging in NetBeans will freeze. Those. of course you can click on the buttons there, but it’s useless since the application that you are trying to debug in NetBeans is currently stopped under the GDB debugger. Do not panic, everything is as it should be!
  2. Open a new console on your computer, run the command
    adb forward tcp:5039 tcp:5039
  3. In the same console, run gdb from the Android NDK:
    gdb libMyNativeLibrary.so
    where libMyNativeLibrary.sois the very .so library that contains the JNI functions of interest to us. The library should be on your computer in the directory which for gdb is current at startup. This will open the gdb console.
  4. In the gdb console, type the following commands:
    (gdb) target remote :5039
    After these manipulations, a message similar to
    Remote debugging using :5039
    0x4009d58c in ?? ()
    and in the ADB console (we still have it open, remember?) something like
    Remote debugging from host 127.0.0.1
  5. In gdb console do
    (gdb) info functions
    to see a list of functions. Among other functions, the list should also include the JNI functions you are interested in, something like:
    0x5b5f7bac  Java_my_app_for_debug_MainActivity_coolNativeMethod
    0x5b5f7c0c  Java_my_app_for_debug_MainActivity_anotherCoolNativeMethod
    0x5b5f7c1c  Java_my_app_for_debug_MainActivity_theCoolestNativeMethodEver
  6. In the gdb console, put breakpoints at the addresses of the JNI functions you are interested in, in our case it is
    (gdb) break *0x5b5f7bac
    (gdb) break *0x5b5f7c0c
    (gdb) break *0x5b5f7c1c
  7. Resume your application using the command cin the gdb console. After executing this command, debugging in NetBeans will “freeze” and you will be able to debug Dalvik bytecode again.

Now, every time a native method is called in the Dalvik bytecode, like
const/high16 v8, 0x4100
invoke-static {v8}, Lmy/app/for/debug/MainActivity;->theCoolestNativeMethodEver(F)V
debugging in NetBeans will freeze, but gdb will please you with messages like
Breakpoint 1, 0x5b5f7c1c in Java_my_app_for_debug_MainActivity_theCoolestNativeMethodEver () from libMyNativeLibrary.so

This is actually it. Further x/i $pc, stepiin general, forward debug one ARM instruction after another (remember, I said at the beginning that the ARM assembler will be needed? - well ...)

Underwater rocks


Oh, there are a lot of them. A whole garden of pitfalls. Here are the most memorable glitches that I came across when using GNU gdb (GDB) 7.4.1 in conjunction with GNU gdbserver (GDB) 7.4.1 on Android 4.0.3 in the Ainol Aurora device (the one still old ):

  1. If after some time you have gdb regularly falling off from gdbserver by watchdog timeout, run gdb in the console set watchdog 18000- this should help.
  2. Sometimes, as a result info functions, the function list does not display the addresses of functions in memory, but offsets in the .so file, for example:
    0x000c0bac  Java_my_app_for_debug_MainActivity_coolNativeMethod
    0x000c0c0c  Java_my_app_for_debug_MainActivity_anotherCoolNativeMethod
    0x000c0c1c  Java_my_app_for_debug_MainActivity_theCoolestNativeMethodEver
    In this case, check or libMyNativeLibrary.soreally lies in the directory which for gdb is current at startup, and restart gdb again with the same command gdb libMyNativeLibrary.so.
  3. Sometimes, as a result info functions, the list of functions displays the addresses of functions in memory and offsets in the .so file, for example:
    0x5b5f7bac  Java_my_app_for_debug_MainActivity_coolNativeMethod
    0x5b5f7c0c  Java_my_app_for_debug_MainActivity_anotherCoolNativeMethod
    0x5b5f7c1c  Java_my_app_for_debug_MainActivity_theCoolestNativeMethodEver
    0x000c0bac  Java_my_app_for_debug_MainActivity_coolNativeMethod
    0x000c0c0c  Java_my_app_for_debug_MainActivity_anotherCoolNativeMethod
    0x000c0c1c  Java_my_app_for_debug_MainActivity_theCoolestNativeMethodEver
    Ignore offsets in the .so file, put breakpoints on the addresses of functions in memory.
  4. If the command breakon function names works fine - you're lucky, if not ... well, actually it doesn’t work for me, so in this article I put breakpoints on the addresses of functions.
  5. May not work set stop-on-solib-events. It does not work for me.
  6. From time to time you will see an inscription Cannot access memory at address 0x1. Ignore it.

I am sure that this is not a complete list of glitches that conceals the debugging of native methods without source codes, and that other researchers will come across completely different, unique glitches that I have not come across. If anyone else finds - please share in the comments. Also in the comment, please ask questions and / or make technical amendments to the text. I’ll try to answer as quickly as possible, but if I’m stupid, please be patient. I will try to answer everyone.

Happy debugging!



PS Request to those who negate the article to unsubscribe in the comments on what exactly did not like. I will try to fix it, if possible.

PPS The article went a big plus - it means the topic of debugging and reversing engineering is interesting to people and I will share my experience further. For what were the cons of the article in the beginning, I still did not understand - oh well, let’s write off the random fluctuations of the habrasila.

PPPS If anyone needs technical assistance on the topic of the article - please contact, I can help with what.

Also popular now: