This is the solution of the OWASP Uncrackable Android Level2. The binary can be found under https://github.com/OWASP/owasp-mstg/tree/master/Crackmes.
I started the analysis with loading the apk file into Jadx-GUI. I opened the MainActivity first.
The system loads a native library called foo. The native function init is called in the onInit of the MainActivity.
The CodeCheck class imports a function from this library called bar.
The (probably obfuscated) method a of CodeCheck uses this function to verify the password.
The next step in our analysis is extracting the library with apktool and loading it into IdaPro. I decompiled the apk with the following command line into the directory temp:
apktool d UnCrackable-Level2.apk -o temp
In the lib folder there are several versions of the libfoo.so. Each lib is compiled for a specific architecture. Since I am using an ARM64 device, I prefer analyzing that library.
First I checked the exported and imported functions.
This is a Java native library and the exported functions should have a special name in order to be able to import them in java environment. The name contains the ‘Java’ word, the package name, the class name and the method name in that order.
The imported function tells something about the functionality of the library. pthread_create and pthread_exit suggest that the library uses threads. Strncmp is a string comparator, probably this is necessary to check the passed password. If we are lucky, the string is hardcoded the password is compared with it. However the usage of thread suggests that the library calculates the string in runtime. Ptrace is a linux system call, that is used for debugging purpose. In our case it is used as an anti-debug technique.
I checked the strings, but there is only one and this is not the password.
Ptrace is used twice. The first call is at 0x918, the second one is at 0x950.
The parameter of the first one is the PID of the current process, and 0x10, which is the PTRACE_ATTACH flag.
ptrace(PTRACE_ATTACH, pid, 0, 0);
This function call attaches the process to itself. Since only one process can be attached to a certain process, another process will not be able to attach to it. This means we will not be able to attach gdb to the process.
One possible way to handle this problem is NOP-ing out the two ptrace syscall. I used the IDAPro ‘Edit/Patch Program/Change byte’ feature, then I selected the ‘Apply patches to input file’.
I installed the application on a rooted device, but I could not use it because it detected the rooted state. I patched the application and removed the root detection and debugger detection from the code. I navigated to the MainActivity.smali file and removed the content of the method a. In case a problem is detected, this method is called. It shows an AlertDialog and exits the application. Patching this method solves our problem. The smali code of the method:
.method private a(Ljava/lang/String;)V .locals 4 return-void .end method
I also replaced the lib with my patched one. Then I rebuilt the application with apktool, resigned it and installed it on my device:
apktool b temp UnCrackable-Level2_patched.apk
I use bash scripts to generate keystore and resign the application. These scripts can be found here.
This time the application started without any problem.
This post describes how to attach gdb to an Android process.
I opened a root shell on the device.
I checked the system partition with mount. It was mounted read-only:
/dev/block/platform/soc.0/f9824900.sdhci/by-name/system /system ext4 ro,seclabel,noatime,data=ordered 0 0
I remounted the system partition read-write …
mount -o rw,remount /dev/block/platform/soc.0/f9824900.sdhci/by-name/system /system
… and copied the gdbserver into the /system/bin folder. Then added execute rights to the binary and remounted the system partition again with read-only mode.
mount -o ro,remount /dev/block/platform/soc.0/f9824900.sdhci/by-name/system /system
I determined the PID of the application …
ps | grep uncrackable
… and attached the gdbserver to the process.
gdbserver :8888 –attach <PID>
On my computer, I forwarded the port 8888 …
adb forward tcp:8888 tcp:8888
I started the gdb and attached to the remote process without any problem.
(gdb) target remote :8888
This command …
(gdb) info sharedlibrary
… lists all the imported libraries. The last item is our libfoo.so lib. The entry point of the libfoo.so is 0x7f77d59840. In the exported functions window of IdaPro we saw that the offset of the start method was 840. So the start address of the libfoo.so is 0x7f77d59000. This can be checked in the Android shell:
In IdaPro I found the address of the strncmp function (0xc88).
The breakpoint should be set to this address: 0x7f77d59c88.
(gdb) b *0x7f77d59c88
First my breakpoint was not hit. The problem was that there is a check before strncmp: The length of the passed string should be 0x17 = 23 character. I entered 23 character and this time the breakpoint was hit.
I dumped the content of the registers.
(gdb) info registers
The address of the entered password string and the address of the calculated password string is passed to strncmp as two paramterers. The parameters are passed in X0 and X1 registers. I dumped the two strings: