diff --git a/app/build.gradle b/app/build.gradle index 5e78366..44843e8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,7 +13,13 @@ android { } buildTypes { release { - minifyEnabled false + // Enables code shrinking, obfuscation, and optimization for only + // your project's release build type. + minifyEnabled true + + // Enables resource shrinking, which is performed by the + // Android Gradle plugin. + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f1b4245..c576118 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -19,3 +19,8 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile + +# To fix errors and force R8 to keep certain code, add a -keep line in the ProGuard rules file. For example: +# -keep public class MyClass +-dontwarn com.crux.sdk.** +-keep class com.crux.sdk.** {*;} \ No newline at end of file diff --git a/app/src/main/java/com/example/liquid_test_2/MainActivity.java b/app/src/main/java/com/example/liquid_test_2/MainActivity.java index 3c476cd..18379d5 100644 --- a/app/src/main/java/com/example/liquid_test_2/MainActivity.java +++ b/app/src/main/java/com/example/liquid_test_2/MainActivity.java @@ -2,6 +2,7 @@ import android.content.Context; import android.os.Bundle; +import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; @@ -38,7 +39,14 @@ public String runScript(final Context androidContextObject) throws IOException, .setWalletClientName("cruxdev") .setPrivateKey("cdf2d276caf0c9c34258ed6ebd0e60e0e8b3d9a7b8a9a717f2e19ed9b37f7c6f"); - final CruxClient client = new CruxClient(configBuilder, androidContextObject); + CruxClient client; + try { + client = new CruxClient(configBuilder, androidContextObject); + } catch(CruxClientError e) { + Toast.makeText(androidContextObject, "Client caught and reraised:" + e.errorMessage, Toast.LENGTH_LONG).show(); + System.out.println("use debug version for development"); + return null; + } final String testAvailabilityCruxId = "yadu007"; client.isCruxIDAvailable(testAvailabilityCruxId, new CruxClientResponseHandler() { diff --git a/sdk/src/main/java/com/crux/sdk/CruxClient.java b/sdk/src/main/java/com/crux/sdk/CruxClient.java index 3c1e6c5..548b2e1 100644 --- a/sdk/src/main/java/com/crux/sdk/CruxClient.java +++ b/sdk/src/main/java/com/crux/sdk/CruxClient.java @@ -1,10 +1,12 @@ package com.crux.sdk; import android.content.Context; +import android.os.Debug; import com.crux.sdk.bridge.CruxJSBridge; import com.crux.sdk.bridge.CruxJSBridgeAsyncRequest; import com.crux.sdk.bridge.handlerImpl.CruxJSBridgeResponseHandlerImpl; +import com.crux.sdk.model.AndroidCruxClientErrorCode; import com.crux.sdk.model.CruxAddress; import com.crux.sdk.model.CruxClientError; import com.crux.sdk.model.CruxClientInitConfig; @@ -12,6 +14,7 @@ import com.crux.sdk.model.CruxIDState; import com.crux.sdk.model.CruxParams; import com.crux.sdk.model.CruxPutAddressMapSuccess; +import com.crux.sdk.security.SdkSafety; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -25,9 +28,15 @@ public class CruxClient { private final CruxJSBridge jsBridge; public CruxClient(CruxClientInitConfig.Builder configBuilder, Context androidContextObject) throws IOException, CruxClientError { + + SdkSafety sf = new SdkSafety(androidContextObject); + if (sf.checkSafety()) { + throw CruxClientError.getCruxClientError(AndroidCruxClientErrorCode.runningInUnsafeEnvironment); + } this.jsBridge = new CruxJSBridge(configBuilder, androidContextObject); } + public void getCruxIDState(final CruxClientResponseHandler handler) { CruxJSBridgeAsyncRequest bridgeRequest = new CruxJSBridgeAsyncRequest("getCruxIDState", new CruxParams(), new CruxJSBridgeResponseHandlerImpl(CruxIDState.class, handler)); jsBridge.executeAsync(bridgeRequest); diff --git a/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorCode.java b/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorCode.java index f393310..fdded3f 100644 --- a/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorCode.java +++ b/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorCode.java @@ -5,6 +5,7 @@ public class AndroidCruxClientErrorCode { // 888s: Android Error Series public static Integer getCruxClientInitConfigStringFailed = 8881000; public static Integer cruxAddressMappingConversionFailed = 8881001; + public static Integer runningInUnsafeEnvironment = 8881002; } diff --git a/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorString.java b/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorString.java index 20e948f..3411d80 100644 --- a/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorString.java +++ b/sdk/src/main/java/com/crux/sdk/model/AndroidCruxClientErrorString.java @@ -9,6 +9,7 @@ public class AndroidCruxClientErrorString { static { errorCodeToErrorStringMap = new HashMap(); errorCodeToErrorStringMap.put(AndroidCruxClientErrorCode.getCruxClientInitConfigStringFailed, "Could not initialize cruxClientConfig"); + errorCodeToErrorStringMap.put(AndroidCruxClientErrorCode.runningInUnsafeEnvironment, "CRUX SDK should not run in unsafe environment"); errorCodeToErrorStringMap.put(AndroidCruxClientErrorCode.cruxAddressMappingConversionFailed, "Could not create CruxAddressMapping"); } } diff --git a/sdk/src/main/java/com/crux/sdk/security/AntiDebug.java b/sdk/src/main/java/com/crux/sdk/security/AntiDebug.java new file mode 100644 index 0000000..8f4d347 --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/AntiDebug.java @@ -0,0 +1,118 @@ +package com.crux.sdk.security; + +import android.content.Context; +import android.os.Debug; +import android.content.pm.ApplicationInfo; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +public class AntiDebug { + + private final Context mContext; + + public AntiDebug(Context context) { + mContext = context; + } + + public boolean isDebugging() { + + if (Debug.isDebuggerConnected()) { + return true; + } + + return (mContext.getApplicationContext().getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } + + //**************************************** TracerPid begin ************************************ + + public static boolean isTracerPid() { + + if (isLocalPortUsing(23946)) { + return true; + } + + String tracerPid = getTracerPid(); + if (!"0".equals(tracerPid)) { + return true; + } + + return false; + } + + /*** + * true:already in using false:not using + * @param port + */ + private static boolean isLocalPortUsing(int port) { + boolean flag = true; + try { + flag = isPortUsing("127.0.0.1", port); + } catch (Exception e) { + } + return flag; + } + + /*** + * true:already in using false:not using + * @param host + * @param port + * @throws UnknownHostException + */ + private static boolean isPortUsing(String host, int port) throws UnknownHostException { + boolean flag = false; + InetAddress theAddress = InetAddress.getByName(host); + try { + Socket socket = new Socket(theAddress, port); + flag = true; + } catch (IOException e) { + } + return flag; + } + + private static String getTracerPid() { + BufferedReader bufferedReader = null; + String readLine = ""; + try { + bufferedReader = new BufferedReader(new FileReader("/proc/self/status")); + do { + readLine = bufferedReader.readLine(); + if (readLine == null) { + break; + } + + } while (!readLine.startsWith("TracerPid:")); + readLine = readLine.substring("TracerPid:".length()).trim(); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return readLine; + } + //**************************************** TracerPid end ************************************** + + //**************************************** network test begin ********************************* + public static boolean checkGrabData() { + try { + String proxyHost = System.getProperty("http.proxyHost"); + String proxyPort = System.getProperty("http.proxyPort"); + return proxyHost != null || proxyPort != null; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + //**************************************** network test end *********************************** +} diff --git a/sdk/src/main/java/com/crux/sdk/security/AntiEmulator.java b/sdk/src/main/java/com/crux/sdk/security/AntiEmulator.java new file mode 100644 index 0000000..5d8d451 --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/AntiEmulator.java @@ -0,0 +1,45 @@ +package com.crux.sdk.security; + +import android.os.Build; + +import androidx.core.os.EnvironmentCompat; + +public class AntiEmulator { + public static boolean isEmulator() { + int rating = 0; + if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("google_sdk") || Build.PRODUCT.equals( + "sdk_x86") || Build.PRODUCT.equals("vbox86p")) { + rating = 1; + } + + if (Build.MANUFACTURER.equals(EnvironmentCompat.MEDIA_UNKNOWN) || Build.MANUFACTURER.equals( + "Genymotion")) { + rating++; + } + + if (Build.BRAND.equals("generic") || Build.BRAND.equals("generic_x86")) { + rating++; + } + + if (Build.DEVICE.equals("generic") || Build.DEVICE.equals("generic_x86") || Build.DEVICE.equals( + "vbox86p")) { + rating++; + } + + if (Build.MODEL.equals("sdk") || Build.MODEL.equals("google_sdk") || Build.MODEL.equals( + "Android SDK built for x86")) { + rating++; + } + + if (Build.HARDWARE.equals("goldfish") || Build.HARDWARE.equals("vbox86")) { + rating++; + } + + if (Build.FINGERPRINT.contains("generic/sdk/generic") || Build.FINGERPRINT.contains( + "generic_x86/sdk_x86/generic_x86") || Build.FINGERPRINT.contains( + "generic/google_sdk/generic") || Build.FINGERPRINT.contains("generic/vbox86p/vbox86p")) { + rating++; + } + return rating >= 2; + } +} diff --git a/sdk/src/main/java/com/crux/sdk/security/AntiRoot.java b/sdk/src/main/java/com/crux/sdk/security/AntiRoot.java new file mode 100644 index 0000000..582ef2a --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/AntiRoot.java @@ -0,0 +1,221 @@ +package com.crux.sdk.security; + +import android.content.Context; +import android.content.pm.PackageManager; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import android.util.Log; + + +public class AntiRoot { + + + private final Context mContext; + private boolean loggingEnabled = true; + private static final String TAG = "AntiRoot"; + + public AntiRoot(Context context) { + mContext = context; + } + + public boolean isRooted() { + + return _detectTestKeys() + || _detectRootManagementApps(null) + || _detectPotentiallyDangerousApps(null) + || _detectRootCloakingApps(null) + || (!_checkForBinary(AntiRootConst.BINARY_SU) || !_checkForBinary(AntiRootConst.BINARY_BUSYBOX) || !_checkForBinary(AntiRootConst.MAGISK)) + || _checkSuExists(); + + // || _checkForRWPaths() + } + + /** + * Check if any package in the list is installed + * @param packages - list of packages to search for + * @return true if any of the packages are installed + */ + private boolean isAnyPackageFromListInstalled(List packages){ + boolean result = false; + + PackageManager pm = mContext.getPackageManager(); + + for (String packageName : packages) { + try { + // Root app detected + pm.getPackageInfo(packageName, 0); + Log.e(TAG, packageName + " ROOT management app detected!"); + result = true; + } catch (PackageManager.NameNotFoundException e) { + // Exception thrown, package is not installed into the system + } + } + + return result; + } + + + /** + * Release-Keys and Test-Keys has to do with how the kernel is signed when it is compiled. + * Test-Keys means it was signed with a custom key generated by a third-party developer. + * @return true if signed with Test-keys + */ + public boolean _detectTestKeys() { + String buildTags = android.os.Build.TAGS; + return buildTags != null && buildTags.contains("test-keys"); + } + + /** + * Using the PackageManager, check for a list of well known root apps. @link {AntiRootConst.knownRootAppsPackages} + * @param additionalRootManagementApps - array of additional packagenames to search for + * @return true if one of the apps it's installed + */ + public boolean _detectRootManagementApps(String[] additionalRootManagementApps) { + + // Create a list of package names to iterate over from constants any others provided + ArrayList packages = new ArrayList<>(Arrays.asList(AntiRootConst.knownRootAppsPackages)); + if (additionalRootManagementApps!=null && additionalRootManagementApps.length>0){ + packages.addAll(Arrays.asList(additionalRootManagementApps)); + } + + return isAnyPackageFromListInstalled(packages); + } + + /** + * Using the PackageManager, check for a list of well known apps that require root. @link {AntiRootConst.knownRootAppsPackages} + * @param additionalDangerousApps - array of additional packagenames to search for + * @return true if one of the apps it's installed + */ + public boolean _detectPotentiallyDangerousApps(String[] additionalDangerousApps) { + + // Create a list of package names to iterate over from constants any others provided + ArrayList packages = new ArrayList<>(); + packages.addAll(Arrays.asList(AntiRootConst.knownDangerousAppsPackages)); + if (additionalDangerousApps!=null && additionalDangerousApps.length>0){ + packages.addAll(Arrays.asList(additionalDangerousApps)); + } + + return isAnyPackageFromListInstalled(packages); + } + + public boolean _detectRootCloakingApps(String[] additionalRootCloakingApps) { + // Create a list of package names to iterate over from constants any others provided + ArrayList packages = new ArrayList<>(); + packages.addAll(Arrays.asList(AntiRootConst.knownRootCloakingPackages)); + if (additionalRootCloakingApps!=null && additionalRootCloakingApps.length>0){ + packages.addAll(Arrays.asList(additionalRootCloakingApps)); + } + return isAnyPackageFromListInstalled(packages); + } + + /** + * A variation on the checking for SU, this attempts a 'which su' + * @return true if su found + */ + public boolean _checkSuExists() { + Process process = null; + try { + process = Runtime.getRuntime().exec(new String[] { "which", AntiRootConst.BINARY_SU }); + BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); + return in.readLine() != null; + } catch (Throwable t) { + return false; + } finally { + if (process != null) process.destroy(); + } + } + + + /** + * + * @param filename - check for this existence of this file + * @return true if found + */ + public boolean _checkForBinary(String filename) { + + String[] pathsArray = AntiRootConst.suPaths; + + boolean result = true; + + for (String path : pathsArray) { + String completePath = path + filename; + File f = new File(path, filename); + boolean fileExists = f.exists(); + if (fileExists) { + Log.v(TAG, completePath + " binary detected!"); + result = false; + } + } + + return !result; + } + + +// private String[] mountReader() { +// try { +// InputStream inputstream = Runtime.getRuntime().exec("mount").getInputStream(); +// if (inputstream == null) return null; +// String propVal = new Scanner(inputstream).useDelimiter("\\A").next(); +// return propVal.split("\n"); +// } catch (IOException | NoSuchElementException e) { +// e.printStackTrace(); +// return null; +// } +// } +// +// /** +// * When you're root you can change the permissions on common system directories, this method checks if any of these paths AntiRootConst.pathsThatShouldNotBeWritable are writable. +// * @return true if one of the dir is writable +// */ +// public boolean _checkForRWPaths() { +// +// boolean result = false; +// +// String[] lines = mountReader(); +// +// if (lines == null){ +// // Could not read, assume false; +// return false; +// } +// +// for (String line : lines) { +// +// // Split lines into parts +// String[] args = line.split(" "); +// +// if (args.length < 4){ +// // If we don't have enough options per line, skip this and log an error +// Log.e(TAG, "Error formatting mount line: "+line); +// continue; +// } +// +// String mountPoint = args[1]; +// String mountOptions = args[3]; +// +// for(String pathToCheck: AntiRootConst.pathsThatShouldNotBeWritable) { +// if (mountPoint.equalsIgnoreCase(pathToCheck)) { +// +// // Split options out and compare against "rw" to avoid false positives +// for (String option : mountOptions.split(",")){ +// +// if (option.equalsIgnoreCase("rw")){ +// Log.v(TAG, pathToCheck+" path is mounted with rw permissions! "+line); +// result = true; +// break; +// } +// } +// } +// } +// } +// +// return result; +// } + + +} diff --git a/sdk/src/main/java/com/crux/sdk/security/AntiRootConst.java b/sdk/src/main/java/com/crux/sdk/security/AntiRootConst.java new file mode 100644 index 0000000..eb36d3a --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/AntiRootConst.java @@ -0,0 +1,77 @@ +package com.crux.sdk.security; + +public final class AntiRootConst { + + public static final String BINARY_SU = "su"; + public static final String BINARY_BUSYBOX = "busybox"; + public static final String MAGISK = "magisk"; + + private AntiRootConst() throws InstantiationException { + throw new InstantiationException("This class is not for instantiation"); + } + + public static final String[] knownRootAppsPackages = { + "com.noshufou.android.su", + "com.noshufou.android.su.elite", + "eu.chainfire.supersu", + "com.koushikdutta.superuser", + "com.thirdparty.superuser", + "com.yellowes.su", + "com.topjohnwu.magisk" + }; + + public static final String[] knownDangerousAppsPackages = { + "com.koushikdutta.rommanager", + "com.koushikdutta.rommanager.license", + "com.dimonvideo.luckypatcher", + "com.chelpus.lackypatch", + "com.ramdroid.appquarantine", + "com.ramdroid.appquarantinepro", + "com.android.vending.billing.InAppBillingService.COIN", + "com.chelpus.luckypatcher" + }; + + public static final String[] knownRootCloakingPackages = { + "com.devadvance.rootcloak", + "com.devadvance.rootcloakplus", + "de.robv.android.xposed.installer", + "com.saurik.substrate", + "com.zachspong.temprootremovejb", + "com.amphoras.hidemyroot", + "com.amphoras.hidemyrootadfree", + "com.formyhm.hiderootPremium", + "com.formyhm.hideroot" + }; + + // These must end with a / + public static final String[] suPaths = { + "/data/local/", + "/data/local/bin/", + "/data/local/xbin/", + "/sbin/", + "/su/bin/", + "/system/bin/", + "/system/bin/.ext/", + "/system/bin/failsafe/", + "/system/sd/xbin/", + "/system/usr/we-need-root/", + "/system/xbin/", + "/cache/", + "/data/", + "/dev/" + }; + + + public static final String[] pathsThatShouldNotBeWritable = { + "/system", + "/system/bin", + "/system/sbin", + "/system/xbin", + "/vendor/bin", + "/sbin", + "/etc", + //"/sys", + //"/proc", + //"/dev" + }; +} diff --git a/sdk/src/main/java/com/crux/sdk/security/AntiTamper.java b/sdk/src/main/java/com/crux/sdk/security/AntiTamper.java new file mode 100644 index 0000000..7728812 --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/AntiTamper.java @@ -0,0 +1,106 @@ +package com.crux.sdk.security; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; + +import java.util.Arrays; +import java.util.List; + +public class AntiTamper { + + private final Context mContext; + + public AntiTamper(Context context) { + mContext = context; + } + + //**************************************** hook detection begin **************************** + + /** + * Detects if there is any suspicious installed application. + * + * @return true if some bad application is installed, false otherwise. + */ + public boolean hookDetected() { + PackageManager packageManager = mContext.getPackageManager(); + List applicationInfoList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA); + String[] dangerousPackages = {"de.robv.android.xposed.installer", "com.saurik.substrate", "de.robv.android.xposed"}; + + for (ApplicationInfo applicationInfo : applicationInfoList) { + if (Arrays.asList(dangerousPackages).contains(applicationInfo.packageName)) { + return true; + } + } + + return this.advancedHookDetection(); + } + + private boolean advancedHookDetection() { + try { + throw new Exception(); + } catch (Exception e) { + int zygoteInitCallCount = 0; + for (StackTraceElement stackTraceElement : e.getStackTrace()) { + if (stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit")) { + zygoteInitCallCount++; + if (zygoteInitCallCount == 2) { + return true; + } + } + + if (stackTraceElement.getClassName().equals("com.saurik.substrate.MS$2") && + stackTraceElement.getMethodName().equals("invoked")) { + return true; + } + + if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && + stackTraceElement.getMethodName().equals("main")) { + return true; + } + + if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && + stackTraceElement.getMethodName().equals("handleHookedMethod")) { + return true; + } + } + } + + return !this.checkFrida(); + } + + private boolean checkFrida() { + ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + List runningServices = activityManager.getRunningServices(300); + + if (runningServices != null) { + for (int i = 0; i < runningServices.size(); ++i) { + if (runningServices.get(i).process.contains("fridaserver")) { + return false; + } + } + } + + return true; + } + + //**************************************** hook detection ends **************************** + + //**************************************** signature testing begin **************************** + public boolean isOwnApp() { + String APP_SIGN = "test"; + + if (mContext == null) { + return false; + } + + String signStr = this.getSignature(); + return APP_SIGN.equals(signStr); + } + + private String getSignature() { + return "test"; + } + //**************************************** signature testing ends ***************************** +} diff --git a/sdk/src/main/java/com/crux/sdk/security/SdkSafety.java b/sdk/src/main/java/com/crux/sdk/security/SdkSafety.java new file mode 100644 index 0000000..cfcbd7c --- /dev/null +++ b/sdk/src/main/java/com/crux/sdk/security/SdkSafety.java @@ -0,0 +1,96 @@ +package com.crux.sdk.security; + +import android.content.Context; +import android.widget.Toast; +import com.crux.sdk.BuildConfig; + +import java.util.Random; + + +public class SdkSafety { + + private final Context mContext; + + public SdkSafety(Context context) { + mContext = context; + } + + public boolean checkSafety() { + + boolean isUnsafe = _checkSafety(); + + if (isUnsafe) { + Toast.makeText(mContext, "sdk informed unsafe env", Toast.LENGTH_LONG).show(); + } + if (isReleaseVersion()) { + return isUnsafe; + // System.exit(0); + } + return false; + } + + private boolean isReleaseVersion() { + // return true; + return BuildConfig.BUILD_TYPE.contentEquals("release"); + } + + private boolean _checkSafety() { + + AntiTamper at = new AntiTamper(mContext); + AntiDebug ad = new AntiDebug(mContext); + AntiRoot ar = new AntiRoot(mContext); + + Random rand = new Random(); + int randomizeCheck = rand.nextInt(1000)/7; + switch (randomizeCheck) { + case 1: + if (AntiEmulator.isEmulator()) { + return true; + } + break; + + case 2: + boolean ownApp = at.isOwnApp(); + if (!ownApp) { + return true; + } + break; + + case 3: + if (ad.isDebugging()) { + return true; + } + break; + + case 4: + if (AntiDebug.isTracerPid()) { + return true; + } + break; + + case 5: + if (at.hookDetected()) { + return true; + } + + case 6: + if (ar.isRooted()) { + return true; + } + + case 0: + if (AntiDebug.checkGrabData()) { + return true; + } + + default: + return AntiEmulator.isEmulator() || AntiDebug.isTracerPid() || at.hookDetected() + || ar.isRooted() || AntiDebug.checkGrabData() || ad.isDebugging(); + } + + return AntiEmulator.isEmulator() || AntiDebug.isTracerPid() || at.hookDetected() + || ar.isRooted() || AntiDebug.checkGrabData() || ad.isDebugging(); + + } + +}