mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-25 02:55:33 +00:00
Update SafetyNet extension implementation
This commit is contained in:
parent
b0a5dbb4c2
commit
90d218ebc8
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,6 +4,9 @@ out
|
|||||||
*.apk
|
*.apk
|
||||||
config.prop
|
config.prop
|
||||||
|
|
||||||
|
# Manually dumped jars
|
||||||
|
snet/libs
|
||||||
|
|
||||||
# Built binaries
|
# Built binaries
|
||||||
native/out
|
native/out
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
1. Building is tested on macOS, Ubuntu, and Windows 10 using the latest stable NDK and NDK r10e. Officially released binaries were built with NDK r10e.
|
1. Building is tested on macOS, Ubuntu, and Windows 10 using the latest stable NDK and NDK r10e. Officially released binaries were built with NDK r10e.
|
||||||
2. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
|
2. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
|
||||||
3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
|
3. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
|
||||||
4. By default, `build.py` will build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (through the `--release` flag), you will need to place a Java Keystore file at `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
|
4. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `--release` flag), you need a Java Keystore file `release-key.jks` to sign Magisk Manager's APK. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
|
||||||
|
5. The SafetyNet extension pack requires the full Magisk Manager as a `compileOnly` dependency. Build the **release** APK, convert it back to Java `.class` files (I use [dex2jar](https://github.com/pxb1988/dex2jar)), and place the converted JAR under `snet/libs` before compiling.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
2
app
2
app
@ -1 +1 @@
|
|||||||
Subproject commit a0466085fe3b5eb8929c893d02459e6d94ecb115
|
Subproject commit 499a157946f0063aea0795b204a1f2858591d8d3
|
7
build.py
7
build.py
@ -83,7 +83,6 @@ def build_all(args):
|
|||||||
build_apk(args)
|
build_apk(args)
|
||||||
zip_main(args)
|
zip_main(args)
|
||||||
zip_uninstaller(args)
|
zip_uninstaller(args)
|
||||||
build_snet(args)
|
|
||||||
|
|
||||||
def collect_binary():
|
def collect_binary():
|
||||||
for arch in ['armeabi-v7a', 'x86']:
|
for arch in ['armeabi-v7a', 'x86']:
|
||||||
@ -235,7 +234,11 @@ def build_snet(args):
|
|||||||
error('Build snet extention failed!')
|
error('Build snet extention failed!')
|
||||||
source = os.path.join('snet', 'build', 'outputs', 'apk', 'release', 'snet-release-unsigned.apk')
|
source = os.path.join('snet', 'build', 'outputs', 'apk', 'release', 'snet-release-unsigned.apk')
|
||||||
target = os.path.join(config['outdir'], 'snet.apk')
|
target = os.path.join(config['outdir'], 'snet.apk')
|
||||||
mv(source, target)
|
# Re-compress the whole APK for smaller size
|
||||||
|
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zout:
|
||||||
|
with zipfile.ZipFile(source) as zin:
|
||||||
|
for item in zin.infolist():
|
||||||
|
zout.writestr(item.filename, zin.read(item))
|
||||||
header('Output: ' + target)
|
header('Output: ' + target)
|
||||||
|
|
||||||
def gen_update_binary():
|
def gen_update_binary():
|
||||||
|
@ -6,7 +6,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.topjohnwu.snet"
|
applicationId "com.topjohnwu.snet"
|
||||||
minSdkVersion 21
|
minSdkVersion 14
|
||||||
targetSdkVersion rootProject.ext.compileSdkVersion
|
targetSdkVersion rootProject.ext.compileSdkVersion
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
@ -15,12 +15,13 @@ android {
|
|||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
shrinkResources true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'com.google.android.gms:play-services-safetynet:7.0.0' /* The oldest version */
|
implementation 'com.google.android.gms:play-services-safetynet:7.0.0' /* The oldest version */
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package com.topjohnwu.snet;
|
|
||||||
|
|
||||||
public interface SafetyNetCallback {
|
|
||||||
void onResponse(int responseCode);
|
|
||||||
}
|
|
@ -1,7 +1,5 @@
|
|||||||
package com.topjohnwu.snet;
|
package com.topjohnwu.snet;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
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;
|
||||||
@ -11,18 +9,19 @@ import com.google.android.gms.common.ConnectionResult;
|
|||||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||||
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.safetynet.SafetyNet;
|
import com.google.android.gms.safetynet.SafetyNet;
|
||||||
import com.google.android.gms.safetynet.SafetyNetApi;
|
import com.google.android.gms.safetynet.SafetyNetApi;
|
||||||
|
import com.topjohnwu.magisk.asyncs.CheckSafetyNet;
|
||||||
|
import com.topjohnwu.magisk.components.Activity;
|
||||||
|
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
public class SafetyNetHelper
|
public class SafetyNetHelper implements ISafetyNetHelper, GoogleApiClient.ConnectionCallbacks,
|
||||||
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
GoogleApiClient.OnConnectionFailedListener, ResultCallback<SafetyNetApi.AttestationResult> {
|
||||||
|
|
||||||
public static final int CAUSE_SERVICE_DISCONNECTED = 0x01;
|
public static final int CAUSE_SERVICE_DISCONNECTED = 0x01;
|
||||||
public static final int CAUSE_NETWORK_LOST = 0x02;
|
public static final int CAUSE_NETWORK_LOST = 0x02;
|
||||||
@ -32,36 +31,24 @@ public class SafetyNetHelper
|
|||||||
public static final int BASIC_PASS = 0x10;
|
public static final int BASIC_PASS = 0x10;
|
||||||
public static final int CTS_PASS = 0x20;
|
public static final int CTS_PASS = 0x20;
|
||||||
|
|
||||||
public static final int SNET_EXT_VER = 7;
|
public static final int SNET_EXT_VER = 8;
|
||||||
|
|
||||||
private GoogleApiClient mGoogleApiClient;
|
private GoogleApiClient mGoogleApiClient;
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
private int responseCode;
|
private Callback callback;
|
||||||
private SafetyNetCallback cb;
|
|
||||||
private String dexPath;
|
|
||||||
private boolean isDarkTheme;
|
|
||||||
|
|
||||||
public static int getVersion() {
|
@Override
|
||||||
|
public int getVersion() {
|
||||||
return SNET_EXT_VER;
|
return SNET_EXT_VER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SafetyNetHelper(Activity activity, String dexPath, SafetyNetCallback cb) {
|
public SafetyNetHelper(Activity activity, Callback cb) {
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
this.cb = cb;
|
callback = cb;
|
||||||
this.dexPath = dexPath;
|
|
||||||
responseCode = 0;
|
|
||||||
|
|
||||||
// Get theme
|
|
||||||
try {
|
|
||||||
Context context = activity.getApplicationContext();
|
|
||||||
Field theme = context.getClass().getField("isDarkTheme");
|
|
||||||
isDarkTheme = (boolean) theme.get(context);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry point to start test
|
// Entry point to start test
|
||||||
|
@Override
|
||||||
public void attest() {
|
public void attest() {
|
||||||
// Connect Google Service
|
// Connect Google Service
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
|
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
|
||||||
@ -74,26 +61,15 @@ public class SafetyNetHelper
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionSuspended(int i) {
|
public void onConnectionSuspended(int i) {
|
||||||
cb.onResponse(i);
|
callback.onResponse(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionFailed(@NonNull ConnectionResult result) {
|
public void onConnectionFailed(@NonNull ConnectionResult result) {
|
||||||
Class<? extends Activity> clazz = mActivity.getClass();
|
mActivity.swapResources(CheckSafetyNet.dexPath.getPath());
|
||||||
try {
|
|
||||||
// Use external resources
|
|
||||||
clazz.getMethod("swapResources", String.class, int.class).invoke(mActivity, dexPath,
|
|
||||||
isDarkTheme ? android.R.style.Theme_Material : android.R.style.Theme_Material_Light);
|
|
||||||
try {
|
|
||||||
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), mActivity, 0).show();
|
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), mActivity, 0).show();
|
||||||
} catch (Exception e) {
|
mActivity.restoreResources();
|
||||||
e.printStackTrace();
|
callback.onResponse(CONNECTION_FAIL);
|
||||||
}
|
|
||||||
clazz.getMethod("restoreResources").invoke(mActivity);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
cb.onResponse(CONNECTION_FAIL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,28 +79,28 @@ public class SafetyNetHelper
|
|||||||
new SecureRandom().nextBytes(nonce);
|
new SecureRandom().nextBytes(nonce);
|
||||||
|
|
||||||
// Call SafetyNet
|
// Call SafetyNet
|
||||||
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
|
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce).setResultCallback(this);
|
||||||
.setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() {
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResult(@NonNull SafetyNetApi.AttestationResult result) {
|
public void onResult(SafetyNetApi.AttestationResult result) {
|
||||||
Status status = result.getStatus();
|
int code = 0;
|
||||||
try {
|
try {
|
||||||
if (!status.isSuccess()) throw new JSONException("");
|
if (!result.getStatus().isSuccess())
|
||||||
String json = new String(Base64.decode(
|
throw new JSONException("");
|
||||||
|
String jsonStr = new String(Base64.decode(
|
||||||
result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
|
result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
|
||||||
JSONObject decoded = new JSONObject(json);
|
JSONObject json = new JSONObject(jsonStr);
|
||||||
responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
|
code |= json.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
|
||||||
responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
|
code |= json.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
responseCode = RESPONSE_ERR;
|
code = RESPONSE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect
|
// Disconnect
|
||||||
mGoogleApiClient.disconnect();
|
mGoogleApiClient.disconnect();
|
||||||
|
|
||||||
// Return results
|
// Return results
|
||||||
cb.onResponse(responseCode);
|
callback.onResponse(code);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user