30

I know this topic has been opened multiple times and I learnt a lot but I stumbled across a problem I really need advice on.

I'm using LVL with Obfuscation. I changed the default LVL ALOT so that anti-LVL does not break it. However, Lucky Patcher with one click breaks it! I tried to see the new broken APK. Yes it simply called my "allow method".

My question is if someone can recommend a way to prevent Lucky Patcher from breaking it? I know I can't make it bullet-proof, but I want it at least to be not so easy for one-click software.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
Snake
  • 14,228
  • 27
  • 117
  • 250

5 Answers5

51

Code to check your certificate:

public void checkSignature(final Context context) {
    try {
        Signature[] signatures = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;

        if (signatures[0].toCharsString() != <YOUR CERTIFICATE STRING GOES HERE>) {
            // Kill the process without warning. If someone changed the certificate
            // is better not to give a hint about why the app stopped working
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    } 
    catch (NameNotFoundException ex) {
        // Must never fail, so if it does, means someone played with the apk, so kill the process
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

Next how to find which one is your certificate. You must produce an APK, in release mode, as the debug certificate is different from the release one. Output your certificate into your Logcat:

signatures[0].toCharsString();

Remember that when you are back to debug mode, the certificate is different again. To avoid debug issues use next line to skip the verification:

if ((context.getApplicationContext().getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0)
    return;

Next the lucky patcher checker. I decompiled all versions of Lucky Patcher, and I've found that its creator used 2 package names between all realeases. So you only need to keep track of new versions and keep adding future package names.

private boolean checkLuckyPatcher() {
    if (packageExists("com.dimonvideo.luckypatcher"))
        return true;

    if (packageExists("com.chelpus.lackypatch"))
        return true;

    if (packageExists("com.android.vending.billing.InAppBillingService.LACK"))
        return true;

    return false;
}

private boolean packageExists(final String packageName) {
    try {
         ApplicationInfo info = this.getPackageManager().getApplicationInfo(packageName, 0);

        if (info == null) {
            // No need really to test for null, if the package does not
            // exist it will really rise an exception. but in case Google
            // changes the API in the future lets be safe and test it
            return false;
        }

        return true;
    }
    catch (Exception ex) {
        // If we get here only means the Package does not exist
    }

    return false;
}
PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • hmm. Thats interesting. And very thank full for it. I will give it a try and post the results here. Mean while. I will mark this answer as accepted :). It is great "chatting" with you on this.. btw, If you can edit your answer and post the code used to check lucky patcher package, then that will be great – Snake Feb 07 '13 at 04:33
  • yes luck patcher changes the certificate if someone repacks the apk for distribution, so signature check will work. And on same device packageExists("packagename") function works thanks for luckypatcher package name idea. – Diljeet Feb 16 '13 at 18:17
  • 6
    tools such as luckypatcher and antilvl already defeat signature checking with and without reflection, so checking against signature will not work. Even with all the suggestions in the video, as well as numerous custom checks, my apps are usually cracked within a day or two of release. – Yahma Feb 21 '13 at 18:30
  • Correct me if i am wrong, but whats to prevent me from installing app - patching using LuckyPatcher - Uninstalling LuckyPatcher - Running patched app. Hmmm?... – TheCodeArtist Jul 22 '13 at 03:25
  • It is possible, but a user will hardly know that he has to un-install lucky patcher for an app to work correctly. On the other hand you can also set some code so if your app detects at least one time lucky patcher then persist a flag somewhere, so after even if un-installing lucky patcher the app will not work. There are many combinations you can work about if lucky patcher is detected, but the average user will hardly guess he has to remove lucky patcher, and even if he does, you can still use this "watching" approach and wait the user to forget un-installing it and then set your flag. – PerracoLabs Aug 04 '13 at 12:48
  • lucky patcher edits .dex files in /data/dalvik-cache, not editing the apk. So signature will not change – MrOnlineCoder Jan 25 '16 at 18:48
  • 2
    @MrOnlineCoder is there any other way to protect our apps in-app billing from lucky patcher? – MeLean Oct 10 '16 at 20:13
  • `so you will get a debug hell` cracked me up xD – mehulmpt Feb 08 '17 at 20:54
  • Your method did not work for me (maybe I have messed it up), so I ended up using this library: https://github.com/javiersantos/PiracyChecker – EtherPaul Dec 15 '19 at 11:18
  • 3
    Lucky Patcher has randomly generated package names, this doesn't seem useful https://www.reddit.com/r/luckypatcher/comments/aba3al/version_80x_looks_all_sorts_of_shady/ – mathematics-and-caffeine Jun 06 '22 at 19:05
6

As of current version (6.4.6), Lucky Patcher generates very short token. For example, real purchase token:

felihnbdiljiajicjhdpcgbb.AO-J1OyQgD6gEBTUHhduDpATg3hLkTYSWyVZUvFwe4KzT3r-O7o5kdt_PbG7sSUuoC1l6dtqsYZW0ZuoEkVUOq5TMi8LO1MvDwdx5Kr7vIHCVBDcjCl3CKP4UigtKmXotCUd6znJ0KfW

And that is Lucky Token:

kvfmqjhewuojbsfiwqngqqmc

Pretty straight forward solution is to check string length of token

@Override public void onIabPurchaseFinished(IabResult result, Purchase info) {
    if (info.getToken().length < 25) {
        Log.wtf("PIRATE", "PIRATE DETECTED");
        return;
    }
}
Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86
  • 1
    is google not taking any countermeasures? – user1616685 May 08 '17 at 17:12
  • I tested this code of yours, and initially it works like a marvel, however, after it goes up the app to play store and downloads it through the play store itself and uses the luck patcher to crack internal purchases the same crackeia as if it were an original purchase and this his method becomes useless. @Dima Rostopira – Rogers Marques Jun 08 '18 at 15:52
  • what if they start producing token length >25 or equal to the desired? – Rohit gupta Jun 13 '23 at 10:14
  • @Rohitgupta then you have to check the token on the server side. – Dmytro Rostopira Jun 13 '23 at 10:54
0

Implement a function that gets called under certain actions, and which checks whether the LuckyPatcher package is installed in the device.

If found, then exit your app. Don’t allow to use it regardless if is paid or not, better bad reviews than thousands of illegal copies. Alternatively you could show a message stating that LuckyPatcher has been found and the app can't run.

If your app gets patched by LuckyPatcher, meaning that it has hacked your LVL implementation, then at least your app will not execute due to the LuckyPatcher package detection.

PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • 1
    Thank you for your detailed answer. But I think you missed my point below. Let's say you have lucky patcher installed and you download my app. You will use lucky patcher to crack the app (without having to actually running the app and thus the preventive code). Now you will take this cracked app and put it on some blackmarket. People downloading the cracked app (that don't have lucky patchers) will just run it. Most people are just downloaders and they don't have cracking tools.See my point? – Snake Feb 06 '13 at 15:35
  • So yes I blocked the cracker from running my app, but I didn't block the 10000 people downloading the cracked version from not running it – Snake Feb 06 '13 at 15:36
  • But, lucky patcher cannot crack an apk at all, cracks the unpacked dex file, so noone really can use at all the cracked pached file, unless is repackaged, which requires your certificate. Or maybe is possible I miss understood how lucky pacher works? – PerracoLabs Feb 06 '13 at 16:21
  • You are correct. It cracks an unpacked dex file, then it repackages it and sign it with a lucky patcher certificate into an apk file. This cracked apk file is not signed by me but is available on black markets and online. Makes sense? – Snake Feb 06 '13 at 22:30
  • 1
    Then easy, just check that your apk has been signed with your certificate, this is quite easy to do, I will post it as an answer so it fits all the code. – PerracoLabs Feb 06 '13 at 22:41
  • signature checks have been defeated already. They will just intercept your signature check respond with what your code expects to see. – Yahma Feb 21 '13 at 18:43
  • Signature check has been defeated only at Java code level. Even though I've supplied a java example, the best is to replicate this function using reflection in native code (NDK). This is actually my way to do it, and so far I haven't found any tool able to crack my APKs, not even AntiLVL. I can't post the code of my NDK protection algorithms as it would open the door to hackers trying to find patterns, but there are several examples on the net of this approach. I have to say that is a bit tedious and not easy to implement the first time. But the NDK approach gives you a well protected APK. – PerracoLabs Feb 23 '13 at 14:57
  • 1
    The only working solution is to use server-side validation within your app i.e. check your public key from the server. Also, the server must use SSL connection to prevent traffic sniffing. All methods suggested in this thread have already been circumvented one way or another. – ChuongPham Aug 14 '13 at 18:17
-1

A way, is to check if lucky patcher is installed and if so, then show a message to the user, and kill your process afterwards. If a user has it, means he is trying to crack your software or other developer's one. So better not to allow to use your app in a phone that has it installed. Fight piracy.

PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • Thats a good suggestion but the problem that a user can install my app and does not have to run it. They would just run lucky patcher and it will generate a cracked version of the app – Snake Feb 06 '13 at 03:32
  • I posted my reply as an answer as it was to long to write it here – PerracoLabs Feb 06 '13 at 14:29
  • this won't work as latest lucky patcher uses dynamic app id and app name – EdgeDev Oct 13 '20 at 20:18
-1

Whenever Lucky Patcher creates a modded APK file, it always ends up with a different package name, as you can't run two apps under the same package name.

Here's a simple solution that checks if your code is running under the wrong package name:

PackageManager pm = getPackageManager();

try {
    PackageInfo packageInfo = pm.getPackageInfo("YOUR_PACKAGE_NAME",PackageManager.GET_ACTIVITIES);
} catch (PackageManager.NameNotFoundException e){
    finish(); 
    //If you get here, your code is running under a different package name... Kill the process!
}

I just call finish(); on my app and I can't break it, but it might be best to use android.os.Process.killProcess(android.os.Process.myPid()); as @PerracoLabs suggested.

Nathan Bird
  • 910
  • 1
  • 9
  • 23
  • 1
    Are you sure?.. – mehulmpt Feb 08 '17 at 20:59
  • 1
    @MehulMohan Absolutely! In fact, my app uses this method. A couple of friends and I tried to break it and we failed. We're not computer hackers but it's a great method to prevent users from hacking a simple game. – Nathan Bird Feb 08 '17 at 22:56
  • 2
    This will actually check if given package name is installed on the device, so if the original app with original package name is still installed this will not work. – Paweł Nadolski Feb 07 '18 at 17:06