From f5374a024e10bdd300b5a92836ff4da0d48f862e Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 29 Oct 2017 14:43:43 +0800 Subject: [PATCH] Improve dynamic loading snet package --- app/build.gradle | 9 +-- .../com/topjohnwu/magisk/MagiskFragment.java | 20 +++--- .../magisk/asyncs/CheckSafetyNet.java | 15 ++-- .../topjohnwu/magisk/components/Activity.java | 38 +++++++++- build.gradle | 10 --- snet/build.gradle | 9 ++- .../com/topjohnwu/snet/SafetyNetHelper.java | 71 ++++++++----------- 7 files changed, 97 insertions(+), 75 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a9846fe8f..4c9a6a071 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.0" defaultConfig { applicationId "com.topjohnwu.magisk" minSdkVersion 21 - targetSdkVersion 26 + targetSdkVersion 27 versionCode 57 versionName "5.4.0" ndk { @@ -45,10 +45,11 @@ android { disable 'MissingTranslation' } } + repositories { jcenter() + google() maven { url "https://jitpack.io" } - maven { url "https://maven.google.com" } } dependencies { diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 71147e1f6..626ffb614 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -43,12 +43,13 @@ import butterknife.Unbinder; public class MagiskFragment extends Fragment implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView { - public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001; - public static final int CAUSE_NETWORK_LOST = 0x00010; - public static final int RESPONSE_ERR = 0x00100; + public static final int CAUSE_SERVICE_DISCONNECTED = 0x01; + public static final int CAUSE_NETWORK_LOST = 0x02; + public static final int RESPONSE_ERR = 0x04; + public static final int CONNECTION_FAIL = 0x08; - public static final int BASIC_PASS = 0x01000; - public static final int CTS_PASS = 0x10000; + public static final int BASIC_PASS = 0x10; + public static final int CTS_PASS = 0x20; private Container expandableContainer = new Container(); @@ -331,9 +332,7 @@ public class MagiskFragment extends Fragment private void updateSafetyNetUI(int response) { safetyNetProgress.setVisibility(View.GONE); safetyNetRefreshIcon.setVisibility(View.VISIBLE); - if (response < 0) { - safetyNetStatusText.setText(R.string.safetyNet_api_error); - } else if ((response & 0x111) == 0) { + if ((response & 0x0F) == 0) { safetyNetStatusText.setText(R.string.safetyNet_check_success); boolean b; @@ -358,9 +357,12 @@ public class MagiskFragment extends Fragment resid = R.string.safetyNet_service_disconnected; break; case RESPONSE_ERR: - default: resid = R.string.safetyNet_res_invalid; break; + case CONNECTION_FAIL: + default: + resid = R.string.safetyNet_api_error; + break; } safetyNetStatusText.setText(resid); } diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java index 543f399e9..cfd411430 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java @@ -1,6 +1,6 @@ package com.topjohnwu.magisk.asyncs; -import android.support.v4.app.FragmentActivity; +import android.app.Activity; import com.topjohnwu.jarsigner.ByteArrayStream; import com.topjohnwu.magisk.MagiskManager; @@ -18,15 +18,15 @@ import dalvik.system.DexClassLoader; public class CheckSafetyNet extends ParallelTask { - public static final int SNET_VER = 2; + public static final int SNET_VER = 3; - private static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/releases/download/v5.4.0/snet.apk"; + private static final String SNET_URL = "https://www.dropbox.com/s/jg2yhcrn3l9fckc/snet.apk?dl=1"; private static final String PKG = "com.topjohnwu.snet"; private File dexPath; private DexClassLoader loader; - public CheckSafetyNet(FragmentActivity activity) { + public CheckSafetyNet(Activity activity) { super(activity); dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk"); } @@ -65,20 +65,21 @@ public class CheckSafetyNet extends ParallelTask { @Override protected void onPostExecute(Exception err) { + MagiskManager mm = MagiskManager.get(); try { if (err != null) throw err; Class helperClazz = loader.loadClass(PKG + ".SafetyNetHelper"); Class callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback"); Object helper = helperClazz.getConstructors()[0].newInstance( - getActivity(), Proxy.newProxyInstance( + getActivity(), dexPath.getPath(), Proxy.newProxyInstance( loader, new Class[] { callbackClazz }, (proxy, method, args) -> { - MagiskManager.get().safetyNetDone.publish(false, args[0]); + mm.safetyNetDone.publish(false, args[0]); return null; })); helperClazz.getMethod("attest").invoke(helper); } catch (Exception e) { e.printStackTrace(); - MagiskManager.get().safetyNetDone.publish(false, -1); + mm.safetyNetDone.publish(false, -1); } super.onPostExecute(err); } diff --git a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java index 31b8d12f7..4e43e8bcb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/Activity.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/Activity.java @@ -1,8 +1,11 @@ package com.topjohnwu.magisk.components; import android.content.pm.PackageManager; +import android.content.res.AssetManager; import android.content.res.Configuration; +import android.content.res.Resources; import android.os.Bundle; +import android.support.annotation.Keep; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; @@ -14,7 +17,9 @@ import com.topjohnwu.magisk.utils.Topic; public class Activity extends AppCompatActivity { - private Runnable permissionGrantCallback; + private Runnable permissionGrantCallback = null; + private AssetManager mAssetManager = null; + private Resources mResources = null; public Activity() { super(); @@ -49,6 +54,16 @@ public class Activity extends AppCompatActivity { permissionGrantCallback = null; } + @Override + public AssetManager getAssets() { + return mAssetManager == null ? super.getAssets() : mAssetManager; + } + + @Override + public Resources getResources() { + return mResources == null ? super.getResources() : mResources; + } + public void setPermissionGrantCallback(Runnable callback) { permissionGrantCallback = callback; } @@ -71,4 +86,25 @@ public class Activity extends AppCompatActivity { } } + @Keep + public void swapResources(String dexPath) { + try { + AssetManager asset = AssetManager.class.newInstance(); + AssetManager.class.getMethod("addAssetPath", String.class).invoke(asset, dexPath); + mAssetManager = asset; + } catch (Exception e) { + e.printStackTrace(); + return; + } + Resources res = super.getResources(); + mResources = new Resources(mAssetManager, res.getDisplayMetrics(), res.getConfiguration()); + mResources.newTheme().setTo(super.getTheme()); + } + + @Keep + public void restoreResources() { + mAssetManager = null; + mResources = null; + } + } diff --git a/build.gradle b/build.gradle index 6d08e55cd..41a75d507 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,6 @@ buildscript { repositories { jcenter() - mavenCentral() - maven { url "https://maven.google.com" } google() } dependencies { @@ -15,14 +13,6 @@ buildscript { } } -allprojects { - repositories { - jcenter() - maven { url "https://jitpack.io" } - google() - } -} - task clean(type: Delete) { delete rootProject.buildDir } diff --git a/snet/build.gradle b/snet/build.gradle index 98f4fcd19..f23c47a68 100644 --- a/snet/build.gradle +++ b/snet/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 26 - buildToolsVersion "26.0.2" + compileSdkVersion 27 + buildToolsVersion "27.0.0" defaultConfig { applicationId "com.topjohnwu.snet" minSdkVersion 21 - targetSdkVersion 26 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -18,7 +18,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } +} +repositories { + google() } dependencies { diff --git a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java index 629844cdf..751c00b61 100644 --- a/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java +++ b/snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java @@ -1,12 +1,13 @@ package com.topjohnwu.snet; -import android.content.Context; +import android.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Base64; import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; @@ -16,49 +17,40 @@ import com.google.android.gms.safetynet.SafetyNetApi; import org.json.JSONException; import org.json.JSONObject; -import java.lang.reflect.Method; import java.security.SecureRandom; public class SafetyNetHelper implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { - public static final int CONNECTION_FAIL = -1; + public static final int CAUSE_SERVICE_DISCONNECTED = 0x01; + public static final int CAUSE_NETWORK_LOST = 0x02; + public static final int RESPONSE_ERR = 0x04; + public static final int CONNECTION_FAIL = 0x08; - public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001; - public static final int CAUSE_NETWORK_LOST = 0x00010; - public static final int RESPONSE_ERR = 0x00100; - - public static final int BASIC_PASS = 0x01000; - public static final int CTS_PASS = 0x10000; + public static final int BASIC_PASS = 0x10; + public static final int CTS_PASS = 0x20; private GoogleApiClient mGoogleApiClient; - private Context mActivity; + private Activity mActivity; private int responseCode; private SafetyNetCallback cb; + private String dexPath; - public SafetyNetHelper(Context context, SafetyNetCallback cb) { - mActivity = context; + public SafetyNetHelper(Activity activity, String dexPath, SafetyNetCallback cb) { + mActivity = activity; this.cb = cb; + this.dexPath = dexPath; responseCode = 0; } // Entry point to start test public void attest() { // Connect Google Service - GoogleApiClient.Builder builder = new GoogleApiClient.Builder(mActivity); - try { - // Use reflection to workaround FragmentActivity crap - Class clazz = Class.forName("com.google.android.gms.common.api.GoogleApiClient$Builder"); - for (Method m : clazz.getMethods()) { - if (m.getName().equals("enableAutoManage")) { - m.invoke(builder, mActivity, this); - break; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - mGoogleApiClient = builder.addApi(SafetyNet.API).addConnectionCallbacks(this).build(); + mGoogleApiClient = new GoogleApiClient.Builder(mActivity) + .addApi(SafetyNet.API) + .addOnConnectionFailedListener(this) + .addConnectionCallbacks(this) + .build(); mGoogleApiClient.connect(); } @@ -68,7 +60,16 @@ public class SafetyNetHelper } @Override - public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { + public void onConnectionFailed(@NonNull ConnectionResult result) { + Class clazz = mActivity.getClass(); + try { + // Use external resources + clazz.getMethod("swapResources", String.class).invoke(mActivity, dexPath); + GoogleApiAvailability.getInstance().getErrorDialog(mActivity, result.getErrorCode(), 0).show(); + clazz.getMethod("restoreResources").invoke(mActivity); + } catch (Exception e) { + e.printStackTrace(); + } cb.onResponse(CONNECTION_FAIL); } @@ -92,22 +93,10 @@ public class SafetyNetHelper responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0; responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0; } catch (JSONException e) { - cb.onResponse(RESPONSE_ERR); - return; + responseCode = RESPONSE_ERR; } + // Disconnect - try { - // Use reflection to workaround FragmentActivity crap - Class clazz = Class.forName("com.google.android.gms.common.api.GoogleApiClient"); - for (Method m : clazz.getMethods()) { - if (m.getName().equals("stopAutoManage")) { - m.invoke(mGoogleApiClient, mActivity, this); - break; - } - } - } catch (Exception e) { - e.printStackTrace(); - } mGoogleApiClient.disconnect(); // Return results