diff --git a/edxp-core/build.gradle b/edxp-core/build.gradle index 3f22d263..9e1a3998 100644 --- a/edxp-core/build.gradle +++ b/edxp-core/build.gradle @@ -47,6 +47,28 @@ afterEvaluate { } pushTask.dependsOn(zipTask) + + + zipTask = task("zipSandhook${nameCapped}", type: Exec, dependsOn: ":edxp-sandhook:makeAndCopy${nameCapped}") { + workingDir '..' + commandLine 'sh', 'build.sh', \ + project.name, \ + "Sandhook-${project.version}-${nameLowered}", \ + "${project.extensions['module_name']}" + } + + pushTask = task("pushSandhook${nameCapped}", type: Exec) { + workingDir 'release' + def commands = ["adb", "push", "magisk-${project.extensions['module_name']}-Sandhook" + + "-${project.version}-${nameLowered}.zip", "/sdcard/"] + if (OperatingSystem.current().isWindows()) { + commandLine 'cmd', '/c', commands.join(" ") + } else { + commandLine commands + } + } + + pushTask.dependsOn(zipTask) } } diff --git a/edxp-core/jni/main/include/config.h b/edxp-core/jni/main/include/config.h index cd963cad..eda55916 100644 --- a/edxp-core/jni/main/include/config.h +++ b/edxp-core/jni/main/include/config.h @@ -10,6 +10,6 @@ #define INJECT_DEX_PATH \ "/system/framework/edxp.jar:/system/framework/eddalvikdx.jar:/system/framework/eddexmaker.jar" -#define ENTRY_CLASS_NAME "com.elderdrivers.riru.edxp.yahfa.Main" +#define ENTRY_CLASS_NAME "com.elderdrivers.riru.edxp.Main" #endif //CONFIG_H \ No newline at end of file diff --git a/edxp-core/template_override/system/etc/public.libraries-edxp.txt b/edxp-core/template_override/system/etc/public.libraries-edxp.txt new file mode 100644 index 00000000..3c8badba --- /dev/null +++ b/edxp-core/template_override/system/etc/public.libraries-edxp.txt @@ -0,0 +1 @@ +libsandhook.edxp.so diff --git a/edxp-core/template_override/system/lib/libsandhook.edxp.so b/edxp-core/template_override/system/lib/libsandhook.edxp.so new file mode 100644 index 00000000..82321291 Binary files /dev/null and b/edxp-core/template_override/system/lib/libsandhook.edxp.so differ diff --git a/edxp-core/template_override/system/lib64/libsandhook.edxp.so b/edxp-core/template_override/system/lib64/libsandhook.edxp.so new file mode 100644 index 00000000..cca107d3 Binary files /dev/null and b/edxp-core/template_override/system/lib64/libsandhook.edxp.so differ diff --git a/edxp-sandhook/.gitignore b/edxp-sandhook/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/edxp-sandhook/.gitignore @@ -0,0 +1 @@ +/build diff --git a/edxp-sandhook/build.gradle b/edxp-sandhook/build.gradle new file mode 100644 index 00000000..322e96ff --- /dev/null +++ b/edxp-sandhook/build.gradle @@ -0,0 +1,63 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "com.elderdrivers.riru.edxp.sandhook" + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + compileOnly files("libs/framework-stub.jar") + implementation project(':edxp-common') + implementation project(':xposed-bridge') + implementation 'com.swift.sandhook:hooklib:3.0.1' + compileOnly project(':dexmaker') +} + + +preBuild.doLast { + def imlFile = file(project.name + ".iml") + println 'Change ' + project.name + '.iml order' + try { + def parsedXml = (new groovy.util.XmlParser()).parse(imlFile) + def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' } + parsedXml.component[1].remove(jdkNode) + def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform" + new groovy.util.Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK']) + groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile)) + } catch (FileNotFoundException e) { + // nop, iml not found + } +} + +afterEvaluate { + + tasks.withType(JavaCompile) { + options.compilerArgs.add("-Xbootclasspath/p:${projectDir.absolutePath}/libs/framework-stub.jar") + } + + android.applicationVariants.all { variant -> + def nameCapped = variant.name.capitalize() + def nameLowered = variant.name.toLowerCase() + + def makeAndCopyTask = task("makeAndCopy${nameCapped}", type: Jar, dependsOn: "assemble${nameCapped}") { + from "build/intermediates/dex/${nameLowered}/mergeDex${nameCapped}/out/" + destinationDir file("../edxp-core/template_override/system/framework/") + baseName "edxp" + } + } +} \ No newline at end of file diff --git a/edxp-sandhook/genhookstubs.py b/edxp-sandhook/genhookstubs.py new file mode 100644 index 00000000..feddcd89 --- /dev/null +++ b/edxp-sandhook/genhookstubs.py @@ -0,0 +1,186 @@ +#!/usr/bin/python + +import os + +STUB_FILE_NAME = "MethodHookerStubs" + +TEMP_STUB_CLASS_WRAPPER = """package com.swift.sandhook.xposedcompat.hookstub; + +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.hookBridge; +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.getMethodId; +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.originMethods; +import static com.swift.sandhook.xposedcompat.utils.DexLog.printCallOriginError; + +/** +* this file is auto gen by genhookstubs.py +* it is for sandhook internal hooker & backup methods +**/ +public class MethodHookerStubs%d { +%s +} +""" + +TEMP_STUB_HOOK_METHOD_NAME = """stub_hook_%d""" +TEMP_STUB_HOOK_BACKUP_NAME = """stub_backup_%d""" +TEMP_STUB_CALL_ORIGIN_NAME = """call_origin_%d_%d""" + +TEMP_STUB_GET_METHOD_ID_NAME = """getMethodId(%d, %d)""" + +JAVA_TYPE_INT = "int" +JAVA_CAST_INT = "(int)" +JAVA_TYPE_LONG = "long" + +TEMP_STUB_HOOK_METHOD = """ + public static %s %s(%s) throws Throwable { + return %s hookBridge(%s, %s %s); + } +""" + +TEMP_STUB_BACKUP_METHOD = """ + public static %s %s(%s) throws Throwable { + try { + printCallOriginError(originMethods[%s]); + } catch (Throwable throwable) {} + return 0; + } +""" + +TEMP_STUB_CALL_ORIGIN_CLASS = """ + static class %s implements CallOriginCallBack { + @Override + public long call(long... args) throws Throwable { + return %s(%s); + } + } +""" + +TEMP_STUB_INFO = """ + public static boolean hasStubBackup = %s; + public static int[] stubSizes = {%s}; +""" + + +STUB_SIZES = [10,20,30,30,30,30,30,20,10,10,5,5,3] +HAS_BACKUP = False; + + +def getMethodId(args, index): + return TEMP_STUB_GET_METHOD_ID_NAME % (args, index) + +def getMethodHookName(index): + return TEMP_STUB_HOOK_METHOD_NAME % index + +def getMethodBackupName(index): + return TEMP_STUB_HOOK_BACKUP_NAME % index + +def getCallOriginClassName(args, index): + return TEMP_STUB_CALL_ORIGIN_NAME % (args, index) + + +def genArgsList(is64Bit, isDefine, length): + args_list = "" + for i in range(length): + if (i != 0): + args_list += ", " + if isDefine: + if (is64Bit): + args_list += (JAVA_TYPE_LONG + " " + "a" + str(i)) + else: + args_list += (JAVA_TYPE_INT + " " + "a" + str(i)) + else: + args_list += ("a" + str(i)) + return args_list + + +def genArgsListForCallOriginMethod(is64Bit, length): + arg_name = """args[%s]""" + args_list = "" + for i in range(length): + if (i != 0): + args_list += ", " + if (is64Bit): + args_list += arg_name % i + else: + args_list += (JAVA_CAST_INT + arg_name % i) + return args_list + + +def genHookMethod(is64Bit, args, index): + java_type = JAVA_TYPE_LONG if is64Bit else JAVA_TYPE_INT + cast = "" if is64Bit else JAVA_CAST_INT + args_list_pre = ", " if args > 0 else "" + args_list = genArgsList(is64Bit, False, args) + args_list_def = genArgsList(is64Bit, True, args) + call_origin_obj = ("new " + getCallOriginClassName(args, index) + "()") if HAS_BACKUP else "null" + method = TEMP_STUB_HOOK_METHOD % (java_type, getMethodHookName(index), args_list_def, cast, getMethodId(args, index), call_origin_obj, args_list_pre + args_list) + return method + + +def genBackupMethod(is64Bit, args, index): + java_type = JAVA_TYPE_LONG if is64Bit else JAVA_TYPE_INT + args_list_def = genArgsList(is64Bit, True, args) + method = TEMP_STUB_BACKUP_METHOD % (java_type, getMethodBackupName(index), args_list_def, getMethodId(args, index)) + return method + +def genCallOriginClass(is64Bit, args, index): + method = TEMP_STUB_CALL_ORIGIN_CLASS % (getCallOriginClassName(args, index), getMethodBackupName(index), genArgsListForCallOriginMethod(is64Bit, args)) + return method + +def genStubInfo(): + hasStub = "true" if HAS_BACKUP else "false" + stubSizes = "" + for args in range(len(STUB_SIZES)): + if (args != 0): + stubSizes += ", " + stubSizes += str(STUB_SIZES[args]) + return TEMP_STUB_INFO % (hasStub, stubSizes) + +def gen32Stub(packageDir): + class_content = genStubInfo() + class_name = STUB_FILE_NAME + "32" + for args in range(len(STUB_SIZES)): + for index in range(STUB_SIZES[args]): + class_content += """\n\n\t//stub of arg size %d, index %d""" % (args, index) + class_content += genHookMethod(False, args, index) + if HAS_BACKUP: + class_content += "\n" + class_content += genCallOriginClass(False, args, index) + class_content += "\n" + class_content += genBackupMethod(False, args, index) + class_content += "\n" + class_str = TEMP_STUB_CLASS_WRAPPER % (32, class_content) + javaFile = open(os.path.join(packageDir, class_name + ".java"), "w") + javaFile.write(class_str) + javaFile.close() + + +def gen64Stub(packageDir): + class_content = genStubInfo() + class_name = STUB_FILE_NAME + "64" + for args in range(len(STUB_SIZES)): + for index in range(STUB_SIZES[args]): + class_content += """\n\n\t//stub of arg size %d, index %d""" % (args, index) + class_content += genHookMethod(True, args, index) + if HAS_BACKUP: + class_content += "\n" + class_content += genCallOriginClass(True, args, index) + class_content += "\n" + class_content += genBackupMethod(True, args, index) + class_content += "\n" + class_str = TEMP_STUB_CLASS_WRAPPER % (64, class_content) + javaFile = open(os.path.join(packageDir, class_name + ".java"), "w") + javaFile.write(class_str) + javaFile.close() + + +def genStub(packageDir): + for fileName in os.listdir(packageDir): + if fileName.startswith(STUB_FILE_NAME): + os.remove(os.path.join(packageDir, fileName)) + gen32Stub(packageDir) + gen64Stub(packageDir) + + +if __name__ == "__main__": + genStub(os.path.join(os.path.dirname(os.path.realpath(__file__)), + "src/main/java/com/swift/sandhook/xposedcompat/hookstub")) diff --git a/edxp-sandhook/libs/framework-stub.jar b/edxp-sandhook/libs/framework-stub.jar new file mode 100644 index 00000000..36cd86b3 Binary files /dev/null and b/edxp-sandhook/libs/framework-stub.jar differ diff --git a/edxp-sandhook/proguard-rules.pro b/edxp-sandhook/proguard-rules.pro new file mode 100644 index 00000000..48bb9c90 --- /dev/null +++ b/edxp-sandhook/proguard-rules.pro @@ -0,0 +1,33 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +-dontobfuscate +-keep class de.robv.android.xposed.** {*;} +-keep class android.** { *; } + +-keep interface com.elderdrivers.riru.common.KeepAll +-keep interface com.elderdrivers.riru.common.KeepMembers + +-keep class * implements com.elderdrivers.riru.common.KeepAll { *; } +-keepclassmembers class * implements com.elderdrivers.riru.common.KeepMembers { *; } + +-keep class com.swift.sandhook.** {*;} \ No newline at end of file diff --git a/edxp-sandhook/src/main/AndroidManifest.xml b/edxp-sandhook/src/main/AndroidManifest.xml new file mode 100644 index 00000000..4d54a3c5 --- /dev/null +++ b/edxp-sandhook/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/Main.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/Main.java new file mode 100644 index 00000000..b4f0ab86 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/Main.java @@ -0,0 +1,144 @@ +package com.elderdrivers.riru.edxp; + +import android.annotation.SuppressLint; +import android.os.Build; +import android.os.Process; + +import com.elderdrivers.riru.common.KeepAll; +import com.elderdrivers.riru.edxp.sandhook.BuildConfig; +import com.elderdrivers.riru.edxp.config.InstallerChooser; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.sandhook.core.HookMethodResolver; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; +import com.elderdrivers.riru.edxp.sandhook.proxy.BlackWhiteListProxy; +import com.elderdrivers.riru.edxp.sandhook.proxy.NormalProxy; +import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; + +import java.lang.reflect.Method; +import java.util.Arrays; + +@SuppressLint("DefaultLocale") +public class Main implements KeepAll { + + public static String appDataDir = ""; + public static String niceName = ""; + public static String appProcessName = ""; + private static String forkAndSpecializePramsStr = ""; + private static String forkSystemServerPramsStr = ""; + + static { + init(Build.VERSION.SDK_INT); + HookMethodResolver.init(); + Router.injectConfig(); + InstallerChooser.setInstallerPackageName(getInstallerPkgName()); + SandHookXposedBridge.setLibPath(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // entry points + /////////////////////////////////////////////////////////////////////////////////////////////// + + public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, int mountExternal, String seInfo, + String niceName, int[] fdsToClose, int[] fdsToIgnore, + boolean startChildZygote, String instructionSet, + String appDataDir) { + if (BuildConfig.DEBUG) { + forkAndSpecializePramsStr = String.format( + "Zygote#forkAndSpecialize(%d, %d, %s, %d, %s, %d, %s, %s, %s, %s, %s, %s, %s)", + uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), + mountExternal, seInfo, niceName, Arrays.toString(fdsToClose), + Arrays.toString(fdsToIgnore), startChildZygote, instructionSet, appDataDir); + } + if (isBlackWhiteListEnabled()) { + BlackWhiteListProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, + mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, + instructionSet, appDataDir); + } else { + NormalProxy.forkAndSpecializePre(uid, gid, gids, debugFlags, rlimits, mountExternal, + seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, + appDataDir); + } + } + + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { + if (pid == 0) { + Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid()); + if (isBlackWhiteListEnabled()) { + BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, niceName); + } else { + NormalProxy.forkAndSpecializePost(pid, appDataDir, niceName); + } + } else { + // in zygote process, res is child zygote pid + // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 + } + } + + public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, + long permittedCapabilities, long effectiveCapabilities) { + if (BuildConfig.DEBUG) { + forkSystemServerPramsStr = String.format("Zygote#forkSystemServer(%d, %d, %s, %d, %s, %d, %d)", + uid, gid, Arrays.toString(gids), debugFlags, Arrays.toString(rlimits), + permittedCapabilities, effectiveCapabilities); + } + if (isBlackWhiteListEnabled()) { + BlackWhiteListProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits, + permittedCapabilities, effectiveCapabilities); + } else { + NormalProxy.forkSystemServerPre(uid, gid, gids, debugFlags, rlimits, + permittedCapabilities, effectiveCapabilities); + } + } + + public static void forkSystemServerPost(int pid) { + if (pid == 0) { + Utils.logD(forkSystemServerPramsStr + " = " + Process.myPid()); + if (isBlackWhiteListEnabled()) { + BlackWhiteListProxy.forkSystemServerPost(pid); + } else { + NormalProxy.forkSystemServerPost(pid); + } + } else { + // in zygote process, res is child zygote pid + // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66 + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // native methods + /////////////////////////////////////////////////////////////////////////////////////////////// + + public static native boolean backupAndHookNative(Object target, Method hook, Method backup); + + public static native void setMethodNonCompilable(Object member); + + public static native void ensureMethodCached(Method hook, Method backup); + + // JNI.ToReflectedMethod() could return either Method or Constructor + public static native Object findMethodNative(Class targetClass, String methodName, String methodSig); + + private static native void init(int SDK_version); + + public static native String getInstallerPkgName(); + + public static native boolean isBlackWhiteListEnabled(); + + public static native boolean isDynamicModulesEnabled(); + + public static native boolean isAppNeedHook(String appDataDir); + + // prevent from fatal error caused by holding not whitelisted file descriptors when forking zygote + // https://github.com/rovo89/Xposed/commit/b3ba245ad04cd485699fb1d2ebde7117e58214ff + public static native void closeFilesBeforeForkNative(); + + public static native void reopenFilesAfterForkNative(); + + public static native void deoptMethodNative(Object object); + + public static native long suspendAllThreads(); + + public static native void resumeAllThreads(long obj); + + public static native int waitForGcToComplete(long thread); +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java new file mode 100644 index 00000000..c3a62805 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookEdxpConfig.java @@ -0,0 +1,23 @@ +package com.elderdrivers.riru.edxp.sandhook.config; + +import com.elderdrivers.riru.edxp.config.EdXpConfig; +import com.elderdrivers.riru.edxp.config.InstallerChooser; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.XposedBlackListHooker; + +public class SandHookEdxpConfig implements EdXpConfig { + @Override + public String getInstallerBaseDir() { + return InstallerChooser.INSTALLER_DATA_BASE_DIR; + } + + @Override + public String getBlackListModulePackageName() { + return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; + } + + @Override + public boolean isDynamicModulesMode() { + return Main.isDynamicModulesEnabled(); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookProvider.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookProvider.java new file mode 100644 index 00000000..da08315b --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookProvider.java @@ -0,0 +1,35 @@ +package com.elderdrivers.riru.edxp.sandhook.config; + +import com.elderdrivers.riru.edxp.hook.HookProvider; +import com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils; +import com.elderdrivers.riru.edxp.sandhook.dexmaker.DynamicBridge; +import com.elderdrivers.riru.edxp.sandhook.util.PrebuiltMethodsDeopter; +import com.swift.sandhook.xposedcompat.XposedCompat; +import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +public class SandHookProvider implements HookProvider { + @Override + public void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo) { + XposedCompat.hookMethod(method, additionalInfo); + } + + @Override + public Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) throws Throwable { + return SandHookXposedBridge.invokeOriginalMethod(method, thisObject, args); + } + + @Override + public Member findMethodNative(Member hookMethod) { + return DexMakerUtils.findMethodNative(hookMethod); + } + + @Override + public void deoptMethods(String packageName, ClassLoader classLoader) { + PrebuiltMethodsDeopter.deoptMethods(packageName, classLoader); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMain.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMain.java new file mode 100644 index 00000000..eeaa50ca --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMain.java @@ -0,0 +1,186 @@ +package com.elderdrivers.riru.edxp.sandhook.core; + +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.OnePlusWorkAroundHooker; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; + +import de.robv.android.xposed.XposedHelpers; + +import static com.elderdrivers.riru.edxp.Main.backupAndHookNative; +import static com.elderdrivers.riru.edxp.Main.findMethodNative; + +public class HookMain { + + private static Set hookItemWhiteList = Collections.singleton(OnePlusWorkAroundHooker.class.getName()); + + public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) { + try { + Class hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader); + String[] hookItemNames = (String[]) hookInfoClass.getField("hookItemNames").get(null); + for (String hookItemName : hookItemNames) { + doHookItemDefault(patchClassLoader, hookItemName, originClassLoader); + } + } catch (Throwable e) { + Utils.logE("error when hooking all in: " + hookInfoClassName, e); + } + } + + private static void doHookItemDefault(ClassLoader patchClassLoader, String hookItemName, ClassLoader originClassLoader) { + try { + Utils.logD("Start hooking with item " + hookItemName); + Class hookItem = Class.forName(hookItemName, true, patchClassLoader); + + String className = (String) hookItem.getField("className").get(null); + String methodName = (String) hookItem.getField("methodName").get(null); + String methodSig = (String) hookItem.getField("methodSig").get(null); + + if (className == null || className.equals("")) { + Utils.logW("No target class. Skipping..."); + return; + } + Class clazz = null; + try { + clazz = Class.forName(className, true, originClassLoader); + } catch (ClassNotFoundException cnfe) { + Utils.logE(className + " not found in " + originClassLoader); + return; + } + if (Modifier.isAbstract(clazz.getModifiers())) { + Utils.logW("Hook may fail for abstract class: " + className); + } + + Method hook = null; + Method backup = null; + for (Method method : hookItem.getDeclaredMethods()) { + if (method.getName().equals("hook") && Modifier.isStatic(method.getModifiers())) { + hook = method; + } else if (method.getName().equals("backup") && Modifier.isStatic(method.getModifiers())) { + backup = method; + } + } + if (hook == null) { + Utils.logE("Cannot find hook for " + methodName); + return; + } + findAndBackupAndHook(clazz, methodName, methodSig, hook, backup); + } catch (Throwable e) { + if (!hookItemWhiteList.contains(hookItemName)) { + Utils.logE("error when hooking " + hookItemName, e); + } + } + } + + public static void findAndHook(Class targetClass, String methodName, String methodSig, Method hook) { + hook(findMethod(targetClass, methodName, methodSig), hook); + } + + public static void findAndBackupAndHook(Class targetClass, String methodName, String methodSig, + Method hook, Method backup) { + backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup); + } + + public static void hook(Object target, Method hook) { + backupAndHook(target, hook, null); + } + + public static void backupAndHook(Object target, Method hook, Method backup) { + Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup)); + if (target == null) { + throw new IllegalArgumentException("null target method"); + } + if (hook == null) { + throw new IllegalArgumentException("null hook method"); + } + + if (!Modifier.isStatic(hook.getModifiers())) { + throw new IllegalArgumentException("Hook must be a static method: " + hook); + } + checkCompatibleMethods(target, hook, "Original", "Hook"); + if (backup != null) { + if (!Modifier.isStatic(backup.getModifiers())) { + throw new IllegalArgumentException("Backup must be a static method: " + backup); + } + // backup is just a placeholder and the constraint could be less strict + checkCompatibleMethods(target, backup, "Original", "Backup"); + } + if (backup != null) { + HookMethodResolver.resolveMethod(hook, backup); + } + // make sure GC completed before hook + Thread currentThread = Thread.currentThread(); + int lastGcType = Main.waitForGcToComplete( + XposedHelpers.getLongField(currentThread, "nativePeer")); + if (lastGcType < 0) { + Utils.logW("waitForGcToComplete failed, using fallback"); + Runtime.getRuntime().gc(); + } + if (!backupAndHookNative(target, hook, backup)) { + throw new RuntimeException("Failed to hook " + target + " with " + hook); + } + } + + public static Object findMethod(Class cls, String methodName, String methodSig) { + if (cls == null) { + throw new IllegalArgumentException("null class"); + } + if (methodName == null) { + throw new IllegalArgumentException("null method name"); + } + if (methodSig == null) { + throw new IllegalArgumentException("null method signature"); + } + return findMethodNative(cls, methodName, methodSig); + } + + private static void checkCompatibleMethods(Object original, Method replacement, String originalName, String replacementName) { + ArrayList> originalParams; + if (original instanceof Method) { + originalParams = new ArrayList<>(Arrays.asList(((Method) original).getParameterTypes())); + } else if (original instanceof Constructor) { + originalParams = new ArrayList<>(Arrays.asList(((Constructor) original).getParameterTypes())); + } else { + throw new IllegalArgumentException("Type of target method is wrong"); + } + + ArrayList> replacementParams = new ArrayList<>(Arrays.asList(replacement.getParameterTypes())); + + if (original instanceof Method + && !Modifier.isStatic(((Method) original).getModifiers())) { + originalParams.add(0, ((Method) original).getDeclaringClass()); + } else if (original instanceof Constructor) { + originalParams.add(0, ((Constructor) original).getDeclaringClass()); + } + + + if (!Modifier.isStatic(replacement.getModifiers())) { + replacementParams.add(0, replacement.getDeclaringClass()); + } + + if (original instanceof Method + && !replacement.getReturnType().isAssignableFrom(((Method) original).getReturnType())) { + throw new IllegalArgumentException("Incompatible return types. " + originalName + ": " + ((Method) original).getReturnType() + ", " + replacementName + ": " + replacement.getReturnType()); + } else if (original instanceof Constructor) { + if (replacement.getReturnType().equals(Void.class)) { + throw new IllegalArgumentException("Incompatible return types. " + "" + ": " + "V" + ", " + replacementName + ": " + replacement.getReturnType()); + } + } + + if (originalParams.size() != replacementParams.size()) { + throw new IllegalArgumentException("Number of arguments don't match. " + originalName + ": " + originalParams.size() + ", " + replacementName + ": " + replacementParams.size()); + } + + for (int i = 0; i < originalParams.size(); i++) { + if (!replacementParams.get(i).isAssignableFrom(originalParams.get(i))) { + throw new IllegalArgumentException("Incompatible argument #" + i + ": " + originalName + ": " + originalParams.get(i) + ", " + replacementName + ": " + replacementParams.get(i)); + } + } + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java new file mode 100644 index 00000000..c5290914 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java @@ -0,0 +1,155 @@ +package com.elderdrivers.riru.edxp.sandhook.core; + +import android.os.Build; + +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * create by Swift Gan on 14/01/2019 + * To ensure method in resolved cache + */ + +public class HookMethodResolver { + + public static Class artMethodClass; + + public static Field resolvedMethodsField; + public static Field dexCacheField; + public static Field dexMethodIndexField; + public static Field artMethodField; + + public static boolean canResolvedInJava = false; + public static boolean isArtMethod = false; + + public static long resolvedMethodsAddress = 0; + public static int dexMethodIndex = 0; + + public static Method testMethod; + public static Object testArtMethod; + + public static void init() { + checkSupport(); + } + + private static void checkSupport() { + try { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + isArtMethod = false; + canResolvedInJava = false; + return; + } + + testMethod = HookMethodResolver.class.getDeclaredMethod("init"); + artMethodField = getField(Method.class, "artMethod"); + + testArtMethod = artMethodField.get(testMethod); + + if (hasJavaArtMethod() && testArtMethod.getClass() == artMethodClass) { + checkSupportForArtMethod(); + isArtMethod = true; + } else if (testArtMethod instanceof Long) { + checkSupportForArtMethodId(); + isArtMethod = false; + } else { + canResolvedInJava = false; + } + + } catch (Throwable throwable) { + Utils.logE("error when checkSupport", throwable); + } + } + + // may 5.0 + private static void checkSupportForArtMethod() throws Exception { + dexMethodIndexField = getField(artMethodClass, "dexMethodIndex"); + dexCacheField = getField(Class.class, "dexCache"); + Object dexCache = dexCacheField.get(testMethod.getDeclaringClass()); + resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods"); + if (resolvedMethodsField.get(dexCache) instanceof Object[]) { + canResolvedInJava = true; + } + } + + // may 6.0 + private static void checkSupportForArtMethodId() throws Exception { + dexMethodIndexField = getField(Method.class, "dexMethodIndex"); + dexMethodIndex = (int) dexMethodIndexField.get(testMethod); + dexCacheField = getField(Class.class, "dexCache"); + Object dexCache = dexCacheField.get(testMethod.getDeclaringClass()); + resolvedMethodsField = getField(dexCache.getClass(), "resolvedMethods"); + Object resolvedMethods = resolvedMethodsField.get(dexCache); + if (resolvedMethods instanceof Long) { + canResolvedInJava = false; + resolvedMethodsAddress = (long) resolvedMethods; + } else if (resolvedMethods instanceof long[]) { + canResolvedInJava = true; + } + } + + public static void resolveMethod(Method hook, Method backup) { + if (canResolvedInJava && artMethodField != null) { + // in java + try { + resolveInJava(hook, backup); + } catch (Exception e) { + // in native + resolveInNative(hook, backup); + } + } else { + // in native + resolveInNative(hook, backup); + } + } + + private static void resolveInJava(Method hook, Method backup) throws Exception { + Object dexCache = dexCacheField.get(hook.getDeclaringClass()); + if (isArtMethod) { + Object artMethod = artMethodField.get(backup); + int dexMethodIndex = (int) dexMethodIndexField.get(artMethod); + Object resolvedMethods = resolvedMethodsField.get(dexCache); + ((Object[])resolvedMethods)[dexMethodIndex] = artMethod; + } else { + int dexMethodIndex = (int) dexMethodIndexField.get(backup); + Object resolvedMethods = resolvedMethodsField.get(dexCache); + long artMethod = (long) artMethodField.get(backup); + ((long[])resolvedMethods)[dexMethodIndex] = artMethod; + } + } + + private static void resolveInNative(Method hook, Method backup) { + Main.ensureMethodCached(hook, backup); + } + + public static Field getField(Class topClass, String fieldName) throws NoSuchFieldException { + while (topClass != null && topClass != Object.class) { + try { + Field field = topClass.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } catch (Exception e) { + } + topClass = topClass.getSuperclass(); + } + throw new NoSuchFieldException(fieldName); + } + + public static boolean hasJavaArtMethod() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return false; + } + if (artMethodClass != null) + return true; + try { + artMethodClass = Class.forName("java.lang.reflect.ArtMethod"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexLog.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexLog.java new file mode 100644 index 00000000..b2dd0f11 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexLog.java @@ -0,0 +1,37 @@ +package com.elderdrivers.riru.edxp.sandhook.dexmaker; + +import android.util.Log; + +import com.elderdrivers.riru.edxp.BuildConfig; + +public class DexLog { + + public static final String TAG = "EdXposed-dexmaker"; + + public static int v(String s) { + return Log.v(TAG, s); + } + + public static int i(String s) { + return Log.i(TAG, s); + } + + public static int d(String s) { + if (BuildConfig.DEBUG) { + return Log.d(TAG, s); + } + return 0; + } + + public static int w(String s) { + return Log.w(TAG, s); + } + + public static int e(String s) { + return Log.e(TAG, s); + } + + public static int e(String s, Throwable t) { + return Log.e(TAG, s, t); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexMakerUtils.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexMakerUtils.java new file mode 100644 index 00000000..5ad71082 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DexMakerUtils.java @@ -0,0 +1,261 @@ +package com.elderdrivers.riru.edxp.sandhook.dexmaker; + +import android.app.AndroidAppHelper; +import android.os.Build; +import android.text.TextUtils; + +import com.elderdrivers.riru.edxp.config.ConfigManager; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.core.HookMain; + +import java.lang.reflect.Member; +import java.security.MessageDigest; +import java.util.HashMap; +import java.util.Map; + +import external.com.android.dx.Code; +import external.com.android.dx.Local; +import external.com.android.dx.TypeId; + +public class DexMakerUtils { + + private static final boolean IN_MEMORY_DEX_ELIGIBLE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; + + public static boolean shouldUseInMemoryHook() { + if (!IN_MEMORY_DEX_ELIGIBLE) { + return false; + } + String packageName = AndroidAppHelper.currentPackageName(); + if (TextUtils.isEmpty(packageName)) { //default to true + DexLog.w("packageName is empty, processName=" + Main.appProcessName + + ", appDataDir=" + Main.appDataDir); + return true; + } + return !ConfigManager.shouldUseCompatMode(packageName); + } + + public static void autoBoxIfNecessary(Code code, Local target, Local source) { + String boxMethod = "valueOf"; + TypeId boxTypeId; + TypeId typeId = source.getType(); + if (typeId.equals(TypeId.BOOLEAN)) { + boxTypeId = TypeId.get(Boolean.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.BOOLEAN), target, source); + } else if (typeId.equals(TypeId.BYTE)) { + boxTypeId = TypeId.get(Byte.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.BYTE), target, source); + } else if (typeId.equals(TypeId.CHAR)) { + boxTypeId = TypeId.get(Character.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.CHAR), target, source); + } else if (typeId.equals(TypeId.DOUBLE)) { + boxTypeId = TypeId.get(Double.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.DOUBLE), target, source); + } else if (typeId.equals(TypeId.FLOAT)) { + boxTypeId = TypeId.get(Float.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.FLOAT), target, source); + } else if (typeId.equals(TypeId.INT)) { + boxTypeId = TypeId.get(Integer.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.INT), target, source); + } else if (typeId.equals(TypeId.LONG)) { + boxTypeId = TypeId.get(Long.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.LONG), target, source); + } else if (typeId.equals(TypeId.SHORT)) { + boxTypeId = TypeId.get(Short.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.SHORT), target, source); + } else if (typeId.equals(TypeId.VOID)) { + code.loadConstant(target, null); + } else { + code.move(target, source); + } + } + + public static void autoUnboxIfNecessary(Code code, Local target, Local source, + Map tmpLocals, boolean castObj) { + String unboxMethod; + TypeId typeId = target.getType(); + TypeId boxTypeId; + if (typeId.equals(TypeId.BOOLEAN)) { + unboxMethod = "booleanValue"; + boxTypeId = TypeId.get("Ljava/lang/Boolean;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.BOOLEAN, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.BYTE)) { + unboxMethod = "byteValue"; + boxTypeId = TypeId.get("Ljava/lang/Byte;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.BYTE, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.CHAR)) { + unboxMethod = "charValue"; + boxTypeId = TypeId.get("Ljava/lang/Character;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.CHAR, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.DOUBLE)) { + unboxMethod = "doubleValue"; + boxTypeId = TypeId.get("Ljava/lang/Double;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.DOUBLE, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.FLOAT)) { + unboxMethod = "floatValue"; + boxTypeId = TypeId.get("Ljava/lang/Float;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.FLOAT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.INT)) { + unboxMethod = "intValue"; + boxTypeId = TypeId.get("Ljava/lang/Integer;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.INT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.LONG)) { + unboxMethod = "longValue"; + boxTypeId = TypeId.get("Ljava/lang/Long;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.LONG, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.SHORT)) { + unboxMethod = "shortValue"; + boxTypeId = TypeId.get("Ljava/lang/Short;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.SHORT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.VOID)) { + code.loadConstant(target, null); + } else if (castObj) { + code.cast(target, source); + } else { + code.move(target, source); + } + } + + public static Map createResultLocals(Code code) { + HashMap resultMap = new HashMap<>(); + Local booleanLocal = code.newLocal(TypeId.BOOLEAN); + Local byteLocal = code.newLocal(TypeId.BYTE); + Local charLocal = code.newLocal(TypeId.CHAR); + Local doubleLocal = code.newLocal(TypeId.DOUBLE); + Local floatLocal = code.newLocal(TypeId.FLOAT); + Local intLocal = code.newLocal(TypeId.INT); + Local longLocal = code.newLocal(TypeId.LONG); + Local shortLocal = code.newLocal(TypeId.SHORT); + Local voidLocal = code.newLocal(TypeId.VOID); + Local objectLocal = code.newLocal(TypeId.OBJECT); + + Local booleanObjLocal = code.newLocal(TypeId.get("Ljava/lang/Boolean;")); + Local byteObjLocal = code.newLocal(TypeId.get("Ljava/lang/Byte;")); + Local charObjLocal = code.newLocal(TypeId.get("Ljava/lang/Character;")); + Local doubleObjLocal = code.newLocal(TypeId.get("Ljava/lang/Double;")); + Local floatObjLocal = code.newLocal(TypeId.get("Ljava/lang/Float;")); + Local intObjLocal = code.newLocal(TypeId.get("Ljava/lang/Integer;")); + Local longObjLocal = code.newLocal(TypeId.get("Ljava/lang/Long;")); + Local shortObjLocal = code.newLocal(TypeId.get("Ljava/lang/Short;")); + Local voidObjLocal = code.newLocal(TypeId.get("Ljava/lang/Void;")); + + // backup need initialized locals + code.loadConstant(booleanLocal, false); + code.loadConstant(byteLocal, (byte) 0); + code.loadConstant(charLocal, '\0'); + code.loadConstant(doubleLocal, 0.0); + code.loadConstant(floatLocal, 0.0f); + code.loadConstant(intLocal, 0); + code.loadConstant(longLocal, 0L); + code.loadConstant(shortLocal, (short) 0); + code.loadConstant(voidLocal, null); + code.loadConstant(objectLocal, null); + // all to null + code.loadConstant(booleanObjLocal, null); + code.loadConstant(byteObjLocal, null); + code.loadConstant(charObjLocal, null); + code.loadConstant(doubleObjLocal, null); + code.loadConstant(floatObjLocal, null); + code.loadConstant(intObjLocal, null); + code.loadConstant(longObjLocal, null); + code.loadConstant(shortObjLocal, null); + code.loadConstant(voidObjLocal, null); + // package all + resultMap.put(TypeId.BOOLEAN, booleanLocal); + resultMap.put(TypeId.BYTE, byteLocal); + resultMap.put(TypeId.CHAR, charLocal); + resultMap.put(TypeId.DOUBLE, doubleLocal); + resultMap.put(TypeId.FLOAT, floatLocal); + resultMap.put(TypeId.INT, intLocal); + resultMap.put(TypeId.LONG, longLocal); + resultMap.put(TypeId.SHORT, shortLocal); + resultMap.put(TypeId.VOID, voidLocal); + resultMap.put(TypeId.OBJECT, objectLocal); + + resultMap.put(TypeId.get("Ljava/lang/Boolean;"), booleanObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Byte;"), byteObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Character;"), charObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Double;"), doubleObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Float;"), floatObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Integer;"), intObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Long;"), longObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Short;"), shortObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Void;"), voidObjLocal); + + return resultMap; + } + + public static TypeId getObjTypeIdIfPrimitive(TypeId typeId) { + if (typeId.equals(TypeId.BOOLEAN)) { + return TypeId.get("Ljava/lang/Boolean;"); + } else if (typeId.equals(TypeId.BYTE)) { + return TypeId.get("Ljava/lang/Byte;"); + } else if (typeId.equals(TypeId.CHAR)) { + return TypeId.get("Ljava/lang/Character;"); + } else if (typeId.equals(TypeId.DOUBLE)) { + return TypeId.get("Ljava/lang/Double;"); + } else if (typeId.equals(TypeId.FLOAT)) { + return TypeId.get("Ljava/lang/Float;"); + } else if (typeId.equals(TypeId.INT)) { + return TypeId.get("Ljava/lang/Integer;"); + } else if (typeId.equals(TypeId.LONG)) { + return TypeId.get("Ljava/lang/Long;"); + } else if (typeId.equals(TypeId.SHORT)) { + return TypeId.get("Ljava/lang/Short;"); + } else if (typeId.equals(TypeId.VOID)) { + return TypeId.get("Ljava/lang/Void;"); + } else { + return typeId; + } + } + + public static void returnRightValue(Code code, Class returnType, Map resultLocals) { + String unboxMethod; + TypeId boxTypeId; + code.returnValue(resultLocals.get(returnType)); + } + + public static String getSha1Hex(String text) { + final MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-1"); + byte[] result = digest.digest(text.getBytes("UTF-8")); + StringBuilder sb = new StringBuilder(); + for (byte b : result) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (Exception e) { + DexLog.e("error hashing target method: " + text, e); + } + return ""; + } + + public static Member findMethodNative(Member hookMethod) { + MethodInfo methodInfo = new MethodInfo(hookMethod); + Class declaringClass = methodInfo.getClassForSure(); + Member reflectMethod = (Member) HookMain.findMethod( + declaringClass, methodInfo.methodName, methodInfo.methodSig); + if (reflectMethod == null) { + DexLog.e("method not found: name=" + + methodInfo.methodName + ", sig=" + methodInfo.methodSig); + reflectMethod = hookMethod; + } + return reflectMethod; + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DynamicBridge.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DynamicBridge.java new file mode 100644 index 00000000..66fca6c7 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DynamicBridge.java @@ -0,0 +1,130 @@ +package com.elderdrivers.riru.edxp.sandhook.dexmaker; + +import com.elderdrivers.riru.edxp.Main; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import de.robv.android.xposed.XposedBridge; + +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; +import static com.elderdrivers.riru.edxp.util.FileUtils.getPackageName; +import static com.elderdrivers.riru.edxp.util.ProcessUtils.getCurrentProcessName; +import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.shouldUseInMemoryHook; + +public final class DynamicBridge { + + private static final HashMap hookedInfo = new HashMap<>(); + private static final HookerDexMaker dexMaker = new HookerDexMaker(); + private static final AtomicBoolean dexPathInited = new AtomicBoolean(false); + private static File dexDir; + + /** + * Reset dexPathInited flag once we enter child process + * since it might have been set to true in zygote process + */ + public static void onForkPost() { + dexPathInited.set(false); + } + + public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) { + DexLog.d("hooking " + hookMethod); + if (!checkMember(hookMethod)) { + return; + } + + if (hookedInfo.containsKey(hookMethod)) { + DexLog.w("already hook method:" + hookMethod.toString()); + return; + } + + DexLog.d("start to generate class for: " + hookMethod); + try { + // for Android Oreo and later use InMemoryClassLoader + if (!shouldUseInMemoryHook()) { + setupDexCachePath(); + } + dexMaker.start(hookMethod, additionalHookInfo, + hookMethod.getDeclaringClass().getClassLoader(), getDexDirPath()); + hookedInfo.put(hookMethod, dexMaker.getCallBackupMethod()); + } catch (Exception e) { + DexLog.e("error occur when generating dex. dexDir=" + dexDir, e); + } + } + + private static String getDexDirPath() { + if (dexDir == null) { + return null; + } + return dexDir.getAbsolutePath(); + } + + private static void setupDexCachePath() { + // using file based DexClassLoader + if (!dexPathInited.compareAndSet(false, true)) { + return; + } + try { + // we always choose to use device encrypted storage data on android N and later + // in case some app is installing hooks before phone is unlocked + String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/"; + dexDir = new File(fixedAppDataDir, "/cache/edhookers/" + + getCurrentProcessName(Main.appProcessName).replace(":", "_") + "/"); + dexDir.mkdirs(); + } catch (Throwable throwable) { + DexLog.e("error when init dex path", throwable); + } + } + + private static boolean checkMember(Member member) { + + if (member instanceof Method) { + return true; + } else if (member instanceof Constructor) { + return true; + } else if (member.getDeclaringClass().isInterface()) { + DexLog.e("Cannot hook interfaces: " + member.toString()); + return false; + } else if (Modifier.isAbstract(member.getModifiers())) { + DexLog.e("Cannot hook abstract methods: " + member.toString()); + return false; + } else { + DexLog.e("Only methods and constructors can be hooked: " + member.toString()); + return false; + } + } + + public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) + throws InvocationTargetException, IllegalAccessException { + Method callBackup = hookedInfo.get(method); + if (callBackup == null) { + throw new IllegalStateException("method not hooked, cannot call original method."); + } + if (!Modifier.isStatic(callBackup.getModifiers())) { + throw new IllegalStateException("original method is not static, something must be wrong!"); + } + callBackup.setAccessible(true); + if (args == null) { + args = new Object[0]; + } + final int argsSize = args.length; + if (Modifier.isStatic(method.getModifiers())) { + return callBackup.invoke(null, args); + } else { + Object[] newArgs = new Object[argsSize + 1]; + newArgs[0] = thisObject; + for (int i = 1; i < newArgs.length; i++) { + newArgs[i] = args[i - 1]; + } + return callBackup.invoke(null, newArgs); + } + } +} + + diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/HookerDexMaker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/HookerDexMaker.java new file mode 100644 index 00000000..537a217a --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/HookerDexMaker.java @@ -0,0 +1,569 @@ +package com.elderdrivers.riru.edxp.sandhook.dexmaker; + +import android.annotation.TargetApi; +import android.os.Build; +import android.text.TextUtils; + +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.core.HookMain; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import dalvik.system.InMemoryDexClassLoader; +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import external.com.android.dx.BinaryOp; +import external.com.android.dx.Code; +import external.com.android.dx.Comparison; +import external.com.android.dx.DexMaker; +import external.com.android.dx.FieldId; +import external.com.android.dx.Label; +import external.com.android.dx.Local; +import external.com.android.dx.MethodId; +import external.com.android.dx.TypeId; + +import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.autoBoxIfNecessary; +import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.autoUnboxIfNecessary; +import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.createResultLocals; +import static com.elderdrivers.riru.edxp.sandhook.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive; + +public class HookerDexMaker { + + public static final String METHOD_NAME_BACKUP = "backup"; + public static final String METHOD_NAME_HOOK = "hook"; + public static final String METHOD_NAME_CALL_BACKUP = "callBackup"; + public static final String METHOD_NAME_SETUP = "setup"; + public static final TypeId objArrayTypeId = TypeId.get(Object[].class); + private static final String CLASS_DESC_PREFIX = "L"; + /** + * Note: this identifier is used in native codes to pass class access verification. + */ + private static final String CLASS_NAME_PREFIX = "EdHooker_"; + private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo"; + private static final String FIELD_NAME_METHOD = "method"; + private static final String PARAMS_FIELD_NAME_METHOD = "method"; + private static final String PARAMS_FIELD_NAME_THIS_OBJECT = "thisObject"; + private static final String PARAMS_FIELD_NAME_ARGS = "args"; + private static final String CALLBACK_METHOD_NAME_BEFORE = "callBeforeHookedMethod"; + private static final String CALLBACK_METHOD_NAME_AFTER = "callAfterHookedMethod"; + private static final String PARAMS_METHOD_NAME_IS_EARLY_RETURN = "isEarlyReturn"; + private static final TypeId throwableTypeId = TypeId.get(Throwable.class); + private static final TypeId memberTypeId = TypeId.get(Member.class); + private static final TypeId callbackTypeId = TypeId.get(XC_MethodHook.class); + private static final TypeId hookInfoTypeId + = TypeId.get(XposedBridge.AdditionalHookInfo.class); + private static final TypeId callbacksTypeId + = TypeId.get(XposedBridge.CopyOnWriteSortedSet.class); + private static final TypeId paramTypeId + = TypeId.get(XC_MethodHook.MethodHookParam.class); + private static final MethodId setResultMethodId = + paramTypeId.getMethod(TypeId.VOID, "setResult", TypeId.OBJECT); + private static final MethodId setThrowableMethodId = + paramTypeId.getMethod(TypeId.VOID, "setThrowable", throwableTypeId); + private static final MethodId getResultMethodId = + paramTypeId.getMethod(TypeId.OBJECT, "getResult"); + private static final MethodId getThrowableMethodId = + paramTypeId.getMethod(throwableTypeId, "getThrowable"); + private static final MethodId hasThrowableMethodId = + paramTypeId.getMethod(TypeId.BOOLEAN, "hasThrowable"); + private static final MethodId callAfterCallbackMethodId = + callbackTypeId.getMethod(TypeId.VOID, CALLBACK_METHOD_NAME_AFTER, paramTypeId); + private static final MethodId callBeforeCallbackMethodId = + callbackTypeId.getMethod(TypeId.VOID, CALLBACK_METHOD_NAME_BEFORE, paramTypeId); + private static final FieldId returnEarlyFieldId = + paramTypeId.getField(TypeId.BOOLEAN, "returnEarly"); + private static final TypeId xposedBridgeTypeId = TypeId.get(XposedBridge.class); + private static final MethodId logThrowableMethodId = + xposedBridgeTypeId.getMethod(TypeId.VOID, "log", throwableTypeId); + private static final MethodId logStrMethodId = + xposedBridgeTypeId.getMethod(TypeId.VOID, "log", TypeId.STRING); + + private static AtomicLong sClassNameSuffix = new AtomicLong(1); + + private FieldId mHookInfoFieldId; + private FieldId mMethodFieldId; + private MethodId mBackupMethodId; + private MethodId mCallBackupMethodId; + private MethodId mHookMethodId; + + private TypeId mHookerTypeId; + private TypeId[] mParameterTypeIds; + private Class[] mActualParameterTypes; + private Class mReturnType; + private TypeId mReturnTypeId; + private boolean mIsStatic; + // TODO use this to generate methods + private boolean mHasThrowable; + + private DexMaker mDexMaker; + private Member mMember; + private XposedBridge.AdditionalHookInfo mHookInfo; + private ClassLoader mAppClassLoader; + private Class mHookClass; + private Method mHookMethod; + private Method mBackupMethod; + private Method mCallBackupMethod; + private String mDexDirPath; + + private static TypeId[] getParameterTypeIds(Class[] parameterTypes, boolean isStatic) { + int parameterSize = parameterTypes.length; + int targetParameterSize = isStatic ? parameterSize : parameterSize + 1; + TypeId[] parameterTypeIds = new TypeId[targetParameterSize]; + int offset = 0; + if (!isStatic) { + parameterTypeIds[0] = TypeId.OBJECT; + offset = 1; + } + for (int i = 0; i < parameterTypes.length; i++) { + parameterTypeIds[i + offset] = TypeId.get(parameterTypes[i]); + } + return parameterTypeIds; + } + + private static Class[] getParameterTypes(Class[] parameterTypes, boolean isStatic) { + if (isStatic) { + return parameterTypes; + } + int parameterSize = parameterTypes.length; + int targetParameterSize = parameterSize + 1; + Class[] newParameterTypes = new Class[targetParameterSize]; + int offset = 1; + newParameterTypes[0] = Object.class; + System.arraycopy(parameterTypes, 0, newParameterTypes, offset, parameterTypes.length); + return newParameterTypes; + } + + public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, + ClassLoader appClassLoader, String dexDirPath) throws Exception { + if (member instanceof Method) { + Method method = (Method) member; + mIsStatic = Modifier.isStatic(method.getModifiers()); + mReturnType = method.getReturnType(); + if (mReturnType.equals(Void.class) || mReturnType.equals(void.class) + || mReturnType.isPrimitive()) { + mReturnTypeId = TypeId.get(mReturnType); + } else { + // all others fallback to plain Object for convenience + mReturnType = Object.class; + mReturnTypeId = TypeId.OBJECT; + } + mParameterTypeIds = getParameterTypeIds(method.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(method.getParameterTypes(), mIsStatic); + mHasThrowable = method.getExceptionTypes().length > 0; + } else if (member instanceof Constructor) { + Constructor constructor = (Constructor) member; + mIsStatic = false; + mReturnType = void.class; + mReturnTypeId = TypeId.VOID; + mParameterTypeIds = getParameterTypeIds(constructor.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(constructor.getParameterTypes(), mIsStatic); + mHasThrowable = constructor.getExceptionTypes().length > 0; + } else if (member.getDeclaringClass().isInterface()) { + throw new IllegalArgumentException("Cannot hook interfaces: " + member.toString()); + } else if (Modifier.isAbstract(member.getModifiers())) { + throw new IllegalArgumentException("Cannot hook abstract methods: " + member.toString()); + } else { + throw new IllegalArgumentException("Only methods and constructors can be hooked: " + member.toString()); + } + mMember = member; + mHookInfo = hookInfo; + mDexDirPath = dexDirPath; + if (appClassLoader == null + || appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) { + mAppClassLoader = this.getClass().getClassLoader(); + } else { + mAppClassLoader = appClassLoader; + } + doMake(); + } + + @TargetApi(Build.VERSION_CODES.O) + private void doMake() throws Exception { + final boolean useInMemoryCl = TextUtils.isEmpty(mDexDirPath); + mDexMaker = new DexMaker(); + ClassLoader loader; + // Generate a Hooker class. + String className = CLASS_NAME_PREFIX; + if (!useInMemoryCl) { + // if not using InMemoryDexClassLoader, className is also used as dex file name + // so it should be different from each other + String suffix = DexMakerUtils.getSha1Hex(mMember.toString()); + if (TextUtils.isEmpty(suffix)) { // just in case + suffix = String.valueOf(sClassNameSuffix.getAndIncrement()); + } + className = className + suffix; + if (!new File(mDexDirPath, className).exists()) { + // if file exists, reuse it and skip generating + doGenerate(className); + } + // load dex file from disk + loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), className); + } else { + // do everything in memory + doGenerate(className); + byte[] dexBytes = mDexMaker.generate(); + loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); + } + + mHookClass = loader.loadClass(className); + // Execute our newly-generated code in-process. + mHookClass.getMethod(METHOD_NAME_SETUP, Member.class, XposedBridge.AdditionalHookInfo.class) + .invoke(null, mMember, mHookInfo); + mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes); + mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); + mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes); + Main.setMethodNonCompilable(mCallBackupMethod); + HookMain.backupAndHook(mMember, mHookMethod, mBackupMethod); + } + + private void doGenerate(String className) { + String classDesc = CLASS_DESC_PREFIX + className + ";"; + mHookerTypeId = TypeId.get(classDesc); + mDexMaker.declare(mHookerTypeId, className + ".generated", Modifier.PUBLIC, TypeId.OBJECT); + generateFields(); + generateSetupMethod(); + generateBackupMethod(); + generateHookMethod(); + generateCallBackupMethod(); + } + + public Method getHookMethod() { + return mHookMethod; + } + + public Method getBackupMethod() { + return mBackupMethod; + } + + public Method getCallBackupMethod() { + return mCallBackupMethod; + } + + public Class getHookClass() { + return mHookClass; + } + + private void generateFields() { + mHookInfoFieldId = mHookerTypeId.getField(hookInfoTypeId, FIELD_NAME_HOOK_INFO); + mMethodFieldId = mHookerTypeId.getField(memberTypeId, FIELD_NAME_METHOD); + mDexMaker.declare(mHookInfoFieldId, Modifier.STATIC, null); + mDexMaker.declare(mMethodFieldId, Modifier.STATIC, null); + } + + private void generateSetupMethod() { + MethodId setupMethodId = mHookerTypeId.getMethod( + TypeId.VOID, METHOD_NAME_SETUP, memberTypeId, hookInfoTypeId); + Code code = mDexMaker.declare(setupMethodId, Modifier.PUBLIC | Modifier.STATIC); + // init logic + // get parameters + Local method = code.getParameter(0, memberTypeId); + Local hookInfo = code.getParameter(1, hookInfoTypeId); + // save params to static + code.sput(mMethodFieldId, method); + code.sput(mHookInfoFieldId, hookInfo); + code.returnVoid(); + } + + private void generateBackupMethod() { + mBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_BACKUP, mParameterTypeIds); + Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + Map resultLocals = createResultLocals(code); + // do nothing + if (mReturnTypeId.equals(TypeId.VOID)) { + code.returnVoid(); + } else { + // we have limited the returnType to primitives or Object, so this should be safe + code.returnValue(resultLocals.get(mReturnTypeId)); + } + } + + private void generateCallBackupMethod() { + mCallBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_CALL_BACKUP, mParameterTypeIds); + Code code = mDexMaker.declare(mCallBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + // just call backup and return its result + Local[] allArgsLocals = createParameterLocals(code); + Map resultLocals = createResultLocals(code); + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + code.returnVoid(); + } else { + Local result = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, result, allArgsLocals); + code.returnValue(result); + } + } + + private void generateHookMethod() { + mHookMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_HOOK, mParameterTypeIds); + Code code = mDexMaker.declare(mHookMethodId, Modifier.PUBLIC | Modifier.STATIC); + + // code starts + + // prepare common labels + Label noHookReturn = new Label(); + Label incrementAndCheckBefore = new Label(); + Label tryBeforeCatch = new Label(); + Label noExceptionBefore = new Label(); + Label checkAndCallBackup = new Label(); + Label beginCallBefore = new Label(); + Label beginCallAfter = new Label(); + Label tryOrigCatch = new Label(); + Label noExceptionOrig = new Label(); + Label tryAfterCatch = new Label(); + Label decrementAndCheckAfter = new Label(); + Label noBackupThrowable = new Label(); + Label throwThrowable = new Label(); + // prepare locals + Local disableHooks = code.newLocal(TypeId.BOOLEAN); + Local hookInfo = code.newLocal(hookInfoTypeId); + Local callbacks = code.newLocal(callbacksTypeId); + Local snapshot = code.newLocal(objArrayTypeId); + Local snapshotLen = code.newLocal(TypeId.INT); + Local callbackObj = code.newLocal(TypeId.OBJECT); + Local callback = code.newLocal(callbackTypeId); + + Local resultObj = code.newLocal(TypeId.OBJECT); // as a temp Local + Local one = code.newLocal(TypeId.INT); + Local nullObj = code.newLocal(TypeId.OBJECT); + Local throwable = code.newLocal(throwableTypeId); + + Local param = code.newLocal(paramTypeId); + Local method = code.newLocal(memberTypeId); + Local thisObject = code.newLocal(TypeId.OBJECT); + Local args = code.newLocal(objArrayTypeId); + Local returnEarly = code.newLocal(TypeId.BOOLEAN); + + Local actualParamSize = code.newLocal(TypeId.INT); + Local argIndex = code.newLocal(TypeId.INT); + + Local beforeIdx = code.newLocal(TypeId.INT); + Local lastResult = code.newLocal(TypeId.OBJECT); + Local lastThrowable = code.newLocal(throwableTypeId); + Local hasThrowable = code.newLocal(TypeId.BOOLEAN); + + Local[] allArgsLocals = createParameterLocals(code); + + Map resultLocals = createResultLocals(code); + + code.loadConstant(args, null); + code.loadConstant(argIndex, 0); + code.loadConstant(one, 1); + code.loadConstant(snapshotLen, 0); + code.loadConstant(nullObj, null); + + // check XposedBridge.disableHooks flag + + FieldId disableHooksField = + xposedBridgeTypeId.getField(TypeId.BOOLEAN, "disableHooks"); + code.sget(disableHooksField, disableHooks); + // disableHooks == true => no hooking + code.compareZ(Comparison.NE, noHookReturn, disableHooks); + + // check callbacks length + code.sget(mHookInfoFieldId, hookInfo); + code.iget(hookInfoTypeId.getField(callbacksTypeId, "callbacks"), callbacks, hookInfo); + code.invokeVirtual(callbacksTypeId.getMethod(objArrayTypeId, "getSnapshot"), snapshot, callbacks); + code.arrayLength(snapshotLen, snapshot); + // snapshotLen == 0 => no hooking + code.compareZ(Comparison.EQ, noHookReturn, snapshotLen); + + // start hooking + + // prepare hooking locals + int paramsSize = mParameterTypeIds.length; + int offset = 0; + // thisObject + if (mIsStatic) { + // thisObject = null + code.loadConstant(thisObject, null); + } else { + // thisObject = args[0] + offset = 1; + code.move(thisObject, allArgsLocals[0]); + } + // actual args (exclude thisObject if this is not a static method) + code.loadConstant(actualParamSize, paramsSize - offset); + code.newArray(args, actualParamSize); + for (int i = offset; i < paramsSize; i++) { + Local parameter = allArgsLocals[i]; + // save parameter to resultObj as Object + autoBoxIfNecessary(code, resultObj, parameter); + code.loadConstant(argIndex, i - offset); + // save Object to args + code.aput(args, argIndex, resultObj); + } + // create param + code.newInstance(param, paramTypeId.getConstructor()); + // set method, thisObject, args + code.sget(mMethodFieldId, method); + code.iput(paramTypeId.getField(memberTypeId, "method"), param, method); + code.iput(paramTypeId.getField(TypeId.OBJECT, "thisObject"), param, thisObject); + code.iput(paramTypeId.getField(objArrayTypeId, "args"), param, args); + + // call beforeCallbacks + code.loadConstant(beforeIdx, 0); + + code.mark(beginCallBefore); + // start of try + code.addCatchClause(throwableTypeId, tryBeforeCatch); + + code.aget(callbackObj, snapshot, beforeIdx); + code.cast(callback, callbackObj); + code.invokeVirtual(callBeforeCallbackMethodId, null, callback, param); + code.jump(noExceptionBefore); + + // end of try + code.removeCatchClause(throwableTypeId); + + // start of catch + code.mark(tryBeforeCatch); + code.moveException(throwable); + code.invokeStatic(logThrowableMethodId, null, throwable); + code.invokeVirtual(setResultMethodId, null, param, nullObj); + code.loadConstant(returnEarly, false); + code.iput(returnEarlyFieldId, param, returnEarly); + code.jump(incrementAndCheckBefore); + + // no exception when calling beforeCallbacks + code.mark(noExceptionBefore); + code.iget(returnEarlyFieldId, returnEarly, param); + // if returnEarly == false, continue + code.compareZ(Comparison.EQ, incrementAndCheckBefore, returnEarly); + // returnEarly == true, break + code.op(BinaryOp.ADD, beforeIdx, beforeIdx, one); + code.jump(checkAndCallBackup); + + // increment and check to continue + code.mark(incrementAndCheckBefore); + code.op(BinaryOp.ADD, beforeIdx, beforeIdx, one); + code.compare(Comparison.LT, beginCallBefore, beforeIdx, snapshotLen); + + // check and call backup + code.mark(checkAndCallBackup); + code.iget(returnEarlyFieldId, returnEarly, param); + // if returnEarly == true, go to call afterCallbacks directly + code.compareZ(Comparison.NE, noExceptionOrig, returnEarly); + // try to call backup + // try start + code.addCatchClause(throwableTypeId, tryOrigCatch); + // we have to load args[] to paramLocals + // because args[] may be changed in beforeHookedMethod + // should consider first param is thisObj if hooked method is not static + offset = mIsStatic ? 0 : 1; + for (int i = offset; i < allArgsLocals.length; i++) { + code.loadConstant(argIndex, i - offset); + code.aget(resultObj, args, argIndex); + autoUnboxIfNecessary(code, allArgsLocals[i], resultObj, resultLocals, true); + } + // get pre-created Local with a matching typeId + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + // TODO maybe keep preset result to do some magic? + code.invokeVirtual(setResultMethodId, null, param, nullObj); + } else { + Local returnedResult = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, returnedResult, allArgsLocals); + // save returnedResult to resultObj as a Object + autoBoxIfNecessary(code, resultObj, returnedResult); + // save resultObj to param + code.invokeVirtual(setResultMethodId, null, param, resultObj); + } + // go to call afterCallbacks + code.jump(noExceptionOrig); + // try end + code.removeCatchClause(throwableTypeId); + // catch + code.mark(tryOrigCatch); + code.moveException(throwable); + // exception occurred when calling backup, save throwable to param + code.invokeVirtual(setThrowableMethodId, null, param, throwable); + + code.mark(noExceptionOrig); + code.op(BinaryOp.SUBTRACT, beforeIdx, beforeIdx, one); + + // call afterCallbacks + code.mark(beginCallAfter); + // save results of backup calling + code.invokeVirtual(getResultMethodId, lastResult, param); + code.invokeVirtual(getThrowableMethodId, lastThrowable, param); + // try start + code.addCatchClause(throwableTypeId, tryAfterCatch); + code.aget(callbackObj, snapshot, beforeIdx); + code.cast(callback, callbackObj); + code.invokeVirtual(callAfterCallbackMethodId, null, callback, param); + // all good, just continue + code.jump(decrementAndCheckAfter); + // try end + code.removeCatchClause(throwableTypeId); + // catch + code.mark(tryAfterCatch); + code.moveException(throwable); + code.invokeStatic(logThrowableMethodId, null, throwable); + // if lastThrowable == null, go to recover lastResult + code.compareZ(Comparison.EQ, noBackupThrowable, lastThrowable); + // lastThrowable != null, recover lastThrowable + code.invokeVirtual(setThrowableMethodId, null, param, lastThrowable); + // continue + code.jump(decrementAndCheckAfter); + code.mark(noBackupThrowable); + // recover lastResult and continue + code.invokeVirtual(setResultMethodId, null, param, lastResult); + // decrement and check continue + code.mark(decrementAndCheckAfter); + code.op(BinaryOp.SUBTRACT, beforeIdx, beforeIdx, one); + code.compareZ(Comparison.GE, beginCallAfter, beforeIdx); + + // callbacks end + // return + code.invokeVirtual(hasThrowableMethodId, hasThrowable, param); + // if hasThrowable, throw the throwable and return + code.compareZ(Comparison.NE, throwThrowable, hasThrowable); + // return getResult + if (mReturnTypeId.equals(TypeId.VOID)) { + code.returnVoid(); + } else { + // getResult always return an Object, so save to resultObj + code.invokeVirtual(getResultMethodId, resultObj, param); + // have to unbox it if returnType is primitive + // casting Object + TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId); + Local matchObjLocal = resultLocals.get(objTypeId); + code.cast(matchObjLocal, resultObj); + // have to use matching typed Object(Integer, Double ...) to do unboxing + Local toReturn = resultLocals.get(mReturnTypeId); + autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true); + // return + code.returnValue(toReturn); + } + // throw throwable + code.mark(throwThrowable); + code.invokeVirtual(getThrowableMethodId, throwable, param); + code.throwValue(throwable); + + // call backup and return + code.mark(noHookReturn); + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + code.returnVoid(); + } else { + Local result = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, result, allArgsLocals); + code.returnValue(result); + } + } + + private Local[] createParameterLocals(Code code) { + Local[] paramLocals = new Local[mParameterTypeIds.length]; + for (int i = 0; i < mParameterTypeIds.length; i++) { + paramLocals[i] = code.getParameter(i, mParameterTypeIds[i]); + } + return paramLocals; + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/MethodInfo.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/MethodInfo.java new file mode 100644 index 00000000..b9908e93 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/MethodInfo.java @@ -0,0 +1,94 @@ +package com.elderdrivers.riru.edxp.sandhook.dexmaker; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +public class MethodInfo { + + public String className; + public String classDesc; + public String methodName; + public String methodSig; + public Method method; + public Constructor constructor; + public boolean isConstructor; + public ClassLoader classLoader; + + public MethodInfo(Member member) { + if (member instanceof Method) { + method = (Method) member; + isConstructor = false; + classLoader = member.getDeclaringClass().getClassLoader(); + generateMethodInfo(); + } else if (member instanceof Constructor) { + constructor = (Constructor) member; + isConstructor = true; + classLoader = member.getDeclaringClass().getClassLoader(); + generateConstructorInfo(); + } else { + throw new IllegalArgumentException("member should be Method or Constructor"); + } + } + + private void generateConstructorInfo() { + methodName = ""; + className = constructor.getDeclaringClass().getName(); + generateCommonInfo(constructor.getParameterTypes(), void.class); + } + + private void generateMethodInfo() { + methodName = method.getName(); + className = method.getDeclaringClass().getName(); + generateCommonInfo(method.getParameterTypes(), method.getReturnType()); + } + + private void generateCommonInfo(Class[] parameterTypes, Class returnType) { + classDesc = "L" + className.replace(".", "/") + ";"; + StringBuilder builder = new StringBuilder(); + builder.append("("); + for (Class parameterType : parameterTypes) { + builder.append(getDescStr(parameterType)); + } + builder.append(")"); + builder.append(getDescStr(returnType)); + methodSig = builder.toString(); + } + + public Class getClassForSure() { + try { + // TODO does initialize make sense? + return Class.forName(className, true, classLoader); + } catch (Throwable throwable) { + DexLog.e("error when getClassForSure", throwable); + return null; + } + } + + public static String getDescStr(Class clazz) { + if (clazz.equals(boolean.class)) { + return "Z"; + } else if (clazz.equals(byte.class)) { + return "B"; + } else if (clazz.equals(char.class)) { + return "C"; + } else if (clazz.equals(double.class)) { + return "D"; + } else if (clazz.equals(float.class)) { + return "F"; + } else if (clazz.equals(int.class)) { + return "I"; + } else if (clazz.equals(long.class)) { + return "J"; + } else if (clazz.equals(short.class)) { + return "S"; + } else if (clazz.equals(void.class)) { + return "V"; + } else { + String prefix = clazz.isArray() ? "" : "L"; + String suffix = clazz.isArray() ? "" : ";"; + return prefix + clazz.getName().replace(".", "/") + suffix; + } + } + +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/Router.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/Router.java new file mode 100644 index 00000000..281c1bd8 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/Router.java @@ -0,0 +1,126 @@ +package com.elderdrivers.riru.edxp.sandhook.entry; + +import android.app.AndroidAppHelper; +import android.text.TextUtils; + +import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.sandhook.config.SandHookEdxpConfig; +import com.elderdrivers.riru.edxp.sandhook.config.SandHookProvider; +import com.elderdrivers.riru.edxp.sandhook.core.HookMain; +import com.elderdrivers.riru.edxp.sandhook.dexmaker.DynamicBridge; +import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.AppBootstrapHookInfo; +import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.SysBootstrapHookInfo; +import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.SysInnerHookInfo; +import com.elderdrivers.riru.edxp.sandhook.entry.bootstrap.WorkAroundHookInfo; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.SystemMainHooker; +import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; + +import java.util.concurrent.atomic.AtomicBoolean; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedInit; + +public class Router { + + public volatile static boolean forkCompleted = false; + + private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); + + + public static void prepare(boolean isSystem) { + // this flag is needed when loadModules + XposedInit.startsSystemServer = isSystem; +// InstallerChooser.setup(); + } + + public static void checkHookState(String appDataDir) { + // determine whether allow xposed or not +// XposedBridge.disableHooks = ConfigManager.shouldHook(parsePackageName(appDataDir)); + } + + private static String parsePackageName(String appDataDir) { + if (TextUtils.isEmpty(appDataDir)) { + return ""; + } + int lastIndex = appDataDir.lastIndexOf("/"); + if (lastIndex < 1) { + return ""; + } + return appDataDir.substring(lastIndex + 1); + } + + public static void installBootstrapHooks(boolean isSystem) { + // Initialize the Xposed framework + try { + if (!bootstrapHooked.compareAndSet(false, true)) { + return; + } + Router.startBootstrapHook(isSystem); + XposedInit.initForZygote(isSystem); + } catch (Throwable t) { + Utils.logE("error during Xposed initialization", t); + XposedBridge.disableHooks = true; + } + } + + public static void loadModulesSafely(boolean isInZygote) { + try { + // FIXME some coredomain app can't reading modules.list + XposedInit.loadModules(isInZygote); + } catch (Exception exception) { + Utils.logE("error loading module list", exception); + } + } + + public static void startBootstrapHook(boolean isSystem) { + Utils.logD("startBootstrapHook starts: isSystem = " + isSystem); + ClassLoader classLoader = XposedBridge.BOOTCLASSLOADER; + if (isSystem) { + HookMain.doHookDefault( + Router.class.getClassLoader(), + classLoader, + SysBootstrapHookInfo.class.getName()); + } else { + HookMain.doHookDefault( + Router.class.getClassLoader(), + classLoader, + AppBootstrapHookInfo.class.getName()); + } + } + + public static void startSystemServerHook() { + HookMain.doHookDefault( + Router.class.getClassLoader(), + SystemMainHooker.systemServerCL, + SysInnerHookInfo.class.getName()); + } + + public static void startWorkAroundHook() { + HookMain.doHookDefault( + Router.class.getClassLoader(), + XposedBridge.BOOTCLASSLOADER, + WorkAroundHookInfo.class.getName()); + } + + public static void onEnterChildProcess() { + forkCompleted = true; + DynamicBridge.onForkPost(); + SandHookXposedBridge.onForkPost(); + } + + public static void logD(String prefix) { + Utils.logD(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), + AndroidAppHelper.currentProcessName())); + } + + public static void logE(String prefix, Throwable throwable) { + Utils.logE(String.format("%s: pkg=%s, prc=%s", prefix, AndroidAppHelper.currentPackageName(), + AndroidAppHelper.currentProcessName()), throwable); + } + + public static void injectConfig() { + EdXpConfigGlobal.sConfig = new SandHookEdxpConfig(); + EdXpConfigGlobal.sHookProvider = new SandHookProvider(); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/AppBootstrapHookInfo.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/AppBootstrapHookInfo.java new file mode 100644 index 00000000..7e630062 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/AppBootstrapHookInfo.java @@ -0,0 +1,14 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.OnePlusWorkAroundHooker; + +public class AppBootstrapHookInfo implements KeepMembers { + public static String[] hookItemNames = { + HandleBindAppHooker.class.getName(), + LoadedApkConstructorHooker.class.getName(), + OnePlusWorkAroundHooker.class.getName() + }; +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysBootstrapHookInfo.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysBootstrapHookInfo.java new file mode 100644 index 00000000..8fed0f42 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysBootstrapHookInfo.java @@ -0,0 +1,16 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.SystemMainHooker; + +public class SysBootstrapHookInfo implements KeepMembers { + public static String[] hookItemNames = { + HandleBindAppHooker.class.getName(), + SystemMainHooker.class.getName(), + LoadedApkConstructorHooker.class.getName(), + OnePlusWorkAroundHooker.class.getName() + }; +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysInnerHookInfo.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysInnerHookInfo.java new file mode 100644 index 00000000..797ad9aa --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysInnerHookInfo.java @@ -0,0 +1,10 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.StartBootstrapServicesHooker; + +public class SysInnerHookInfo implements KeepMembers { + public static String[] hookItemNames = { + StartBootstrapServicesHooker.class.getName() + }; +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/WorkAroundHookInfo.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/WorkAroundHookInfo.java new file mode 100644 index 00000000..8713185c --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/WorkAroundHookInfo.java @@ -0,0 +1,10 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.hooker.OnePlusWorkAroundHooker; + +public class WorkAroundHookInfo implements KeepMembers { + public static String[] hookItemNames = { + OnePlusWorkAroundHooker.class.getName() + }; +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/HandleBindAppHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/HandleBindAppHooker.java new file mode 100644 index 00000000..db2fe706 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/HandleBindAppHooker.java @@ -0,0 +1,89 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import android.app.ActivityThread; +import android.app.LoadedApk; +import android.content.ComponentName; +import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; +import de.robv.android.xposed.XposedInit; +import de.robv.android.xposed.callbacks.XC_LoadPackage; + +import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME; +import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader; +import static com.elderdrivers.riru.edxp.sandhook.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; + +// normal process initialization (for new Activity, Service, BroadcastReceiver etc.) +public class HandleBindAppHooker implements KeepMembers { + + public static String className = "android.app.ActivityThread"; + public static String methodName = "handleBindApplication"; + public static String methodSig = "(Landroid/app/ActivityThread$AppBindData;)V"; + + public static void hook(Object thiz, Object bindData) { + if (XposedBlackListHooker.shouldDisableHooks("")) { + backup(thiz, bindData); + return; + } + try { + Router.logD("ActivityThread#handleBindApplication() starts"); + ActivityThread activityThread = (ActivityThread) thiz; + ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo"); + // save app process name here for later use + Main.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName"); + String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName; + Utils.logD("processName=" + Main.appProcessName + + ", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir); + + if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) { + return; + } + + ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName"); + if (instrumentationName != null) { + Router.logD("Instrumentation detected, disabling framework for"); + XposedBridge.disableHooks = true; + return; + } + CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo"); + if (appInfo.sourceDir == null) { + return; + } + + XposedHelpers.setObjectField(activityThread, "mBoundApplication", bindData); + XposedInit.loadedPackagesInProcess.add(reportedPackageName); + LoadedApk loadedApk = activityThread.getPackageInfoNoCheck(appInfo, compatInfo); + + replaceParentClassLoader(loadedApk.getClassLoader()); + + XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks); + lpparam.packageName = reportedPackageName; + lpparam.processName = (String) XposedHelpers.getObjectField(bindData, "processName"); + lpparam.classLoader = loadedApk.getClassLoader(); + lpparam.appInfo = appInfo; + lpparam.isFirstApplication = true; + XC_LoadPackage.callAll(lpparam); + + if (reportedPackageName.equals(INSTALLER_PACKAGE_NAME)) { + XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader); + } + if (reportedPackageName.equals(BLACK_LIST_PACKAGE_NAME)) { + XposedBlackListHooker.hook(lpparam.classLoader); + } + } catch (Throwable t) { + Router.logE("error when hooking bindApp", t); + } finally { + backup(thiz, bindData); + } + } + + public static void backup(Object thiz, Object bindData) { + } +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/LoadedApkConstructorHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/LoadedApkConstructorHooker.java new file mode 100644 index 00000000..d31aa728 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/LoadedApkConstructorHooker.java @@ -0,0 +1,98 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import android.app.ActivityThread; +import android.app.AndroidAppHelper; +import android.app.LoadedApk; +import android.content.pm.ApplicationInfo; +import android.content.res.CompatibilityInfo; +import android.util.Log; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; +import de.robv.android.xposed.XposedInit; +import de.robv.android.xposed.callbacks.XC_LoadPackage; + +import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader; + +// when a package is loaded for an existing process, trigger the callbacks as well +// ed: remove resources related hooking +public class LoadedApkConstructorHooker implements KeepMembers { + public static String className = "android.app.LoadedApk"; + public static String methodName = ""; + public static String methodSig = "(Landroid/app/ActivityThread;" + + "Landroid/content/pm/ApplicationInfo;" + + "Landroid/content/res/CompatibilityInfo;" + + "Ljava/lang/ClassLoader;ZZZ)V"; + + public static void hook(Object thiz, ActivityThread activityThread, + ApplicationInfo aInfo, CompatibilityInfo compatInfo, + ClassLoader baseLoader, boolean securityViolation, + boolean includeCode, boolean registerPackage) { + + if (XposedBlackListHooker.shouldDisableHooks("")) { + backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, + includeCode, registerPackage); + return; + } + + Router.logD("LoadedApk# starts"); + backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, + includeCode, registerPackage); + + try { + LoadedApk loadedApk = (LoadedApk) thiz; + String packageName = loadedApk.getPackageName(); + Object mAppDir = XposedHelpers.getObjectField(thiz, "mAppDir"); + Router.logD("LoadedApk# ends: " + mAppDir); + + if (XposedBlackListHooker.shouldDisableHooks(packageName)) { + return; + } + + if (packageName.equals("android")) { + Router.logD("LoadedApk# is android, skip: " + mAppDir); + return; + } + + // mIncludeCode checking should go ahead of loadedPackagesInProcess added checking + if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) { + Router.logD("LoadedApk# mIncludeCode == false: " + mAppDir); + return; + } + + if (!XposedInit.loadedPackagesInProcess.add(packageName)) { + Router.logD("LoadedApk# has been loaded before, skip: " + mAppDir); + return; + } + + // OnePlus magic... + if (Log.getStackTraceString(new Throwable()). + contains("android.app.ActivityThread$ApplicationThread.schedulePreload")) { + Router.logD("LoadedApk# maybe oneplus's custom opt, skip"); + return; + } + + replaceParentClassLoader(loadedApk.getClassLoader()); + + XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks); + lpparam.packageName = packageName; + lpparam.processName = AndroidAppHelper.currentProcessName(); + lpparam.classLoader = loadedApk.getClassLoader(); + lpparam.appInfo = loadedApk.getApplicationInfo(); + lpparam.isFirstApplication = false; + XC_LoadPackage.callAll(lpparam); + } catch (Throwable t) { + Router.logE("error when hooking LoadedApk.", t); + } + } + + public static void backup(Object thiz, ActivityThread activityThread, + ApplicationInfo aInfo, CompatibilityInfo compatInfo, + ClassLoader baseLoader, boolean securityViolation, + boolean includeCode, boolean registerPackage) { + + } +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/OnePlusWorkAroundHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/OnePlusWorkAroundHooker.java new file mode 100644 index 00000000..e83b1f45 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/OnePlusWorkAroundHooker.java @@ -0,0 +1,41 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; + +import de.robv.android.xposed.XposedBridge; + +/** + * On OnePlus stock roms (Android Pie), {@link dalvik.system.BaseDexClassLoader#findClass(String)} + * will open /dev/binder to communicate with PackageManagerService to check whether + * current package name inCompatConfigList, which is an OnePlus OEM feature enabled only when + * system prop "persist.sys.oem.region" set to "CN".(detail of related source code: + * https://gist.github.com/solohsu/ecc07141759958fc096ba0781fac0a5f) + * If we invoke intZygoteCallbacks in + * {@link Main#forkAndSpecializePre}, where in zygote process, + * we would get a chance to invoke findclass, leaving fd of /dev/binder open in zygote process, + * which is not allowed because /dev/binder is not in predefined whitelist here: + * http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/fd_utils.cpp#35 + * So we just hook BaseDexClassLoader#inCompatConfigList to return false to prevent + * open of /dev/binder and we haven't found side effects yet. + * Other roms might share the same problems but not reported too. + */ +public class OnePlusWorkAroundHooker implements KeepMembers { + + public static String className = "dalvik.system.BaseDexClassLoader"; + public static String methodName = "inCompatConfigList"; + public static String methodSig = "(ILjava/lang/String;)Z"; + + public static boolean hook(int type, String packageName) { + if (XposedBridge.disableHooks || Router.forkCompleted) { + return backup(type, packageName); + } + Router.logD("BaseDexClassLoader#inCompatConfigList() starts"); + return false; + } + + public static boolean backup(int type, String packageName) { + return false; + } +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/StartBootstrapServicesHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/StartBootstrapServicesHooker.java new file mode 100644 index 00000000..0b2f8428 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/StartBootstrapServicesHooker.java @@ -0,0 +1,66 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import android.os.Build; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; + +import de.robv.android.xposed.XC_MethodReplacement; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; +import de.robv.android.xposed.XposedInit; +import de.robv.android.xposed.callbacks.XC_LoadPackage; + +import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader; +import static com.elderdrivers.riru.edxp.util.Utils.logD; +import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; + +public class StartBootstrapServicesHooker implements KeepMembers { + public static String className = "com.android.server.SystemServer"; + public static String methodName = "startBootstrapServices"; + public static String methodSig = "()V"; + + public static void hook(Object systemServer) { + + if (XposedBridge.disableHooks) { + backup(systemServer); + return; + } + + logD("SystemServer#startBootstrapServices() starts"); + + try { + XposedInit.loadedPackagesInProcess.add("android"); + + replaceParentClassLoader(SystemMainHooker.systemServerCL); + + XC_LoadPackage.LoadPackageParam lpparam = new XC_LoadPackage.LoadPackageParam(XposedBridge.sLoadedPackageCallbacks); + lpparam.packageName = "android"; + lpparam.processName = "android"; // it's actually system_server, but other functions return this as well + lpparam.classLoader = SystemMainHooker.systemServerCL; + lpparam.appInfo = null; + lpparam.isFirstApplication = true; + XC_LoadPackage.callAll(lpparam); + + // Huawei + try { + findAndHookMethod("com.android.server.pm.HwPackageManagerService", SystemMainHooker.systemServerCL, "isOdexMode", XC_MethodReplacement.returnConstant(false)); + } catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) { + } + + try { + String className = "com.android.server.pm." + (Build.VERSION.SDK_INT >= 23 ? "PackageDexOptimizer" : "PackageManagerService"); + findAndHookMethod(className, SystemMainHooker.systemServerCL, "dexEntryExists", String.class, XC_MethodReplacement.returnConstant(true)); + } catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) { + } + } catch (Throwable t) { + Router.logE("error when hooking startBootstrapServices", t); + } finally { + backup(systemServer); + } + } + + public static void backup(Object systemServer) { + + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/SystemMainHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/SystemMainHooker.java new file mode 100644 index 00000000..f33db3e7 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/SystemMainHooker.java @@ -0,0 +1,43 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import android.app.ActivityThread; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; +import com.elderdrivers.riru.edxp.sandhook.util.PrebuiltMethodsDeopter; + +import de.robv.android.xposed.XposedBridge; + + +// system_server initialization +// ed: only support sdk >= 21 for now +public class SystemMainHooker implements KeepMembers { + + public static String className = "android.app.ActivityThread"; + public static String methodName = "systemMain"; + public static String methodSig = "()Landroid/app/ActivityThread;"; + + public static ClassLoader systemServerCL; + + public static ActivityThread hook() { + if (XposedBridge.disableHooks) { + return backup(); + } + Router.logD("ActivityThread#systemMain() starts"); + ActivityThread activityThread = backup(); + try { + // get system_server classLoader + systemServerCL = Thread.currentThread().getContextClassLoader(); + // deopt methods in SYSTEMSERVERCLASSPATH + PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL); + Router.startSystemServerHook(); + } catch (Throwable t) { + Router.logE("error when hooking systemMain", t); + } + return activityThread; + } + + public static ActivityThread backup() { + return null; + } +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java new file mode 100644 index 00000000..c86dddfc --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java @@ -0,0 +1,87 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.os.Build; + +import com.elderdrivers.riru.edxp.util.Utils; + +import java.io.File; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XSharedPreferences; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME; +import static com.elderdrivers.riru.edxp.util.FileUtils.IS_USING_PROTECTED_STORAGE; + +public class XposedBlackListHooker { + + public static final String BLACK_LIST_PACKAGE_NAME = "com.flarejune.xposedblacklist"; + private static final String BLACK_LIST_PREF_NAME = "list"; + private static final String PREF_KEY_BLACK_LIST = "blackList"; + public static final String PREF_FILE_PATH = (IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data") + + BLACK_LIST_PACKAGE_NAME + "/shared_prefs/" + BLACK_LIST_PREF_NAME + ".xml"; + private static final XSharedPreferences PREFERENCES = new XSharedPreferences(new File(PREF_FILE_PATH)); + // always white list. empty string is to make sure blackList does not contain empty packageName + private static final List WHITE_LIST = Arrays.asList(INSTALLER_PACKAGE_NAME, BLACK_LIST_PACKAGE_NAME, ""); + + static { + try { + PREFERENCES.makeWorldReadable(); + } catch (Throwable throwable) { + Utils.logE("error making pref worldReadable", throwable); + } + } + + public static boolean shouldDisableHooks(String packageName) { + return XposedBridge.disableHooks || getBlackList().contains(packageName); + } + + public static Set getBlackList() { + try { + PREFERENCES.reload(); + Set result = PREFERENCES.getStringSet(PREF_KEY_BLACK_LIST, new HashSet()); + if (result != null) result.removeAll(WHITE_LIST); + return result; + } catch (Throwable throwable) { + Utils.logE("error when reading black list", throwable); + return new HashSet<>(); + } + } + + public static void hook(ClassLoader classLoader) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + return; + } + try { + XposedHelpers.findAndHookMethod(ContextWrapper.class, "getSharedPreferences", String.class, int.class, new XC_MethodHook() { + @TargetApi(Build.VERSION_CODES.N) + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + try { + String prefName = (String) param.args[0]; + if (!prefName.equals(BLACK_LIST_PREF_NAME)) { + return; + } + Activity activity = (Activity) param.thisObject; + Context context = activity.createDeviceProtectedStorageContext(); + context.moveSharedPreferencesFrom(activity, prefName); + param.setResult(context.getSharedPreferences(prefName, (int) param.args[1])); + } catch (Throwable throwable) { + Utils.logE("error hooking Xposed BlackList", throwable); + } + } + }); + } catch (Throwable throwable) { + Utils.logE("error hooking Xposed BlackList", throwable); + } + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java new file mode 100644 index 00000000..e3b83a77 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java @@ -0,0 +1,64 @@ +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; + +import com.elderdrivers.riru.edxp.util.Utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XC_MethodReplacement; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +import static com.elderdrivers.riru.edxp.config.InstallerChooser.LEGACY_INSTALLER_PACKAGE_NAME; + +public class XposedInstallerHooker { + + public static void hookXposedInstaller(ClassLoader classLoader) { + try { + final String xposedAppClass = LEGACY_INSTALLER_PACKAGE_NAME + ".XposedApp"; + final Class InstallZipUtil = XposedHelpers.findClass(LEGACY_INSTALLER_PACKAGE_NAME + + ".util.InstallZipUtil", classLoader); + XposedHelpers.findAndHookMethod(xposedAppClass, classLoader, "getActiveXposedVersion", + XC_MethodReplacement.returnConstant(XposedBridge.getXposedVersion())); + XposedHelpers.findAndHookMethod(xposedAppClass, classLoader, + "reloadXposedProp", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(MethodHookParam param) throws Throwable { + Utils.logD("before reloadXposedProp..."); + final String propFieldName = "mXposedProp"; + final Object thisObject = param.thisObject; + if (XposedHelpers.getObjectField(thisObject, propFieldName) != null) { + param.setResult(null); + Utils.logD("reloadXposedProp already done, skip..."); + return; + } + File file = new File("/system/framework/edconfig.jar"); + FileInputStream is = null; + try { + is = new FileInputStream(file); + Object props = XposedHelpers.callStaticMethod(InstallZipUtil, + "parseXposedProp", is); + synchronized (thisObject) { + XposedHelpers.setObjectField(thisObject, propFieldName, props); + } + Utils.logD("reloadXposedProp done..."); + param.setResult(null); + } catch (IOException e) { + Utils.logE("Could not read " + file.getPath(), e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ignored) { + } + } + } + } + }); + } catch (Throwable t) { + Utils.logE("Could not hook Xposed Installer", t); + } + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/BlackWhiteListProxy.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/BlackWhiteListProxy.java new file mode 100644 index 00000000..5ddfdc2a --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/BlackWhiteListProxy.java @@ -0,0 +1,132 @@ +package com.elderdrivers.riru.edxp.sandhook.proxy; + +import android.text.TextUtils; + +import com.elderdrivers.riru.edxp.config.ConfigManager; +import com.elderdrivers.riru.edxp.util.ProcessUtils; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; +import com.elderdrivers.riru.edxp.sandhook.util.PrebuiltMethodsDeopter; + +import de.robv.android.xposed.XposedBridge; + +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; +import static com.elderdrivers.riru.edxp.Main.isAppNeedHook; + +/** + * 1. Non dynamic mode + * - system_server is whitelisted + * * for all child processes of main zygote + * What've been done in main zygote pre-forking system_server + * 1) non dynamic flag set (no need to reset) + * 2) boot image methods deopted (no need to redo) + * 3) startSystemServer flag set to true (need to reset) + * 4) workaround hooks installed (need to redo) + * 5) module list loaded and initZygote called (no need to redo) + * 6) close all fds (no need to redo because of 5)) + * * for all child processes of secondary zygote + * 1) do the same things pre-forking first child process + * - system_server is blacklisted: + * * for all child processes of both main zygote and secondary zygote + * 1) do the same things pre-forking first child process + * 2. Dynamic mode: + * to be continued + */ +public class BlackWhiteListProxy { + + public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, int mountExternal, String seInfo, + String niceName, int[] fdsToClose, int[] fdsToIgnore, + boolean startChildZygote, String instructionSet, + String appDataDir) { + final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled(); + if (isDynamicModulesMode) { + // should never happen + return; + } + // only enter here when isDynamicModulesMode is off + onForkPreForNonDynamicMode(false); + } + + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { + onForkPostCommon(false, appDataDir, niceName); + } + + public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, long permittedCapabilities, + long effectiveCapabilities) { + final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled(); + if (isDynamicModulesMode) { + // should never happen + return; + } + // only enter here when isDynamicModulesMode is off + onForkPreForNonDynamicMode(true); + } + + public static void forkSystemServerPost(int pid) { + onForkPostCommon(true, getDataPathPrefix() + "android", "system_server"); + } + + /** + * Some details are different between main zygote and secondary zygote. + */ + private static void onForkPreForNonDynamicMode(boolean isSystemServer) { + ConfigManager.setDynamicModulesMode(false); + // set startsSystemServer flag used when loadModules + Router.prepare(isSystemServer); + // deoptBootMethods once for all child processes of zygote + PrebuiltMethodsDeopter.deoptBootMethods(); + // we never install bootstrap hooks here in black/white list mode except workaround hooks + // because installed hooks would be propagated to all child processes of zygote + Router.startWorkAroundHook(); + // loadModules once for all child processes of zygote + // TODO maybe just save initZygote callbacks and call them when whitelisted process forked? + Router.loadModulesSafely(true); + Main.closeFilesBeforeForkNative(); + } + + private static void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) { + Main.appDataDir = appDataDir; + Main.niceName = niceName; + final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled(); + ConfigManager.setDynamicModulesMode(isDynamicModulesMode); + Router.onEnterChildProcess(); + if (!isDynamicModulesMode) { + Main.reopenFilesAfterForkNative(); + } + if (!checkNeedHook(appDataDir, niceName)) { + // if is blacklisted, just stop here + return; + } + Router.prepare(isSystemServer); + PrebuiltMethodsDeopter.deoptBootMethods(); + Router.installBootstrapHooks(isSystemServer); + if (isDynamicModulesMode) { + Router.loadModulesSafely(false); + } + } + + private static boolean checkNeedHook(String appDataDir, String niceName) { + boolean needHook; + if (TextUtils.isEmpty(appDataDir)) { + Utils.logE("niceName:" + niceName + ", procName:" + + ProcessUtils.getCurrentProcessName(Main.appProcessName) + ", appDataDir is null, blacklisted!"); + needHook = false; + } else { + // FIXME some process cannot read app_data_file because of MLS, e.g. bluetooth + needHook = isAppNeedHook(appDataDir); + } + if (!needHook) { + // clean up the scene + onBlackListed(); + } + return needHook; + } + + private static void onBlackListed() { + XposedBridge.clearLoadedPackages(); + XposedBridge.clearInitPackageResources(); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/NormalProxy.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/NormalProxy.java new file mode 100644 index 00000000..b09ff554 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/proxy/NormalProxy.java @@ -0,0 +1,70 @@ +package com.elderdrivers.riru.edxp.sandhook.proxy; + +import com.elderdrivers.riru.edxp.config.ConfigManager; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; +import com.elderdrivers.riru.edxp.sandhook.util.PrebuiltMethodsDeopter; + +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; + +public class NormalProxy { + + public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugFlags, + int[][] rlimits, int mountExternal, String seInfo, + String niceName, int[] fdsToClose, int[] fdsToIgnore, + boolean startChildZygote, String instructionSet, + String appDataDir) { + // mainly for secondary zygote + final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled(); + ConfigManager.setDynamicModulesMode(isDynamicModulesMode); + // call this to ensure the flag is set to false ASAP + Router.prepare(false); + PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for secondary zygote + // install bootstrap hooks for secondary zygote + Router.installBootstrapHooks(false); + // only load modules for secondary zygote + Router.loadModulesSafely(true); + Main.closeFilesBeforeForkNative(); + } + + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { + // TODO consider processes without forkAndSpecializePost called + Main.appDataDir = appDataDir; + Main.niceName = niceName; + Router.prepare(false); + Main.reopenFilesAfterForkNative(); + Router.onEnterChildProcess(); + // load modules for each app process on its forked if dynamic modules mode is on + Router.loadModulesSafely(false); + } + + public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, + long permittedCapabilities, long effectiveCapabilities) { + final boolean isDynamicModulesMode = Main.isDynamicModulesEnabled(); + ConfigManager.setDynamicModulesMode(isDynamicModulesMode); + // set startsSystemServer flag used when loadModules + Router.prepare(true); + PrebuiltMethodsDeopter.deoptBootMethods(); // do it once for main zygote + // install bootstrap hooks for main zygote as early as possible + // in case we miss some processes not forked via forkAndSpecialize + // for instance com.android.phone + Router.installBootstrapHooks(true); + // loadModules have to be executed in zygote even isDynamicModules is false + // because if not global hooks installed in initZygote might not be + // propagated to processes not forked via forkAndSpecialize + Router.loadModulesSafely(true); + Main.closeFilesBeforeForkNative(); + } + + public static void forkSystemServerPost(int pid) { + // in system_server process + Main.appDataDir = getDataPathPrefix() + "android"; + Main.niceName = "system_server"; + Router.prepare(true); + Main.reopenFilesAfterForkNative(); + Router.onEnterChildProcess(); + // reload module list if dynamic mode is on + Router.loadModulesSafely(false); + } + +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/InlinedMethodCallers.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/InlinedMethodCallers.java new file mode 100644 index 00000000..4ef716e1 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/InlinedMethodCallers.java @@ -0,0 +1,49 @@ +package com.elderdrivers.riru.edxp.sandhook.util; + +import java.util.HashMap; + +/** + * Providing a whitelist of methods which are the callers of the target methods we want to hook. + * Because the target methods are inlined into the callers, we deoptimize the callers to + * run in intercept mode to make target methods hookable. + *

