Improve dynamic loading snet package

This commit is contained in:
topjohnwu 2017-10-29 14:43:43 +08:00
parent 4956d826fb
commit f5374a024e
7 changed files with 97 additions and 75 deletions

View File

@ -1,13 +1,13 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion "26.0.2" buildToolsVersion "27.0.0"
defaultConfig { defaultConfig {
applicationId "com.topjohnwu.magisk" applicationId "com.topjohnwu.magisk"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 27
versionCode 57 versionCode 57
versionName "5.4.0" versionName "5.4.0"
ndk { ndk {
@ -45,10 +45,11 @@ android {
disable 'MissingTranslation' disable 'MissingTranslation'
} }
} }
repositories { repositories {
jcenter() jcenter()
google()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
} }
dependencies { dependencies {

View File

@ -43,12 +43,13 @@ import butterknife.Unbinder;
public class MagiskFragment extends Fragment public class MagiskFragment extends Fragment
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView { implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView {
public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001; public static final int CAUSE_SERVICE_DISCONNECTED = 0x01;
public static final int CAUSE_NETWORK_LOST = 0x00010; public static final int CAUSE_NETWORK_LOST = 0x02;
public static final int RESPONSE_ERR = 0x00100; 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 BASIC_PASS = 0x10;
public static final int CTS_PASS = 0x10000; public static final int CTS_PASS = 0x20;
private Container expandableContainer = new Container(); private Container expandableContainer = new Container();
@ -331,9 +332,7 @@ public class MagiskFragment extends Fragment
private void updateSafetyNetUI(int response) { private void updateSafetyNetUI(int response) {
safetyNetProgress.setVisibility(View.GONE); safetyNetProgress.setVisibility(View.GONE);
safetyNetRefreshIcon.setVisibility(View.VISIBLE); safetyNetRefreshIcon.setVisibility(View.VISIBLE);
if (response < 0) { if ((response & 0x0F) == 0) {
safetyNetStatusText.setText(R.string.safetyNet_api_error);
} else if ((response & 0x111) == 0) {
safetyNetStatusText.setText(R.string.safetyNet_check_success); safetyNetStatusText.setText(R.string.safetyNet_check_success);
boolean b; boolean b;
@ -358,9 +357,12 @@ public class MagiskFragment extends Fragment
resid = R.string.safetyNet_service_disconnected; resid = R.string.safetyNet_service_disconnected;
break; break;
case RESPONSE_ERR: case RESPONSE_ERR:
default:
resid = R.string.safetyNet_res_invalid; resid = R.string.safetyNet_res_invalid;
break; break;
case CONNECTION_FAIL:
default:
resid = R.string.safetyNet_api_error;
break;
} }
safetyNetStatusText.setText(resid); safetyNetStatusText.setText(resid);
} }

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.asyncs; package com.topjohnwu.magisk.asyncs;
import android.support.v4.app.FragmentActivity; import android.app.Activity;
import com.topjohnwu.jarsigner.ByteArrayStream; import com.topjohnwu.jarsigner.ByteArrayStream;
import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.MagiskManager;
@ -18,15 +18,15 @@ import dalvik.system.DexClassLoader;
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> { public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
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 static final String PKG = "com.topjohnwu.snet";
private File dexPath; private File dexPath;
private DexClassLoader loader; private DexClassLoader loader;
public CheckSafetyNet(FragmentActivity activity) { public CheckSafetyNet(Activity activity) {
super(activity); super(activity);
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk"); dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
} }
@ -65,20 +65,21 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
@Override @Override
protected void onPostExecute(Exception err) { protected void onPostExecute(Exception err) {
MagiskManager mm = MagiskManager.get();
try { try {
if (err != null) throw err; if (err != null) throw err;
Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper"); Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper");
Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback"); Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback");
Object helper = helperClazz.getConstructors()[0].newInstance( Object helper = helperClazz.getConstructors()[0].newInstance(
getActivity(), Proxy.newProxyInstance( getActivity(), dexPath.getPath(), Proxy.newProxyInstance(
loader, new Class[] { callbackClazz }, (proxy, method, args) -> { loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
MagiskManager.get().safetyNetDone.publish(false, args[0]); mm.safetyNetDone.publish(false, args[0]);
return null; return null;
})); }));
helperClazz.getMethod("attest").invoke(helper); helperClazz.getMethod("attest").invoke(helper);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
MagiskManager.get().safetyNetDone.publish(false, -1); mm.safetyNetDone.publish(false, -1);
} }
super.onPostExecute(err); super.onPostExecute(err);
} }

View File

@ -1,8 +1,11 @@
package com.topjohnwu.magisk.components; package com.topjohnwu.magisk.components;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Keep;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
@ -14,7 +17,9 @@ import com.topjohnwu.magisk.utils.Topic;
public class Activity extends AppCompatActivity { public class Activity extends AppCompatActivity {
private Runnable permissionGrantCallback; private Runnable permissionGrantCallback = null;
private AssetManager mAssetManager = null;
private Resources mResources = null;
public Activity() { public Activity() {
super(); super();
@ -49,6 +54,16 @@ public class Activity extends AppCompatActivity {
permissionGrantCallback = null; 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) { public void setPermissionGrantCallback(Runnable callback) {
permissionGrantCallback = 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;
}
} }

View File

@ -3,8 +3,6 @@
buildscript { buildscript {
repositories { repositories {
jcenter() jcenter()
mavenCentral()
maven { url "https://maven.google.com" }
google() google()
} }
dependencies { dependencies {
@ -15,14 +13,6 @@ buildscript {
} }
} }
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
google()
}
}
task clean(type: Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View File

@ -1,13 +1,13 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion "26.0.2" buildToolsVersion "27.0.0"
defaultConfig { defaultConfig {
applicationId "com.topjohnwu.snet" applicationId "com.topjohnwu.snet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 27
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
} }
@ -18,7 +18,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
}
repositories {
google()
} }
dependencies { dependencies {

View File

@ -1,12 +1,13 @@
package com.topjohnwu.snet; package com.topjohnwu.snet;
import android.content.Context; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Base64; import android.util.Base64;
import com.google.android.gms.common.ConnectionResult; 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.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status; 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.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.lang.reflect.Method;
import java.security.SecureRandom; import java.security.SecureRandom;
public class SafetyNetHelper public class SafetyNetHelper
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { 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 BASIC_PASS = 0x10;
public static final int CAUSE_NETWORK_LOST = 0x00010; public static final int CTS_PASS = 0x20;
public static final int RESPONSE_ERR = 0x00100;
public static final int BASIC_PASS = 0x01000;
public static final int CTS_PASS = 0x10000;
private GoogleApiClient mGoogleApiClient; private GoogleApiClient mGoogleApiClient;
private Context mActivity; private Activity mActivity;
private int responseCode; private int responseCode;
private SafetyNetCallback cb; private SafetyNetCallback cb;
private String dexPath;
public SafetyNetHelper(Context context, SafetyNetCallback cb) { public SafetyNetHelper(Activity activity, String dexPath, SafetyNetCallback cb) {
mActivity = context; mActivity = activity;
this.cb = cb; this.cb = cb;
this.dexPath = dexPath;
responseCode = 0; responseCode = 0;
} }
// Entry point to start test // Entry point to start test
public void attest() { public void attest() {
// Connect Google Service // Connect Google Service
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(mActivity); mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
try { .addApi(SafetyNet.API)
// Use reflection to workaround FragmentActivity crap .addOnConnectionFailedListener(this)
Class<?> clazz = Class.forName("com.google.android.gms.common.api.GoogleApiClient$Builder"); .addConnectionCallbacks(this)
for (Method m : clazz.getMethods()) { .build();
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.connect(); mGoogleApiClient.connect();
} }
@ -68,7 +60,16 @@ public class SafetyNetHelper
} }
@Override @Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { public void onConnectionFailed(@NonNull ConnectionResult result) {
Class<? extends Activity> 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); cb.onResponse(CONNECTION_FAIL);
} }
@ -92,22 +93,10 @@ public class SafetyNetHelper
responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0; responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0; responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
} catch (JSONException e) { } catch (JSONException e) {
cb.onResponse(RESPONSE_ERR); responseCode = RESPONSE_ERR;
return;
} }
// Disconnect // 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(); mGoogleApiClient.disconnect();
// Return results // Return results