Aerosol Posted December 7, 2014 Report Posted December 7, 2014 In this paper, I’ll describe how to start reverse code engineering in Android devices. In this tutorial, you’ll learn:Installation & configuration of Android Virtual Device.How to build your debugging environment.Short ARM assembly description.Debugging with GDB inside your Android device.Remote Debugging using gdbserver.Remote debugging using IDA.1. Installation & configuration of Android Virtual DeviceThe first thing to do is to download Android SDK and NDK. We will use GDB, other binutils, and also GCC and LD cross compiling chains. The cross compilers are able to compile binaries for other architectures. In our case, we want to compile ARM binaries from x64 architecture, since we are working on Linux x86_64, and we want to compile binaries for ARM android, so we have to use them.If you are curious about how to build these cross compiling chain tools,here are the commands:# wget -c ftp://ftp.gnu.org/gnu/binutils/binutils-2.11.2.tar.gz# tar xvf binutils-2.11.2.tar.gz# cd binutils-2.11.2# ./configure –target=arm-linuxIn our case, we don’t need to do this, as NDK contains all the things we need. Let’s go back and download Android SDK and Android NDK from here:# https://developer.android.com/tools/sdk/ndk/index.html# https://developer.android.com/sdk/index.htmlor we can download the pre-compiled arm-linux-gnueab- toolchain .tarball these file in /opt/ and then add its path in $PATH variable environment.After that we have to install and configure an Android Virtual Device (AVD).This is where our binaries will run.Type :# android avdClick to New :Click OK, then start your Virtual Device. However, we don’t need its grapical user interface, we will connect to it using shell. AVD gives as a rooted device, so we can do everything, which will be great when we debug Linux internals and keep tracking syscalls.Once you click on the start button, your Virtual Device appears like this:In my case, I used Android 4.2 as a target and Nexus 7 as device,though there is nothing wrong with using other targets or devices.Let’s run our device shell:$ adb shell# iduid=0(root) gid=0(root)2.How to build your debugging environmentNothing’s new here, just mentionning that we will show three ways to debug an Android binary. The first one is to put GDB inside the device and start debugging as you are on a Linux box, thus we can keep track of several things like symbols, GOT, linked libraries, etc.The second one is by using gdbserver and opening a port in the device and forwarding it to an external port to gain access into the device using a GDB client.The third is debugging with IDA Pro.Debugging Android binaries without understanding ARM Assembly is worthless. We will show in the next chapter some basic stuff in ARM Assembly.3.Short ARM descriptionPersonally, I like ARM assembly because it’s very easy to learn and dive into its programming. We will show some basic instructions and conventions:3.1.RegistersARM Assembly has 16 registers. Some of them are for function arguments, others for local variables, program counter, stack pointer, and other registers.R0 to R3 : for function arguments. Alternative names are a0-a3.R4 to R9 : for local variables.R7 : almost holds the syscall number.R10 (sl) : Stack Limit.R11 (fp) : Fame Pointer.R12 (ip) : Intra Procedure.R13 (sp) : used as Stack Pointer like RSP in x86_64.R14 (lr) : Link Register.R15 (pc) : Program Counter (like RIP in x86_64 & EIP in x86).3.2.BranchingBranching instructions are used when the program needs some loops, procedures and functions. The behaviour of the calling function in ARM is different from x86 assembly .Here are the basic branching instructions:B BranchBL Branch with LinkBX Branch with ExchangeBLX Branch with Link and ExchangeThe B (Branch) doesn’t affect LR. That means if we jump to a subroutine we don’t have any traceback for where we were. It’s like JMP instruction in x86 assembly.The BL (Branch with Link) instruction makes a subroutine call by storing PC-4 in LR of the current place, and to return from subroutine, we simply need to restore PC from LR like: mov pc,lr.BX and BLX instructions are used in THUMB MODE which we don’t dive into in this part.3.3.Data ProcessingAs we know, ARM is a LOAD/STORE architecture it contains 4 main instructions classes:- Arithmetic operations:ADD op1+op2ADC op1+op2+carrySUB op1-op2+carry-1syntax : <operation> {<cond>}{S} Rd,Rn,operandexamples :ADD r0,r1,r2SUB R1,R2,#1- Comparison:CMP op1-op2TST op1 & op2TEQ op1 ^ op2By the way, the results of these operations are not written.Syntax : <operation> {<cond>} Rn,Opexamples :CMP R0,R1CMP R0,#2- Logical operations:AND op1,op2EOR op1,op2ORR op1,op2- Data movement between registers:MOV op1,op2syntax : <Operation>{<cond>}{S} Rn, Op2Examples:MOV r0, r1We have shown some basic ARM instructions and as we said, it is easy to learn by practicing with some small examples.4.Debugging with GDB inside your Android deviceYou should download GDB ARM version statically linked. After we have GDB for arm targets, we have to push it on the Android device.# adb push ~/Bureau/arm-gdb /dataSo we make a small ARM binary as an example inside the device and we’ll keep track of its behaviour:#include <stdio.h>#include <string.h>int main(int argc,char **argv){ char buf[16]; if(argc < 2) return -1; strcpy(buf,argv[1]); printf("Hello : %s n",buf); return 0;}Let’s compile it:# arm-linux-gnueabi-gcc -o s s.c -static -zexecstack -fno-stack-protector# adb shellroot@generic:/ # /data/gdb -q /data/sWARNING: generic atexit() called from legacy shared libraryReading symbols from /data/s…(no debugging symbols found)…done.(gdb) disas mainDump of assembler code for function main: 0x00008c24 <+0>: push {r7, lr} 0x00008c26 <+2>: sub sp, #24 0x00008c28 <+4>: add r7, sp, #0 0x00008c2a <+6>: str r0, [r7, #4] 0x00008c2c <+8>: str r1, [r7, #0] 0x00008c2e <+10>: ldr r3, [r7, #4] 0x00008c30 <+12>: cmp r3, #1 0x00008c32 <+14>: bgt.n 0x8c3a <main+22> 0x00008c34 <+16>: mov.w r3, #4294967295 0x00008c38 <+20>: b.n 0x8c5e <main+58> 0x00008c3a <+22>: ldr r3, [r7, #0] 0x00008c3c <+24>: add.w r3, r3, #4 0x00008c40 <+28>: ldr r3, [r3, #0] 0x00008c42 <+30>: add.w r2, r7, #8 0x00008c46 <+34>: mov r0, r2 0x00008c48 <+36>: mov r1, r3 0x00008c4a <+38>: blx 0x12e00 <strcpy> 0x00008c4e <+42>: movw r0, #51124 ; 0xc7b4 0x00008c52 <+46>: movt r0, #6 0x00008c56 <+50>: blx 0x99a8 <puts> 0x00008c5a <+54>: mov.w r3, #0 0x00008c5e <+58>: mov r0, r3 0x00008c60 <+60>: add.w r7, r7, #24 0x00008c64 <+64>: mov sp, r7 0x00008c66 <+66>: pop {r7, pc}End of assembler dump.(gdb) r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaStarting program: /data/s aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaHello aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaProgram received signal SIGSEGV, Segmentation fault.0x61616160 in ?? ()5.Remote debugging using gdbserverThis is another cool way to debug outside your device , so we copy gdbserver into /data directory or whatever you want. In the latest Android version, gdbserver has been included by default. Next, you choose between either attaching to a running process or executing a new process.The first thing we should do is port forwarding:adb forward tcp:<PC port> tcp:<device port>.Example:# adb forward tcp:1234 tcp:1234# adb shellWe choose any running process:root@generic:/ # gdbserver :1234 --attach 1436Attached; pid = 1436Listening on port 1234Remote debugging from host 127.0.0.1In our box we use:# cd /android-ndk-r9/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin # ./arm-linux-androideabi-gdbGNU gdb (GDB) 7.3.1-gg2Copyright (C) 2011 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".For bug reporting instructions, please see:<http://source.android.com/source/report-bugs.html>.(gdb) target remote :1234Remote debugging using :1234Remote communication error. Target disconnected.: Connection reset by peer.(gdb)(gdb) target remote :1234Remote debugging using :12340xb6eb1f9c in ?? ()(gdb) x/10i $pcCannot access memory at address 0x5b6=> 0xb6eb1f9c: svc 0x00000000 0xb6eb1fa0: mov r7, r12 0xb6eb1fa4: cmn r0, #4096 ; 0x1000 0xb6eb1fa8: bxls lr 0xb6eb1fac: rsb r0, r0, #0 0xb6eb1fb0: b 0xb6ecdb28 0xb6eb1fb4: mov r12, r7 0xb6eb1fb8: mov r7, #174 ; 0xae 0xb6eb1fbc: svc 0x00000000 0xb6eb1fc0: mov r7, r12(gdb)6. Remote debugging using IDA Pro:This is like gdbserver, but we should push android_server in the device machine.# adb push android_server /dataIn IDA go to Debbugger ? Remote ARMLinux / Android server debugger, and set the host and the port with the path of the application.That’s all, we have described all the techniques. Moreover, I made this tutorial practical and as a reference for those of you who are interested.Source Quote