+ * Only for methods which are included in pre-compiled framework codes. + * TODO recompile system apps and priv-apps since their original dex files are available + */ +public class InlinedMethodCallers { + + public static final String KEY_BOOT_IMAGE = "boot_image"; + public static final String KEY_SYSTEM_SERVER = "system_server"; + + /** + * Key should be {@link #KEY_BOOT_IMAGE}, {@link #KEY_SYSTEM_SERVER}, or a package name + * of system apps or priv-apps i.e. com.android.systemui + */ + private static final HashMap CALLERS = new HashMap<>(); + + /** + * format for each row: {className, methodName, methodSig} + */ + private static final String[][] BOOT_IMAGE = { + // callers of Application#attach(Context) + {"android.app.Instrumentation", "newApplication", "(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Context;)Landroid/app/Application;"} + }; + + private static final String[][] SYSTEM_SERVER = {}; + + private static final String[][] SYSTEM_UI = {}; + + static { + CALLERS.put(KEY_BOOT_IMAGE, BOOT_IMAGE); + CALLERS.put(KEY_SYSTEM_SERVER, SYSTEM_SERVER); + CALLERS.put("com.android.systemui", SYSTEM_UI); + } + + public static HashMap getAll() { + return CALLERS; + } + + public static String[][] get(String where) { + return CALLERS.get(where); + } +} diff --git a/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/PrebuiltMethodsDeopter.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/PrebuiltMethodsDeopter.java new file mode 100644 index 00000000..01f871b2 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/util/PrebuiltMethodsDeopter.java @@ -0,0 +1,41 @@ +package com.elderdrivers.riru.edxp.sandhook.util; + +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; + +import java.util.Arrays; + +import de.robv.android.xposed.XposedHelpers; + +import static com.elderdrivers.riru.edxp.sandhook.util.InlinedMethodCallers.KEY_BOOT_IMAGE; +import static com.elderdrivers.riru.edxp.sandhook.util.InlinedMethodCallers.KEY_SYSTEM_SERVER; + +public class PrebuiltMethodsDeopter { + + public static void deoptMethods(String where, ClassLoader cl) { + String[][] callers = InlinedMethodCallers.get(where); + if (callers == null) { + return; + } + for (String[] caller : callers) { + try { + Object method = Main.findMethodNative( + XposedHelpers.findClass(caller[0], cl), caller[1], caller[2]); + if (method != null) { + Main.deoptMethodNative(method); + } + } catch (Throwable throwable) { + Utils.logE("error when deopting method: " + Arrays.toString(caller), throwable); + } + } + } + + public static void deoptBootMethods() { + // todo check if has been done before + deoptMethods(KEY_BOOT_IMAGE, null); + } + + public static void deoptSystemServerMethods(ClassLoader sysCL) { + deoptMethods(KEY_SYSTEM_SERVER, sysCL); + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java new file mode 100644 index 00000000..7b494b50 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java @@ -0,0 +1,48 @@ +package com.swift.sandhook.xposedcompat; + +import com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader; +import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; +import com.swift.sandhook.xposedcompat.utils.FileUtils; + +import java.io.File; +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +public class XposedCompat { + + //try to use internal stub hooker & backup method to speed up hook + public static volatile boolean useInternalStub = true; + public static volatile boolean useNewDexMaker = true; + public static volatile boolean retryWhenCallOriginError = false; + + private static ClassLoader sandHookXposedClassLoader; + + public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) { + SandHookXposedBridge.hookMethod(hookMethod, additionalHookInfo); + } + + public static ClassLoader getSandHookXposedClassLoader(ClassLoader appOriginClassLoader, ClassLoader sandBoxHostClassLoader) { + if (sandHookXposedClassLoader != null) { + return sandHookXposedClassLoader; + } else { + sandHookXposedClassLoader = new ComposeClassLoader(sandBoxHostClassLoader, appOriginClassLoader); + return sandHookXposedClassLoader; + } + } + +// public static boolean clearCache() { +// try { +// FileUtils.delete(cacheDir); +// cacheDir.mkdirs(); +// return true; +// } catch (Throwable throwable) { +// return false; +// } +// } +// +// public static void clearOatCache() { +// SandHookXposedBridge.clearOatFile(); +// } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/classloaders/ComposeClassLoader.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/classloaders/ComposeClassLoader.java new file mode 100644 index 00000000..6d968f6f --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/classloaders/ComposeClassLoader.java @@ -0,0 +1,34 @@ +package com.swift.sandhook.xposedcompat.classloaders; + +/** + * Created by weishu on 17/11/30. + */ + +public class ComposeClassLoader extends ClassLoader { + + private final ClassLoader mAppClassLoader; + public ComposeClassLoader(ClassLoader parent, ClassLoader appClassLoader) { + super(parent); + mAppClassLoader = appClassLoader; + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class clazz = null; + + try { + clazz = mAppClassLoader.loadClass(name); + } catch (ClassNotFoundException e) { + // IGNORE. + } + if (clazz == null) { + clazz = super.loadClass(name, resolve); + } + + if (clazz == null) { + throw new ClassNotFoundException(); + } + + return clazz; + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/CallOriginCallBack.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/CallOriginCallBack.java new file mode 100644 index 00000000..65657ef3 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/CallOriginCallBack.java @@ -0,0 +1,5 @@ +package com.swift.sandhook.xposedcompat.hookstub; + +public interface CallOriginCallBack { + long call(long... args) throws Throwable; +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookMethodEntity.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookMethodEntity.java new file mode 100644 index 00000000..1436908c --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookMethodEntity.java @@ -0,0 +1,93 @@ +package com.swift.sandhook.xposedcompat.hookstub; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.utils.ParamWrapper; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public class HookMethodEntity { + + public Member origin; + public Method hook; + public Method backup; + public Class[] parType; + public Class retType; + + public HookMethodEntity(Member origin, Method hook, Method backup) { + this.origin = origin; + this.hook = hook; + this.backup = backup; + } + + public Object[] getArgs(long... addresses) { + if (addresses == null || addresses.length == 0) + return new Object[0]; + if (parType == null || parType.length == 0) + return new Object[0]; + int argStart = 0; + if (!isStatic()) { + argStart = 1; + } + Object[] args = new Object[parType.length]; + for (int i = argStart;i < parType.length + argStart;i++) { + args[i - argStart] = getArg(i - argStart, addresses[i]); + } + return args; + } + + public long[] getArgsAddress(long[] oldAddress, Object... args) { + if (oldAddress == null || oldAddress.length == 0) + return new long[0]; + long[] addresses; + int argStart = 0; + if (!isStatic()) { + argStart = 1; + addresses = new long[oldAddress.length + 1]; + addresses[0] = oldAddress[0]; + } else { + addresses = new long[oldAddress.length]; + } + for (int i = 0;i < parType.length;i++) { + addresses[i + argStart] = ParamWrapper.objectToAddress(parType[i], args[i]); + } + return addresses; + } + + public Object getThis(long address) { + if (isStatic()) + return null; + return SandHook.getObject(address); + } + + public Object getArg(int index, long address) { + return ParamWrapper.addressToObject(parType[index], address); + } + + public Object getResult(long address) { + if (isVoid()) + return null; + return ParamWrapper.addressToObject(retType, address); + } + + public long getResultAddress(Object result) { + if (isVoid()) + return 0; + return ParamWrapper.objectToAddress(retType, result); + } + + public boolean isVoid() { + return retType == null || Void.TYPE.equals(retType); + } + + public boolean isConstructor() { + return origin instanceof Constructor; + } + + public boolean isStatic() { + return Modifier.isStatic(origin.getModifiers()); + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java new file mode 100644 index 00000000..1b27ed4a --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java @@ -0,0 +1,409 @@ +package com.swift.sandhook.xposedcompat.hookstub; + +import android.util.Log; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.SandHookMethodResolver; +import com.swift.sandhook.utils.ParamWrapper; +import com.swift.sandhook.wrapper.BackupMethodStubs; +import com.swift.sandhook.xposedcompat.utils.DexLog; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +import static de.robv.android.xposed.XposedBridge.sHookedMethodCallbacks; + +public class HookStubManager { + + + public static int MAX_STUB_ARGS = 0; + + public static int[] stubSizes; + + public static boolean hasStubBackup = false; + + public static AtomicInteger[] curUseStubIndexes; + + public static int ALL_STUB = 0; + + public static Member[] originMethods; + public static HookMethodEntity[] hookMethodEntities; + + private static final Map> hookCallbacks + = sHookedMethodCallbacks; + + static { + Class stubClass = SandHook.is64Bit() ? MethodHookerStubs64.class : MethodHookerStubs32.class; + stubSizes = (int[]) XposedHelpers.getStaticObjectField(stubClass, "stubSizes"); + Boolean hasBackup = (Boolean) XposedHelpers.getStaticObjectField(stubClass, "hasStubBackup"); + hasStubBackup = hasBackup == null ? false : hasBackup; + if (stubSizes != null && stubSizes.length > 0) { + MAX_STUB_ARGS = stubSizes.length - 1; + curUseStubIndexes = new AtomicInteger[MAX_STUB_ARGS + 1]; + for (int i = 0; i < MAX_STUB_ARGS + 1; i++) { + curUseStubIndexes[i] = new AtomicInteger(0); + ALL_STUB += stubSizes[i]; + } + originMethods = new Member[ALL_STUB]; + hookMethodEntities = new HookMethodEntity[ALL_STUB]; + } + } + + + public static HookMethodEntity getHookMethodEntity(Member origin) { + + if (!support()) { + return null; + } + + Class[] parType; + Class retType; + boolean isStatic = Modifier.isStatic(origin.getModifiers()); + + if (origin instanceof Method) { + Method method = (Method) origin; + retType = method.getReturnType(); + parType = method.getParameterTypes(); + } else if (origin instanceof Constructor) { + Constructor constructor = (Constructor) origin; + retType = Void.TYPE; + parType = constructor.getParameterTypes(); + } else { + return null; + } + + if (!ParamWrapper.support(retType)) + return null; + + int needStubArgCount = isStatic ? 0 : 1; + + if (parType != null) { + needStubArgCount += parType.length; + if (needStubArgCount > MAX_STUB_ARGS) + return null; + for (Class par:parType) { + if (!ParamWrapper.support(par)) + return null; + } + } else { + parType = new Class[0]; + } + + synchronized (HookStubManager.class) { + StubMethodsInfo stubMethodInfo = getStubMethodPair(SandHook.is64Bit(), needStubArgCount); + if (stubMethodInfo == null) + return null; + HookMethodEntity entity = new HookMethodEntity(origin, stubMethodInfo.hook, stubMethodInfo.backup); + entity.retType = retType; + entity.parType = parType; + int id = getMethodId(stubMethodInfo.args, stubMethodInfo.index); + originMethods[id] = origin; + hookMethodEntities[id] = entity; + if (hasStubBackup && !tryCompileAndResolveCallOriginMethod(entity.backup, stubMethodInfo.args, stubMethodInfo.index)) { + DexLog.w("internal stub <" + entity.hook.getName() + "> call origin compile failure, skip use internal stub"); + return null; + } else { + return entity; + } + } + } + + public static int getMethodId(int args, int index) { + int id = index; + for (int i = 0;i < args;i++) { + id += stubSizes[i]; + } + return id; + } + + public static String getHookMethodName(int index) { + return "stub_hook_" + index; + } + + public static String getBackupMethodName(int index) { + return "stub_backup_" + index; + } + + public static String getCallOriginClassName(int args, int index) { + return "call_origin_" + args + "_" + index; + } + + + static class StubMethodsInfo { + int args = 0; + int index = 0; + Method hook; + Method backup; + + public StubMethodsInfo(int args, int index, Method hook, Method backup) { + this.args = args; + this.index = index; + this.hook = hook; + this.backup = backup; + } + } + + private static synchronized StubMethodsInfo getStubMethodPair(boolean is64Bit, int stubArgs) { + + stubArgs = getMatchStubArgsCount(stubArgs); + + if (stubArgs < 0) + return null; + + int curUseStubIndex = curUseStubIndexes[stubArgs].getAndIncrement(); + Class[] pars = getFindMethodParTypes(is64Bit, stubArgs); + try { + if (is64Bit) { + Method hook = MethodHookerStubs64.class.getDeclaredMethod(getHookMethodName(curUseStubIndex), pars); + Method backup = hasStubBackup ? MethodHookerStubs64.class.getDeclaredMethod(getBackupMethodName(curUseStubIndex), pars) : BackupMethodStubs.getStubMethod(); + if (hook == null || backup == null) + return null; + return new StubMethodsInfo(stubArgs, curUseStubIndex, hook, backup); + } else { + Method hook = MethodHookerStubs32.class.getDeclaredMethod(getHookMethodName(curUseStubIndex), pars); + Method backup = hasStubBackup ? MethodHookerStubs32.class.getDeclaredMethod(getBackupMethodName(curUseStubIndex), pars) : BackupMethodStubs.getStubMethod(); + if (hook == null || backup == null) + return null; + return new StubMethodsInfo(stubArgs, curUseStubIndex, hook, backup); + } + } catch (Throwable throwable) { + return null; + } + } + + public static Method getCallOriginMethod(int args, int index) { + Class stubClass = SandHook.is64Bit() ? MethodHookerStubs64.class : MethodHookerStubs32.class; + String className = stubClass.getName(); + className += "$"; + className += getCallOriginClassName(args, index); + try { + Class callOriginClass = Class.forName(className, true, stubClass.getClassLoader()); + return callOriginClass.getDeclaredMethod("call", long[].class); + } catch (Throwable e) { + Log.e("HookStubManager", "load call origin class error!", e); + return null; + } + } + + public static boolean tryCompileAndResolveCallOriginMethod(Method backupMethod, int args, int index) { + Method method = getCallOriginMethod(args, index); + if (method != null) { + SandHookMethodResolver.resolveMethod(method, backupMethod); + return SandHook.compileMethod(method); + } else { + return false; + } + } + + public static int getMatchStubArgsCount(int stubArgs) { + for (int i = stubArgs;i <= MAX_STUB_ARGS;i++) { + if (curUseStubIndexes[i].get() < stubSizes[i]) + return i; + } + return -1; + } + + public static Class[] getFindMethodParTypes(boolean is64Bit, int stubArgs) { + if (stubArgs == 0) + return null; + Class[] args = new Class[stubArgs]; + if (is64Bit) { + for (int i = 0;i < stubArgs;i++) { + args[i] = long.class; + } + } else { + for (int i = 0;i < stubArgs;i++) { + args[i] = int.class; + } + } + return args; + } + + public static long hookBridge(int id, CallOriginCallBack callOrigin, long... stubArgs) throws Throwable { + + Member originMethod = originMethods[id]; + HookMethodEntity entity = hookMethodEntities[id]; + + Object thiz = null; + Object[] args = null; + + if (hasArgs(stubArgs)) { + thiz = entity.getThis(stubArgs[0]); + args = entity.getArgs(stubArgs); + } + + if (XposedBridge.disableHooks) { + if (hasStubBackup) { + return callOrigin.call(stubArgs); + } else { + return callOrigin(entity, originMethod, thiz, args); + } + } + + DexLog.printMethodHookIn(originMethod); + + Object[] snapshot = hookCallbacks.get(originMethod).getSnapshot(); + if (snapshot == null || snapshot.length == 0) { + if (hasStubBackup) { + return callOrigin.call(stubArgs); + } else { + return callOrigin(entity, originMethod, thiz, args); + } + } + + XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam(); + + param.method = originMethod; + param.thisObject = thiz; + param.args = args; + + int beforeIdx = 0; + do { + try { + ((XC_MethodHook) snapshot[beforeIdx]).callBeforeHookedMethod(param); + } catch (Throwable t) { + // reset result (ignoring what the unexpectedly exiting callback did) + param.setResult(null); + param.returnEarly = false; + continue; + } + + if (param.returnEarly) { + // skip remaining "before" callbacks and corresponding "after" callbacks + beforeIdx++; + break; + } + } while (++beforeIdx < snapshot.length); + + // call original method if not requested otherwise + if (!param.returnEarly) { + try { + if (hasStubBackup) { + //prepare new args + long[] newArgs = entity.getArgsAddress(stubArgs, param.args); + param.setResult(entity.getResult(callOrigin.call(newArgs))); + } else { + param.setResult(SandHook.callOriginMethod(originMethod, thiz, param.args)); + } + } catch (Throwable e) { + XposedBridge.log(e); + param.setThrowable(e); + } + } + + // call "after method" callbacks + int afterIdx = beforeIdx - 1; + do { + Object lastResult = param.getResult(); + Throwable lastThrowable = param.getThrowable(); + + try { + ((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param); + } catch (Throwable t) { + XposedBridge.log(t); + if (lastThrowable == null) + param.setResult(lastResult); + else + param.setThrowable(lastThrowable); + } + } while (--afterIdx >= 0); + if (!param.hasThrowable()) { + return entity.getResultAddress(param.getResult()); + } else { + throw param.getThrowable(); + } + } + + public static Object hookBridge(Member origin, Object thiz, Object... args) throws Throwable { + + + if (XposedBridge.disableHooks) { + return SandHook.callOriginMethod(origin, thiz, args); + } + + DexLog.printMethodHookIn(origin); + + Object[] snapshot = hookCallbacks.get(origin).getSnapshot(); + if (snapshot == null || snapshot.length == 0) { + return SandHook.callOriginMethod(origin, thiz, args); + } + + XC_MethodHook.MethodHookParam param = new XC_MethodHook.MethodHookParam(); + + param.method = origin; + param.thisObject = thiz; + param.args = args; + + int beforeIdx = 0; + do { + try { + ((XC_MethodHook) snapshot[beforeIdx]).callBeforeHookedMethod(param); + } catch (Throwable t) { + // reset result (ignoring what the unexpectedly exiting callback did) + param.setResult(null); + param.returnEarly = false; + continue; + } + + if (param.returnEarly) { + // skip remaining "before" callbacks and corresponding "after" callbacks + beforeIdx++; + break; + } + } while (++beforeIdx < snapshot.length); + + // call original method if not requested otherwise + if (!param.returnEarly) { + try { + param.setResult(SandHook.callOriginMethod(origin, thiz, param.args)); + } catch (Throwable e) { + XposedBridge.log(e); + param.setThrowable(e); + } + } + + // call "after method" callbacks + int afterIdx = beforeIdx - 1; + do { + Object lastResult = param.getResult(); + Throwable lastThrowable = param.getThrowable(); + + try { + ((XC_MethodHook) snapshot[afterIdx]).callAfterHookedMethod(param); + } catch (Throwable t) { + XposedBridge.log(t); + if (lastThrowable == null) + param.setResult(lastResult); + else + param.setThrowable(lastThrowable); + } + } while (--afterIdx >= 0); + if (!param.hasThrowable()) { + return param.getResult(); + } else { + throw param.getThrowable(); + } + } + + public static long callOrigin(HookMethodEntity entity, Member origin, Object thiz, Object[] args) throws Throwable { + Object res = SandHook.callOriginMethod(origin, thiz, args); + return entity.getResultAddress(res); + } + + private static boolean hasArgs(long... args) { + return args != null && args.length > 0; + } + + public static boolean support() { + return MAX_STUB_ARGS > 0 && SandHook.canGetObject() && SandHook.canGetObjectAddress(); + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs32.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs32.java new file mode 100644 index 00000000..573eb4aa --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs32.java @@ -0,0 +1,1413 @@ +package com.swift.sandhook.xposedcompat.hookstub; + +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.getMethodId; +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.hookBridge; + +/** +* this file is auto gen by genhookstubs.py +* it is for sandhook internal hooker & backup methods +**/ +public class MethodHookerStubs32 { + + public static boolean hasStubBackup = false; + public static int[] stubSizes = {10, 20, 30, 30, 30, 30, 30, 20, 10, 10, 5, 5, 3}; + + + //stub of arg size 0, index 0 + public static int stub_hook_0() throws Throwable { + return (int) hookBridge(getMethodId(0, 0), null ); + } + + + //stub of arg size 0, index 1 + public static int stub_hook_1() throws Throwable { + return (int) hookBridge(getMethodId(0, 1), null ); + } + + + //stub of arg size 0, index 2 + public static int stub_hook_2() throws Throwable { + return (int) hookBridge(getMethodId(0, 2), null ); + } + + + //stub of arg size 0, index 3 + public static int stub_hook_3() throws Throwable { + return (int) hookBridge(getMethodId(0, 3), null ); + } + + + //stub of arg size 0, index 4 + public static int stub_hook_4() throws Throwable { + return (int) hookBridge(getMethodId(0, 4), null ); + } + + + //stub of arg size 0, index 5 + public static int stub_hook_5() throws Throwable { + return (int) hookBridge(getMethodId(0, 5), null ); + } + + + //stub of arg size 0, index 6 + public static int stub_hook_6() throws Throwable { + return (int) hookBridge(getMethodId(0, 6), null ); + } + + + //stub of arg size 0, index 7 + public static int stub_hook_7() throws Throwable { + return (int) hookBridge(getMethodId(0, 7), null ); + } + + + //stub of arg size 0, index 8 + public static int stub_hook_8() throws Throwable { + return (int) hookBridge(getMethodId(0, 8), null ); + } + + + //stub of arg size 0, index 9 + public static int stub_hook_9() throws Throwable { + return (int) hookBridge(getMethodId(0, 9), null ); + } + + + //stub of arg size 1, index 0 + public static int stub_hook_0(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 0), null , a0); + } + + + //stub of arg size 1, index 1 + public static int stub_hook_1(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 1), null , a0); + } + + + //stub of arg size 1, index 2 + public static int stub_hook_2(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 2), null , a0); + } + + + //stub of arg size 1, index 3 + public static int stub_hook_3(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 3), null , a0); + } + + + //stub of arg size 1, index 4 + public static int stub_hook_4(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 4), null , a0); + } + + + //stub of arg size 1, index 5 + public static int stub_hook_5(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 5), null , a0); + } + + + //stub of arg size 1, index 6 + public static int stub_hook_6(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 6), null , a0); + } + + + //stub of arg size 1, index 7 + public static int stub_hook_7(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 7), null , a0); + } + + + //stub of arg size 1, index 8 + public static int stub_hook_8(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 8), null , a0); + } + + + //stub of arg size 1, index 9 + public static int stub_hook_9(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 9), null , a0); + } + + + //stub of arg size 1, index 10 + public static int stub_hook_10(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 10), null , a0); + } + + + //stub of arg size 1, index 11 + public static int stub_hook_11(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 11), null , a0); + } + + + //stub of arg size 1, index 12 + public static int stub_hook_12(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 12), null , a0); + } + + + //stub of arg size 1, index 13 + public static int stub_hook_13(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 13), null , a0); + } + + + //stub of arg size 1, index 14 + public static int stub_hook_14(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 14), null , a0); + } + + + //stub of arg size 1, index 15 + public static int stub_hook_15(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 15), null , a0); + } + + + //stub of arg size 1, index 16 + public static int stub_hook_16(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 16), null , a0); + } + + + //stub of arg size 1, index 17 + public static int stub_hook_17(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 17), null , a0); + } + + + //stub of arg size 1, index 18 + public static int stub_hook_18(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 18), null , a0); + } + + + //stub of arg size 1, index 19 + public static int stub_hook_19(int a0) throws Throwable { + return (int) hookBridge(getMethodId(1, 19), null , a0); + } + + + //stub of arg size 2, index 0 + public static int stub_hook_0(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 0), null , a0, a1); + } + + + //stub of arg size 2, index 1 + public static int stub_hook_1(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 1), null , a0, a1); + } + + + //stub of arg size 2, index 2 + public static int stub_hook_2(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 2), null , a0, a1); + } + + + //stub of arg size 2, index 3 + public static int stub_hook_3(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 3), null , a0, a1); + } + + + //stub of arg size 2, index 4 + public static int stub_hook_4(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 4), null , a0, a1); + } + + + //stub of arg size 2, index 5 + public static int stub_hook_5(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 5), null , a0, a1); + } + + + //stub of arg size 2, index 6 + public static int stub_hook_6(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 6), null , a0, a1); + } + + + //stub of arg size 2, index 7 + public static int stub_hook_7(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 7), null , a0, a1); + } + + + //stub of arg size 2, index 8 + public static int stub_hook_8(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 8), null , a0, a1); + } + + + //stub of arg size 2, index 9 + public static int stub_hook_9(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 9), null , a0, a1); + } + + + //stub of arg size 2, index 10 + public static int stub_hook_10(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 10), null , a0, a1); + } + + + //stub of arg size 2, index 11 + public static int stub_hook_11(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 11), null , a0, a1); + } + + + //stub of arg size 2, index 12 + public static int stub_hook_12(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 12), null , a0, a1); + } + + + //stub of arg size 2, index 13 + public static int stub_hook_13(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 13), null , a0, a1); + } + + + //stub of arg size 2, index 14 + public static int stub_hook_14(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 14), null , a0, a1); + } + + + //stub of arg size 2, index 15 + public static int stub_hook_15(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 15), null , a0, a1); + } + + + //stub of arg size 2, index 16 + public static int stub_hook_16(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 16), null , a0, a1); + } + + + //stub of arg size 2, index 17 + public static int stub_hook_17(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 17), null , a0, a1); + } + + + //stub of arg size 2, index 18 + public static int stub_hook_18(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 18), null , a0, a1); + } + + + //stub of arg size 2, index 19 + public static int stub_hook_19(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 19), null , a0, a1); + } + + + //stub of arg size 2, index 20 + public static int stub_hook_20(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 20), null , a0, a1); + } + + + //stub of arg size 2, index 21 + public static int stub_hook_21(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 21), null , a0, a1); + } + + + //stub of arg size 2, index 22 + public static int stub_hook_22(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 22), null , a0, a1); + } + + + //stub of arg size 2, index 23 + public static int stub_hook_23(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 23), null , a0, a1); + } + + + //stub of arg size 2, index 24 + public static int stub_hook_24(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 24), null , a0, a1); + } + + + //stub of arg size 2, index 25 + public static int stub_hook_25(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 25), null , a0, a1); + } + + + //stub of arg size 2, index 26 + public static int stub_hook_26(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 26), null , a0, a1); + } + + + //stub of arg size 2, index 27 + public static int stub_hook_27(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 27), null , a0, a1); + } + + + //stub of arg size 2, index 28 + public static int stub_hook_28(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 28), null , a0, a1); + } + + + //stub of arg size 2, index 29 + public static int stub_hook_29(int a0, int a1) throws Throwable { + return (int) hookBridge(getMethodId(2, 29), null , a0, a1); + } + + + //stub of arg size 3, index 0 + public static int stub_hook_0(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 0), null , a0, a1, a2); + } + + + //stub of arg size 3, index 1 + public static int stub_hook_1(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 1), null , a0, a1, a2); + } + + + //stub of arg size 3, index 2 + public static int stub_hook_2(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 2), null , a0, a1, a2); + } + + + //stub of arg size 3, index 3 + public static int stub_hook_3(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 3), null , a0, a1, a2); + } + + + //stub of arg size 3, index 4 + public static int stub_hook_4(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 4), null , a0, a1, a2); + } + + + //stub of arg size 3, index 5 + public static int stub_hook_5(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 5), null , a0, a1, a2); + } + + + //stub of arg size 3, index 6 + public static int stub_hook_6(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 6), null , a0, a1, a2); + } + + + //stub of arg size 3, index 7 + public static int stub_hook_7(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 7), null , a0, a1, a2); + } + + + //stub of arg size 3, index 8 + public static int stub_hook_8(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 8), null , a0, a1, a2); + } + + + //stub of arg size 3, index 9 + public static int stub_hook_9(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 9), null , a0, a1, a2); + } + + + //stub of arg size 3, index 10 + public static int stub_hook_10(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 10), null , a0, a1, a2); + } + + + //stub of arg size 3, index 11 + public static int stub_hook_11(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 11), null , a0, a1, a2); + } + + + //stub of arg size 3, index 12 + public static int stub_hook_12(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 12), null , a0, a1, a2); + } + + + //stub of arg size 3, index 13 + public static int stub_hook_13(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 13), null , a0, a1, a2); + } + + + //stub of arg size 3, index 14 + public static int stub_hook_14(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 14), null , a0, a1, a2); + } + + + //stub of arg size 3, index 15 + public static int stub_hook_15(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 15), null , a0, a1, a2); + } + + + //stub of arg size 3, index 16 + public static int stub_hook_16(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 16), null , a0, a1, a2); + } + + + //stub of arg size 3, index 17 + public static int stub_hook_17(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 17), null , a0, a1, a2); + } + + + //stub of arg size 3, index 18 + public static int stub_hook_18(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 18), null , a0, a1, a2); + } + + + //stub of arg size 3, index 19 + public static int stub_hook_19(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 19), null , a0, a1, a2); + } + + + //stub of arg size 3, index 20 + public static int stub_hook_20(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 20), null , a0, a1, a2); + } + + + //stub of arg size 3, index 21 + public static int stub_hook_21(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 21), null , a0, a1, a2); + } + + + //stub of arg size 3, index 22 + public static int stub_hook_22(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 22), null , a0, a1, a2); + } + + + //stub of arg size 3, index 23 + public static int stub_hook_23(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 23), null , a0, a1, a2); + } + + + //stub of arg size 3, index 24 + public static int stub_hook_24(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 24), null , a0, a1, a2); + } + + + //stub of arg size 3, index 25 + public static int stub_hook_25(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 25), null , a0, a1, a2); + } + + + //stub of arg size 3, index 26 + public static int stub_hook_26(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 26), null , a0, a1, a2); + } + + + //stub of arg size 3, index 27 + public static int stub_hook_27(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 27), null , a0, a1, a2); + } + + + //stub of arg size 3, index 28 + public static int stub_hook_28(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 28), null , a0, a1, a2); + } + + + //stub of arg size 3, index 29 + public static int stub_hook_29(int a0, int a1, int a2) throws Throwable { + return (int) hookBridge(getMethodId(3, 29), null , a0, a1, a2); + } + + + //stub of arg size 4, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 0), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 1), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 2), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 3), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 4), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 5), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 6), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 7), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 8), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 9), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 10 + public static int stub_hook_10(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 10), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 11 + public static int stub_hook_11(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 11), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 12 + public static int stub_hook_12(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 12), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 13 + public static int stub_hook_13(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 13), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 14 + public static int stub_hook_14(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 14), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 15 + public static int stub_hook_15(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 15), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 16 + public static int stub_hook_16(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 16), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 17 + public static int stub_hook_17(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 17), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 18 + public static int stub_hook_18(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 18), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 19 + public static int stub_hook_19(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 19), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 20 + public static int stub_hook_20(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 20), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 21 + public static int stub_hook_21(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 21), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 22 + public static int stub_hook_22(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 22), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 23 + public static int stub_hook_23(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 23), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 24 + public static int stub_hook_24(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 24), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 25 + public static int stub_hook_25(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 25), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 26 + public static int stub_hook_26(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 26), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 27 + public static int stub_hook_27(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 27), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 28 + public static int stub_hook_28(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 28), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 29 + public static int stub_hook_29(int a0, int a1, int a2, int a3) throws Throwable { + return (int) hookBridge(getMethodId(4, 29), null , a0, a1, a2, a3); + } + + + //stub of arg size 5, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 0), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 1), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 2), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 3), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 4), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 5), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 6), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 7), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 8), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 9), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 10 + public static int stub_hook_10(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 10), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 11 + public static int stub_hook_11(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 11), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 12 + public static int stub_hook_12(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 12), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 13 + public static int stub_hook_13(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 13), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 14 + public static int stub_hook_14(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 14), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 15 + public static int stub_hook_15(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 15), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 16 + public static int stub_hook_16(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 16), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 17 + public static int stub_hook_17(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 17), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 18 + public static int stub_hook_18(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 18), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 19 + public static int stub_hook_19(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 19), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 20 + public static int stub_hook_20(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 20), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 21 + public static int stub_hook_21(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 21), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 22 + public static int stub_hook_22(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 22), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 23 + public static int stub_hook_23(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 23), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 24 + public static int stub_hook_24(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 24), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 25 + public static int stub_hook_25(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 25), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 26 + public static int stub_hook_26(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 26), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 27 + public static int stub_hook_27(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 27), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 28 + public static int stub_hook_28(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 28), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 29 + public static int stub_hook_29(int a0, int a1, int a2, int a3, int a4) throws Throwable { + return (int) hookBridge(getMethodId(5, 29), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 6, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 0), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 1), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 2), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 3), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 4), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 5), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 6), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 7), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 8), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 9), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 10 + public static int stub_hook_10(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 10), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 11 + public static int stub_hook_11(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 11), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 12 + public static int stub_hook_12(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 12), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 13 + public static int stub_hook_13(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 13), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 14 + public static int stub_hook_14(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 14), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 15 + public static int stub_hook_15(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 15), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 16 + public static int stub_hook_16(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 16), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 17 + public static int stub_hook_17(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 17), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 18 + public static int stub_hook_18(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 18), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 19 + public static int stub_hook_19(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 19), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 20 + public static int stub_hook_20(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 20), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 21 + public static int stub_hook_21(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 21), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 22 + public static int stub_hook_22(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 22), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 23 + public static int stub_hook_23(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 23), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 24 + public static int stub_hook_24(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 24), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 25 + public static int stub_hook_25(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 25), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 26 + public static int stub_hook_26(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 26), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 27 + public static int stub_hook_27(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 27), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 28 + public static int stub_hook_28(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 28), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 29 + public static int stub_hook_29(int a0, int a1, int a2, int a3, int a4, int a5) throws Throwable { + return (int) hookBridge(getMethodId(6, 29), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 7, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 0), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 1), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 2), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 3), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 4), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 5), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 6), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 7), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 8), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 9), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 10 + public static int stub_hook_10(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 10), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 11 + public static int stub_hook_11(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 11), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 12 + public static int stub_hook_12(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 12), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 13 + public static int stub_hook_13(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 13), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 14 + public static int stub_hook_14(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 14), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 15 + public static int stub_hook_15(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 15), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 16 + public static int stub_hook_16(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 16), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 17 + public static int stub_hook_17(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 17), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 18 + public static int stub_hook_18(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 18), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 19 + public static int stub_hook_19(int a0, int a1, int a2, int a3, int a4, int a5, int a6) throws Throwable { + return (int) hookBridge(getMethodId(7, 19), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 8, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 0), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 1), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 2), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 3), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 4), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 5), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 6), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 7), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 8), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7) throws Throwable { + return (int) hookBridge(getMethodId(8, 9), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 9, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 5 + public static int stub_hook_5(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 5), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 6 + public static int stub_hook_6(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 6), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 7 + public static int stub_hook_7(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 7), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 8 + public static int stub_hook_8(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 8), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 9 + public static int stub_hook_9(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) throws Throwable { + return (int) hookBridge(getMethodId(9, 9), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 10, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) throws Throwable { + return (int) hookBridge(getMethodId(10, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) throws Throwable { + return (int) hookBridge(getMethodId(10, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) throws Throwable { + return (int) hookBridge(getMethodId(10, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) throws Throwable { + return (int) hookBridge(getMethodId(10, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) throws Throwable { + return (int) hookBridge(getMethodId(10, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 11, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) throws Throwable { + return (int) hookBridge(getMethodId(11, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) throws Throwable { + return (int) hookBridge(getMethodId(11, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) throws Throwable { + return (int) hookBridge(getMethodId(11, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 3 + public static int stub_hook_3(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) throws Throwable { + return (int) hookBridge(getMethodId(11, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 4 + public static int stub_hook_4(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10) throws Throwable { + return (int) hookBridge(getMethodId(11, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 12, index 0 + public static int stub_hook_0(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11) throws Throwable { + return (int) hookBridge(getMethodId(12, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + + //stub of arg size 12, index 1 + public static int stub_hook_1(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11) throws Throwable { + return (int) hookBridge(getMethodId(12, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + + //stub of arg size 12, index 2 + public static int stub_hook_2(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11) throws Throwable { + return (int) hookBridge(getMethodId(12, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs64.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs64.java new file mode 100644 index 00000000..17887583 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs64.java @@ -0,0 +1,1413 @@ +package com.swift.sandhook.xposedcompat.hookstub; + +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.getMethodId; +import static com.swift.sandhook.xposedcompat.hookstub.HookStubManager.hookBridge; + +/** +* this file is auto gen by genhookstubs.py +* it is for sandhook internal hooker & backup methods +**/ +public class MethodHookerStubs64 { + + public static boolean hasStubBackup = false; + public static int[] stubSizes = {10, 20, 30, 30, 30, 30, 30, 20, 10, 10, 5, 5, 3}; + + + //stub of arg size 0, index 0 + public static long stub_hook_0() throws Throwable { + return hookBridge(getMethodId(0, 0), null ); + } + + + //stub of arg size 0, index 1 + public static long stub_hook_1() throws Throwable { + return hookBridge(getMethodId(0, 1), null ); + } + + + //stub of arg size 0, index 2 + public static long stub_hook_2() throws Throwable { + return hookBridge(getMethodId(0, 2), null ); + } + + + //stub of arg size 0, index 3 + public static long stub_hook_3() throws Throwable { + return hookBridge(getMethodId(0, 3), null ); + } + + + //stub of arg size 0, index 4 + public static long stub_hook_4() throws Throwable { + return hookBridge(getMethodId(0, 4), null ); + } + + + //stub of arg size 0, index 5 + public static long stub_hook_5() throws Throwable { + return hookBridge(getMethodId(0, 5), null ); + } + + + //stub of arg size 0, index 6 + public static long stub_hook_6() throws Throwable { + return hookBridge(getMethodId(0, 6), null ); + } + + + //stub of arg size 0, index 7 + public static long stub_hook_7() throws Throwable { + return hookBridge(getMethodId(0, 7), null ); + } + + + //stub of arg size 0, index 8 + public static long stub_hook_8() throws Throwable { + return hookBridge(getMethodId(0, 8), null ); + } + + + //stub of arg size 0, index 9 + public static long stub_hook_9() throws Throwable { + return hookBridge(getMethodId(0, 9), null ); + } + + + //stub of arg size 1, index 0 + public static long stub_hook_0(long a0) throws Throwable { + return hookBridge(getMethodId(1, 0), null , a0); + } + + + //stub of arg size 1, index 1 + public static long stub_hook_1(long a0) throws Throwable { + return hookBridge(getMethodId(1, 1), null , a0); + } + + + //stub of arg size 1, index 2 + public static long stub_hook_2(long a0) throws Throwable { + return hookBridge(getMethodId(1, 2), null , a0); + } + + + //stub of arg size 1, index 3 + public static long stub_hook_3(long a0) throws Throwable { + return hookBridge(getMethodId(1, 3), null , a0); + } + + + //stub of arg size 1, index 4 + public static long stub_hook_4(long a0) throws Throwable { + return hookBridge(getMethodId(1, 4), null , a0); + } + + + //stub of arg size 1, index 5 + public static long stub_hook_5(long a0) throws Throwable { + return hookBridge(getMethodId(1, 5), null , a0); + } + + + //stub of arg size 1, index 6 + public static long stub_hook_6(long a0) throws Throwable { + return hookBridge(getMethodId(1, 6), null , a0); + } + + + //stub of arg size 1, index 7 + public static long stub_hook_7(long a0) throws Throwable { + return hookBridge(getMethodId(1, 7), null , a0); + } + + + //stub of arg size 1, index 8 + public static long stub_hook_8(long a0) throws Throwable { + return hookBridge(getMethodId(1, 8), null , a0); + } + + + //stub of arg size 1, index 9 + public static long stub_hook_9(long a0) throws Throwable { + return hookBridge(getMethodId(1, 9), null , a0); + } + + + //stub of arg size 1, index 10 + public static long stub_hook_10(long a0) throws Throwable { + return hookBridge(getMethodId(1, 10), null , a0); + } + + + //stub of arg size 1, index 11 + public static long stub_hook_11(long a0) throws Throwable { + return hookBridge(getMethodId(1, 11), null , a0); + } + + + //stub of arg size 1, index 12 + public static long stub_hook_12(long a0) throws Throwable { + return hookBridge(getMethodId(1, 12), null , a0); + } + + + //stub of arg size 1, index 13 + public static long stub_hook_13(long a0) throws Throwable { + return hookBridge(getMethodId(1, 13), null , a0); + } + + + //stub of arg size 1, index 14 + public static long stub_hook_14(long a0) throws Throwable { + return hookBridge(getMethodId(1, 14), null , a0); + } + + + //stub of arg size 1, index 15 + public static long stub_hook_15(long a0) throws Throwable { + return hookBridge(getMethodId(1, 15), null , a0); + } + + + //stub of arg size 1, index 16 + public static long stub_hook_16(long a0) throws Throwable { + return hookBridge(getMethodId(1, 16), null , a0); + } + + + //stub of arg size 1, index 17 + public static long stub_hook_17(long a0) throws Throwable { + return hookBridge(getMethodId(1, 17), null , a0); + } + + + //stub of arg size 1, index 18 + public static long stub_hook_18(long a0) throws Throwable { + return hookBridge(getMethodId(1, 18), null , a0); + } + + + //stub of arg size 1, index 19 + public static long stub_hook_19(long a0) throws Throwable { + return hookBridge(getMethodId(1, 19), null , a0); + } + + + //stub of arg size 2, index 0 + public static long stub_hook_0(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 0), null , a0, a1); + } + + + //stub of arg size 2, index 1 + public static long stub_hook_1(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 1), null , a0, a1); + } + + + //stub of arg size 2, index 2 + public static long stub_hook_2(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 2), null , a0, a1); + } + + + //stub of arg size 2, index 3 + public static long stub_hook_3(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 3), null , a0, a1); + } + + + //stub of arg size 2, index 4 + public static long stub_hook_4(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 4), null , a0, a1); + } + + + //stub of arg size 2, index 5 + public static long stub_hook_5(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 5), null , a0, a1); + } + + + //stub of arg size 2, index 6 + public static long stub_hook_6(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 6), null , a0, a1); + } + + + //stub of arg size 2, index 7 + public static long stub_hook_7(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 7), null , a0, a1); + } + + + //stub of arg size 2, index 8 + public static long stub_hook_8(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 8), null , a0, a1); + } + + + //stub of arg size 2, index 9 + public static long stub_hook_9(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 9), null , a0, a1); + } + + + //stub of arg size 2, index 10 + public static long stub_hook_10(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 10), null , a0, a1); + } + + + //stub of arg size 2, index 11 + public static long stub_hook_11(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 11), null , a0, a1); + } + + + //stub of arg size 2, index 12 + public static long stub_hook_12(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 12), null , a0, a1); + } + + + //stub of arg size 2, index 13 + public static long stub_hook_13(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 13), null , a0, a1); + } + + + //stub of arg size 2, index 14 + public static long stub_hook_14(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 14), null , a0, a1); + } + + + //stub of arg size 2, index 15 + public static long stub_hook_15(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 15), null , a0, a1); + } + + + //stub of arg size 2, index 16 + public static long stub_hook_16(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 16), null , a0, a1); + } + + + //stub of arg size 2, index 17 + public static long stub_hook_17(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 17), null , a0, a1); + } + + + //stub of arg size 2, index 18 + public static long stub_hook_18(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 18), null , a0, a1); + } + + + //stub of arg size 2, index 19 + public static long stub_hook_19(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 19), null , a0, a1); + } + + + //stub of arg size 2, index 20 + public static long stub_hook_20(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 20), null , a0, a1); + } + + + //stub of arg size 2, index 21 + public static long stub_hook_21(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 21), null , a0, a1); + } + + + //stub of arg size 2, index 22 + public static long stub_hook_22(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 22), null , a0, a1); + } + + + //stub of arg size 2, index 23 + public static long stub_hook_23(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 23), null , a0, a1); + } + + + //stub of arg size 2, index 24 + public static long stub_hook_24(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 24), null , a0, a1); + } + + + //stub of arg size 2, index 25 + public static long stub_hook_25(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 25), null , a0, a1); + } + + + //stub of arg size 2, index 26 + public static long stub_hook_26(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 26), null , a0, a1); + } + + + //stub of arg size 2, index 27 + public static long stub_hook_27(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 27), null , a0, a1); + } + + + //stub of arg size 2, index 28 + public static long stub_hook_28(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 28), null , a0, a1); + } + + + //stub of arg size 2, index 29 + public static long stub_hook_29(long a0, long a1) throws Throwable { + return hookBridge(getMethodId(2, 29), null , a0, a1); + } + + + //stub of arg size 3, index 0 + public static long stub_hook_0(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 0), null , a0, a1, a2); + } + + + //stub of arg size 3, index 1 + public static long stub_hook_1(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 1), null , a0, a1, a2); + } + + + //stub of arg size 3, index 2 + public static long stub_hook_2(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 2), null , a0, a1, a2); + } + + + //stub of arg size 3, index 3 + public static long stub_hook_3(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 3), null , a0, a1, a2); + } + + + //stub of arg size 3, index 4 + public static long stub_hook_4(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 4), null , a0, a1, a2); + } + + + //stub of arg size 3, index 5 + public static long stub_hook_5(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 5), null , a0, a1, a2); + } + + + //stub of arg size 3, index 6 + public static long stub_hook_6(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 6), null , a0, a1, a2); + } + + + //stub of arg size 3, index 7 + public static long stub_hook_7(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 7), null , a0, a1, a2); + } + + + //stub of arg size 3, index 8 + public static long stub_hook_8(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 8), null , a0, a1, a2); + } + + + //stub of arg size 3, index 9 + public static long stub_hook_9(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 9), null , a0, a1, a2); + } + + + //stub of arg size 3, index 10 + public static long stub_hook_10(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 10), null , a0, a1, a2); + } + + + //stub of arg size 3, index 11 + public static long stub_hook_11(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 11), null , a0, a1, a2); + } + + + //stub of arg size 3, index 12 + public static long stub_hook_12(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 12), null , a0, a1, a2); + } + + + //stub of arg size 3, index 13 + public static long stub_hook_13(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 13), null , a0, a1, a2); + } + + + //stub of arg size 3, index 14 + public static long stub_hook_14(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 14), null , a0, a1, a2); + } + + + //stub of arg size 3, index 15 + public static long stub_hook_15(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 15), null , a0, a1, a2); + } + + + //stub of arg size 3, index 16 + public static long stub_hook_16(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 16), null , a0, a1, a2); + } + + + //stub of arg size 3, index 17 + public static long stub_hook_17(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 17), null , a0, a1, a2); + } + + + //stub of arg size 3, index 18 + public static long stub_hook_18(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 18), null , a0, a1, a2); + } + + + //stub of arg size 3, index 19 + public static long stub_hook_19(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 19), null , a0, a1, a2); + } + + + //stub of arg size 3, index 20 + public static long stub_hook_20(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 20), null , a0, a1, a2); + } + + + //stub of arg size 3, index 21 + public static long stub_hook_21(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 21), null , a0, a1, a2); + } + + + //stub of arg size 3, index 22 + public static long stub_hook_22(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 22), null , a0, a1, a2); + } + + + //stub of arg size 3, index 23 + public static long stub_hook_23(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 23), null , a0, a1, a2); + } + + + //stub of arg size 3, index 24 + public static long stub_hook_24(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 24), null , a0, a1, a2); + } + + + //stub of arg size 3, index 25 + public static long stub_hook_25(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 25), null , a0, a1, a2); + } + + + //stub of arg size 3, index 26 + public static long stub_hook_26(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 26), null , a0, a1, a2); + } + + + //stub of arg size 3, index 27 + public static long stub_hook_27(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 27), null , a0, a1, a2); + } + + + //stub of arg size 3, index 28 + public static long stub_hook_28(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 28), null , a0, a1, a2); + } + + + //stub of arg size 3, index 29 + public static long stub_hook_29(long a0, long a1, long a2) throws Throwable { + return hookBridge(getMethodId(3, 29), null , a0, a1, a2); + } + + + //stub of arg size 4, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 0), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 1), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 2), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 3), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 4), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 5), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 6), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 7), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 8), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 9), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 10 + public static long stub_hook_10(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 10), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 11 + public static long stub_hook_11(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 11), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 12 + public static long stub_hook_12(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 12), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 13 + public static long stub_hook_13(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 13), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 14 + public static long stub_hook_14(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 14), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 15 + public static long stub_hook_15(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 15), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 16 + public static long stub_hook_16(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 16), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 17 + public static long stub_hook_17(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 17), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 18 + public static long stub_hook_18(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 18), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 19 + public static long stub_hook_19(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 19), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 20 + public static long stub_hook_20(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 20), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 21 + public static long stub_hook_21(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 21), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 22 + public static long stub_hook_22(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 22), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 23 + public static long stub_hook_23(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 23), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 24 + public static long stub_hook_24(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 24), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 25 + public static long stub_hook_25(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 25), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 26 + public static long stub_hook_26(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 26), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 27 + public static long stub_hook_27(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 27), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 28 + public static long stub_hook_28(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 28), null , a0, a1, a2, a3); + } + + + //stub of arg size 4, index 29 + public static long stub_hook_29(long a0, long a1, long a2, long a3) throws Throwable { + return hookBridge(getMethodId(4, 29), null , a0, a1, a2, a3); + } + + + //stub of arg size 5, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 0), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 1), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 2), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 3), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 4), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 5), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 6), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 7), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 8), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 9), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 10 + public static long stub_hook_10(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 10), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 11 + public static long stub_hook_11(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 11), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 12 + public static long stub_hook_12(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 12), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 13 + public static long stub_hook_13(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 13), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 14 + public static long stub_hook_14(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 14), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 15 + public static long stub_hook_15(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 15), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 16 + public static long stub_hook_16(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 16), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 17 + public static long stub_hook_17(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 17), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 18 + public static long stub_hook_18(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 18), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 19 + public static long stub_hook_19(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 19), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 20 + public static long stub_hook_20(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 20), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 21 + public static long stub_hook_21(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 21), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 22 + public static long stub_hook_22(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 22), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 23 + public static long stub_hook_23(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 23), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 24 + public static long stub_hook_24(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 24), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 25 + public static long stub_hook_25(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 25), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 26 + public static long stub_hook_26(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 26), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 27 + public static long stub_hook_27(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 27), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 28 + public static long stub_hook_28(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 28), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 5, index 29 + public static long stub_hook_29(long a0, long a1, long a2, long a3, long a4) throws Throwable { + return hookBridge(getMethodId(5, 29), null , a0, a1, a2, a3, a4); + } + + + //stub of arg size 6, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 0), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 1), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 2), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 3), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 4), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 5), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 6), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 7), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 8), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 9), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 10 + public static long stub_hook_10(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 10), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 11 + public static long stub_hook_11(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 11), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 12 + public static long stub_hook_12(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 12), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 13 + public static long stub_hook_13(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 13), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 14 + public static long stub_hook_14(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 14), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 15 + public static long stub_hook_15(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 15), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 16 + public static long stub_hook_16(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 16), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 17 + public static long stub_hook_17(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 17), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 18 + public static long stub_hook_18(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 18), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 19 + public static long stub_hook_19(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 19), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 20 + public static long stub_hook_20(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 20), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 21 + public static long stub_hook_21(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 21), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 22 + public static long stub_hook_22(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 22), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 23 + public static long stub_hook_23(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 23), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 24 + public static long stub_hook_24(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 24), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 25 + public static long stub_hook_25(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 25), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 26 + public static long stub_hook_26(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 26), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 27 + public static long stub_hook_27(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 27), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 28 + public static long stub_hook_28(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 28), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 29 + public static long stub_hook_29(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 29), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 7, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 0), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 1), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 2), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 3), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 4), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 5), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 6), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 7), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 8), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 9), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 10 + public static long stub_hook_10(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 10), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 11 + public static long stub_hook_11(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 11), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 12 + public static long stub_hook_12(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 12), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 13 + public static long stub_hook_13(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 13), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 14 + public static long stub_hook_14(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 14), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 15 + public static long stub_hook_15(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 15), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 16 + public static long stub_hook_16(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 16), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 17 + public static long stub_hook_17(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 17), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 18 + public static long stub_hook_18(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 18), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 19 + public static long stub_hook_19(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 19), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 8, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 0), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 1), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 2), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 3), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 4), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 5), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 6), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 7), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 8), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 8, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7) throws Throwable { + return hookBridge(getMethodId(8, 9), null , a0, a1, a2, a3, a4, a5, a6, a7); + } + + + //stub of arg size 9, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 5 + public static long stub_hook_5(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 5), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 6 + public static long stub_hook_6(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 6), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 7 + public static long stub_hook_7(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 7), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 8 + public static long stub_hook_8(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 8), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 9, index 9 + public static long stub_hook_9(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8) throws Throwable { + return hookBridge(getMethodId(9, 9), null , a0, a1, a2, a3, a4, a5, a6, a7, a8); + } + + + //stub of arg size 10, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { + return hookBridge(getMethodId(10, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { + return hookBridge(getMethodId(10, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { + return hookBridge(getMethodId(10, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { + return hookBridge(getMethodId(10, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 10, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9) throws Throwable { + return hookBridge(getMethodId(10, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + + //stub of arg size 11, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) throws Throwable { + return hookBridge(getMethodId(11, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) throws Throwable { + return hookBridge(getMethodId(11, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) throws Throwable { + return hookBridge(getMethodId(11, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 3 + public static long stub_hook_3(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) throws Throwable { + return hookBridge(getMethodId(11, 3), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 11, index 4 + public static long stub_hook_4(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10) throws Throwable { + return hookBridge(getMethodId(11, 4), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + } + + + //stub of arg size 12, index 0 + public static long stub_hook_0(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10, long a11) throws Throwable { + return hookBridge(getMethodId(12, 0), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + + //stub of arg size 12, index 1 + public static long stub_hook_1(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10, long a11) throws Throwable { + return hookBridge(getMethodId(12, 1), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + + + //stub of arg size 12, index 2 + public static long stub_hook_2(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long a7, long a8, long a9, long a10, long a11) throws Throwable { + return hookBridge(getMethodId(12, 2), null , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/ErrorCatch.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/ErrorCatch.java new file mode 100644 index 00000000..c6a5a82d --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/ErrorCatch.java @@ -0,0 +1,22 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import android.util.Log; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.xposedcompat.XposedCompat; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +public class ErrorCatch { + + public static Object callOriginError(Member originMethod, Method backupMethod, Object thiz, Object[] args) throws Throwable { + if (XposedCompat.retryWhenCallOriginError) { + Log.w("SandHook", "method <" + originMethod.toString() + "> use invoke to call origin!"); + return SandHook.callOriginMethod(originMethod, backupMethod, thiz, args); + } else { + return null; + } + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookMaker.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookMaker.java new file mode 100644 index 00000000..ae5c05e7 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookMaker.java @@ -0,0 +1,14 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import de.robv.android.xposed.XposedBridge; + +public interface HookMaker { + void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, + ClassLoader appClassLoader, String dexDirPath) throws Exception; + Method getHookMethod(); + Method getBackupMethod(); + Method getCallBackupMethod(); +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java new file mode 100644 index 00000000..4a72537b --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java @@ -0,0 +1,698 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import android.text.TextUtils; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.SandHookMethodResolver; +import com.swift.sandhook.wrapper.HookWrapper; +import com.swift.sandhook.xposedcompat.XposedCompat; +import com.swift.sandhook.xposedcompat.utils.DexLog; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import external.com.android.dx.BinaryOp; +import external.com.android.dx.Code; +import external.com.android.dx.Comparison; +import external.com.android.dx.DexMaker; +import external.com.android.dx.FieldId; +import external.com.android.dx.Label; +import external.com.android.dx.Local; +import external.com.android.dx.MethodId; +import external.com.android.dx.TypeId; + +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive; + +public class HookerDexMaker implements HookMaker { + + public static final String METHOD_NAME_BACKUP = "backup"; + public static final String METHOD_NAME_HOOK = "hook"; + public static final String METHOD_NAME_CALL_BACKUP = "callBackup"; + public static final String METHOD_NAME_SETUP = "setup"; + public static final String METHOD_NAME_LOG = "printMethodHookIn"; + public static final TypeId objArrayTypeId = TypeId.get(Object[].class); + private static final String CLASS_DESC_PREFIX = "L"; + private static final String CLASS_NAME_PREFIX = "SandHooker"; + private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo"; + private static final String FIELD_NAME_METHOD = "method"; + private static final String FIELD_NAME_BACKUP_METHOD = "backupMethod"; + private static final String PARAMS_FIELD_NAME_METHOD = "method"; + private static final String PARAMS_FIELD_NAME_THIS_OBJECT = "thisObject"; + private static final String PARAMS_FIELD_NAME_ARGS = "args"; + private static final String CALLBACK_METHOD_NAME_BEFORE = "callBeforeHookedMethod"; + private static final String CALLBACK_METHOD_NAME_AFTER = "callAfterHookedMethod"; + private static final TypeId throwableTypeId = TypeId.get(Throwable.class); + private static final TypeId memberTypeId = TypeId.get(Member.class); + private static final TypeId methodTypeId = TypeId.get(Method.class); + private static final TypeId callbackTypeId = TypeId.get(XC_MethodHook.class); + private static final TypeId hookInfoTypeId + = TypeId.get(XposedBridge.AdditionalHookInfo.class); + private static final TypeId callbacksTypeId + = TypeId.get(XposedBridge.CopyOnWriteSortedSet.class); + private static final TypeId paramTypeId + = TypeId.get(XC_MethodHook.MethodHookParam.class); + private static final MethodId setResultMethodId = + paramTypeId.getMethod(TypeId.VOID, "setResult", TypeId.OBJECT); + private static final MethodId setThrowableMethodId = + paramTypeId.getMethod(TypeId.VOID, "setThrowable", throwableTypeId); + private static final MethodId getResultMethodId = + paramTypeId.getMethod(TypeId.OBJECT, "getResult"); + private static final MethodId getThrowableMethodId = + paramTypeId.getMethod(throwableTypeId, "getThrowable"); + private static final MethodId hasThrowableMethodId = + paramTypeId.getMethod(TypeId.BOOLEAN, "hasThrowable"); + private static final MethodId callAfterCallbackMethodId = + callbackTypeId.getMethod(TypeId.VOID, CALLBACK_METHOD_NAME_AFTER, paramTypeId); + private static final MethodId callBeforeCallbackMethodId = + callbackTypeId.getMethod(TypeId.VOID, CALLBACK_METHOD_NAME_BEFORE, paramTypeId); + private static final FieldId returnEarlyFieldId = + paramTypeId.getField(TypeId.BOOLEAN, "returnEarly"); + private static final TypeId xposedBridgeTypeId = TypeId.get(XposedBridge.class); + private static final MethodId logThrowableMethodId = + xposedBridgeTypeId.getMethod(TypeId.VOID, "log", throwableTypeId); + + private FieldId mHookInfoFieldId; + private FieldId mMethodFieldId; + private FieldId mBackupMethodFieldId; + private MethodId mBackupMethodId; + private MethodId mCallBackupMethodId; + private MethodId mHookMethodId; + private MethodId mPrintLogMethodId; + private MethodId mSandHookCallOriginMethodId; + + private TypeId mHookerTypeId; + private TypeId[] mParameterTypeIds; + private Class[] mActualParameterTypes; + private Class mReturnType; + private TypeId mReturnTypeId; + private boolean mIsStatic; + // TODO use this to generate methods + private boolean mHasThrowable; + + private DexMaker mDexMaker; + private Member mMember; + private XposedBridge.AdditionalHookInfo mHookInfo; + private ClassLoader mAppClassLoader; + private Class mHookClass; + private Method mHookMethod; + private Method mBackupMethod; + private Method mCallBackupMethod; + private String mDexDirPath; + + private static TypeId[] getParameterTypeIds(Class[] parameterTypes, boolean isStatic) { + int parameterSize = parameterTypes.length; + int targetParameterSize = isStatic ? parameterSize : parameterSize + 1; + TypeId[] parameterTypeIds = new TypeId[targetParameterSize]; + int offset = 0; + if (!isStatic) { + parameterTypeIds[0] = TypeId.OBJECT; + offset = 1; + } + for (int i = 0; i < parameterTypes.length; i++) { + parameterTypeIds[i + offset] = TypeId.get(parameterTypes[i]); + } + return parameterTypeIds; + } + + private static Class[] getParameterTypes(Class[] parameterTypes, boolean isStatic) { + if (isStatic) { + return parameterTypes; + } + int parameterSize = parameterTypes.length; + int targetParameterSize = parameterSize + 1; + Class[] newParameterTypes = new Class[targetParameterSize]; + int offset = 1; + newParameterTypes[0] = Object.class; + System.arraycopy(parameterTypes, 0, newParameterTypes, offset, parameterTypes.length); + return newParameterTypes; + } + + public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, + ClassLoader appClassLoader, String dexDirPath) throws Exception { + if (member instanceof Method) { + Method method = (Method) member; + mIsStatic = Modifier.isStatic(method.getModifiers()); + mReturnType = method.getReturnType(); + if (mReturnType.equals(Void.class) || mReturnType.equals(void.class) + || mReturnType.isPrimitive()) { + mReturnTypeId = TypeId.get(mReturnType); + } else { + // all others fallback to plain Object for convenience + mReturnType = Object.class; + mReturnTypeId = TypeId.OBJECT; + } + mParameterTypeIds = getParameterTypeIds(method.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(method.getParameterTypes(), mIsStatic); + mHasThrowable = method.getExceptionTypes().length > 0; + } else if (member instanceof Constructor) { + Constructor constructor = (Constructor) member; + mIsStatic = false; + mReturnType = void.class; + mReturnTypeId = TypeId.VOID; + mParameterTypeIds = getParameterTypeIds(constructor.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(constructor.getParameterTypes(), mIsStatic); + mHasThrowable = constructor.getExceptionTypes().length > 0; + } else if (member.getDeclaringClass().isInterface()) { + throw new IllegalArgumentException("Cannot hook interfaces: " + member.toString()); + } else if (Modifier.isAbstract(member.getModifiers())) { + throw new IllegalArgumentException("Cannot hook abstract methods: " + member.toString()); + } else { + throw new IllegalArgumentException("Only methods and constructors can be hooked: " + member.toString()); + } + mMember = member; + mHookInfo = hookInfo; + mDexDirPath = dexDirPath; + if (appClassLoader == null + || appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) { + mAppClassLoader = this.getClass().getClassLoader(); + } else { + mAppClassLoader = appClassLoader; + } + + mDexMaker = new DexMaker(); + // Generate a Hooker class. + String className = getClassName(mMember); + String dexName = className + ".jar"; + + HookWrapper.HookEntity hookEntity = null; + //try load cache first + try { + ClassLoader loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName); + if (loader != null) { + hookEntity = loadHookerClass(loader, className); + } + } catch (Throwable throwable) {} + + //do generate + if (hookEntity == null) { + hookEntity = doMake(className, dexName); + } + SandHook.hook(hookEntity); + } + + private HookWrapper.HookEntity doMake(String className, String dexName) throws Exception { + mHookerTypeId = TypeId.get(CLASS_DESC_PREFIX + className + ";"); + mDexMaker.declare(mHookerTypeId, className + ".generated", Modifier.PUBLIC, TypeId.OBJECT); + generateFields(); + generateSetupMethod(); + if (XposedCompat.retryWhenCallOriginError) { + generateBackupAndCallOriginCheckMethod(); + } else { + generateBackupMethod(); + } + generateCallBackupMethod(); + generateHookMethod(); + + ClassLoader loader; + if (TextUtils.isEmpty(mDexDirPath)) { + throw new IllegalArgumentException("dexDirPath should not be empty!!!"); + } + // Create the dex file and load it. + loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName); + return loadHookerClass(loader, className); + } + + private HookWrapper.HookEntity loadHookerClass(ClassLoader loader, String className) throws Exception { + mHookClass = loader.loadClass(className); + // Execute our newly-generated code in-process. + mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes); + mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes); + mCallBackupMethod = mHookClass.getMethod(METHOD_NAME_CALL_BACKUP, mActualParameterTypes); + SandHook.resolveStaticMethod(mCallBackupMethod); + SandHookMethodResolver.resolveMethod(mCallBackupMethod, mBackupMethod); + SandHook.compileMethod(mCallBackupMethod); + mHookClass.getMethod(METHOD_NAME_SETUP, Member.class, Method.class, XposedBridge.AdditionalHookInfo.class).invoke(null, mMember, mBackupMethod, mHookInfo); + return new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod); + } + + private String getClassName(Member originMethod) { + return CLASS_NAME_PREFIX + "_" + MD5(originMethod.toString()); + } + + public Method getHookMethod() { + return mHookMethod; + } + + public Method getBackupMethod() { + return mBackupMethod; + } + + public Method getCallBackupMethod() { + return mCallBackupMethod; + } + + public Class getHookClass() { + return mHookClass; + } + + private void generateFields() { + mHookInfoFieldId = mHookerTypeId.getField(hookInfoTypeId, FIELD_NAME_HOOK_INFO); + mMethodFieldId = mHookerTypeId.getField(memberTypeId, FIELD_NAME_METHOD); + mBackupMethodFieldId = mHookerTypeId.getField(methodTypeId, FIELD_NAME_BACKUP_METHOD); + mDexMaker.declare(mHookInfoFieldId, Modifier.STATIC, null); + mDexMaker.declare(mMethodFieldId, Modifier.STATIC, null); + mDexMaker.declare(mBackupMethodFieldId, Modifier.STATIC, null); + } + + private void generateSetupMethod() { + MethodId setupMethodId = mHookerTypeId.getMethod( + TypeId.VOID, METHOD_NAME_SETUP, memberTypeId, methodTypeId, hookInfoTypeId); + Code code = mDexMaker.declare(setupMethodId, Modifier.PUBLIC | Modifier.STATIC); + // init logic + // get parameters + Local method = code.getParameter(0, memberTypeId); + Local backupMethod = code.getParameter(1, methodTypeId); + Local hookInfo = code.getParameter(2, hookInfoTypeId); + // save params to static + code.sput(mMethodFieldId, method); + code.sput(mBackupMethodFieldId, backupMethod); + code.sput(mHookInfoFieldId, hookInfo); + code.returnVoid(); + } + + private void generateBackupMethod() { + mBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_BACKUP, mParameterTypeIds); + Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + + Local method = code.newLocal(memberTypeId); + + Map resultLocals = createResultLocals(code); + MethodId errLogMethod = TypeId.get(DexLog.class).getMethod(TypeId.get(Void.TYPE), "printCallOriginError", memberTypeId); + + + //very very important!!!!!!!!!!! + //add a try cache block avoid inline + Label tryCatchBlock = new Label(); + + code.addCatchClause(throwableTypeId, tryCatchBlock); + code.sget(mMethodFieldId, method); + code.invokeStatic(errLogMethod, null, method); + // start of try + code.mark(tryCatchBlock); + + // do nothing + if (mReturnTypeId.equals(TypeId.VOID)) { + code.returnVoid(); + } else { + // we have limited the returnType to primitives or Object, so this should be safe + code.returnValue(resultLocals.get(mReturnTypeId)); + } + } + + private void generateBackupAndCallOriginCheckMethod() { + mBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_BACKUP, mParameterTypeIds); + mSandHookCallOriginMethodId = TypeId.get(ErrorCatch.class).getMethod(TypeId.get(Object.class), "callOriginError", memberTypeId, methodTypeId, TypeId.get(Object.class), TypeId.get(Object[].class)); + MethodId errLogMethod = TypeId.get(DexLog.class).getMethod(TypeId.get(Void.TYPE), "printCallOriginError", methodTypeId); + + Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + + Local method = code.newLocal(memberTypeId); + Local backupMethod = code.newLocal(methodTypeId); + Local thisObject = code.newLocal(TypeId.OBJECT); + Local args = code.newLocal(objArrayTypeId); + Local actualParamSize = code.newLocal(TypeId.INT); + Local argIndex = code.newLocal(TypeId.INT); + Local resultObj = code.newLocal(TypeId.OBJECT); + Label tryCatchBlock = new Label(); + + Local[] allArgsLocals = createParameterLocals(code); + Map resultLocals = createResultLocals(code); + + + + //very very important!!!!!!!!!!! + //add a try cache block avoid inline + + + // start of try + code.addCatchClause(throwableTypeId, tryCatchBlock); + code.sget(mMethodFieldId, method); + code.invokeStatic(errLogMethod, null, method); + //call origin by invoke + code.loadConstant(args, null); + code.loadConstant(argIndex, 0); + code.sget(mBackupMethodFieldId, backupMethod); + int paramsSize = mParameterTypeIds.length; + int offset = 0; + // thisObject + if (mIsStatic) { + // thisObject = null + code.loadConstant(thisObject, null); + } else { + // thisObject = args[0] + offset = 1; + code.move(thisObject, allArgsLocals[0]); + } + +// offset = mIsStatic ? 0 : 1; +// for (int i = offset; i < allArgsLocals.length; i++) { +// code.loadConstant(argIndex, i - offset); +// code.aget(resultObj, args, argIndex); +// autoUnboxIfNecessary(code, allArgsLocals[i], resultObj, resultLocals, true); +// } + + // actual args (exclude thisObject if this is not a static method) + code.loadConstant(actualParamSize, paramsSize - offset); + code.newArray(args, actualParamSize); + for (int i = offset; i < paramsSize; i++) { + Local parameter = allArgsLocals[i]; + // save parameter to resultObj as Object + autoBoxIfNecessary(code, resultObj, parameter); + code.loadConstant(argIndex, i - offset); + // save Object to args + code.aput(args, argIndex, resultObj); + } + + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mSandHookCallOriginMethodId, null, method, backupMethod, thisObject, args); + code.returnVoid(); + } else { + code.invokeStatic(mSandHookCallOriginMethodId, resultObj, method, backupMethod, thisObject, args); + TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId); + Local matchObjLocal = resultLocals.get(objTypeId); + code.cast(matchObjLocal, resultObj); + // have to use matching typed Object(Integer, Double ...) to do unboxing + Local toReturn = resultLocals.get(mReturnTypeId); + autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true); + code.returnValue(toReturn); + } + + code.mark(tryCatchBlock); + // do nothing + if (mReturnTypeId.equals(TypeId.VOID)) { + code.returnVoid(); + } else { + // we have limited the returnType to primitives or Object, so this should be safe + code.returnValue(resultLocals.get(mReturnTypeId)); + } + } + + private void generateCallBackupMethod() { + mCallBackupMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_CALL_BACKUP, mParameterTypeIds); + Code code = mDexMaker.declare(mCallBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + // just call backup and return its result + + Local localOrigin = code.newLocal(memberTypeId); + Local localBackup = code.newLocal(methodTypeId); + Local[] allArgsLocals = createParameterLocals(code); + Map resultLocals = createResultLocals(code); + + + code.sget(mMethodFieldId, localOrigin); + code.sget(mBackupMethodFieldId, localBackup); + + MethodId methodId = TypeId.get(SandHook.class).getMethod(TypeId.get(Void.TYPE), "ensureBackupMethod", memberTypeId, methodTypeId); + code.invokeStatic(methodId, null, localOrigin, localBackup); + + + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + code.returnVoid(); + } else { + Local result = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, result, allArgsLocals); + code.returnValue(result); + } + } + + private void generateHookMethod() { + mHookMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_HOOK, mParameterTypeIds); + mPrintLogMethodId = TypeId.get(DexLog.class).getMethod(TypeId.get(Void.TYPE), METHOD_NAME_LOG, TypeId.get(Member.class)); + Code code = mDexMaker.declare(mHookMethodId, Modifier.PUBLIC | Modifier.STATIC); + + // code starts + + // prepare common labels + Label noHookReturn = new Label(); + Label incrementAndCheckBefore = new Label(); + Label tryBeforeCatch = new Label(); + Label noExceptionBefore = new Label(); + Label checkAndCallBackup = new Label(); + Label beginCallBefore = new Label(); + Label beginCallAfter = new Label(); + Label tryOrigCatch = new Label(); + Label noExceptionOrig = new Label(); + Label tryAfterCatch = new Label(); + Label decrementAndCheckAfter = new Label(); + Label noBackupThrowable = new Label(); + Label throwThrowable = new Label(); + // prepare locals + Local disableHooks = code.newLocal(TypeId.BOOLEAN); + Local hookInfo = code.newLocal(hookInfoTypeId); + Local callbacks = code.newLocal(callbacksTypeId); + Local snapshot = code.newLocal(objArrayTypeId); + Local snapshotLen = code.newLocal(TypeId.INT); + Local callbackObj = code.newLocal(TypeId.OBJECT); + Local callback = code.newLocal(callbackTypeId); + + Local resultObj = code.newLocal(TypeId.OBJECT); // as a temp Local + Local one = code.newLocal(TypeId.INT); + Local nullObj = code.newLocal(TypeId.OBJECT); + Local throwable = code.newLocal(throwableTypeId); + + Local param = code.newLocal(paramTypeId); + Local method = code.newLocal(memberTypeId); + Local thisObject = code.newLocal(TypeId.OBJECT); + Local args = code.newLocal(objArrayTypeId); + Local returnEarly = code.newLocal(TypeId.BOOLEAN); + + Local actualParamSize = code.newLocal(TypeId.INT); + Local argIndex = code.newLocal(TypeId.INT); + + Local beforeIdx = code.newLocal(TypeId.INT); + Local lastResult = code.newLocal(TypeId.OBJECT); + Local lastThrowable = code.newLocal(throwableTypeId); + Local hasThrowable = code.newLocal(TypeId.BOOLEAN); + + Local[] allArgsLocals = createParameterLocals(code); + + Map resultLocals = createResultLocals(code); + + code.loadConstant(args, null); + code.loadConstant(argIndex, 0); + code.loadConstant(one, 1); + code.loadConstant(snapshotLen, 0); + code.loadConstant(nullObj, null); + + code.sget(mMethodFieldId, method); + //print log + code.invokeStatic(mPrintLogMethodId, null, method); + + // check XposedBridge.disableHooks flag + + FieldId disableHooksField = + xposedBridgeTypeId.getField(TypeId.BOOLEAN, "disableHooks"); + code.sget(disableHooksField, disableHooks); + // disableHooks == true => no hooking + code.compareZ(Comparison.NE, noHookReturn, disableHooks); + + // check callbacks length + code.sget(mHookInfoFieldId, hookInfo); + code.iget(hookInfoTypeId.getField(callbacksTypeId, "callbacks"), callbacks, hookInfo); + code.invokeVirtual(callbacksTypeId.getMethod(objArrayTypeId, "getSnapshot"), snapshot, callbacks); + code.arrayLength(snapshotLen, snapshot); + // snapshotLen == 0 => no hooking + code.compareZ(Comparison.EQ, noHookReturn, snapshotLen); + + // start hooking + + // prepare hooking locals + int paramsSize = mParameterTypeIds.length; + int offset = 0; + // thisObject + if (mIsStatic) { + // thisObject = null + code.loadConstant(thisObject, null); + } else { + // thisObject = args[0] + offset = 1; + code.move(thisObject, allArgsLocals[0]); + } + // actual args (exclude thisObject if this is not a static method) + code.loadConstant(actualParamSize, paramsSize - offset); + code.newArray(args, actualParamSize); + for (int i = offset; i < paramsSize; i++) { + Local parameter = allArgsLocals[i]; + // save parameter to resultObj as Object + autoBoxIfNecessary(code, resultObj, parameter); + code.loadConstant(argIndex, i - offset); + // save Object to args + code.aput(args, argIndex, resultObj); + } + // create param + code.newInstance(param, paramTypeId.getConstructor()); + // set method, thisObject, args + code.iput(paramTypeId.getField(memberTypeId, PARAMS_FIELD_NAME_METHOD), param, method); + code.iput(paramTypeId.getField(TypeId.OBJECT, PARAMS_FIELD_NAME_THIS_OBJECT), param, thisObject); + code.iput(paramTypeId.getField(objArrayTypeId, PARAMS_FIELD_NAME_ARGS), param, args); + + // call beforeCallbacks + code.loadConstant(beforeIdx, 0); + + code.mark(beginCallBefore); + // start of try + code.addCatchClause(throwableTypeId, tryBeforeCatch); + + code.aget(callbackObj, snapshot, beforeIdx); + code.cast(callback, callbackObj); + code.invokeVirtual(callBeforeCallbackMethodId, null, callback, param); + code.jump(noExceptionBefore); + + // end of try + code.removeCatchClause(throwableTypeId); + + // start of catch + code.mark(tryBeforeCatch); + code.moveException(throwable); + code.invokeStatic(logThrowableMethodId, null, throwable); + code.invokeVirtual(setResultMethodId, null, param, nullObj); + code.loadConstant(returnEarly, false); + code.iput(returnEarlyFieldId, param, returnEarly); + code.jump(incrementAndCheckBefore); + + // no exception when calling beforeCallbacks + code.mark(noExceptionBefore); + code.iget(returnEarlyFieldId, returnEarly, param); + // if returnEarly == false, continue + code.compareZ(Comparison.EQ, incrementAndCheckBefore, returnEarly); + // returnEarly == true, break + code.op(BinaryOp.ADD, beforeIdx, beforeIdx, one); + code.jump(checkAndCallBackup); + + // increment and check to continue + code.mark(incrementAndCheckBefore); + code.op(BinaryOp.ADD, beforeIdx, beforeIdx, one); + code.compare(Comparison.LT, beginCallBefore, beforeIdx, snapshotLen); + + // check and call backup + code.mark(checkAndCallBackup); + code.iget(returnEarlyFieldId, returnEarly, param); + // if returnEarly == true, go to call afterCallbacks directly + code.compareZ(Comparison.NE, noExceptionOrig, returnEarly); + // try to call backup + // try start + code.addCatchClause(throwableTypeId, tryOrigCatch); + // we have to load args[] to paramLocals + // because args[] may be changed in beforeHookedMethod + // should consider first param is thisObj if hooked method is not static + offset = mIsStatic ? 0 : 1; + for (int i = offset; i < allArgsLocals.length; i++) { + code.loadConstant(argIndex, i - offset); + code.aget(resultObj, args, argIndex); + autoUnboxIfNecessary(code, allArgsLocals[i], resultObj, resultLocals, true); + } + // get pre-created Local with a matching typeId + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + // TODO maybe keep preset result to do some magic? + code.invokeVirtual(setResultMethodId, null, param, nullObj); + } else { + Local returnedResult = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, returnedResult, allArgsLocals); + // save returnedResult to resultObj as a Object + autoBoxIfNecessary(code, resultObj, returnedResult); + // save resultObj to param + code.invokeVirtual(setResultMethodId, null, param, resultObj); + } + // go to call afterCallbacks + code.jump(noExceptionOrig); + // try end + code.removeCatchClause(throwableTypeId); + // catch + code.mark(tryOrigCatch); + code.moveException(throwable); + // exception occurred when calling backup, save throwable to param + code.invokeVirtual(setThrowableMethodId, null, param, throwable); + + code.mark(noExceptionOrig); + code.op(BinaryOp.SUBTRACT, beforeIdx, beforeIdx, one); + + // call afterCallbacks + code.mark(beginCallAfter); + // save results of backup calling + code.invokeVirtual(getResultMethodId, lastResult, param); + code.invokeVirtual(getThrowableMethodId, lastThrowable, param); + // try start + code.addCatchClause(throwableTypeId, tryAfterCatch); + code.aget(callbackObj, snapshot, beforeIdx); + code.cast(callback, callbackObj); + code.invokeVirtual(callAfterCallbackMethodId, null, callback, param); + // all good, just continue + code.jump(decrementAndCheckAfter); + // try end + code.removeCatchClause(throwableTypeId); + // catch + code.mark(tryAfterCatch); + code.moveException(throwable); + code.invokeStatic(logThrowableMethodId, null, throwable); + // if lastThrowable == null, go to recover lastResult + code.compareZ(Comparison.EQ, noBackupThrowable, lastThrowable); + // lastThrowable != null, recover lastThrowable + code.invokeVirtual(setThrowableMethodId, null, param, lastThrowable); + // continue + code.jump(decrementAndCheckAfter); + code.mark(noBackupThrowable); + // recover lastResult and continue + code.invokeVirtual(setResultMethodId, null, param, lastResult); + // decrement and check continue + code.mark(decrementAndCheckAfter); + code.op(BinaryOp.SUBTRACT, beforeIdx, beforeIdx, one); + code.compareZ(Comparison.GE, beginCallAfter, beforeIdx); + + // callbacks end + // return + code.invokeVirtual(hasThrowableMethodId, hasThrowable, param); + // if hasThrowable, throw the throwable and return + code.compareZ(Comparison.NE, throwThrowable, hasThrowable); + // return getResult + if (mReturnTypeId.equals(TypeId.VOID)) { + code.returnVoid(); + } else { + // getResult always return an Object, so save to resultObj + code.invokeVirtual(getResultMethodId, resultObj, param); + // have to unbox it if returnType is primitive + // casting Object + TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId); + Local matchObjLocal = resultLocals.get(objTypeId); + code.cast(matchObjLocal, resultObj); + // have to use matching typed Object(Integer, Double ...) to do unboxing + Local toReturn = resultLocals.get(mReturnTypeId); + autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true); + // return + code.returnValue(toReturn); + } + // throw throwable + code.mark(throwThrowable); + code.invokeVirtual(getThrowableMethodId, throwable, param); + code.throwValue(throwable); + + // call backup and return + code.mark(noHookReturn); + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mBackupMethodId, null, allArgsLocals); + code.returnVoid(); + } else { + Local result = resultLocals.get(mReturnTypeId); + code.invokeStatic(mBackupMethodId, result, allArgsLocals); + code.returnValue(result); + } + } + + private Local[] createParameterLocals(Code code) { + Local[] paramLocals = new Local[mParameterTypeIds.length]; + for (int i = 0; i < mParameterTypeIds.length; i++) { + paramLocals[i] = code.getParameter(i, mParameterTypeIds[i]); + } + return paramLocals; + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMakerNew.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMakerNew.java new file mode 100644 index 00000000..ebd99af4 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMakerNew.java @@ -0,0 +1,298 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import android.text.TextUtils; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.wrapper.HookWrapper; +import com.swift.sandhook.xposedcompat.hookstub.HookStubManager; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; +import external.com.android.dx.Code; +import external.com.android.dx.DexMaker; +import external.com.android.dx.FieldId; +import external.com.android.dx.Local; +import external.com.android.dx.MethodId; +import external.com.android.dx.TypeId; + +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals; +import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive; + +public class HookerDexMakerNew implements HookMaker { + + public static final String METHOD_NAME_BACKUP = "backup"; + public static final String METHOD_NAME_HOOK = "hook"; + public static final TypeId objArrayTypeId = TypeId.get(Object[].class); + private static final String CLASS_DESC_PREFIX = "L"; + private static final String CLASS_NAME_PREFIX = "SandHookerN"; + private static final String FIELD_NAME_HOOK_INFO = "additionalHookInfo"; + private static final String FIELD_NAME_METHOD = "method"; + private static final String FIELD_NAME_BACKUP_METHOD = "backupMethod"; + private static final TypeId memberTypeId = TypeId.get(Member.class); + private static final TypeId methodTypeId = TypeId.get(Method.class); + private static final TypeId hookInfoTypeId + = TypeId.get(XposedBridge.AdditionalHookInfo.class); + + + private FieldId mHookInfoFieldId; + private FieldId mMethodFieldId; + private FieldId mBackupMethodFieldId; + private MethodId mHookMethodId; + private MethodId mBackupMethodId; + private MethodId mSandHookBridgeMethodId; + + private TypeId mHookerTypeId; + private TypeId[] mParameterTypeIds; + private Class[] mActualParameterTypes; + private Class mReturnType; + private TypeId mReturnTypeId; + private boolean mIsStatic; + // TODO use this to generate methods + private boolean mHasThrowable; + + private DexMaker mDexMaker; + private Member mMember; + private XposedBridge.AdditionalHookInfo mHookInfo; + private ClassLoader mAppClassLoader; + private Class mHookClass; + private Method mHookMethod; + private Method mBackupMethod; + private String mDexDirPath; + + private static TypeId[] getParameterTypeIds(Class[] parameterTypes, boolean isStatic) { + int parameterSize = parameterTypes.length; + int targetParameterSize = isStatic ? parameterSize : parameterSize + 1; + TypeId[] parameterTypeIds = new TypeId[targetParameterSize]; + int offset = 0; + if (!isStatic) { + parameterTypeIds[0] = TypeId.OBJECT; + offset = 1; + } + for (int i = 0; i < parameterTypes.length; i++) { + parameterTypeIds[i + offset] = TypeId.get(parameterTypes[i]); + } + return parameterTypeIds; + } + + private static Class[] getParameterTypes(Class[] parameterTypes, boolean isStatic) { + if (isStatic) { + return parameterTypes; + } + int parameterSize = parameterTypes.length; + int targetParameterSize = parameterSize + 1; + Class[] newParameterTypes = new Class[targetParameterSize]; + int offset = 1; + newParameterTypes[0] = Object.class; + System.arraycopy(parameterTypes, 0, newParameterTypes, offset, parameterTypes.length); + return newParameterTypes; + } + + public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, + ClassLoader appClassLoader, String dexDirPath) throws Exception { + if (member instanceof Method) { + Method method = (Method) member; + mIsStatic = Modifier.isStatic(method.getModifiers()); + mReturnType = method.getReturnType(); + if (mReturnType.equals(Void.class) || mReturnType.equals(void.class) + || mReturnType.isPrimitive()) { + mReturnTypeId = TypeId.get(mReturnType); + } else { + // all others fallback to plain Object for convenience + mReturnType = Object.class; + mReturnTypeId = TypeId.OBJECT; + } + mParameterTypeIds = getParameterTypeIds(method.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(method.getParameterTypes(), mIsStatic); + mHasThrowable = method.getExceptionTypes().length > 0; + } else if (member instanceof Constructor) { + Constructor constructor = (Constructor) member; + mIsStatic = false; + mReturnType = void.class; + mReturnTypeId = TypeId.VOID; + mParameterTypeIds = getParameterTypeIds(constructor.getParameterTypes(), mIsStatic); + mActualParameterTypes = getParameterTypes(constructor.getParameterTypes(), mIsStatic); + mHasThrowable = constructor.getExceptionTypes().length > 0; + } else if (member.getDeclaringClass().isInterface()) { + throw new IllegalArgumentException("Cannot hook interfaces: " + member.toString()); + } else if (Modifier.isAbstract(member.getModifiers())) { + throw new IllegalArgumentException("Cannot hook abstract methods: " + member.toString()); + } else { + throw new IllegalArgumentException("Only methods and constructors can be hooked: " + member.toString()); + } + mMember = member; + mHookInfo = hookInfo; + mDexDirPath = dexDirPath; + if (appClassLoader == null + || appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) { + mAppClassLoader = this.getClass().getClassLoader(); + } else { + mAppClassLoader = appClassLoader; + } + + mDexMaker = new DexMaker(); + // Generate a Hooker class. + String className = getClassName(mMember); + String dexName = className + ".jar"; + + HookWrapper.HookEntity hookEntity = null; + //try load cache first + try { + ClassLoader loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName); + if (loader != null) { + hookEntity = loadHookerClass(loader, className); + } + } catch (Throwable throwable) {} + + //do generate + if (hookEntity == null) { + hookEntity = doMake(className, dexName); + } + SandHook.hook(hookEntity); + } + + private HookWrapper.HookEntity doMake(String className, String dexName) throws Exception { + mHookerTypeId = TypeId.get(CLASS_DESC_PREFIX + className + ";"); + mDexMaker.declare(mHookerTypeId, className + ".generated", Modifier.PUBLIC, TypeId.OBJECT); + generateFields(); + generateHookMethod(); + generateBackupMethod(); + + ClassLoader loader; + if (TextUtils.isEmpty(mDexDirPath)) { + throw new IllegalArgumentException("dexDirPath should not be empty!!!"); + } + // Create the dex file and load it. + loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName); + return loadHookerClass(loader, className); + } + + private HookWrapper.HookEntity loadHookerClass(ClassLoader loader, String className) throws Exception { + mHookClass = loader.loadClass(className); + // Execute our newly-generated code in-process. + mHookMethod = mHookClass.getMethod(METHOD_NAME_HOOK, mActualParameterTypes); + mBackupMethod = mHookClass.getMethod(METHOD_NAME_BACKUP); + setup(mHookClass); + return new HookWrapper.HookEntity(mMember, mHookMethod, mBackupMethod, false); + } + + private void setup(Class mHookClass) { + XposedHelpers.setStaticObjectField(mHookClass, FIELD_NAME_METHOD, mMember); + XposedHelpers.setStaticObjectField(mHookClass, FIELD_NAME_BACKUP_METHOD, mBackupMethod); + XposedHelpers.setStaticObjectField(mHookClass, FIELD_NAME_HOOK_INFO, mHookInfo); + } + + private String getClassName(Member originMethod) { + return CLASS_NAME_PREFIX + "_" + MD5(originMethod.toString()); + } + + public Method getHookMethod() { + return mHookMethod; + } + + public Method getBackupMethod() { + return mBackupMethod; + } + + public Method getCallBackupMethod() { + return mBackupMethod; + } + + public Class getHookClass() { + return mHookClass; + } + + private void generateFields() { + mHookInfoFieldId = mHookerTypeId.getField(hookInfoTypeId, FIELD_NAME_HOOK_INFO); + mMethodFieldId = mHookerTypeId.getField(memberTypeId, FIELD_NAME_METHOD); + mBackupMethodFieldId = mHookerTypeId.getField(methodTypeId, FIELD_NAME_BACKUP_METHOD); + mDexMaker.declare(mHookInfoFieldId, Modifier.STATIC, null); + mDexMaker.declare(mMethodFieldId, Modifier.STATIC, null); + mDexMaker.declare(mBackupMethodFieldId, Modifier.STATIC, null); + } + + private void generateBackupMethod() { + mBackupMethodId = mHookerTypeId.getMethod(TypeId.VOID, METHOD_NAME_BACKUP); + Code code = mDexMaker.declare(mBackupMethodId, Modifier.PUBLIC | Modifier.STATIC); + code.returnVoid(); + } + + private void generateHookMethod() { + mHookMethodId = mHookerTypeId.getMethod(mReturnTypeId, METHOD_NAME_HOOK, mParameterTypeIds); + mSandHookBridgeMethodId = TypeId.get(HookStubManager.class).getMethod(TypeId.get(Object.class), "hookBridge", memberTypeId, TypeId.get(Object.class), TypeId.get(Object[].class)); + + Code code = mDexMaker.declare(mHookMethodId, Modifier.PUBLIC | Modifier.STATIC); + + Local method = code.newLocal(memberTypeId); + // Local backupMethod = code.newLocal(methodTypeId); + Local thisObject = code.newLocal(TypeId.OBJECT); + Local args = code.newLocal(objArrayTypeId); + Local actualParamSize = code.newLocal(TypeId.INT); + Local argIndex = code.newLocal(TypeId.INT); + Local resultObj = code.newLocal(TypeId.OBJECT); + + Local[] allArgsLocals = createParameterLocals(code); + Map resultLocals = createResultLocals(code); + + + code.sget(mMethodFieldId, method); + code.loadConstant(args, null); + code.loadConstant(argIndex, 0); +// code.sget(mBackupMethodFieldId, backupMethod); + int paramsSize = mParameterTypeIds.length; + int offset = 0; + // thisObject + if (mIsStatic) { + // thisObject = null + code.loadConstant(thisObject, null); + } else { + // thisObject = args[0] + offset = 1; + code.move(thisObject, allArgsLocals[0]); + } + + // actual args (exclude thisObject if this is not a static method) + code.loadConstant(actualParamSize, paramsSize - offset); + code.newArray(args, actualParamSize); + for (int i = offset; i < paramsSize; i++) { + Local parameter = allArgsLocals[i]; + // save parameter to resultObj as Object + autoBoxIfNecessary(code, resultObj, parameter); + code.loadConstant(argIndex, i - offset); + // save Object to args + code.aput(args, argIndex, resultObj); + } + + if (mReturnTypeId.equals(TypeId.VOID)) { + code.invokeStatic(mSandHookBridgeMethodId, null, method, thisObject, args); + code.returnVoid(); + } else { + code.invokeStatic(mSandHookBridgeMethodId, resultObj, method, thisObject, args); + TypeId objTypeId = getObjTypeIdIfPrimitive(mReturnTypeId); + Local matchObjLocal = resultLocals.get(objTypeId); + code.cast(matchObjLocal, resultObj); + // have to use matching typed Object(Integer, Double ...) to do unboxing + Local toReturn = resultLocals.get(mReturnTypeId); + autoUnboxIfNecessary(code, toReturn, matchObjLocal, resultLocals, true); + code.returnValue(toReturn); + } + + } + + private Local[] createParameterLocals(Code code) { + Local[] paramLocals = new Local[mParameterTypeIds.length]; + for (int i = 0; i < mParameterTypeIds.length; i++) { + paramLocals[i] = code.getParameter(i, mParameterTypeIds[i]); + } + return paramLocals; + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java new file mode 100644 index 00000000..22227e44 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java @@ -0,0 +1,161 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import android.os.Process; +import android.os.Trace; + +import com.elderdrivers.riru.edxp.Main; +import com.swift.sandhook.SandHook; +import com.swift.sandhook.SandHookConfig; +import com.swift.sandhook.wrapper.HookWrapper; +import com.swift.sandhook.xposedcompat.XposedCompat; +import com.swift.sandhook.xposedcompat.hookstub.HookMethodEntity; +import com.swift.sandhook.xposedcompat.hookstub.HookStubManager; +import com.swift.sandhook.xposedcompat.utils.DexLog; +import com.swift.sandhook.xposedcompat.utils.FileUtils; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import de.robv.android.xposed.XposedBridge; + +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; +import static com.elderdrivers.riru.edxp.util.FileUtils.getPackageName; +import static com.elderdrivers.riru.edxp.util.ProcessUtils.getCurrentProcessName; + +public final class SandHookXposedBridge { + + private static final HashMap hookedInfo = new HashMap<>(); + private static HookMaker hookMaker = XposedCompat.useNewDexMaker ? new HookerDexMakerNew() : new HookerDexMaker(); + private static final AtomicBoolean dexPathInited = new AtomicBoolean(false); + private static File dexDir; + + public static Map entityMap = new HashMap<>(); + + public static void onForkPost() { + dexPathInited.set(false); + } + + public static synchronized void hookMethod(Member hookMethod, XposedBridge.AdditionalHookInfo additionalHookInfo) { + + if (!checkMember(hookMethod)) { + return; + } + + if (hookedInfo.containsKey(hookMethod) || entityMap.containsKey(hookMethod)) { + DexLog.w("already hook method:" + hookMethod.toString()); + return; + } + + try { + setupDexCachePath(); + Trace.beginSection("SandHook-Xposed"); + long timeStart = System.currentTimeMillis(); + HookMethodEntity stub = null; + if (XposedCompat.useInternalStub) { + stub = HookStubManager.getHookMethodEntity(hookMethod); + } + if (stub != null) { + SandHook.hook(new HookWrapper.HookEntity(hookMethod, stub.hook, stub.backup, false)); + entityMap.put(hookMethod, stub); + } else { + hookMaker.start(hookMethod, additionalHookInfo, + null, dexDir == null ? null : dexDir.getAbsolutePath()); + hookedInfo.put(hookMethod, hookMaker.getCallBackupMethod()); + } + DexLog.d("hook method <" + hookMethod.toString() + "> cost " + (System.currentTimeMillis() - timeStart) + " ms, by " + (stub != null ? "internal stub." : "dex maker")); + Trace.endSection(); + } catch (Exception e) { + DexLog.e("error occur when hook method <" + hookMethod.toString() + ">", e); + } + } + + private static void setupDexCachePath() { + // using file based DexClassLoader + if (!dexPathInited.compareAndSet(false, true)) { + return; + } + try { + // we always choose to use device encrypted storage data on android N and later + // in case some app is installing hooks before phone is unlocked + String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/"; + dexDir = new File(fixedAppDataDir, "/cache/sandxposed/" + + getCurrentProcessName(Main.appProcessName).replace(":", "_") + "/"); + dexDir.mkdirs(); + } catch (Throwable throwable) { + com.elderdrivers.riru.edxp.sandhook.dexmaker.DexLog.e("error when init dex path", throwable); + } + } + +// public static void clearOatFile() { +// String fixedAppDataDir = XposedCompat.cacheDir.getAbsolutePath(); +// File dexOatDir = new File(fixedAppDataDir, "/sandxposed/oat/"); +// if (!dexOatDir.exists()) +// return; +// try { +// FileUtils.delete(dexOatDir); +// dexOatDir.mkdirs(); +// } catch (Throwable throwable) { +// } +// } + + private static boolean checkMember(Member member) { + + if (member instanceof Method) { + return true; + } else if (member instanceof Constructor) { + return true; + } else if (member.getDeclaringClass().isInterface()) { + DexLog.e("Cannot hook interfaces: " + member.toString()); + return false; + } else if (Modifier.isAbstract(member.getModifiers())) { + DexLog.e("Cannot hook abstract methods: " + member.toString()); + return false; + } else { + DexLog.e("Only methods and constructors can be hooked: " + member.toString()); + return false; + } + } + + public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) + throws Throwable { + Method callBackup = hookedInfo.get(method); + if (callBackup == null) { + //method hook use internal stub + return SandHook.callOriginMethod(method, thisObject, args); + } + if (!Modifier.isStatic(callBackup.getModifiers())) { + throw new IllegalStateException("original method is not static, something must be wrong!"); + } + callBackup.setAccessible(true); + if (args == null) { + args = new Object[0]; + } + final int argsSize = args.length; + if (Modifier.isStatic(method.getModifiers())) { + return callBackup.invoke(null, args); + } else { + Object[] newArgs = new Object[argsSize + 1]; + newArgs[0] = thisObject; + for (int i = 1; i < newArgs.length; i++) { + newArgs[i] = args[i - 1]; + } + return callBackup.invoke(null, newArgs); + } + } + + public static void setLibPath() { + if (Process.is64Bit()) { + SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so"; + } else { + SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so"; + } + } +} + + diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ApplicationUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ApplicationUtils.java new file mode 100644 index 00000000..205d7c1f --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ApplicationUtils.java @@ -0,0 +1,34 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.app.Application; + +import java.lang.reflect.Method; + +public class ApplicationUtils { + + private static Class classActivityThread; + private static Method currentApplicationMethod; + + static Application application; + + public static Application currentApplication() { + if (application != null) + return application; + if (currentApplicationMethod == null) { + try { + classActivityThread = Class.forName("android.app.ActivityThread"); + currentApplicationMethod = classActivityThread.getDeclaredMethod("currentApplication"); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (currentApplicationMethod == null) + return null; + try { + application = (Application) currentApplicationMethod.invoke(null); + } catch (Exception e) { + } + return application; + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java new file mode 100644 index 00000000..4acfa841 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ClassLoaderUtils.java @@ -0,0 +1,106 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.os.Build; +import android.util.ArrayMap; + +import com.elderdrivers.riru.edxp.sandhook.BuildConfig; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import dalvik.system.PathClassLoader; + +public class ClassLoaderUtils { + + public static final String DEXPATH = "/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex"; + + public static void replaceParentClassLoader(ClassLoader appClassLoader) { + if (appClassLoader == null) { + DexLog.e("appClassLoader is null, you might be kidding me?"); + return; + } + try { + ClassLoader curCL = ClassLoaderUtils.class.getClassLoader(); + ClassLoader parent = appClassLoader; + ClassLoader lastChild = appClassLoader; + while (parent != null) { + ClassLoader tmp = parent.getParent(); + if (tmp == curCL) { + DexLog.d("replacing has been done before, skip."); + return; + } + if (tmp == null) { + DexLog.d("before replacing =========================================>"); + dumpClassLoaders(appClassLoader); + Field parentField = ClassLoader.class.getDeclaredField("parent"); + parentField.setAccessible(true); + parentField.set(curCL, parent); + parentField.set(lastChild, curCL); + DexLog.d("after replacing ==========================================>"); + dumpClassLoaders(appClassLoader); + } + lastChild = parent; + parent = tmp; + } + } catch (Throwable throwable) { + DexLog.e("error when replacing class loader.", throwable); + } + } + + private static void dumpClassLoaders(ClassLoader classLoader) { + if (BuildConfig.DEBUG) { + while (classLoader != null) { + DexLog.d(classLoader + " =>"); + classLoader = classLoader.getParent(); + } + } + } + + public static List getAppClassLoader() { + List cacheLoaders = new ArrayList<>(0); + try { + DexLog.d("start getting app classloader"); + Class appLoadersClass = Class.forName("android.app.ApplicationLoaders"); + Field loadersField = appLoadersClass.getDeclaredField("gApplicationLoaders"); + loadersField.setAccessible(true); + Object loaders = loadersField.get(null); + Field mLoaderMapField = loaders.getClass().getDeclaredField("mLoaders"); + mLoaderMapField.setAccessible(true); + ArrayMap mLoaderMap = (ArrayMap) mLoaderMapField.get(loaders); + DexLog.d("mLoaders size = " + mLoaderMap.size()); + cacheLoaders = new ArrayList<>(mLoaderMap.values()); + } catch (Exception ex) { + DexLog.e("error get app class loader.", ex); + } + return cacheLoaders; + } + + private static HashSet classLoaders = new HashSet<>(); + + public static boolean addPathToClassLoader(ClassLoader classLoader) { + if (!(classLoader instanceof PathClassLoader)) { + DexLog.w(classLoader + " is not a BaseDexClassLoader!!!"); + return false; + } + if (classLoaders.contains(classLoader)) { + DexLog.d(classLoader + " has been hooked before"); + return true; + } + try { + PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + //baseDexClassLoader.addDexPath(DEXPATH); + } else { + DexUtils.injectDexAtFirst(DEXPATH, baseDexClassLoader); + } + classLoaders.add(classLoader); + return true; + } catch (Throwable throwable) { + DexLog.e("error when addPath to ClassLoader: " + classLoader, throwable); + } + return false; + } + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexLog.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexLog.java new file mode 100644 index 00000000..cda8f193 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexLog.java @@ -0,0 +1,51 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.util.Log; + +import java.lang.reflect.Member; + + +public class DexLog { + + public static final String TAG = "SandXposed-dexmaker"; + + public static boolean DEBUG = true; + + public static int v(String s) { + return Log.v(TAG, s); + } + + public static int i(String s) { + return Log.i(TAG, s); + } + + public static int d(String s) { + return Log.d(TAG, s); + } + + public static void printMethodHookIn(Member member) { + if (DEBUG && member != null) { + Log.d("SandHook-Xposed", "method <" + member.toString() + "> hook in"); + } + } + + public static void printCallOriginError(Member member) { + if (member != null) { + Log.e("SandHook-Xposed", "method <" + member.toString() + "> call origin error!"); + } + } + + public static int w(String s) { + return Log.w(TAG, s); + } + + public static int e(String s) { + return Log.e(TAG, s); + } + + public static int e(String s, Throwable t) { + return Log.e(TAG, s, t); + } + + +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexMakerUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexMakerUtils.java new file mode 100644 index 00000000..ad9142df --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexMakerUtils.java @@ -0,0 +1,224 @@ +package com.swift.sandhook.xposedcompat.utils; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; + +import external.com.android.dx.Code; +import external.com.android.dx.Local; +import external.com.android.dx.TypeId; + +public class DexMakerUtils { + + + private static volatile Method addInstMethod, specMethod; + + public static void autoBoxIfNecessary(Code code, Local target, Local source) { + String boxMethod = "valueOf"; + TypeId boxTypeId; + TypeId typeId = source.getType(); + if (typeId.equals(TypeId.BOOLEAN)) { + boxTypeId = TypeId.get(Boolean.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.BOOLEAN), target, source); + } else if (typeId.equals(TypeId.BYTE)) { + boxTypeId = TypeId.get(Byte.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.BYTE), target, source); + } else if (typeId.equals(TypeId.CHAR)) { + boxTypeId = TypeId.get(Character.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.CHAR), target, source); + } else if (typeId.equals(TypeId.DOUBLE)) { + boxTypeId = TypeId.get(Double.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.DOUBLE), target, source); + } else if (typeId.equals(TypeId.FLOAT)) { + boxTypeId = TypeId.get(Float.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.FLOAT), target, source); + } else if (typeId.equals(TypeId.INT)) { + boxTypeId = TypeId.get(Integer.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.INT), target, source); + } else if (typeId.equals(TypeId.LONG)) { + boxTypeId = TypeId.get(Long.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.LONG), target, source); + } else if (typeId.equals(TypeId.SHORT)) { + boxTypeId = TypeId.get(Short.class); + code.invokeStatic(boxTypeId.getMethod(boxTypeId, boxMethod, TypeId.SHORT), target, source); + } else if (typeId.equals(TypeId.VOID)) { + code.loadConstant(target, null); + } else { + code.move(target, source); + } + } + + public static void autoUnboxIfNecessary(Code code, Local target, Local source, + Map tmpLocals, boolean castObj) { + String unboxMethod; + TypeId typeId = target.getType(); + TypeId boxTypeId; + if (typeId.equals(TypeId.BOOLEAN)) { + unboxMethod = "booleanValue"; + boxTypeId = TypeId.get("Ljava/lang/Boolean;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.BOOLEAN, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.BYTE)) { + unboxMethod = "byteValue"; + boxTypeId = TypeId.get("Ljava/lang/Byte;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.BYTE, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.CHAR)) { + unboxMethod = "charValue"; + boxTypeId = TypeId.get("Ljava/lang/Character;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.CHAR, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.DOUBLE)) { + unboxMethod = "doubleValue"; + boxTypeId = TypeId.get("Ljava/lang/Double;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.DOUBLE, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.FLOAT)) { + unboxMethod = "floatValue"; + boxTypeId = TypeId.get("Ljava/lang/Float;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.FLOAT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.INT)) { + unboxMethod = "intValue"; + boxTypeId = TypeId.get("Ljava/lang/Integer;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.INT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.LONG)) { + unboxMethod = "longValue"; + boxTypeId = TypeId.get("Ljava/lang/Long;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.LONG, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.SHORT)) { + unboxMethod = "shortValue"; + boxTypeId = TypeId.get("Ljava/lang/Short;"); + Local boxTypedLocal = tmpLocals.get(boxTypeId); + code.cast(boxTypedLocal, source); + code.invokeVirtual(boxTypeId.getMethod(TypeId.SHORT, unboxMethod), target, boxTypedLocal); + } else if (typeId.equals(TypeId.VOID)) { + code.loadConstant(target, null); + } else if (castObj) { + code.cast(target, source); + } else { + code.move(target, source); + } + } + + public static Map createResultLocals(Code code) { + HashMap resultMap = new HashMap<>(); + Local booleanLocal = code.newLocal(TypeId.BOOLEAN); + Local byteLocal = code.newLocal(TypeId.BYTE); + Local charLocal = code.newLocal(TypeId.CHAR); + Local doubleLocal = code.newLocal(TypeId.DOUBLE); + Local floatLocal = code.newLocal(TypeId.FLOAT); + Local intLocal = code.newLocal(TypeId.INT); + Local longLocal = code.newLocal(TypeId.LONG); + Local shortLocal = code.newLocal(TypeId.SHORT); + Local voidLocal = code.newLocal(TypeId.VOID); + Local objectLocal = code.newLocal(TypeId.OBJECT); + + Local booleanObjLocal = code.newLocal(TypeId.get("Ljava/lang/Boolean;")); + Local byteObjLocal = code.newLocal(TypeId.get("Ljava/lang/Byte;")); + Local charObjLocal = code.newLocal(TypeId.get("Ljava/lang/Character;")); + Local doubleObjLocal = code.newLocal(TypeId.get("Ljava/lang/Double;")); + Local floatObjLocal = code.newLocal(TypeId.get("Ljava/lang/Float;")); + Local intObjLocal = code.newLocal(TypeId.get("Ljava/lang/Integer;")); + Local longObjLocal = code.newLocal(TypeId.get("Ljava/lang/Long;")); + Local shortObjLocal = code.newLocal(TypeId.get("Ljava/lang/Short;")); + Local voidObjLocal = code.newLocal(TypeId.get("Ljava/lang/Void;")); + + // backup need initialized locals + code.loadConstant(booleanLocal, false); + code.loadConstant(byteLocal, (byte) 0); + code.loadConstant(charLocal, '\0'); + code.loadConstant(doubleLocal,0.0); + code.loadConstant(floatLocal,0.0f); + code.loadConstant(intLocal, 0); + code.loadConstant(longLocal, 0L); + code.loadConstant(shortLocal, (short) 0); + code.loadConstant(voidLocal, null); + code.loadConstant(objectLocal, null); + // all to null + code.loadConstant(booleanObjLocal, null); + code.loadConstant(byteObjLocal, null); + code.loadConstant(charObjLocal, null); + code.loadConstant(doubleObjLocal, null); + code.loadConstant(floatObjLocal, null); + code.loadConstant(intObjLocal, null); + code.loadConstant(longObjLocal, null); + code.loadConstant(shortObjLocal, null); + code.loadConstant(voidObjLocal, null); + // package all + resultMap.put(TypeId.BOOLEAN, booleanLocal); + resultMap.put(TypeId.BYTE, byteLocal); + resultMap.put(TypeId.CHAR, charLocal); + resultMap.put(TypeId.DOUBLE, doubleLocal); + resultMap.put(TypeId.FLOAT, floatLocal); + resultMap.put(TypeId.INT, intLocal); + resultMap.put(TypeId.LONG, longLocal); + resultMap.put(TypeId.SHORT, shortLocal); + resultMap.put(TypeId.VOID, voidLocal); + resultMap.put(TypeId.OBJECT, objectLocal); + + resultMap.put(TypeId.get("Ljava/lang/Boolean;"), booleanObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Byte;"), byteObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Character;"), charObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Double;"), doubleObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Float;"), floatObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Integer;"), intObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Long;"), longObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Short;"), shortObjLocal); + resultMap.put(TypeId.get("Ljava/lang/Void;"), voidObjLocal); + + return resultMap; + } + + public static TypeId getObjTypeIdIfPrimitive(TypeId typeId) { + if (typeId.equals(TypeId.BOOLEAN)) { + return TypeId.get("Ljava/lang/Boolean;"); + } else if (typeId.equals(TypeId.BYTE)) { + return TypeId.get("Ljava/lang/Byte;"); + } else if (typeId.equals(TypeId.CHAR)) { + return TypeId.get("Ljava/lang/Character;"); + } else if (typeId.equals(TypeId.DOUBLE)) { + return TypeId.get("Ljava/lang/Double;"); + } else if (typeId.equals(TypeId.FLOAT)) { + return TypeId.get("Ljava/lang/Float;"); + } else if (typeId.equals(TypeId.INT)) { + return TypeId.get("Ljava/lang/Integer;"); + } else if (typeId.equals(TypeId.LONG)) { + return TypeId.get("Ljava/lang/Long;"); + } else if (typeId.equals(TypeId.SHORT)) { + return TypeId.get("Ljava/lang/Short;"); + } else if (typeId.equals(TypeId.VOID)) { + return TypeId.get("Ljava/lang/Void;"); + } else { + return typeId; + } + } + + public static void returnRightValue(Code code, Class returnType, Map resultLocals) { + String unboxMethod; + TypeId boxTypeId; + code.returnValue(resultLocals.get(returnType)); + } + + public static String MD5(String source) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + messageDigest.update(source.getBytes()); + return new BigInteger(1, messageDigest.digest()).toString(32); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return source; + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java new file mode 100644 index 00000000..55bd02f4 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexUtils.java @@ -0,0 +1,66 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.annotation.TargetApi; +import android.os.Build; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; + +import dalvik.system.BaseDexClassLoader; +import dalvik.system.DexClassLoader; + +/** + * For 6.0 only. + */ +@TargetApi(Build.VERSION_CODES.M) +public class DexUtils { + + public static void injectDexAtFirst(String dexPath, BaseDexClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException { + DexClassLoader dexClassLoader = new DexClassLoader(dexPath, null, dexPath, classLoader); + Object baseDexElements = getDexElements(getPathList(classLoader)); + Object newDexElements = getDexElements(getPathList(dexClassLoader)); + Object allDexElements = combineArray(newDexElements, baseDexElements); + Object pathList = getPathList(classLoader); + setField(pathList, pathList.getClass(), "dexElements", allDexElements); + } + + private static Object getDexElements(Object paramObject) + throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException { + return getField(paramObject, paramObject.getClass(), "dexElements"); + } + + private static Object getPathList(Object baseDexClassLoader) + throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException { + return getField(baseDexClassLoader, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList"); + } + + private static Object combineArray(Object firstArray, Object secondArray) { + Class localClass = firstArray.getClass().getComponentType(); + int firstArrayLength = Array.getLength(firstArray); + int allLength = firstArrayLength + Array.getLength(secondArray); + Object result = Array.newInstance(localClass, allLength); + for (int k = 0; k < allLength; ++k) { + if (k < firstArrayLength) { + Array.set(result, k, Array.get(firstArray, k)); + } else { + Array.set(result, k, Array.get(secondArray, k - firstArrayLength)); + } + } + return result; + } + + public static Object getField(Object obj, Class cl, String field) + throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { + Field localField = cl.getDeclaredField(field); + localField.setAccessible(true); + return localField.get(obj); + } + + public static void setField(Object obj, Class cl, String field, Object value) + throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { + Field localField = cl.getDeclaredField(field); + localField.setAccessible(true); + localField.set(obj, value); + } + +} \ No newline at end of file diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java new file mode 100644 index 00000000..c3c7acc1 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/FileUtils.java @@ -0,0 +1,77 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.os.Build; +import android.text.TextUtils; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +public class FileUtils { + + public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; + + /** + * Delete a file or a directory and its children. + * + * @param file The directory to delete. + * @throws IOException Exception when problem occurs during deleting the directory. + */ + public static void delete(File file) throws IOException { + + for (File childFile : file.listFiles()) { + + if (childFile.isDirectory()) { + delete(childFile); + } else { + if (!childFile.delete()) { + throw new IOException(); + } + } + } + + if (!file.delete()) { + throw new IOException(); + } + } + + public static String readLine(File file) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + return reader.readLine(); + } catch (Throwable throwable) { + return ""; + } + } + + public static void writeLine(File file, String line) { + try { + file.createNewFile(); + } catch (IOException ex) { + } + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write(line); + writer.flush(); + } catch (Throwable throwable) { + DexLog.e("error writing line to file " + file + ": " + throwable.getMessage()); + } + } + + public static String getPackageName(String dataDir) { + if (TextUtils.isEmpty(dataDir)) { + DexLog.e("getPackageName using empty dataDir"); + return ""; + } + int lastIndex = dataDir.lastIndexOf("/"); + if (lastIndex < 0) { + return dataDir; + } + return dataDir.substring(lastIndex + 1); + } + + public static String getDataPathPrefix() { + return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/"; + } +} diff --git a/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java new file mode 100644 index 00000000..2adcf4f3 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java @@ -0,0 +1,64 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by swift_gan on 2017/11/23. + */ + +public class ProcessUtils { + + private static volatile String processName = null; + + public static String getProcessName(Context context) { + if (!TextUtils.isEmpty(processName)) + return processName; + processName = doGetProcessName(context); + return processName; + } + + private static String doGetProcessName(Context context) { + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List runningApps = am.getRunningAppProcesses(); + if (runningApps == null) { + return null; + } + for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) { + if (proInfo.pid == android.os.Process.myPid()) { + if (proInfo.processName != null) { + return proInfo.processName; + } + } + } + return context.getPackageName(); + } + + public static boolean isMainProcess(Context context) { + String processName = getProcessName(context); + String pkgName = context.getPackageName(); + if (!TextUtils.isEmpty(processName) && !TextUtils.equals(processName, pkgName)) { + return false; + } else { + return true; + } + } + + public static List findActivitiesForPackage(Context context, String packageName) { + final PackageManager packageManager = context.getPackageManager(); + + final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + mainIntent.setPackage(packageName); + + final List apps = packageManager.queryIntentActivities(mainIntent, 0); + return apps != null ? apps : new ArrayList(); + } +} diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/Main.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java similarity index 99% rename from edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/Main.java rename to edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java index f855d593..d6bb5997 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/Main.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.edxp.yahfa; +package com.elderdrivers.riru.edxp; import android.annotation.SuppressLint; import android.os.Build; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java index 3a27654f..352f0c05 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java @@ -2,7 +2,7 @@ package com.elderdrivers.riru.edxp.yahfa.config; import com.elderdrivers.riru.edxp.config.EdXpConfig; import com.elderdrivers.riru.edxp.config.InstallerChooser; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.yahfa.entry.hooker.XposedBlackListHooker; public class YahfaEdxpConfig implements EdXpConfig { diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaHookProvider.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaHookProvider.java index c573f441..2f0709ae 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaHookProvider.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaHookProvider.java @@ -1,11 +1,10 @@ package com.elderdrivers.riru.edxp.yahfa.config; import com.elderdrivers.riru.edxp.hook.HookProvider; -import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; import com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils; import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge; +import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import de.robv.android.xposed.XposedBridge; @@ -17,7 +16,7 @@ public class YahfaHookProvider implements HookProvider { } @Override - public Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + public Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) throws Throwable { return DynamicBridge.invokeOriginalMethod(method, thisObject, args); } diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java index bbf7d68a..13da190a 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java @@ -1,6 +1,6 @@ package com.elderdrivers.riru.edxp.yahfa.core; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; import com.elderdrivers.riru.edxp.util.Utils; @@ -14,8 +14,8 @@ import java.util.Set; import de.robv.android.xposed.XposedHelpers; -import static com.elderdrivers.riru.edxp.yahfa.Main.backupAndHookNative; -import static com.elderdrivers.riru.edxp.yahfa.Main.findMethodNative; +import static com.elderdrivers.riru.edxp.Main.backupAndHookNative; +import static com.elderdrivers.riru.edxp.Main.findMethodNative; public class HookMain { diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java index 9b2d496b..d8f616b5 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java @@ -2,7 +2,7 @@ package com.elderdrivers.riru.edxp.yahfa.core; import android.os.Build; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.util.Utils; import java.lang.reflect.Field; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java index 5b56caf3..7ca85d47 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java @@ -3,9 +3,8 @@ package com.elderdrivers.riru.edxp.yahfa.dexmaker; import android.app.AndroidAppHelper; import android.os.Build; import android.text.TextUtils; -import android.util.Log; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.yahfa.core.HookMain; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java index a6307f7b..b998a29e 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java @@ -1,6 +1,6 @@ package com.elderdrivers.riru.edxp.yahfa.dexmaker; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import java.io.File; import java.lang.reflect.Constructor; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java index 3b281da5..56695e55 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java @@ -4,7 +4,7 @@ import android.annotation.TargetApi; import android.os.Build; import android.text.TextUtils; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.yahfa.core.HookMain; import java.io.File; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java index 2d3050e7..12d7ef2c 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java @@ -8,7 +8,7 @@ import android.content.res.CompatibilityInfo; import com.elderdrivers.riru.common.KeepMembers; import com.elderdrivers.riru.edxp.util.Utils; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.yahfa.entry.Router; import de.robv.android.xposed.XposedBridge; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java index 87cda6b2..f3261f9d 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java @@ -1,7 +1,7 @@ package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.yahfa.entry.Router; import de.robv.android.xposed.XposedBridge; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java index dd59ee82..ba9842d9 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java @@ -2,7 +2,7 @@ package com.elderdrivers.riru.edxp.yahfa.proxy; import android.text.TextUtils; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.yahfa.entry.Router; import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; @@ -11,7 +11,7 @@ import com.elderdrivers.riru.edxp.util.Utils; import de.robv.android.xposed.XposedBridge; -import static com.elderdrivers.riru.edxp.yahfa.Main.isAppNeedHook; +import static com.elderdrivers.riru.edxp.Main.isAppNeedHook; import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; /** diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java index 0df49cd6..9c1d3dba 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java @@ -1,6 +1,6 @@ package com.elderdrivers.riru.edxp.yahfa.proxy; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import com.elderdrivers.riru.edxp.config.ConfigManager; import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; import com.elderdrivers.riru.edxp.yahfa.entry.Router; diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java index 86041628..ecd8813d 100644 --- a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java @@ -1,7 +1,7 @@ package com.elderdrivers.riru.edxp.yahfa.util; import com.elderdrivers.riru.edxp.util.Utils; -import com.elderdrivers.riru.edxp.yahfa.Main; +import com.elderdrivers.riru.edxp.Main; import java.util.Arrays; diff --git a/settings.gradle b/settings.gradle index 2b7924b5..c96662e1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':edxp-core', ':xposed-bridge', ':hiddenapi-stubs', ':dexmaker', ':dalvikdx', ':edxp-yahfa', ':edxp-common' \ No newline at end of file +include ':edxp-core', ':xposed-bridge', ':hiddenapi-stubs', ':dexmaker', ':dalvikdx', ':edxp-common', ':edxp-yahfa', ':edxp-sandhook' \ No newline at end of file diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/hook/HookProvider.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/hook/HookProvider.java index f2f553f0..671bd828 100644 --- a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/hook/HookProvider.java +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/hook/HookProvider.java @@ -9,7 +9,7 @@ public interface HookProvider { void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo); - Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; + Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) throws Throwable; Member findMethodNative(Member hookMethod); diff --git a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java index 25abdc04..92d9fc2b 100644 --- a/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -60,7 +60,7 @@ public final class XposedBridge { private static final Object[] EMPTY_ARRAY = new Object[0]; // built-in handlers - private static final Map> sHookedMethodCallbacks = new HashMap<>(); + public static final Map> sHookedMethodCallbacks = new HashMap<>(); public static final CopyOnWriteSortedSet sLoadedPackageCallbacks = new CopyOnWriteSortedSet<>(); /*package*/ static final CopyOnWriteSortedSet sInitPackageResourcesCallbacks = new CopyOnWriteSortedSet<>(); @@ -402,7 +402,7 @@ public final class XposedBridge { Class[] parameterTypes, Class returnType, Object thisObject, Object[] args) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + throws Throwable { return EdXpConfigGlobal.getHookProvider().invokeOriginalMethod(method, thisObject, args); } @@ -432,7 +432,7 @@ public final class XposedBridge { * if an exception was thrown by the invoked method */ public static Object invokeOriginalMethod(Member method, Object thisObject, Object[] args) - throws NullPointerException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + throws Throwable { if (args == null) { args = EMPTY_ARRAY; }