Lucky patcher, how can I protect from it? [duplicate]

Solution 1:

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;
}

Solution 2:

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;
    }
}