How the Android License Verification Library is Lulling You into a False Sense of Security

Are you an Android developer? Have you ever wondered why your app keeps getting hacked, ending up on shady forums and websites?

Some of you might remember the old copy protection measure that Google used to have. You can still find it on your publisher page, with the following warning in red: “The copy protection feature will be deprecated soon….” Enter Android’s License Verification Library (LVL): a new tool to save the day!

Android’s License Verification Library (LVL): A false sense of security

How does the license verification library work? It manages a connection between your app and the Android Market (now Google Play), and performs a license check with the server to see if the user has a valid license for your app (i.e. it was purchased legitimately through the market). In other words, it’s a form of Digital Rights Management (DRM).

Unfortunately, the license verification library is also a joke to crack and bypass.

It literally takes a pirate no more than a few seconds to run a tool that will decompile your application, detect your licensing code, patch it to bypass all of the checks, repackage everything into a new APK and resign it. This tool is called AntiLVL. By the way, it can also bypass much of Proguard’s obfuscation, and even techniques using reflection.

For obvious reasons, I won’t link to it here, but you can find it if you do a bit of searching. This is also just one tool that’s freely available to download; who knows what other tools are hidden from public release.

What does Google recommend?

Unfortunately, you have to do a lot of digging to find out what you should do, and just how vulnerable you are. Google doesn’t offer much in the way of help and advice directly from their website, except for “well, you should probably not use it as-is and obfuscate the code somewhat.” They also give advice like “In most cases, you should add the license check to your application’s main Activity, in the onCreate() method,” which directly contradicts the advice given by Google engineers in the talk, “Evading Pirates and Stopping Vampires using License Verification Library, In-App Billing, and App Engine,” where they recommend that you don’t add the checks to non-obfuscated methods such as onCreate().

I highly recommend you view the presentation or watch the video. I would not necessarily use them directly as-is, but you can take the ideas and go with variants.

What are the weakest points?

Here are some of the checks that are removed very quickly and easily by tools such as AntiLVL:

Non-obfuscated code

A trivial check will easily take care of methods with names such as checkLicense().

Unmodified code

The default signatures of some methods are very easy to trap. For example, ServerManagedPolicy.allowAccess() has a call to System.currentTimeMillis() at the top of the method body. AntiLVL finds this code, and replaces it with a force return true.

Another bit of easily-hacked code is the enum Policy.LicenseResponse. This enum contains three constants, “LICENSED”, “NOT_LICENSED”, and “RETRY”. Even with Proguard obfuscation enabled, these constants get embedded into your code as strings, containing the same value as the enum! AntiLVL replaces the “NOT_LICENSED” string with “LICENSED”, which causes other checks to pass.

Package checks

AntiLVL can check if you’re trying to validate that your classes or signature have been modified and intercept those validation calls, even if you’re using reflection.

And much more…

There is a lot more that AntiLVL can detect and modify; you can download it and look at the XML files inside the jar to see what else it can detect. There’s also a sample project with all of the usual tricks, which are easily detected and cracked by AntiLVL.

What can I do?

The minimum you can do is download AntiLVL, run it in a virtual machine with no connection to the Internet if you don’t trust the code, and test it against your APK until it can no longer crack it automatically.

