How I Defeated an Obfuscated and Anti-Tamper APK With Some Python and a Home-Made Smali Emulator.


During this Saturday afternoon I was chatting with a friend of mine ( Matteo ) and he asked for some help to fix a Python script he was working on.

He was trying to deobfuscate an APK in order to understand its obfuscation and anti tampering (more on this later) protections so I started working on it as well.

This was definitely way more challenging ( and fun! ) than my usual APK reversing session ( dex2jar -> jd-gui -> done ), moreover this required me to write a new tool which I find kinda cool and unique ( IMHO of course ), so I’m going to share the story in this post.

I’m going to intentionally skip a few details here and there because I do not want to cause any harm to the people who wrote that application, all the involved protection mechanisms are there to avoid piracy.

Weird Characters Are Weird

Like every other reverser who experienced APK decompilation I’m used to Proguard messing with class and method names ( or Dexguard messing with strings, and so forth ), this is not usually a big deal to me, but what I saw when I executed apktool was definitely surprising:

apktool

wtf

Most of the classes and methods names were weird binary strings, this almost freezed every single tool or editor I used to inspect those files, so the very first step was to fix ( to be honest, reimplement from scratch XD ) the python script that Matteo was trying to use to rename each obfuscated entry, the script itself was quite simple:

  • Loop all smali files with non printable names.
  • Replace the obfuscated class name with ClassXXX ( where XXX is an incremental integer ).
  • Rename the files.
  • Search for every references to those classes and patch them with the new names ( regular expressions FTW! ).
  • Repeat the process against .field directives ( class members, methods, etc ).

At the end of the process, I finally had a browsable folder and readable smali files :)

after basic deobfuscation

But I was definitely far from having done …

Anti Tampering

Before I continue, there’re two things I need to point out in order to make the reasons behind my approach clearer:

  1. Matteo told me that the application had some misterious anti tampering ( and most likely anti debugging ) protection, therefore rebuilding the smali to a new APK with some injected code was not possible, neither was debugging.
  2. Such protections not only prevented code injection/modification, but also uninstalled the application if such tampering was detected.

So no code injection ( nope, XPosed neither ), no debugging, absolutely no chance to use my standard approach for reversing it :(

sad

Encrypted Strings

As the lazy (or smart, you decide) reverser I am, instead of trying to understand the logic, at first I tried to search for meaningful strings that could give me some hints about what was going on in the app, but again I had a nasty surprise instead.

Every single string was encrypted with a custom algorithm, basically every reference to a string was replaced by something like:

1
String decrypted = Class623::method5( new int[]{ -12, 44, -35, ... }, 52 );

Just a long array of integers and another integer as the second argument (maybe some sort of key?)

What I usually do in these cases is:

  1. Decompile the APK to java ( with dex2jar + jd-gui or just jadx ).
  2. Take the java code of the decryption routine and paste it in a stand alone java console application.
  3. Run the decryption routine against the encrypted stuff and eventually get the clear text results.

Guess what? Every single tool failed to correctly transform the smali code of Class623::method5 into java … the output was just nonsense, not working, nada … and for the record I’m not that good in reading smali code (the routine itself was quite complicated, at least for my smali skills) … but I couldn’t just give up … no way!

challenge accepted

All hail the Smali Emulator

Of course I could take the smali code of Class623::method5, create a new Android app, decompile it with apktool, inject the smali code of that routine into the output, insert a smali call to that code into the app, rebuild it and launch it … but:

  1. Again, I’m lazy.
  2. This solution wouldn’t be elegant.
  3. A new idea was just born in my head and it was just too cool, I had to try it!

Long story short, I said to myself:

Fuck this, I'm gonna write a smali parser and emulator and feed it with this
routine, eventually it will output all the cleartexts I need!

So I started reading Dalvik opcodes specs ( tnx to Gabor Paller for this! ) and putting some code together, after a few hours I had this simple script ready for testing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from smali.emulator import Emulator

emu = Emulator()

# The smali file to emulate.
filename = 'decryptor.smali'
# Arguments for the method.
args = {
'p0': (-62, -99, -106, -125, -123, -105, -98, -37, -105, -97, -103, -41, -118, -97, -113, -103, -109, -104, -115, 111, 98, 103, 35, 52),
'p1': 19
}

ret = emu.run( filename, args )

print emu.stats

print "RESULT:\n"
print "'%s'" % ret

Aaaaaaand:

decrypted

BINGO!!!

I executed the script against every encrypted string and it worked like a charm, the emulator was able to correctly parse and execute the smali code of the decryption routine and decrypt every single entry I’ve extracted from the decompiled application … from that point on it was just a matter of replacing encrypted entries with their cleartexts and the reversing process became as easy as pie :)

victory

Conclusions

I’ve released the code on github as usual, it still lacks the support for a lot of Dalvik opcodes, I’ve just implemented the ones I needed in order to emulate that routine ( which you can find in the repo as well ), but it’s quite easy to improve it and probably I’ll complete it in the next few days :)

Become a Patron!