From 373bda9f0219ecd3f1069bf5fe0637c61dc87787 Mon Sep 17 00:00:00 2001 From: YuutaW <17158086+Trumeet@users.noreply.github.com> Date: Thu, 28 Feb 2019 20:32:26 -0800 Subject: feat(app): hide and obfuscate license checking codes as much as we can Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com> --- app/src/main/java/moe/yuuta/ext/ConnCallback.java | 9 ++ .../main/java/moe/yuuta/ext/IPCResultListener.java | 15 +++ .../main/java/moe/yuuta/ext/IResultListener.java | 102 +++++++++++++++++++++ app/src/main/java/moe/yuuta/ext/IService.java | 102 +++++++++++++++++++++ .../main/java/moe/yuuta/ext/LicServiceConn.java | 23 +++++ .../main/java/moe/yuuta/ext/ResultCallback.java | 6 ++ app/src/main/java/moe/yuuta/ext/package-info.java | 4 + 7 files changed, 261 insertions(+) create mode 100644 app/src/main/java/moe/yuuta/ext/ConnCallback.java create mode 100644 app/src/main/java/moe/yuuta/ext/IPCResultListener.java create mode 100644 app/src/main/java/moe/yuuta/ext/IResultListener.java create mode 100644 app/src/main/java/moe/yuuta/ext/IService.java create mode 100644 app/src/main/java/moe/yuuta/ext/LicServiceConn.java create mode 100644 app/src/main/java/moe/yuuta/ext/ResultCallback.java create mode 100644 app/src/main/java/moe/yuuta/ext/package-info.java (limited to 'app/src/main/java/moe/yuuta/ext') diff --git a/app/src/main/java/moe/yuuta/ext/ConnCallback.java b/app/src/main/java/moe/yuuta/ext/ConnCallback.java new file mode 100644 index 0000000..13af66d --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/ConnCallback.java @@ -0,0 +1,9 @@ +package moe.yuuta.ext; + +import android.content.ComponentName; +import android.os.IBinder; + +public interface ConnCallback { + void onServiceConnected(ComponentName name, IBinder service); + void onServiceDisconnected(ComponentName name); +} diff --git a/app/src/main/java/moe/yuuta/ext/IPCResultListener.java b/app/src/main/java/moe/yuuta/ext/IPCResultListener.java new file mode 100644 index 0000000..bf0045b --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/IPCResultListener.java @@ -0,0 +1,15 @@ +package moe.yuuta.ext; + +public class IPCResultListener extends IResultListener.Stub { + private final ResultCallback mCallback; + + public IPCResultListener(ResultCallback mCallback) { + this.mCallback = mCallback; + } + + @Override + public void exec(final int responseCode, final String signedData, + final String signature) { + mCallback.verifyLicense(responseCode, signedData, signature); + } +} diff --git a/app/src/main/java/moe/yuuta/ext/IResultListener.java b/app/src/main/java/moe/yuuta/ext/IResultListener.java new file mode 100644 index 0000000..706b34a --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/IResultListener.java @@ -0,0 +1,102 @@ +package moe.yuuta.ext; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +import androidx.annotation.NonNull; + +import moe.yuuta.gplicense.util.Base64; +import moe.yuuta.gplicense.util.Base64DecoderException; + +public interface IResultListener extends IInterface { + abstract class Stub extends Binder implements IResultListener { + private static final String DESCRIPTOR; + + static { + try { + // Base64 encoded - + // com.android.vending.licensing.ILicenseResultListener + DESCRIPTOR = new String(Base64.decode( + "Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2VSZXN1bHRMaXN0ZW5lcg==")); + } catch (Base64DecoderException e) { + throw new RuntimeException(e); + } + } + + protected Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + static IResultListener asInterface(IBinder obj) { + if ((obj == null)) { + return null; + } + IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (iin instanceof IResultListener) { + return (IResultListener) iin; + } + return new Stub.Proxy(obj); + } + + @Override + public IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags) throws RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + case TRANSACTION: { + data.enforceInterface(DESCRIPTOR); + int responseCode = data.readInt(); + String signedData = data.readString(); + String signature = data.readString(); + this.exec(responseCode, signedData, signature); + return true; + } + default: { + return super.onTransact(code, data, reply, flags); + } + } + } + + private static class Proxy implements IResultListener { + private IBinder mRemote; + + Proxy(IBinder remote) { + mRemote = remote; + } + + @Override + public IBinder asBinder() { + return mRemote; + } + + @Override + public void exec(int responseCode, String signedData, String signature) throws RemoteException { + Parcel args = Parcel.obtain(); + try { + args.writeInterfaceToken(DESCRIPTOR); + args.writeInt(responseCode); + args.writeString(signedData); + args.writeString(signature); + mRemote.transact(TRANSACTION, args, null, IBinder.FLAG_ONEWAY); + } finally { + args.recycle(); + } + } + } + + static final int TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; + } + + // verifyLicense + void exec(int responseCode, String signedData, String signature) throws RemoteException; +} \ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/ext/IService.java b/app/src/main/java/moe/yuuta/ext/IService.java new file mode 100644 index 0000000..ea0b136 --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/IService.java @@ -0,0 +1,102 @@ +package moe.yuuta.ext; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +import androidx.annotation.NonNull; + +import moe.yuuta.gplicense.util.Base64; +import moe.yuuta.gplicense.util.Base64DecoderException; + +public interface IService extends IInterface { + abstract class Stub extends Binder implements IService { + private static final String DESCRIPTOR; + + static { + try { + // Base64 encoded - + // com.android.vending.licensing.ILicensingService + DESCRIPTOR = new String(Base64.decode( + "Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")); + } catch (Base64DecoderException e) { + throw new RuntimeException(e); + } + } + + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + public static IService asInterface(IBinder obj) { + if ((obj == null)) { + return null; + } + IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (iin instanceof IService) { + return (IService) iin; + } + return new IService.Stub.Proxy(obj); + } + + @Override + public IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags) throws RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + case TRANSACTION_checkLicense: { + data.enforceInterface(DESCRIPTOR); + long nonce = data.readLong(); + String packageName = data.readString(); + IResultListener listener = IResultListener.Stub.asInterface(data.readStrongBinder()); + this.exec(nonce, packageName, listener); + return true; + } + default: { + return super.onTransact(code, data, reply, flags); + } + } + } + + private static class Proxy implements IService { + private IBinder mRemote; + + Proxy(IBinder remote) { + mRemote = remote; + } + + @Override + public IBinder asBinder() { + return mRemote; + } + + @Override + public void exec(long nonce, String packageName, IResultListener listener) throws RemoteException { + Parcel args = Parcel.obtain(); + try { + args.writeInterfaceToken(DESCRIPTOR); + args.writeLong(nonce); + args.writeString(packageName); + args.writeStrongBinder(listener != null ? listener.asBinder() : null); + mRemote.transact(TRANSACTION_checkLicense, args, null, IBinder.FLAG_ONEWAY); + } finally { + args.recycle(); + } + } + } + + static final int TRANSACTION_checkLicense = IBinder.FIRST_CALL_TRANSACTION; + } + + // checkLicense + void exec(long nonce, String packageName, IResultListener listener) throws RemoteException; +} \ No newline at end of file diff --git a/app/src/main/java/moe/yuuta/ext/LicServiceConn.java b/app/src/main/java/moe/yuuta/ext/LicServiceConn.java new file mode 100644 index 0000000..f0ad766 --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/LicServiceConn.java @@ -0,0 +1,23 @@ +package moe.yuuta.ext; + +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; + +public class LicServiceConn implements ServiceConnection { + private final ConnCallback mCallback; + + public LicServiceConn(ConnCallback mCallback) { + this.mCallback = mCallback; + } + + @Override + public synchronized void onServiceConnected(ComponentName name, IBinder service) { + mCallback.onServiceConnected(name, service); + } + + @Override + public synchronized void onServiceDisconnected(ComponentName name) { + mCallback.onServiceDisconnected(name); + } +} diff --git a/app/src/main/java/moe/yuuta/ext/ResultCallback.java b/app/src/main/java/moe/yuuta/ext/ResultCallback.java new file mode 100644 index 0000000..4feafba --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/ResultCallback.java @@ -0,0 +1,6 @@ +package moe.yuuta.ext; + +public interface ResultCallback { + void verifyLicense(final int responseCode, final String signedData, + final String signature); +} diff --git a/app/src/main/java/moe/yuuta/ext/package-info.java b/app/src/main/java/moe/yuuta/ext/package-info.java new file mode 100644 index 0000000..128e042 --- /dev/null +++ b/app/src/main/java/moe/yuuta/ext/package-info.java @@ -0,0 +1,4 @@ +/** + * Classes which cannot be processed by ProGuard are moved to here to keep LicenseChecker processed. + */ +package moe.yuuta.ext; \ No newline at end of file -- cgit v1.2.3