Reversing Bytecode That Your Avarage Decompiler Can’t Handle By Hand

Hello guys, long time no crocodile, or how did it go, huh? Meaning, haven’t written here for too long.. Enough excuses!

Recently I was facing a problem, regarding taking a screenshot in Android programmatically, without falling back on unsupported API’s meaning, using the MediaProjection API’s introduced in API level 21, however, the actual problem I had, following their official examples or those of third party ones is a subject for another blog post!

Today we are covering, yet again, reverse engineering of a proven working application, this time, not for abuse of virtual benefits, but to copy a working functionality from a third party app, not in line by line manner, but in a overall concept, to avoid any copyright related takedowns.

scales-36417_640

IANAL but not that these kind of small companies have any power to pursue such or take down every app that uses similar technology to compare the code, but you can never be too sure or secure, or have too much moral to secure nightsleep.

Fun fact, the app I broke down seems to actually have a class leeched from rival application.

I wouldn’t have noticed, if they hadn’t kept the exact same package name as the rival application is released under.. Smart..

Initial steps I took to figure what I was doing wrong with the MediaProjection, to only receive the black screen, was ofcourse to find one application that does screencapture from service or such, that’s available in Google Play currently, and there’s plenty, not to name any, not that I am going to release a screenshotting application for now..

hacker-1446193_640

When I first found one I obviously put it through my favorite set of Android reverse engineering tools, which of easiest and quickest is bytecode viewer, big shootout for them, the UX is crap, but its for me, the easiest way to drop an APK in and receive both bytecode and human readable version of the code inside, and not even talking about the search tools, which are hard to use, but useful!

To my disappointment after finally finding the reference to the API I knew the app was using, due to the Android’s forced dialogue of giving app permission of capturing the screen, the decompiler were unable to reverse the bytecode due to the complicated branching or whatever.

After that I looked at the bytecode, that spanned across maybe 200 lines and ran it through in my head, couldn’t initially figure the difference between it and my rough implementation that I had partially scrapped from the API example, but for one, there was 500 ms sleep in added in the code, I tried adding it between same API calls, but no luck.. We had to go deeper!

Before digging deeper and spending all my time just to find out I am looking at wrong piece of code, as the application had what, 20 ways of capturing a screenshot, to support some legacy phones that I wasn’t looking to support, I copied baldly the .smali files, containing the dalvik code, to my own project, after ‘baksmaling’ it using apktool, and added a quick call to the function, which worked flawlessy and resulted in good looking screenshot, I was ready to proceed with the reverse engineering efforts!

I tried another decompiler or two, with no luck, hard to tell what it is, that breaks the decompiler, and I am not too much into those anyway, I started writing the code by hand, following the Dalvik code on my other screen.

If you’re not a robot or a machine in any other way, it will be pretty hard to go through so many lines of bytecode and getting the grasp of what’s happening without spending countless of hours on it.

brain-1295128_640

I found its much easier to implement the logic in other language or even in pseudo code, for the ease of my brains, which has the most working paths of understanding Java, I did it in java, which is good, as it is the final language I am going the feature to implement in, even tough, implementing all the branches which are implemented in dalvik using labels, gotos and conditionals might get pretty tedious, after having it all written down, it will be easy to refactor it for real world use!

Lets look at an example!

const-string v1, "screenshot"

new-instance v2, Ljava/lang/StringBuilder;

invoke-direct {v2}, Ljava/lang/StringBuilder;->()V

invoke-virtual {v2, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v2

const-string v3, " "

invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v2

invoke-virtual {v2, p3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v2

const-string v3, " "

invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v2

invoke-virtual {v2, p4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

move-result-object v2

invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

move-result-object v2

invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

This isn’t too complicated, but if you have to stitch tens of this size patches of code in your mind, it gets pretty hard..

A quick rundown of above code in pseudo code for comparison

takeScreenShot(a, b, c, d)
 log("screenshot", b + " " + c + " " + d)

This is not(IIRC) not part of the applications code, but part of the code I used to find out which parameters the reverse engineered app passes to the function

As you can see, a small piece of java goodness turns into crazy amount of bytecode, and without even including the conditionals with all the labels, don’t even let me get into that part!

applause-297115_640
Round of applause for the findings

TL/DR
When reverse engineering bytecode your decompiler or other tool can’t handle, and its too overwhelming, just write it down in pseudo code or in your favorite language to give your brains a break!

Leave a Reply

Your email address will not be published. Required fields are marked *