diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt index 78b699f4..25612577 100644 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt @@ -263,6 +263,12 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { packageName = PackageName.YukiHookBridge_Impl, content = data.sources()[ClassName.YukiHookBridge_Impl] ) + /** 插入 YukiHookModuleStatus_Impl 代码 */ + createCodeFile( + fileName = ClassName.YukiHookModuleStatus_Impl, + packageName = PackageName.YukiHookModuleStatus_Impl, + content = data.sources()[ClassName.YukiHookModuleStatus_Impl] + ) /** 插入 xposed_init 代码 */ createCodeFile( fileName = data.xInitClassName, @@ -275,6 +281,20 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { packageName = data.entryPackageName, content = data.sources()[ClassName.XposedInit_Impl] ) + /* 插入 FreeReflection 代码 */ + createCodeFile( + fileName = ClassName.BootstrapClass, + packageName = PackageName.BootstrapReflectionClass, + content = data.sources()[ClassName.BootstrapClass], + extensionName = JAVA_FILE_EXT_NAME + ) + /* 插入 FreeReflection 代码 */ + createCodeFile( + fileName = ClassName.Reflection, + packageName = PackageName.BootstrapReflectionClass, + content = data.sources()[ClassName.Reflection], + extensionName = JAVA_FILE_EXT_NAME + ) } /** diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt index 39401d60..1b5bd649 100644 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt @@ -37,6 +37,8 @@ import java.util.* object PackageName { const val ModuleApplication_Impl = "com.highcapable.yukihookapi.hook.xposed.application" const val YukiHookBridge_Impl = "com.highcapable.yukihookapi.hook.xposed.bridge" + const val YukiHookModuleStatus_Impl = "com.highcapable.yukihookapi.hook.xposed.bridge.status" + const val BootstrapReflectionClass = "com.highcapable.yukihookapi.thirdparty.me.weishu.reflection" } /** @@ -45,8 +47,21 @@ object PackageName { object ClassName { const val ModuleApplication_Impl = "ModuleApplication_Impl" const val YukiHookBridge_Impl = "YukiHookBridge_Impl" + const val YukiHookModuleStatus_Impl = "YukiHookModuleStatus_Impl" const val XposedInit = "xposed_init" const val XposedInit_Impl = "xposed_init_Impl" + const val BootstrapClass = "BootstrapClass" + const val Reflection = "Reflection" +} + +/** + * YukiHookModuleStatus 方法名称定义类 + */ +object YukiHookModuleStatusJvmName { + const val IS_ACTIVE_METHOD_NAME = "__--" + const val HAS_RESOURCES_HOOK_METHOD_NAME = "_--_" + const val GET_XPOSED_VERSION_METHOD_NAME = "--__" + const val GET_XPOSED_TAG_METHOD_NAME = "_-_-" } /** @@ -64,7 +79,7 @@ private fun createCommentContent(entryClassName: String = "", currrentClassTag: (if (entryClassName.isNotBlank()) " * HookEntryClass: [$entryClassName]\n *\n" else "") + " * Generate Date: ${SimpleDateFormat.getDateTimeInstance().format(Date())}\n" + " *\n" + - " * Powered by YukiHookAPI (C) HighCapable 2022\n" + + " * Powered by YukiHookAPI (C) HighCapable 2019-2022\n" + " *\n" + " * Project Address: [YukiHookAPI](https://github.com/fankes/YukiHookAPI)\n" + " */\n") @@ -97,6 +112,28 @@ fun GenerateData.sources() = mapOf( "\n" + " val compiledTimestamp get() = ${System.currentTimeMillis()}\n" + "}"), + ClassName.YukiHookModuleStatus_Impl to ("@file:Suppress(\"ClassName\")\n" + + "\n" + + "package com.highcapable.yukihookapi.hook.xposed.bridge.status\n" + + "\n" + + "import androidx.annotation.Keep\n" + + "\n" + + createCommentContent(currrentClassTag = ClassName.YukiHookModuleStatus_Impl) + + "@Keep\n" + + "object YukiHookModuleStatus_Impl {\n" + + "\n" + + " @JvmName(\"${YukiHookModuleStatusJvmName.IS_ACTIVE_METHOD_NAME}\")\n" + + " fun isActive() = false\n" + + "\n" + + " @JvmName(\"${YukiHookModuleStatusJvmName.HAS_RESOURCES_HOOK_METHOD_NAME}\")\n" + + " fun hasResourcesHook() = false\n" + + "\n" + + " @JvmName(\"${YukiHookModuleStatusJvmName.GET_XPOSED_VERSION_METHOD_NAME}\")\n" + + " fun getXposedVersion() = -1\n" + + "\n" + + " @JvmName(\"${YukiHookModuleStatusJvmName.GET_XPOSED_TAG_METHOD_NAME}\")\n" + + " fun getXposedBridgeTag() = \"unknown\"\n" + + "}"), ClassName.XposedInit to ("@file:Suppress(\"ClassName\")\n" + "\n" + "package $entryPackageName\n" + @@ -192,5 +229,149 @@ fun GenerateData.sources() = mapOf( " fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + " if (resparam != null) callXposedLoaded(resparam = resparam)\n" + " }\n" + + "}"), + ClassName.BootstrapClass to ("package ${PackageName.BootstrapReflectionClass};\n" + + "\n" + + "import static android.os.Build.VERSION.SDK_INT;\n" + + "\n" + + "import android.os.Build;\n" + + "import android.util.Log;\n" + + "\n" + + "import androidx.annotation.Keep;\n" + + "\n" + + "import java.lang.reflect.Method;\n" + + "\n" + + createCommentContent(currrentClassTag = ClassName.BootstrapClass) + + "@Keep\n" + + "public final class BootstrapClass {\n" + + "\n" + + " private static final String TAG = \"BootstrapClass\";\n" + + "\n" + + " private static Object sVmRuntime;\n" + + " private static Method setHiddenApiExemptions;\n" + + "\n" + + " static {\n" + + " if (SDK_INT >= Build.VERSION_CODES.P) {\n" + + " try {\n" + + " Method forName = Class.class.getDeclaredMethod(\"forName\", String.class);\n" + + " Method getDeclaredMethod = Class.class.getDeclaredMethod(\"getDeclaredMethod\", String.class, Class[].class);\n" + + " Class vmRuntimeClass = (Class) forName.invoke(null, \"dalvik.system.VMRuntime\");\n" + + " Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, \"getRuntime\", null);\n" + + " setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, \"setHiddenApiExemptions\", new Class[]{String[].class});\n" + + " sVmRuntime = getRuntime.invoke(null);\n" + + " } catch (Throwable e) {\n" + + " Log.w(TAG, \"reflect bootstrap failed:\", e);\n" + + " }\n" + + " }\n" + + " }\n" + + "\n" + + " public static boolean exempt(String method) {\n" + + " return exempt(new String[]{method});\n" + + " }\n" + + "\n" + + " public static boolean exempt(String... methods) {\n" + + " if (sVmRuntime == null || setHiddenApiExemptions == null) {\n" + + " return false;\n" + + " }\n" + + "\n" + + " try {\n" + + " setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{methods});\n" + + " return true;\n" + + " } catch (Throwable e) {\n" + + " return false;\n" + + " }\n" + + " }\n" + + "\n" + + " public static boolean exemptAll() {\n" + + " return exempt(new String[]{\"L\"});\n" + + " }\n" + + "}"), + ClassName.Reflection to ("package ${PackageName.BootstrapReflectionClass};\n" + + "\n" + + "import static android.os.Build.VERSION.SDK_INT;\n" + + "import static com.highcapable.yukihookapi.thirdparty.me.weishu.reflection.BootstrapClass.exemptAll;\n" + + "\n" + + "import android.content.Context;\n" + + "import android.text.TextUtils;\n" + + "import android.util.Base64;\n" + + "\n" + + "import androidx.annotation.Keep;\n" + + "\n" + + "import java.io.File;\n" + + "import java.io.FileOutputStream;\n" + + "import java.lang.reflect.Method;\n" + + "\n" + + "import dalvik.system.DexFile;\n" + + "\n" + + createCommentContent(currrentClassTag = ClassName.Reflection) + + "@Keep\n" + + "public class Reflection {\n" + + " private static final String TAG = \"Reflection\";\n" + + "\n" + + " private static final String DEX = \"ZGV4CjAzNQCXDT0vQ44GJqsrjm32y0qlQmxUevbk56r0CwAAcAAAAHhWNBIAAAAAAAAAADwLAABDAAAAcAAAABMAAAB8AQAACwAAAMgBAAAMAAAATAIAAA8AAACsAgAAAwAAACQDAABwCAAAhAMAAIQDAACGAwAAiwMAAJUDAACdAwAArQMAALkDAADJAwAA3gMAAPADAAD3AwAA/wMAAAIEAAAGBAAACgQAABAEAAATBAAAGAQAADMEAABZBAAAdQQAAIkEAADYBAAAJgUAAHAFAACDBQAAmQUAAK0FAADBBQAA1QUAAOwFAAAIBgAAFAYAACUGAAAuBgAAMwYAADYGAABEBgAAUgYAAFYGAABZBgAAXQYAAHEGAACGBgAAmwYAAKQGAAC9BgAAwAYAAMgGAADTBgAA3AYAAO0GAAABBwAAFAcAACAHAAAoBwAANQcAAE8HAABXBwAAYAcAAHsHAACEBwAAkAcAAKgHAAC6BwAAwgcAANAHAAALAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAaAAAAGwAAABwAAAAdAAAAHgAAACMAAAAnAAAAKQAAACoAAAArAAAADAAAAAAAAAD4BwAADQAAAAAAAAAMCAAADgAAAAAAAAAACAAADwAAAAIAAAAAAAAAEAAAAAkAAAAUCAAAEAAAAA0AAADoBwAAIwAAAA4AAAAAAAAAJgAAAA4AAADgBwAAJwAAAA8AAAAAAAAAKAAAAA8AAADgBwAAKAAAAA8AAADwBwAAAgAAAD8AAAADAAAAIQAAAAUACgAEAAAABQAKAAUAAAAFAA8ACQAAAAUACgAKAAAABQAAACQAAAAFAAoAJQAAAAYACgAiAAAABgAJAD0AAAAGAA0APgAAAAcACgAiAAAAAQADADMAAAAEAAIALgAAAAUABgADAAAABgAGAAIAAAAGAAYAAwAAAAYACQAvAAAABgAKAC8AAAAGAAgAMAAAAAcABgADAAAABwABAEAAAAAHAAAAQQAAAAgABQA0AAAACQAGAAMAAAALAAcANwAAAA0ABAA2AAAABQAAABEAAAAJAAAAAAAAAAgAAAAAAAAA7AoAAB8IAAAGAAAAEQAAAAkAAAAAAAAABwAAAAAAAAACCwAAHAgAAAcAAAABAAAACQAAAAAAAAAgAAAAAAAAACULAAArCAAAAAADMS4wAAg8Y2xpbml0PgAGPGluaXQ+AA5BUFBMSUNBVElPTl9JRAAKQlVJTERfVFlQRQAOQm9vdHN0cmFwQ2xhc3MAE0Jvb3RzdHJhcENsYXNzLmphdmEAEEJ1aWxkQ29uZmlnLmphdmEABURFQlVHAAZGTEFWT1IAAUkAAklJAAJJTAAESUxMTAABTAADTExMABlMYW5kcm9pZC9jb250ZW50L0NvbnRleHQ7ACRMYW5kcm9pZC9jb250ZW50L3BtL0FwcGxpY2F0aW9uSW5mbzsAGkxhbmRyb2lkL29zL0J1aWxkJFZFUlNJT047ABJMYW5kcm9pZC91dGlsL0xvZzsATUxjb20vaGlnaGNhcGFibGUveXVraWhvb2thcGkvdGhpcmRwYXJ0eS9tZS93ZWlzaHUvZnJlZXJlZmxlY3Rpb24vQnVpbGRDb25maWc7AExMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vQm9vdHN0cmFwQ2xhc3M7AEhMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vUmVmbGVjdGlvbjsAEUxqYXZhL2xhbmcvQ2xhc3M7ABRMamF2YS9sYW5nL0NsYXNzPCo+OwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwAKUmVmbGVjdGlvbgAPUmVmbGVjdGlvbi5qYXZhAAdTREtfSU5UAANUQUcAAVYADFZFUlNJT05fQ09ERQAMVkVSU0lPTl9OQU1FAAJWTAABWgACWkwAEltMamF2YS9sYW5nL0NsYXNzOwATW0xqYXZhL2xhbmcvT2JqZWN0OwATW0xqYXZhL2xhbmcvU3RyaW5nOwAHY29udGV4dAAXZGFsdmlrLnN5c3RlbS5WTVJ1bnRpbWUAAWUABmV4ZW1wdAAJZXhlbXB0QWxsAAdmb3JOYW1lAA9mcmVlLXJlZmxlY3Rpb24AEmdldEFwcGxpY2F0aW9uSW5mbwARZ2V0RGVjbGFyZWRNZXRob2QACmdldFJ1bnRpbWUABmludm9rZQALbG9hZExpYnJhcnkAGG1lLndlaXNodS5mcmVlcmVmbGVjdGlvbgAGbWV0aG9kAAdtZXRob2RzABlyZWZsZWN0IGJvb3RzdHJhcCBmYWlsZWQ6AAdyZWxlYXNlAApzVm1SdW50aW1lABZzZXRIaWRkZW5BcGlFeGVtcHRpb25zABB0YXJnZXRTZGtWZXJzaW9uAAZ1bnNlYWwADHVuc2VhbE5hdGl2ZQAOdm1SdW50aW1lQ2xhc3MAAQAAAAoAAAACAAAACgAQAAEAAAASAAAAAQAAAAAAAAADAAAACgAKAAwAAAABAAAAAQAAAAIAAAAJABEAARcGBhc4FzwfFwAEARcBARcfAAAAAAAABgAHDgAWAAcOav8DATIOARUQAwI1DvAEBEMJGgESDwMDNg4BGw+pBQIFAwUEGR4DAC8NAA4ABw4ALAE6Bw4ANgE7ByydGuIBAQMALw0eAEgABw4ADQAHDgATAS0HHXIZa1oAAAEAAQABAAAANAgAAAQAAABwEAwAAAAOAAoAAAADAAEAOQgAAHsAAABgBQEAEwYcADRlbQAcBQgAGgYxABIXI3cQABIIHAkKAE0JBwhuMAsAZQcMARwFCAAaBjQAEicjdxAAEggcCQoATQkHCBIYHAkQAE0JBwhuMAsAZQcMAhIFEhYjZhEAEgcaCC0ATQgGB24wDgBRBgwEHwQIABIlI1URABIGGgc1AE0HBQYSFhIHTQcFBm4wDgBCBQwDHwMNABIlI1URABIGGgc+AE0HBQYSFhIXI3cQABIIHAkSAE0JBwhNBwUGbjAOAEIFDAUfBQ0AaQUKABIFEgYjZhEAbjAOAFMGDAVpBQkADgANABoFBgAaBjsAcTABAGUAKPcAAAYAAABrAAEAAQEMcgEAAQABAAAAaAgAAAQAAABwEAwAAAAOAAMAAQABAAAAbQgAAAsAAAASECMAEgASAU0CAAFxEAYAAAAKAA8AAAAIAAEAAwABAHMIAAAdAAAAEhESAmIDCQA4AwYAYgMKADkDBAABIQ8BYgMKAGIECQASFSNVEQASBk0HBQZuMA4AQwUo8g0AASEo7wAADAAAAA0AAQABAQwaAwAAAAEAAACDCAAADQAAABIQIwASABIBGgIPAE0CAAFxEAYAAAAKAA8AAAABAAEAAQAAAIgIAAAEAAAAcBAMAAAADgAEAAEAAQAAAI0IAAAeAAAAEgBgAQEAEwIcADUhAwAPAHEABwAAAAoBOQH7/xoAMgBxEA0AAABuEAAAAwAMAFIAAABxEAoAAAAKACjqBgABAAIZARkBGQEZARkBGQKBgASYEQMABQAIGgEKAQoDiIAEsBEBgYAExBMBCdwTAYkBhBQBCdwUAQADAAsaCIGABIgVAQmgFQGKAgAAAAAPAAAAAAAAAAEAAAAAAAAAAQAAAEMAAABwAAAAAgAAABMAAAB8AQAAAwAAAAsAAADIAQAABAAAAAwAAABMAgAABQAAAA8AAACsAgAABgAAAAMAAAAkAwAAAiAAAEMAAACEAwAAARAAAAcAAADgBwAABSAAAAMAAAAcCAAAAxAAAAEAAAAwCAAAAyAAAAgAAAA0CAAAASAAAAgAAACYCAAAACAAAAMAAADsCgAAABAAAAEAAAA8CwAA\";\n" + + "\n" + + " private static native int unsealNative(int targetSdkVersion);\n" + + "\n" + + " public static int unseal(Context context) {\n" + + " if (SDK_INT < 28) {\n" + + " // Below Android P, ignore\n" + + " return 0;\n" + + " }\n" + + "\n" + + " // try exempt API first.\n" + + " if (exemptAll()) {\n" + + " return 0;\n" + + " }\n" + + " if (unsealByDexFile(context)) {\n" + + " return 0;\n" + + " }\n" + + "\n" + + " return -1;\n" + + " }\n" + + "\n" + + " @SuppressWarnings({\"deprecation\", \"ResultOfMethodCallIgnored\"})\n" + + " private static boolean unsealByDexFile(Context context) {\n" + + " byte[] bytes = Base64.decode(DEX, Base64.NO_WRAP);\n" + + " File codeCacheDir = getCodeCacheDir(context);\n" + + " if (codeCacheDir == null) {\n" + + " return false;\n" + + " }\n" + + " File code = new File(codeCacheDir, \"__temp_\" + System.currentTimeMillis() + \".dex\");\n" + + " try {\n" + + "\n" + + " try (FileOutputStream fos = new FileOutputStream(code)) {\n" + + " fos.write(bytes);\n" + + " }\n" + + "\n" + + " DexFile dexFile = new DexFile(code);\n" + + " // This class is hardcoded in the dex, Don't use BootstrapClass.class to reference it\n" + + " // it maybe obfuscated!!\n" + + " Class bootstrapClass = dexFile.loadClass(\"com.highcapable.yukihookapi.thirdparty.me.weishu.reflection.BootstrapClass\", null);\n" + + " Method exemptAll = bootstrapClass.getDeclaredMethod(\"exemptAll\");\n" + + " return (boolean) exemptAll.invoke(null);\n" + + " } catch (Throwable e) {\n" + + " e.printStackTrace();\n" + + " return false;\n" + + " } finally {\n" + + " if (code.exists()) {\n" + + " code.delete();\n" + + " }\n" + + " }\n" + + " }\n" + + "\n" + + " private static File getCodeCacheDir(Context context) {\n" + + " if (context != null) {\n" + + " return context.getCodeCacheDir();\n" + + " }\n" + + " String tmpDir = System.getProperty(\"java.io.tmpdir\");\n" + + " if (TextUtils.isEmpty(tmpDir)) {\n" + + " return null;\n" + + " }\n" + + " File tmp = new File(tmpDir);\n" + + " if (!tmp.exists()) {\n" + + " return null;\n" + + " }\n" + + " return tmp;\n" + + " }\n" + "}") ) \ No newline at end of file diff --git a/yukihookapi-stub/build.gradle b/yukihookapi-stub/build.gradle index 9029f9c5..ff154fb9 100644 --- a/yukihookapi-stub/build.gradle +++ b/yukihookapi-stub/build.gradle @@ -6,4 +6,10 @@ plugins { java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 +} + +dependencies { + // Used 82 API Version + compileOnly 'de.robv.android.xposed:api:82' + compileOnly fileTree(include: ['*.jar'], dir: '../yukihookapi/libs') } \ No newline at end of file diff --git a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt new file mode 100644 index 00000000..3347825f --- /dev/null +++ b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus_Impl.kt @@ -0,0 +1,86 @@ +/* + * YukiHookAPI - An efficient Kotlin version of the Xposed Hook API. + * Copyright (C) 2019-2022 HighCapable + * https://github.com/fankes/YukiHookAPI + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * This file is Created by fankes on 2023/1/1. + */ +@file:Suppress("ClassName") + +package com.highcapable.yukihookapi.hook.xposed.bridge.status + +import de.robv.android.xposed.XposedBridge + +/** + * YukiHookModuleStatus 注入 Stub + */ +object YukiHookModuleStatus_Impl { + + /** 定义 Jvm 方法名 */ + private const val IS_ACTIVE_METHOD_NAME = "__--" + + /** 定义 Jvm 方法名 */ + private const val HAS_RESOURCES_HOOK_METHOD_NAME = "_--_" + + /** 定义 Jvm 方法名 */ + private const val GET_XPOSED_VERSION_METHOD_NAME = "--__" + + /** 定义 Jvm 方法名 */ + private const val GET_XPOSED_TAG_METHOD_NAME = "_-_-" + + /** + * 此方法经过 Hook 后返回 true 即模块已激活 + * + * 返回值将在每次编译时自动生成 + * @return [Boolean] + */ + @JvmName(IS_ACTIVE_METHOD_NAME) + fun isActive(): Boolean = error("Stub!") + + /** + * 此方法经过 Hook 后返回 true 即当前 Hook Framework 支持资源钩子(Resources Hook) + * + * 返回值将在每次编译时自动生成 + * @return [Boolean] + */ + @JvmName(HAS_RESOURCES_HOOK_METHOD_NAME) + fun hasResourcesHook(): Boolean = error("Stub!") + + /** + * 此方法经过 Hook 后返回 [XposedBridge.getXposedVersion] + * + * 返回值将在每次编译时自动生成 + * @return [Int] + */ + @JvmName(GET_XPOSED_VERSION_METHOD_NAME) + fun getXposedVersion(): Int = error("Stub!") + + /** + * 此方法经过 Hook 后返回 [XposedBridge] 的 TAG + * + * 返回值将在每次编译时自动生成 + * @return [String] + */ + @JvmName(GET_XPOSED_TAG_METHOD_NAME) + fun getXposedBridgeTag(): String = error("Stub!") +} \ No newline at end of file diff --git a/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java new file mode 100644 index 00000000..33ef03de --- /dev/null +++ b/yukihookapi-stub/src/main/java/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java @@ -0,0 +1,50 @@ +/* + * YukiHookAPI - An efficient Kotlin version of the Xposed Hook API. + * Copyright (C) 2019-2022 HighCapable + * https://github.com/fankes/YukiHookAPI + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * This file is Created by weishu on 2018/6/7. + * This file is Forked from https://github.com/tiann/FreeReflection and make it to stub + */ +package com.highcapable.yukihookapi.thirdparty.me.weishu.reflection; + +import android.content.Context; + +/** + * FreeReflection 注入 Stub + */ +@SuppressWarnings("unused") +public class Reflection { + + /** + * 调用启动方法 + *

+ * 方法内容将在每次编译时自动生成 + * + * @param context The Base Context + * @return int + */ + public static int unseal(Context context) { + throw new RuntimeException("Stub!"); + } +} \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt index 0e57d9bb..d901c9ea 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/factory/ReflectionFactory.kt @@ -421,7 +421,7 @@ inline fun Class<*>.allFields(isAccessible: Boolean = true, result: (index: Int, */ @PublishedApi internal fun Class<*>.checkingInternal() { - if (name == classOf().name) return + if (name == YukiHookModuleStatus.IMPL_CLASS_NAME) return if (name == classOf().name || name.startsWith("com.highcapable.yukihookapi.hook")) throw RuntimeException( "!!!DO NOT ALLOWED!!! You cannot hook or reflection to call the internal class of the YukiHookAPI itself, " + "The called class is [$this]" diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt index 2692b0fe..3e656d99 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/application/ModuleApplication.kt @@ -75,7 +75,7 @@ open class ModuleApplication : Application() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) - Reflection.unseal(base) + runCatching { Reflection.unseal(base) } } override fun onCreate() { diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt index 9369188f..9174098c 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/bridge/status/YukiHookModuleStatus.kt @@ -27,9 +27,7 @@ */ package com.highcapable.yukihookapi.hook.xposed.bridge.status -import androidx.annotation.Keep import com.highcapable.yukihookapi.YukiHookAPI -import com.highcapable.yukihookapi.hook.log.yLoggerD import de.robv.android.xposed.XposedBridge /** @@ -65,6 +63,9 @@ internal object YukiHookModuleStatus { /** 定义 Jvm 方法名 */ internal const val GET_XPOSED_TAG_METHOD_NAME = "_-_-" + /** [YukiHookModuleStatus_Impl] 完整类名 */ + internal const val IMPL_CLASS_NAME = "com.highcapable.yukihookapi.hook.xposed.bridge.status.YukiHookModuleStatus_Impl" + /** * 获取当前 Hook 框架的名称 * @@ -73,7 +74,10 @@ internal object YukiHookModuleStatus { * 请使用 [YukiHookAPI.Status.executorName] 获取 * @return [String] 模块未激活会返回 unknown */ - internal val executorName get() = getXposedBridgeTag().replace("Bridge", "").replace("-", "").trim() + internal val executorName + get() = runCatching { + YukiHookModuleStatus_Impl.getXposedBridgeTag().replace("Bridge", "").replace("-", "").trim() + }.getOrNull() ?: "unknown" /** * 获取当前 Hook 框架的版本 @@ -83,7 +87,7 @@ internal object YukiHookModuleStatus { * 请使用 [YukiHookAPI.Status.executorVersion] 获取 * @return [Int] 模块未激活会返回 -1 */ - internal val executorVersion get() = getXposedVersion() + internal val executorVersion get() = runCatching { YukiHookModuleStatus_Impl.getXposedVersion() }.getOrNull() ?: -1 /** * 此方法经过 Hook 后返回 true 即模块已激活 @@ -91,12 +95,7 @@ internal object YukiHookModuleStatus { * 请使用 [YukiHookAPI.Status.isModuleActive]、[YukiHookAPI.Status.isXposedModuleActive]、[YukiHookAPI.Status.isTaiChiModuleActive] 判断模块激活状态 * @return [Boolean] */ - @Keep - @JvmName(IS_ACTIVE_METHOD_NAME) - internal fun isActive(): Boolean { - yLoggerD(msg = IS_ACTIVE_METHOD_NAME, isDisableLog = true) - return false - } + internal fun isActive() = runCatching { YukiHookModuleStatus_Impl.isActive() }.getOrNull() ?: false /** * 此方法经过 Hook 后返回 true 即当前 Hook Framework 支持资源钩子(Resources Hook) @@ -104,32 +103,5 @@ internal object YukiHookModuleStatus { * 请使用 [YukiHookAPI.Status.isSupportResourcesHook] 判断支持状态 * @return [Boolean] */ - @Keep - @JvmName(HAS_RESOURCES_HOOK_METHOD_NAME) - internal fun hasResourcesHook(): Boolean { - yLoggerD(msg = HAS_RESOURCES_HOOK_METHOD_NAME, isDisableLog = true) - return false - } - - /** - * 此方法经过 Hook 后返回 [XposedBridge.getXposedVersion] - * @return [Int] - */ - @Keep - @JvmName(GET_XPOSED_VERSION_METHOD_NAME) - private fun getXposedVersion(): Int { - yLoggerD(msg = GET_XPOSED_VERSION_METHOD_NAME, isDisableLog = true) - return -1 - } - - /** - * 此方法经过 Hook 后返回 [XposedBridge] 的 TAG - * @return [String] - */ - @Keep - @JvmName(GET_XPOSED_TAG_METHOD_NAME) - private fun getXposedBridgeTag(): String { - yLoggerD(msg = GET_XPOSED_TAG_METHOD_NAME, isDisableLog = true) - return "unknown" - } + internal fun hasResourcesHook() = runCatching { YukiHookModuleStatus_Impl.hasResourcesHook() }.getOrNull() ?: false } \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt index e04b0feb..43ffad42 100644 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt +++ b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/hook/xposed/parasitic/AppParasitics.kt @@ -148,7 +148,7 @@ internal object AppParasitics { if ((param.args?.get(0) as? String?)?.endsWith("preferences.xml") == true) param.args?.set(1, 1) } }) - if (YukiHookAPI.Configs.isEnableHookModuleStatus) classOf(loader).apply { + if (YukiHookAPI.Configs.isEnableHookModuleStatus) YukiHookModuleStatus.IMPL_CLASS_NAME.toClassOrNull(loader)?.apply { if (type != HookEntryType.RESOURCES) { YukiHookHelper.hook(method { name = YukiHookModuleStatus.IS_ACTIVE_METHOD_NAME }, object : YukiMemberReplacement() { override fun replaceHookedMember(param: Param) = true diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/BootstrapClass.java b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/BootstrapClass.java deleted file mode 100644 index 69ec05be..00000000 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/BootstrapClass.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * YukiHookAPI - An efficient Kotlin version of the Xposed Hook API. - * Copyright (C) 2019-2022 HighCapable - * https://github.com/fankes/YukiHookAPI - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * This file is Created by weishu on 2020/7/13. - * This file is Forked from https://github.com/tiann/FreeReflection - */ -package com.highcapable.yukihookapi.thirdparty.me.weishu.reflection; - -import static android.os.Build.VERSION.SDK_INT; - -import android.os.Build; -import android.util.Log; - -import androidx.annotation.Keep; - -import java.lang.reflect.Method; - -/** - * NO ANNOTATION - */ -@SuppressWarnings("unused") -@Keep -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"}); - } -} \ No newline at end of file diff --git a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java b/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java deleted file mode 100644 index c1c0c524..00000000 --- a/yukihookapi/src/api/kotlin/com/highcapable/yukihookapi/thirdparty/me/weishu/reflection/Reflection.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * YukiHookAPI - An efficient Kotlin version of the Xposed Hook API. - * Copyright (C) 2019-2022 HighCapable - * https://github.com/fankes/YukiHookAPI - * - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * This file is Created by weishu on 2018/6/7. - * This file is Forked from https://github.com/tiann/FreeReflection - */ -package com.highcapable.yukihookapi.thirdparty.me.weishu.reflection; - -import static android.os.Build.VERSION.SDK_INT; -import static com.highcapable.yukihookapi.thirdparty.me.weishu.reflection.BootstrapClass.exemptAll; - -import android.content.Context; -import android.text.TextUtils; -import android.util.Base64; - -import androidx.annotation.Keep; - -import java.io.File; -import java.io.FileOutputStream; -import java.lang.reflect.Method; - -import dalvik.system.DexFile; - -/** - * NO ANNOTATION - */ -@SuppressWarnings("unused") -@Keep -public class Reflection { - private static final String TAG = "Reflection"; - - private static final String DEX = "ZGV4CjAzNQCXDT0vQ44GJqsrjm32y0qlQmxUevbk56r0CwAAcAAAAHhWNBIAAAAAAAAAADwLAABDAAAAcAAAABMAAAB8AQAACwAAAMgBAAAMAAAATAIAAA8AAACsAgAAAwAAACQDAABwCAAAhAMAAIQDAACGAwAAiwMAAJUDAACdAwAArQMAALkDAADJAwAA3gMAAPADAAD3AwAA/wMAAAIEAAAGBAAACgQAABAEAAATBAAAGAQAADMEAABZBAAAdQQAAIkEAADYBAAAJgUAAHAFAACDBQAAmQUAAK0FAADBBQAA1QUAAOwFAAAIBgAAFAYAACUGAAAuBgAAMwYAADYGAABEBgAAUgYAAFYGAABZBgAAXQYAAHEGAACGBgAAmwYAAKQGAAC9BgAAwAYAAMgGAADTBgAA3AYAAO0GAAABBwAAFAcAACAHAAAoBwAANQcAAE8HAABXBwAAYAcAAHsHAACEBwAAkAcAAKgHAAC6BwAAwgcAANAHAAALAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAaAAAAGwAAABwAAAAdAAAAHgAAACMAAAAnAAAAKQAAACoAAAArAAAADAAAAAAAAAD4BwAADQAAAAAAAAAMCAAADgAAAAAAAAAACAAADwAAAAIAAAAAAAAAEAAAAAkAAAAUCAAAEAAAAA0AAADoBwAAIwAAAA4AAAAAAAAAJgAAAA4AAADgBwAAJwAAAA8AAAAAAAAAKAAAAA8AAADgBwAAKAAAAA8AAADwBwAAAgAAAD8AAAADAAAAIQAAAAUACgAEAAAABQAKAAUAAAAFAA8ACQAAAAUACgAKAAAABQAAACQAAAAFAAoAJQAAAAYACgAiAAAABgAJAD0AAAAGAA0APgAAAAcACgAiAAAAAQADADMAAAAEAAIALgAAAAUABgADAAAABgAGAAIAAAAGAAYAAwAAAAYACQAvAAAABgAKAC8AAAAGAAgAMAAAAAcABgADAAAABwABAEAAAAAHAAAAQQAAAAgABQA0AAAACQAGAAMAAAALAAcANwAAAA0ABAA2AAAABQAAABEAAAAJAAAAAAAAAAgAAAAAAAAA7AoAAB8IAAAGAAAAEQAAAAkAAAAAAAAABwAAAAAAAAACCwAAHAgAAAcAAAABAAAACQAAAAAAAAAgAAAAAAAAACULAAArCAAAAAADMS4wAAg8Y2xpbml0PgAGPGluaXQ+AA5BUFBMSUNBVElPTl9JRAAKQlVJTERfVFlQRQAOQm9vdHN0cmFwQ2xhc3MAE0Jvb3RzdHJhcENsYXNzLmphdmEAEEJ1aWxkQ29uZmlnLmphdmEABURFQlVHAAZGTEFWT1IAAUkAAklJAAJJTAAESUxMTAABTAADTExMABlMYW5kcm9pZC9jb250ZW50L0NvbnRleHQ7ACRMYW5kcm9pZC9jb250ZW50L3BtL0FwcGxpY2F0aW9uSW5mbzsAGkxhbmRyb2lkL29zL0J1aWxkJFZFUlNJT047ABJMYW5kcm9pZC91dGlsL0xvZzsATUxjb20vaGlnaGNhcGFibGUveXVraWhvb2thcGkvdGhpcmRwYXJ0eS9tZS93ZWlzaHUvZnJlZXJlZmxlY3Rpb24vQnVpbGRDb25maWc7AExMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vQm9vdHN0cmFwQ2xhc3M7AEhMY29tL2hpZ2hjYXBhYmxlL3l1a2lob29rYXBpL3RoaXJkcGFydHkvbWUvd2Vpc2h1L3JlZmxlY3Rpb24vUmVmbGVjdGlvbjsAEUxqYXZhL2xhbmcvQ2xhc3M7ABRMamF2YS9sYW5nL0NsYXNzPCo+OwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwAKUmVmbGVjdGlvbgAPUmVmbGVjdGlvbi5qYXZhAAdTREtfSU5UAANUQUcAAVYADFZFUlNJT05fQ09ERQAMVkVSU0lPTl9OQU1FAAJWTAABWgACWkwAEltMamF2YS9sYW5nL0NsYXNzOwATW0xqYXZhL2xhbmcvT2JqZWN0OwATW0xqYXZhL2xhbmcvU3RyaW5nOwAHY29udGV4dAAXZGFsdmlrLnN5c3RlbS5WTVJ1bnRpbWUAAWUABmV4ZW1wdAAJZXhlbXB0QWxsAAdmb3JOYW1lAA9mcmVlLXJlZmxlY3Rpb24AEmdldEFwcGxpY2F0aW9uSW5mbwARZ2V0RGVjbGFyZWRNZXRob2QACmdldFJ1bnRpbWUABmludm9rZQALbG9hZExpYnJhcnkAGG1lLndlaXNodS5mcmVlcmVmbGVjdGlvbgAGbWV0aG9kAAdtZXRob2RzABlyZWZsZWN0IGJvb3RzdHJhcCBmYWlsZWQ6AAdyZWxlYXNlAApzVm1SdW50aW1lABZzZXRIaWRkZW5BcGlFeGVtcHRpb25zABB0YXJnZXRTZGtWZXJzaW9uAAZ1bnNlYWwADHVuc2VhbE5hdGl2ZQAOdm1SdW50aW1lQ2xhc3MAAQAAAAoAAAACAAAACgAQAAEAAAASAAAAAQAAAAAAAAADAAAACgAKAAwAAAABAAAAAQAAAAIAAAAJABEAARcGBhc4FzwfFwAEARcBARcfAAAAAAAABgAHDgAWAAcOav8DATIOARUQAwI1DvAEBEMJGgESDwMDNg4BGw+pBQIFAwUEGR4DAC8NAA4ABw4ALAE6Bw4ANgE7ByydGuIBAQMALw0eAEgABw4ADQAHDgATAS0HHXIZa1oAAAEAAQABAAAANAgAAAQAAABwEAwAAAAOAAoAAAADAAEAOQgAAHsAAABgBQEAEwYcADRlbQAcBQgAGgYxABIXI3cQABIIHAkKAE0JBwhuMAsAZQcMARwFCAAaBjQAEicjdxAAEggcCQoATQkHCBIYHAkQAE0JBwhuMAsAZQcMAhIFEhYjZhEAEgcaCC0ATQgGB24wDgBRBgwEHwQIABIlI1URABIGGgc1AE0HBQYSFhIHTQcFBm4wDgBCBQwDHwMNABIlI1URABIGGgc+AE0HBQYSFhIXI3cQABIIHAkSAE0JBwhNBwUGbjAOAEIFDAUfBQ0AaQUKABIFEgYjZhEAbjAOAFMGDAVpBQkADgANABoFBgAaBjsAcTABAGUAKPcAAAYAAABrAAEAAQEMcgEAAQABAAAAaAgAAAQAAABwEAwAAAAOAAMAAQABAAAAbQgAAAsAAAASECMAEgASAU0CAAFxEAYAAAAKAA8AAAAIAAEAAwABAHMIAAAdAAAAEhESAmIDCQA4AwYAYgMKADkDBAABIQ8BYgMKAGIECQASFSNVEQASBk0HBQZuMA4AQwUo8g0AASEo7wAADAAAAA0AAQABAQwaAwAAAAEAAACDCAAADQAAABIQIwASABIBGgIPAE0CAAFxEAYAAAAKAA8AAAABAAEAAQAAAIgIAAAEAAAAcBAMAAAADgAEAAEAAQAAAI0IAAAeAAAAEgBgAQEAEwIcADUhAwAPAHEABwAAAAoBOQH7/xoAMgBxEA0AAABuEAAAAwAMAFIAAABxEAoAAAAKACjqBgABAAIZARkBGQEZARkBGQKBgASYEQMABQAIGgEKAQoDiIAEsBEBgYAExBMBCdwTAYkBhBQBCdwUAQADAAsaCIGABIgVAQmgFQGKAgAAAAAPAAAAAAAAAAEAAAAAAAAAAQAAAEMAAABwAAAAAgAAABMAAAB8AQAAAwAAAAsAAADIAQAABAAAAAwAAABMAgAABQAAAA8AAACsAgAABgAAAAMAAAAkAwAAAiAAAEMAAACEAwAAARAAAAcAAADgBwAABSAAAAMAAAAcCAAAAxAAAAEAAAAwCAAAAyAAAAgAAAA0CAAAASAAAAgAAACYCAAAACAAAAMAAADsCgAAABAAAAEAAAA8CwAA"; - - private static native int unsealNative(int targetSdkVersion); - - /** - * Begin - * - * @param context The Base Context - * @return int - */ - public static int unseal(Context context) { - if (SDK_INT < 28) { - // Below Android P, ignore - return 0; - } - - // try exempt API first. - if (exemptAll()) { - return 0; - } - if (unsealByDexFile(context)) { - return 0; - } - - return -1; - } - - @SuppressWarnings({"deprecation", "ResultOfMethodCallIgnored"}) - private static boolean unsealByDexFile(Context context) { - byte[] bytes = Base64.decode(DEX, Base64.NO_WRAP); - File codeCacheDir = getCodeCacheDir(context); - if (codeCacheDir == null) { - return false; - } - File code = new File(codeCacheDir, "__temp_" + System.currentTimeMillis() + ".dex"); - try { - - try (FileOutputStream fos = new FileOutputStream(code)) { - fos.write(bytes); - } - - DexFile dexFile = new DexFile(code); - // This class is hardcoded in the dex, Don't use BootstrapClass.class to reference it - // it maybe obfuscated!! - Class bootstrapClass = dexFile.loadClass("com.highcapable.yukihookapi.thirdparty.me.weishu.reflection.BootstrapClass", null); - Method exemptAll = bootstrapClass.getDeclaredMethod("exemptAll"); - return (boolean) exemptAll.invoke(null); - } catch (Throwable e) { - e.printStackTrace(); - return false; - } finally { - if (code.exists()) { - code.delete(); - } - } - } - - private static File getCodeCacheDir(Context context) { - if (context != null) { - return context.getCodeCacheDir(); - } - String tmpDir = System.getProperty("java.io.tmpdir"); - if (TextUtils.isEmpty(tmpDir)) { - return null; - } - File tmp = new File(tmpDir); - if (!tmp.exists()) { - return null; - } - return tmp; - } -} \ No newline at end of file