Skip to content

Commit

Permalink
3.0.1
Browse files Browse the repository at this point in the history
Signed-off-by: tiann <twsxtd@gmail.com>
  • Loading branch information
tiann committed Jul 13, 2020
1 parent 1a660a9 commit f1a175e
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 76 deletions.
6 changes: 4 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ android {
compileSdkVersion 28
defaultConfig {
applicationId "me.weishu.freereflection.app"
minSdkVersion 15
targetSdkVersion 28
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"

signingConfig signingConfigs.debug
}
buildTypes {
release {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ public void onClick(View v) {
findViewById(R.id.unreal).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// int ret = Reflection.unseal(MainActivity.this);
// toast("unseal result: " + ret);
boolean exempt = Reflection.exemptAll();
toast("exempt result: " + exempt);
int ret = Reflection.unseal(MainActivity.this);
toast("unseal result: " + ret);
}
});
}
Expand Down
14 changes: 7 additions & 7 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 15
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
Expand All @@ -25,11 +25,11 @@ android {
}
}

externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
// externalNativeBuild {
// cmake {
// path "src/main/cpp/CMakeLists.txt"
// }
// }
lintOptions {
abortOnError false
}
Expand All @@ -48,7 +48,7 @@ publish {
userOrg = 'twsxtd'
groupId = 'me.weishu'
artifactId = 'free_reflection'
publishVersion = '2.2.0'
publishVersion = '3.0.1'
desc = 'Use Relection above Android P without any restriction'
website = 'https://github.com/tiann/FreeRelfection'
}
74 changes: 74 additions & 0 deletions library/src/main/java/me/weishu/reflection/BootstrapClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package me.weishu.reflection;

import android.os.Build;
import android.util.Log;

import java.lang.reflect.Method;

import static android.os.Build.VERSION.SDK_INT;

/**
* @author weishu
* @date 2020/7/13.
*/
public final class BootstrapClass {

private static final String TAG = "BootstrapClass";

private static Object sVmRuntime;
private static Method setHiddenApiExemptions;

static {
if (SDK_INT >= Build.VERSION_CODES.P) {
try {
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
sVmRuntime = getRuntime.invoke(null);
} catch (Throwable e) {
Log.w(TAG, "reflect bootstrap failed:", e);
}
}
}

/**
* make the method exempted from hidden API check.
*
* @param method the method signature prefix.
* @return true if success.
*/
public static boolean exempt(String method) {
return exempt(new String[]{method});
}

/**
* make specific methods exempted from hidden API check.
*
* @param methods the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L"
* @return true if success
*/
public static boolean exempt(String... methods) {
if (sVmRuntime == null || setHiddenApiExemptions == null) {
return false;
}

try {
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
return true;
} catch (Throwable e) {
return false;
}
}

/**
* Make all hidden API exempted.
*
* @return true if success.
*/
public static boolean exemptAll() {
return exempt(new String[]{"L"});
}
}
88 changes: 25 additions & 63 deletions library/src/main/java/me/weishu/reflection/Reflection.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package me.weishu.reflection;

import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.util.Base64;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Method;

import dalvik.system.DexFile;

import static android.os.Build.VERSION.SDK_INT;
import static me.weishu.reflection.BootstrapClass.exemptAll;

/**
* @author weishu
Expand All @@ -16,37 +20,10 @@
public class Reflection {
private static final String TAG = "Reflection";

private static Object sVmRuntime;
private static Method setHiddenApiExemptions;

static {
if (SDK_INT >= Build.VERSION_CODES.P) {
try {
Method forName = Class.class.getDeclaredMethod("forName", String.class);
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);

Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");
Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);
setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});
sVmRuntime = getRuntime.invoke(null);
} catch (Throwable e) {
Log.e(TAG, "reflect bootstrap failed:", e);
}
}

// System.loadLibrary("free-reflection");
}
private static final String DEX = "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TGFuZHJvaWQvdXRpbC9Mb2c7ABFMamF2YS9sYW5nL0NsYXNzOwAUTGphdmEvbGFuZy9DbGFzczwqPjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5c3RlbTsAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwAaTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsAJkxtZS93ZWlzaHUvZnJlZXJlZmxlY3Rpb24vQnVpbGRDb25maWc7ACVMbWUvd2Vpc2h1L3JlZmxlY3Rpb24vQm9vdHN0cmFwQ2xhc3M7ACFMbWUvd2Vpc2h1L3JlZmxlY3Rpb24vUmVmbGVjdGlvbjsAClJlZmxlY3Rpb24AD1JlZmxlY3Rpb24uamF2YQAHU0RLX0lOVAADVEFHAAFWAAxWRVJTSU9OX0NPREUADFZFUlNJT05fTkFNRQACVkwAAVoAAlpMABJbTGphdmEvbGFuZy9DbGFzczsAE1tMamF2YS9sYW5nL09iamVjdDsAE1tMamF2YS9sYW5nL1N0cmluZzsAB2NvbnRleHQAF2RhbHZpay5zeXN0ZW0uVk1SdW50aW1lAAFlAAZleGVtcHQACWV4ZW1wdEFsbAAHZm9yTmFtZQAPZnJlZS1yZWZsZWN0aW9uABJnZXRBcHBsaWNhdGlvbkluZm8AEWdldERlY2xhcmVkTWV0aG9kAApnZXRSdW50aW1lAAZpbnZva2UAC2xvYWRMaWJyYXJ5ABhtZS53ZWlzaHUuZnJlZXJlZmxlY3Rpb24ABm1ldGhvZAAHbWV0aG9kcwAZcmVmbGVjdCBib290c3RyYXAgZmFpbGVkOgAHcmVsZWFzZQAKc1ZtUnVudGltZQAWc2V0SGlkZGVuQXBpRXhlbXB0aW9ucwAQdGFyZ2V0U2RrVmVyc2lvbgAEdGhpcwAGdW5zZWFsAAx1bnNlYWxOYXRpdmUADnZtUnVudGltZUNsYXNzAAYABw4AFgAHDmr/AwEyCwEVEAMCNQvwBAREBhcBEg8DAzYLARsPqQUCBQMFBBkeAwAvCgAOAAcOACwBOgcOADYBOwcsnRriAQEDAC8KHgBIAAcOAA0ABw4AEwEtBx1yGWtaAAYXOBc8HxcABAEXAQEXBgEXHwYAAQACGQEZARkBGQEZARkGgYAEiAcDAAUACBoBCgEKB4iABKAHAYGABLQJAQnMCQGJAfQJAQnMCgEAAwALGgyBgAT4CgEJkAsBigIAAAAADgAAAAAAAAABAAAAAAAAAAEAAABEAAAAcAAAAAIAAAATAAAAgAEAAAMAAAALAAAAzAEAAAQAAAAMAAAAUAIAAAUAAAAPAAAAsAIAAAYAAAADAAAAKAMAAAEgAAAIAAAAiAMAAAEQAAAHAAAA3AUAAAIgAABEAAAAFgYAAAMgAAAIAAAAAwoAAAUgAAADAAAAZgoAAAAgAAADAAAAeAoAAAAQAAABAAAAyAoAAA==";

private static native int unsealNative(int targetSdkVersion);

private static int UNKNOWN = -9999;

private static final int ERROR_SET_APPLICATION_FAILED = -20;

private static final int ERROR_EXEMPT_FAILED = -21;

private static int unsealed = UNKNOWN;

public static int unseal(Context context) {
if (SDK_INT < 28) {
// Below Android P, ignore
Expand All @@ -56,46 +33,31 @@ public static int unseal(Context context) {
// try exempt API first.
if (exemptAll()) {
return 0;
} else {
return ERROR_EXEMPT_FAILED;
}
}
if (unsealByDexFile(context)) {
return 0;
}

/**
* make the method exempted from hidden API check.
*
* @param method the method signature prefix.
* @return true if success.
*/
public static boolean exempt(String method) {
return exempt(new String[]{method});
return -1;
}

/**
* make specific methods exempted from hidden API check.
*
* @param methods the method signature prefix, such as "Ldalvik/system", "Landroid" or even "L"
* @return true if success
*/
public static boolean exempt(String... methods) {
if (sVmRuntime == null || setHiddenApiExemptions == null) {
return false;
}

private static boolean unsealByDexFile(Context context) {
byte[] bytes = Base64.decode(DEX, Base64.NO_WRAP);
try {
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});
return true;
File codeCacheDir = context.getCodeCacheDir();
File code = new File(codeCacheDir, System.currentTimeMillis() + ".dex");

try(FileOutputStream fos = new FileOutputStream(code)) {
fos.write(bytes);
}

DexFile dexFile = new DexFile(code);
Class<?> bootstrapClass = dexFile.loadClass(BootstrapClass.class.getCanonicalName(), null);
Method exemptAll = bootstrapClass.getDeclaredMethod("exemptAll");
return (boolean) exemptAll.invoke(null);
} catch (Throwable e) {
e.printStackTrace();
return false;
}
}

/**
* Make all hidden API exempted.
*
* @return true if success.
*/
public static boolean exemptAll() {
return exempt(new String[]{"L"});
}
}

0 comments on commit f1a175e

Please sign in to comment.