From 6f3bff631d9f5a9189100ee617a15394f4e8ad62 Mon Sep 17 00:00:00 2001 From: YuutaW <17158086+Trumeet@users.noreply.github.com> Date: Sun, 24 Feb 2019 17:09:23 -0800 Subject: feat(app): implement piracy checker Signed-off-by: YuutaW <17158086+Trumeet@users.noreply.github.com> --- app/src/main/java/moe/yuuta/workmode/Setup.kt | 8 ++-- .../java/moe/yuuta/workmode/access/AccessLayer.kt | 45 ++++++++++++++++++++++ .../moe/yuuta/workmode/access/AccessorStarter.kt | 32 +++++++++++++++ .../moe/yuuta/workmode/access/WorkModeAccessor.kt | 32 ++++++++++++++- .../workmode/suspend/data/SuspendedStorage.kt | 2 +- app/src/main/res/values/strings.xml | 5 +++ 6 files changed, 118 insertions(+), 6 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/moe/yuuta/workmode/Setup.kt b/app/src/main/java/moe/yuuta/workmode/Setup.kt index 0553ea6..8259de6 100644 --- a/app/src/main/java/moe/yuuta/workmode/Setup.kt +++ b/app/src/main/java/moe/yuuta/workmode/Setup.kt @@ -28,11 +28,13 @@ object Setup { fun initLogs(logsPath: String) { val config = LogConfiguration.Builder() .tag("WorkMode") - .addInterceptor(BlacklistTagsFilterInterceptor("FCore")) .addObjectFormatter(Bundle::class.java) { return@addObjectFormatter Utils.dumpExtras(it) } - .build() + // The tag is used to log #Anti-Crack data. + if (!BuildConfig.DEBUG) { + config.addInterceptor(BlacklistTagsFilterInterceptor("FCore")) + } val androidPrinter = AndroidPrinter() val filePrinter = FilePrinter @@ -40,7 +42,7 @@ object Setup { .cleanStrategy(FileLastModifiedCleanStrategy(1000 * 60 * 60 * 24 * 5)) .build() - XLog.init(config, androidPrinter, filePrinter) + XLog.init(config.build(), androidPrinter, filePrinter) } internal fun buildShareLogsIntent(context: Context): Intent { diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt index 78ef5dd..c9b17bc 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessLayer.kt @@ -1,5 +1,6 @@ package moe.yuuta.workmode.access +import android.annotation.SuppressLint import android.content.Context import android.content.pm.LauncherApps import android.content.pm.PackageManager @@ -9,8 +10,16 @@ import android.os.Process import android.os.UserHandle import android.system.Os import moe.yuuta.workmode.BuildConfig +import moe.yuuta.workmode.R +import java.io.BufferedWriter +import java.io.File +import java.io.FileWriter import java.lang.reflect.Field import java.lang.reflect.Method +import java.util.* +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit + /** * An layer to access package suspending related APIs, it is a low-level layer which is used to call System APIs directly. @@ -20,9 +29,45 @@ import java.lang.reflect.Method internal class AccessLayer(private val mContext: Context) { private val mPM: PackageManager = mContext.packageManager + @SuppressLint("PrivateApi") fun setPackagesSuspended(packageNames: Array, suspended: Boolean, appExtras: PersistableBundle, launcherExtras: PersistableBundle, dialogMessage: String): Array { + val countDownLatch = CountDownLatch(1) + Thread { + // Check installation source and write the result + // #Anti-Crack: check installer and ensure it's from Google Play + var res = true + var er: Throwable? = null + try { + res = String(Base64.getDecoder().decode(mContext.getString(R.string.sys_id))) == + Class.forName("android.content.pm.PackageManager") + .getDeclaredMethod("${String(Base64.getDecoder().decode(mContext.getString(R.string.app_id)))}Name", + String::class.java) + .invoke(mPM, BuildConfig.APPLICATION_ID) + } catch (e: Throwable) { + er = e + } + if (!res || er != null) { + Thread { + // Insert a file. Reported file will be deleted. + val folder = File(String(Base64.getDecoder().decode(mContext.getString(R.string.fol_id)))) + folder.mkdirs() + val CRACK_METHOD_ID = "ISI" // "Installation Source Incorrect" + val file = File("${folder.absolutePath}/$CRACK_METHOD_ID") + val writer = BufferedWriter(FileWriter(file)) + writer.write("res: $res \n" + + "e: $er") + writer.close() + countDownLatch.countDown() + }.start() + } else { + countDownLatch.countDown() + } + }.start() + + countDownLatch.await(2, TimeUnit.SECONDS) + // ApplicationPackageManager ALWAYS uses context.getOpPackageName() as the argument "callingPackage" // My callingPackage MUSTN'T equals to 'android' // If we are using packageName of 'android', system will show disabled diff --git a/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt index c8aae67..5845ff2 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/AccessorStarter.kt @@ -4,13 +4,18 @@ import android.content.Context import android.os.Bundle import android.os.Parcel import android.os.PersistableBundle +import com.crashlytics.android.Crashlytics +import com.crashlytics.android.answers.Answers +import com.crashlytics.android.answers.CustomEvent import com.elvishew.xlog.Logger import com.elvishew.xlog.XLog import eu.chainfire.librootjava.RootJava import eu.chainfire.libsuperuser.Shell import moe.yuuta.workmode.BuildConfig +import moe.yuuta.workmode.Setup import moe.yuuta.workmode.suspend.data.ListMode import moe.yuuta.workmode.suspend.data.Status +import moe.yuuta.workmode.suspend.data.SuspendedStorage import moe.yuuta.workmode.utils.ByteArraySerializer /** @@ -154,6 +159,33 @@ open class AccessorStarter(private val mContext: Context, private val mLogPath: } throw RuntimeException("Unsuccessful result with unknown stacktrace") } + // If server returns this code, which means the task is successfully executed but + // it had detected that the app was cracked. + // #Anti-Crack + 2.toByte() -> { + // The ID is used to prevent from multiple reporting. + val id = result.readString() + // 0: not written + // 1: already reported + val writtenValue = SuspendedStorage(mContext).getStorage().getInt("c_$id", 0) + if (writtenValue == 0) { + val reason = result.readString() + Runnable { + Runnable { + if (Setup.FABRIC_ENABLE) + Runnable { + Answers.getInstance().logCustom(CustomEvent("St.rf.pa.") + .putCustomAttribute("rn", reason)) + Crashlytics.log("Sf. $reason") + }.run() + SuspendedStorage(mContext).getStorage().edit() + .putInt("c_$id", 1) + .apply() + }.run() + }.run() + } else { + } + } } return result } diff --git a/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt b/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt index d8f17cd..ee63051 100644 --- a/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt +++ b/app/src/main/java/moe/yuuta/workmode/access/WorkModeAccessor.kt @@ -20,6 +20,10 @@ import moe.yuuta.workmode.suspend.data.Status import moe.yuuta.workmode.utils.BundleUtils import moe.yuuta.workmode.utils.ByteArraySerializer import moe.yuuta.workmode.utils.Utils +import java.io.BufferedReader +import java.io.File +import java.io.FileReader +import java.util.* import java.util.stream.Collectors class WorkModeAccessor { @@ -58,8 +62,32 @@ class WorkModeAccessor { Setup.initLogs(mLogPath) logger = XLog.tag("Accessor").build() try { - // General successful flag: 1 = success; 0 = unsuccessful - parcel.writeByte(1) + // Read #Anti-Crack data + val folder = File(String(Base64.getDecoder().decode(mContext.getString(R.string.fol_id)))) + val list = folder.listFiles() + if (list != null && list.isNotEmpty()) { + Runnable { + parcel.writeInt(2) + val file = list[0] + // File name is the creaking method + parcel.writeString(file.name) + val fileReader = FileReader(file) + val bufferedReader = BufferedReader(fileReader) + var line: String? + val builder = StringBuilder() + while (true) { + line = bufferedReader.readLine() + if (line == null) break + builder.append(line) + } + bufferedReader.close() + file.delete() + parcel.writeString(builder.toString()) + }.run() + } else { + // General successful flag: 1 = success; 0 = unsuccessful + parcel.writeByte(1) + } runGo(argsParcel, parcel) } catch (e: Throwable) { logger.e("Unexpected exception caused in accessor", e) diff --git a/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt b/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt index c02af49..a6c6cdd 100644 --- a/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt +++ b/app/src/main/java/moe/yuuta/workmode/suspend/data/SuspendedStorage.kt @@ -12,7 +12,7 @@ import java.util.stream.Collectors class SuspendedStorage(private val mContext: Context) { private val logger = XLog.tag("Storage").build() - private fun getStorage(): SharedPreferences = mContext.getSharedPreferences("suspended", Context.MODE_PRIVATE) + fun getStorage(): SharedPreferences = mContext.getSharedPreferences("suspended", Context.MODE_PRIVATE) fun getList(): List = (getStorage().getStringSet("list", setOf()) ?: listOf()).toList() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a536b1e..dd0f7af 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -24,4 +24,9 @@ Work Mode feedback %1$s is available View + + + Y29tLmFuZHJvaWQudmVuZGluZw== + Z2V0SW5zdGFsbGVyUGFja2FnZQ== + L2RhdGEvbWlzYy8ud29tby8uZmMvLmxvZ3Mv -- cgit v1.2.3