Skip to content

The smallest Android license check

We all know the License Verification Library a.k.a. Google LVL. It is a bunch of code witch does the IPC call to the Market, verifies the signature of the answer, interprets the result according to policies, stores the result encrypted on storage, etc.

LVL has 20+ classes/interfaces and 2000 lines of code. It is also quite cracked, with tools available that automatically patch an APK that uses the LVL (even obfuscated), producing an un-protected APK that skips the license check, with no effort at all.

Google advises to “roll your own” license verification using the LVL source only as a starting point, in order to circumvent the generic cracking tools. You may start with LVL and gradually remove bits you don’t need, or you may start from “zero”, the bare minimum IPC call/response to the Market, and build up.

Here is the simplest IPC call to the market, for illustration only. It is not fit as a real license check, it’s just a starting point on which you can build. The advantage is that it’s quite.. extremely small — 50 lines of code. PS: don’t forget to add <uses-permission android:name=”com.android.vending.CHECK_LICENSE” /> to your manifest.

import android.content.*;
import android.os.*;

class LicenseListener extends android.os.Binder {
    static final String LISTENER = "com.android.vending.licensing.ILicenseResultListener";

    public boolean onTransact(int op, Parcel in, Parcel reply, int flags) {
        if (op == 1) {
            in.enforceInterface(LISTENER);
            int code         = in.readInt();
            String data      = in.readString();
            String signature = in.readString();
            if (code == 0 || code == 2) {
                // LICENSED or LICENSED_OLD_KEY
            } else if (code == 1) {
                // NOT_LICENSED
            } else {
                // ERROR
            }
        }
        return true;
    }
}

class License {
    static final String SERVICE = "com.android.vending.licensing.ILicensingService";

    static void check(Context context) {
        context.bindService(
            new Intent(SERVICE),
            new ServiceConnection() {
                public void onServiceConnected(ComponentName name, IBinder binder) {
                    Parcel d = Parcel.obtain();
                    try {
                        d.writeInterfaceToken(LICENSING_SERVICE);
                        d.writeLong(0);
                        d.writeString(context.getPackageName());
                        d.writeStrongBinder(new LicenseListener());
                        binder.transact(1, d, null, IBinder.FLAG_ONEWAY);
                    } catch (RemoteException e) {
                    }
                    d.recycle();
                }

                public void onServiceDisconnected(ComponentName name) {}
            },
            Context.BIND_AUTO_CREATE);
    }
}

Post a Comment

Your email is never published nor shared. Required fields are marked *