Tuesday, October 2, 2012

Can android app be protected from piracy?

If you are android developer , you know how much skill, effort, creativity and innovation is required to make competitive android application.

After investing your knowledge, creativity and time, you probably don't want your app to be copied, repackaged, and sold by unauthorized parties.

So, what can we do to protect our work?

There are many methods,like those suggested in this presentation, that could be used for this purpose.
Unfortunately, there are tools available that allow people to crack many of this protection methods, even people with very little or no knowledge at all of android development and java programming in general.

In my apps , I use simple technique that can be described in one sentence.
Check if app was tampered with, and if so, make it stop working properly.

I prefer this method since it doesn't require connection to google market server or any other server on the  net.

Checking the signature is trivial, but it will not be of much use if the attacker can easy find the part of your code that does the checking and remove it.
So the hardest part of protecting application this way is to hide the code that does the checking best we can.

Using obfuscator is basic stuff, so we use it as a first line of defence. It will make decompiled code very hard to read and to follow program flow. The problem is that attacker doesn't actually need to understand how your app works in general, he just needs to find your protection and disable it.
Since all methods for checking app authenticity (signature checking that we use is one of these methods) are well known, attacker will probably focus on finding them in your code. Obfuscated code will rename your variables and methods to some meaningless names, throw in bunch of junk stuff etc., but calls to android framework methods will remain unchanged and easy to find in decompiled code.

Here is an example of the code for getting app signature:

Signature[] myAppSignatures = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), PackageManager.GET_SIGNATURES).signatures;

More advanced obfuscators such as Dexguard can help hiding this code by using reflection to call getPackageInfo method instead of directly calling this. You also want to encrypt method name strings like "getPackageInfo" so that attacker can not simply search decompiled code for it.
Dexguard even comes with configuration template that already contains settings for doing this, you only need to uncomment few lines to use it.

After using reflection in combination with string encryption it is very hard for attacker to find this method call in decompiled code.

However, this level of protection is still not good enough. Why?
Because  tools like anti-lvl intercept getPackageInfo() method even if you use reflection with encrypted strings.

It  does it by replacing all method.invoke(...) calls with it's own code (hook) that checks method name after the method object is already initiated. If method name equals "getPackageInfo" hook returns PackageInfo with fake signatures (your original signatures instead of repackaged app signature). Otherwise, if the method is not relevant for checking app authenticity, hook will just call method.invoke method as you originally intended.

Can we do something about this?

We can encrypt whole class instead of only encrypting string used for method invocation via reflection. With encryption applied,  Method.invoke(...) calls become invisible for cracking tool so it can not replace it with hook.
So, encrypting the class containing signature checking will stop anti-lvl tool (current version at least) to crack the app.

You should be aware of the fact that  encrypted classes can be decrypted, actually intercepted after decryption, but as far as I know anti-lvl doesn't yet do that.

This means that with some additional manual work of decrypting classes before applying anti-lvl, signature checking method still can be cracked.

No comments: