Uncrackable3
This android challenge is the third one of a series of challenges offered by OWASP Mobile Application Security.
Make sure to check the writeups for the first and second ones, as some of its elements will be referred to and will lack of details in the current writeup : Uncrackable1 & Uncrackable2
Understanding the app
Once again, the app has a root detector even though the popup is different from the ones in the previous apps. We still see the textfield in which to type the secret string.
Let’s call Jadx !
The structure of the apk is quite similar to the second one with some additions.
Let’s see MainActivity :
So, the app stills check if we the device is rooted, however, this time, it also checks the integrity of the libfoo
native library. If the device is rooted or the native library is tampered, MainActivity.showDialog
is called.
So all this is easily bypassable by hooking MainActivity.showDialog
and making it useless.
Furthermore, the init
native function is called, at the beginning of onCreate, using the string pizzapizzapizzapizzapizz
as bytes argument.
Once again, the verify
method passes the user input through CodeCheck.check_code
.
This method calls the native function bar
.
Finding the string
Let’s reverse the library using IDA, and let’s understand how init
and bar
work.
Init
This init
function seems easy to understand, it probably copy the argument into a memory area called dest
.
Bar
The bar
function starts by setting the 25 first values of an array called v7
to 0.
Then a function named sub_12C0
is called with v7
as argument.
Then we encounter a loop, in this loop v4
that is probably the user input is compared byte by byte (from the byte indexed to 0 to the one indexed at 24 because then the counter gets superior to 25 and ends the loop) to the result of the xor operation between dest
and v7
.
Therefore, it would be weird if v7 was only composed of 0
, so we can guess that sub_12C0
modifies v7
.
Let’s see what sub_12C0
is made of !
The worst obfuscation in the world
Get ready to see the most useless obfuscation technique I have ever seen.
The function consists of a succession of operations that are more or less similar. However none of the data manipulated affects the argument :clown_face: .
Then looking at the end of function gives us the final value of the modified argument :
a1
is the argument, so finally, its 16 first bytes are byte_3B40
and the 8 finale ones are 0x14130817005A0E08
So the value of v7 (in hex) is 1d0811130f1749150d0003195a1d1315080e5a0017081314
Let’s write a small python script in order to make the xor operation and retrieve the secret string !
str1 = "pizzapizzapizzapizzapizz"
str1 = str.encode(str1)
hex2 = "1d0811130f1749150d0003195a1d1315080e5a0017081314"
hex2 = bytes.fromhex(hex2)
print(''.join([chr(hex2[i]^str1[i]) for i in range(24)]))
This leads us to find the secret string : making owasp great again
`