Here are some ideas:

  • Wrap all logging calls in a static boolean, set to false when you build the release version of your app.
  • Encode all hard-coded strings using a two-way encoder/decoder function, such as a Caesarian Shift. Change all string constants and hard-encode the encoded value into your Java source file. Decode before using.
  • If you only need to test equality, use a hash such as SHA1, and compare the hashed values.
    • Don’t do: public static final String SOME_STRING = SHA1.encode(“Unhashed Value”);
    • Do: public static final String SOME_STRING = “5dad4014ec894587f83626ee31a8dd418d1371f1”;
    • It’s better if you use a combination of techniques, since the pirates can easily search for the known hashes to figure out which bit of code is which.
  • Remove ILicensingService from your ProGuard config with this one change:
     
    Change:

    boolean bindResult = mContext.bindService(
    new Intent(ILicensingService.class.getName())

    To:

    boolean bindResult = mContext.bindService(
    new Intent(“com.android.vending.licensing.ILicensingService”)

    That string can also be encoded in the source and decoded using the techniques described above, to make it a bit less obvious.

  • Move your functions around, inline some stuff, change switch statements to if statements, move statements around, and reverse the roles of some methods.
  • Increase your Proguard obfuscation:
     
    -repackageclasses
    -allowaccessmodification

Of course, none of this will help if the pirate finds where the license check code is being called in your app. He can cut out this weakest link, and not worry about the rest. All of these measures will only slow down the pirates, but they won’t stop them.

Is it worth it?

You have to acknowledge that your app will get pirated. Even the biggest companies cannot prevent their stuff from getting pirated. Here are a couple practical ways to at least mitigate the damage:

  • Place some logic on the server. Whether it be leader boards or other features, tying some logic into the server cuts pirate users out of some of the loop.
  • Add additional features in the form of server downloads. Without a valid key, the user can’t download these additional features.

Why is it that some people don’t think twice about spending $40 on a movie night, but are too cheap to pay $2 for an app? Do they hate developers that much? While these people should be ashamed of themselves, perhaps other people live in an area where paid downloads are not an option, or they might not actually have the means to buy a lot of apps.

These users can be used as a source of good will, to help spread awareness of your app. Obviously, as a developer you need to eat, but not everyone’s going to go to some shady website to download code they can’t necessarily trust. There is a lot to be said for the convenience of regular updates and downloads from a trusted site.

What Google should have really done

If all the logic is in the client, then cracking an app is not a question of if, but when. The question is, how difficult can we make it for the pirates?

I think the current implementation of “copy protection” on Android is a complete joke and lulling many developers into a false sense of security. Your app is cracked in seconds, uploaded onto forums and download sites in minutes, and may even be re-uploaded to the market under a different name. Even worse, the verification process penalizes legitimate users when the market screws up the license check, and this happens more often than you think.

One thing Google could have done to make things a lot harder for the pirates is use a bytecode tool to generate the license library on the fly, using random permutations and injecting it everywhere into the bytecode, instead of asking the developer to use a very easily hacked method of adding some classes to their project. These checks could be generated in a slightly different form for each new release, making it much harder to replay a crack against your next release.

With an open platform, we have to accept the fact that a crack will happen. You’d need to have an AI built into the OS smart enough to determine that a modified cracked copy side-loaded onto the device is derived from a market release, and even then, that wouldn’t help you on a rooted device.

What are your thoughts on the Android License Verification Library and the current direction of the Android Market? If you haven’t yet seen it, I recommend looking at “Evading Pirates and Stopping Vampires using License Verification Library, In-App Billing, and App Engine!”

Tags: , , , , , ,

21 Responses to “How the Android License Verification Library is Lulling You into a False Sense of Security”

  1. ASchilling August 13, 2012 at 12:16 pm #

    Great article! Frustrating for me as a developer, but very informative!
    Thanks!

    I would really like to hear your opinion on App-Ecryption in Jelly Bean!
    Is it as useless as the previous copy protection measures?

    It’s unbelievable, Google treats criminals like kings and developers like cattle!

    • Kevin August 13, 2012 at 12:42 pm #

      I’ve read that the implementation is flawed and prevents paid app widgets and live wallpapers from working properly, which is really not good!

      I’m also not sure how effective it is, since couldn’t any would-be pirate just run an earlier version of Android, or a rooted device that doesn’t do the encryption?

      Instead of breaking things for customers (Jellybean also has a nasty bug that crashes applications that use styled text, under certain screen sizes / orientations), Google should be focused on making the purchase process smoother than it already is, focus on reducing errors, and work on getting paid apps to more countries. I think that most people are honest and want to support the developers, and they won’t pirate so long as it’s easier to buy than it is to pirate. If this weren’t true, then none of the music streaming services would be able to survive.

      I found this posting which was interesting: http://blog.gsmarena.com/google-disables-jelly-bean-app-encryption-after-issues-with-several-paid-apps/

      • Kevin August 13, 2012 at 1:04 pm #

        I also wanted to share this; quite interesting thoughts by another developer: http://mattgemmell.com/2012/07/23/closed-for-business/

        • ASchilling August 13, 2012 at 1:43 pm #

          Thanks for the quick feedback! And the links!
          I’d read these articles before … they’re also very good!

          I’m in the lucky position that most of the users of my App (AndroClass) are honest people which value the first class support I provide. And the support is it what they are really paying for. And I make sure that no one from the dark side gets any answers from me.

          By the way, your App looks very good! Clean, functional design. I like that!
          I think I’ll try it out this evening (evening in Germany 🙂 …

          Thanks again!

          • Kevin August 13, 2012 at 2:24 pm #

            Thanks for the compliments; I just took a look at AndroClass in the market, and it looks very nice and professional! I’ll get in touch with you via email for some more questions. 🙂

  2. andi October 20, 2012 at 1:35 pm #

    Can you help send to me or post real code modified LVL

    • Kevin October 20, 2012 at 3:24 pm #

      Hi Andi,

      For better protection against one-click tools, the best way is for each developer to make their own modifications to the library. There’s no way to really stop cracking, but there are ways to make it more expensive in terms of time and annoyance. I recommend following the tips in this blog post and the links as well, as those are the same resources I have used.

      I’ve also heard good things about DexGuard (http://www.saikoa.com/dexguard), though I’ve not tried it myself! By obfuscating strings, it makes it more time consuming to crack. Starting off with Proguard obfuscation and a flat package will help things out.

      Best of luck! 🙂

      • Andi October 20, 2012 at 11:08 pm #

        Thanks for reply, i will try it.

  3. Chuong November 14, 2012 at 10:38 am #

    Good article, Kevin.

    I’m a late Android starter but the latest LVL offering is horseshit. Even the anti-tampering techniques proposed by a Google engineer in the video link above are outdated and can be easily circumvented (like Lucky Patcher). DexGuard might be good; but until I see demonstrated proven examples that it actually work, I won’t be forking out a few hundred euros to buy it.

    Bytecode was flawed since its conception (good concept; but bad execution). Sun, Oracle and now Google haven’t done a damn thing to improve the Java language with regard to bytecode. So sad!…

    • Kevin November 14, 2012 at 7:33 pm #

      What’s also crazy is how readable smali code is after running your program through ApkTool! Unfortunately the only way to combat this is by making it more attractive to get your product the legitimate way and by making it take longer to crack by using some of these techniques, most importantly the social ones such as delaying the check or altering the impact.

      • Chuong November 16, 2012 at 1:39 am #

        @Kevin: I couldn’t agree more!

        I tried ApkTool and can see quite a lot – not to mention going the other way with JD GUI. I might have to ditch Google licensing and opt for alternatives, or keep Google LVL but use DexGuard (or something else) over it. Either way, as it stand, I cannot use LVL and be confident with it.

        • Kevin November 16, 2012 at 1:04 pm #

          Hi Chuong,

          It also depends on your use case. If you expect to sell low volume at a high price, I do think that LVL will not work out for you at all. If you’re going for high volume at a low price and want to reduce friction, I am now starting to think it might be better to just get rid of LVL or at least neuter it greatly, as it does nothing to stop the pirates but it does a lot to piss off your legitimate users.

          • Chuong November 16, 2012 at 1:10 pm #

            Thanks for your comment, Kevin.

            Yeah, I’ll need to seriously rethink my business approach and the model I’m going to adopt to earn a living – at least with Google and Android anyway…

  4. Tammy February 21, 2013 at 2:48 am #

    I printed out over 40 pages about “how simple it is to use LVL”. What a confusion and complex mess. How is the average developer going to figure this thing out? How many 100s of hours is this going to take? Are you kidding me? Why can’t I just drop in *ONE* library, make *ONE* call to *ONE* method… and it’s done?

    Besides, the app can still be easily hacked.

    • Kevin February 21, 2013 at 2:10 pm #

      I wouldn’t put it into the 100s of hours, but it’s definitely not just a drop-in either if you don’t want to be one-click hacked.

  5. NA Multimedia June 7, 2013 at 10:23 am #

    We developed ‘Na LVL’ (https://play.google.com/store/apps/details?id=na.lvl.downloader). It is 100% compatible with official Google LVL and protected against one-click piracy.

  6. Bill September 24, 2013 at 8:17 pm #

    If devices can be rooted is there anything google can do to encrypt packages without having programmers do it on their own? It seems like this would be the most reasonable answer in solving the lvl problem.

    • Kevin September 28, 2013 at 10:14 pm #

      Since devices can be rooted even Google Play can be hacked and cracked. 😉 There isn’t much of a way around this unless you go the server-side logic route with a dumb client, like some games do. Aside from games, though, you’ll find most pirates are people who wouldn’t have paid, anyway, so don’t fret their loss too much. Just use some simple techniques to discourage casual copying and ensure that the legit way is better than the pirate way and leads to a better experience for the customer.

  7. David November 7, 2013 at 12:06 am #

    You guys complain because it can be cracked easily? What about just being full of bugs?

    Did someone actually try in app billing v3? It’s full of bugs, NullPointer exceptions (really, Google?) when you run your code in a device without Google services… just horrible. A year or so later and you still have to manually tell the library to dispose old operations that may be still around (it’s a 1 line call to flagEndAsync, but it’s not smart enough to do it by itself), keeping track of which ServiceConnections are open or not inside their own abstracted classes… and I could go on and on… all the abstractions leaking everywhere, at every single place and side!

    You need not only to implement their API, but also check for mistakes in it as you progress. No wonder they adopt open source, but it’s for all the wrong reasons: they just can’t stand behind their code. It’s broken. You make a step, and stop to fix everything by yourself, losing hours as you go by in order to give 30% of the money to them.

    Sorry for the rant, but I’m tired of diagnosing and fixing bugs in the Android/Google API.

    • Kevin November 7, 2013 at 2:53 pm #

      Yes, these sort of things can be very frustrating. 🙁 I hope we get more competition in the mobile space, especially at the lower end so it doesn’t continue to be solely dominated by Android. Google will only improve with competitive pressure to do so.

      • Bill November 7, 2013 at 3:54 pm #

        I’d like to think Apple is enough competition for Google to keep improving in this space. The lvl is definitely a joke. They either don’t care, realize there’s nothing they can do about it, or are leaving it up to developers to custom their lvl pretty extensively. I’m not sure.

Leave a Reply

*