draw.per - THCon 2021
Draw APK - THCon 2021
- 14 solves
- 249 points
First steps
As the challenge creator tells me this app is “based on a Trojan Horse” and it is “not recommended to install it on a real smartphone”, even if there is actually “no malicious payload”, I am very reluctant at first to test the app, even in an emulator.
So, I start off with my favorite static analysis combination: DroidLysis and JEB. The results are disappointing, I spot several “suspicious” parts (use of com.andrognito for example) but they are False Positives.
Dexcalibur and Zip
I decide therefore to run the app in an Android emulator, instrumented with Dexcalibur. I use the default set of hooks, and spawn the app. Nothing important happens until I click on the Settings menu. There, I notice the creation of a files.zip.

I find this suspicious: apart if configuration elements are zipped (but why? storing them in shared preferences seems easier), I see no reason why the app would need to create a Zip file.
I retrieve the zip file via ADB. It contains:
- ExtClass.enc: this file is obviously encrypted
- inf.enc: same, encrypted.
- theme.jpg: this file is a … PNG image. I don’t know why eog (Eye of Gnome) refuses to open it, but Gimp has no problem to open it.
It says we have been pwned. So, I am obviously in the right direction :)

Dexcalibur and Dex
Then, I notice in Dexcalibur that a Dalvik Executable is loaded (highly suspicious):

I grab the DEX via ADB. It is a valid DEX file, that I immediately decompile. The code is simple, with a single class ExtClass, and methods such as isInfected() : exactly what I expect in a challenge.
ExtClass code
The image of the Zip is used by the method changeWallpaper(). It sets it as wallpaper.
| |
I am interested in method checkInf(), which decrypts inf.enc file. As this file is small (48 bytes), it could very well hold the encrypted flag.
| |
I write the matching standalone Java code, but when I run it, it fails with no available provider for AES_256/CBC/PKCS7Padding.
How to lose time, silly
At this point thinking that if my computer does not have this provider, for sure Android phones and emulators have it, so I am going to hook the decryption method doFinal and display the decrypted text.
I hook doFinal and ensure that it displays the decrypted result (ret).

Then, I spawn the malware (note each time, I have to uninstall it and re-install it, to run it clean):

I considered hooking directly checkInf(), except I can’t with Dexcalibur because it is from dynamically loaded code and Dexcalibur does not find it. It is possible to write a Frida hook instead (without using Dexcalibur), but I’m lazy and don’t do it.
So, I get the result of the decrypted text and re-build the file… except this is useless, because those bytes are not from inf.enc but the decrypted value of ExtClass.enc !
And unfortunately, I register no other call to doFinal() for inf.enc… Dead end.
Back on track
I consider my Java decryption code and search on Internet why it does not find a provider for this algorithm and where I can find one.
I bump into this page which says that PKCS7 padding is not supported by Java, only PKCS5 (naming issue see the stackoverflow page). So, I simply change PKCS7 padding to PKCS5 in my code.
| |
Solution
Bingo.
| |
How does it work?
When the end-user selects Settings, this starts SettingsActivity.
At some point, this calls method invoke on the SettingsActivity.
This calls a method named executePayload.
| |
This method:
- Retrieves external files via
loadServerFiles(). This downloadsfiles.zipfrom a Google Drive. Then, it unzips the file and decrypts the DEX. Note the secret key and IV are different from the one used to decryptinf.enc. - Checks the integrity of the external DEX. This consists in checking the SHA256 hash against the expected one.
- Calls
executePayload.1. This will load the DEX (withPathClassLoader, something I did not detect with DroidLysis at the time of the challenge), callinitLibfrom the dynamic class, check if the smartphone is infected withisInfectedand finally modify the wallpaper.