diff --git a/Bridge/build.gradle b/Bridge/build.gradle deleted file mode 100644 index 37b44fa3..00000000 --- a/Bridge/build.gradle +++ /dev/null @@ -1,138 +0,0 @@ -import groovy.xml.XmlUtil - -apply plugin: 'com.android.application' - -gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs.add('-Xbootclasspath/p:libs/framework-stub.jar') - } -} - -android { - compileSdkVersion 28 - buildToolsVersion '28.0.3' - - defaultConfig { - multiDexEnabled false - minSdkVersion 23 - } - - sourceSets { - main { - java.srcDirs += ['src/main/apacheCommonsLang'] - jniLibs.srcDirs = ['libs'] - } - } - - buildTypes { - release { - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - - // Only build the release variant -// variantFilter { variant -> -// if (variant.buildType.name != BuilderConstants.DEBUG) { -// variant.ignore = true -// } -// } -} - -task generateStubs(type: Javadoc, dependsOn: 'compileReleaseSources') { - source = file('src/main/java') - ext.stubsDir = "$buildDir/api/stub-sources" - outputs.dir ext.stubsDir - title = null - - options { - doclet = 'com.google.doclava.Doclava' - docletpath = fileTree(dir: 'doclib', include: '**/*.jar').asType(List) - jFlags '-Dignore.symbol.file' - addBooleanOption 'nodocs', true - addFileOption 'stubs', file(ext.stubsDir) - addFileOption 'api', file('doclib/api/current.txt') - addBooleanOption 'hide 111', true - addBooleanOption 'hide 113', true - addBooleanOption 'hidePackage xposed.dummy', true - } -} - -task compileStubs(type: JavaCompile, dependsOn: 'generateStubs') { - source = fileTree(generateStubs.ext.stubsDir) - destinationDir = file("$buildDir/api/stub-classes") - options.compilerArgs += '-XDsuppressNotes' -} - -task jarStubs(type: Jar) { - from compileStubs - destinationDir = file("$buildDir/api") - baseName = 'api' -} - -task jarStubsSource(type: Jar) { - from generateStubs.source - destinationDir = jarStubs.destinationDir - baseName = jarStubs.baseName - classifier = 'sources' -} - -task generateAPI(dependsOn: ['generateStubs', 'jarStubs', 'jarStubsSource']) - -// Make sure that hiddenapistubs are placed before the Android SDK in app.iml -// as there doesn't seem to be any way to configure this in Android Studio. -task fixIml { - ext.imlFile = projectDir.absolutePath + '/' + project.name + '.iml' - inputs.file imlFile - outputs.file imlFile - - println imlFile - doLast { - def imlFile = file(project.name + ".iml") - println 'Change ' + project.name + '.iml order' - try { - def parsedXml = (new 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 Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK']) - XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile)) - } catch (FileNotFoundException e) { - // nop, iml not found - } - } -} - -tasks.preBuild.dependsOn fixIml - -dependencies { - compileOnly files("libs/framework-stub.jar") - compileOnly project(':dexmaker') -} - -afterEvaluate { - - task javac - - tasks.withType(JavaCompile) { - options.compilerArgs.add('-Xbootclasspath/p:libs/framework-stub.jar') - } - - android.applicationVariants.all { variant -> - def nameCapped = variant.name.capitalize() - def nameLowered = variant.name.toLowerCase() - - def makeAndCopyTask = task("makeAndCopy${nameCapped}", type: Copy, dependsOn: "assemble${nameCapped}") { - from "build/intermediates/transforms/dexMerger/${nameLowered}/0/classes.dex" - into '../Core/template_override/system/framework' - rename("classes.dex", "edxposed.dex") - } - -// def makeAndCopyTask = task("makeAndCopy${nameCapped}", type: Jar, dependsOn: "assemble${nameCapped}") { -// from "build/intermediates/transforms/dexMerger/${nameLowered}/0/" -// destinationDir file("../Core/template_override/system/framework/") -// baseName "edxposed" -// } - } - -} \ No newline at end of file diff --git a/Bridge/src/main/java/de/robv/android/xposed/GeneClass_Template.java b/Bridge/src/main/java/de/robv/android/xposed/GeneClass_Template.java deleted file mode 100644 index 7d0e096e..00000000 --- a/Bridge/src/main/java/de/robv/android/xposed/GeneClass_Template.java +++ /dev/null @@ -1,74 +0,0 @@ -package de.robv.android.xposed; - -public class GeneClass_Template { - public static java.lang.reflect.Member method; - public static de.robv.android.xposed.XposedBridge.AdditionalHookInfo tAdditionalInfoObj; - - public static boolean backup(java.lang.Object obj, int i) { - return false; - } - - public static boolean hook(java.lang.Object obj, int i) throws Throwable { - java.lang.Throwable th; - if (!de.robv.android.xposed.XposedBridge.disableHooks) { - java.lang.Object[] snapshot = tAdditionalInfoObj.callbacks.getSnapshot(); - int length = snapshot.length; - if (length != 0) { - de.robv.android.xposed.XC_MethodHook.MethodHookParam methodHookParam = new de.robv.android.xposed.XC_MethodHook.MethodHookParam(); - methodHookParam.method = method; - java.lang.Object[] objArr = new java.lang.Object[1]; - methodHookParam.args = objArr; - methodHookParam.thisObject = obj; - objArr[0] = java.lang.Integer.valueOf(i); - int i2 = 0; - do { - try { - ((de.robv.android.xposed.XC_MethodHook) snapshot[i2]).callBeforeHookedMethod(methodHookParam); - if (methodHookParam.returnEarly) { - i2++; - break; - } - } catch (java.lang.Throwable th2) { - de.robv.android.xposed.XposedBridge.log(th2); - methodHookParam.setResult(null); - methodHookParam.returnEarly = false; - } - i2++; - } while (i2 < length); - if (!methodHookParam.returnEarly) { - try { - methodHookParam.setResult(java.lang.Boolean.valueOf(backup(obj, i))); - } catch (java.lang.Throwable th3) { - methodHookParam.setThrowable(th3); - } - } - i2--; - do { - java.lang.Object result = methodHookParam.getResult(); - Throwable th2 = methodHookParam.getThrowable(); - try { - ((de.robv.android.xposed.XC_MethodHook) snapshot[i2]).callAfterHookedMethod(methodHookParam); - } catch (java.lang.Throwable th4) { - de.robv.android.xposed.XposedBridge.log(th4); - if (th2 == null) { - methodHookParam.setResult(result); - } else { - methodHookParam.setThrowable(th2); - } - } - i2--; - } while (i2 >= 0); - if (!methodHookParam.hasThrowable()) { - return ((java.lang.Boolean) methodHookParam.getResult()).booleanValue(); - } - throw methodHookParam.getThrowable(); - } - } - return backup(obj, i); - } - - public static void setup(java.lang.reflect.Member member, de.robv.android.xposed.XposedBridge.AdditionalHookInfo additionalHookInfo) { - method = member; - tAdditionalInfoObj = additionalHookInfo; - } -} \ No newline at end of file diff --git a/Core/.gitignore b/Core/.gitignore deleted file mode 100644 index 57726a41..00000000 --- a/Core/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/.externalNativeBuild -/build -/libs -/obj -/release -/template_override/system/framework/edxposed.dex -*.iml \ No newline at end of file diff --git a/Core/build.gradle b/Core/build.gradle deleted file mode 100644 index bcb47d16..00000000 --- a/Core/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -import org.gradle.internal.os.OperatingSystem; - -apply plugin: 'com.android.library' -version "v0.3.1.6_beta-SNAPSHOT" -extensions["module_name"] = "EdXposed" -android { - compileSdkVersion 28 - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - - externalNativeBuild { - ndkBuild { - abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' - arguments "NDK_PROJECT_PATH=jni/" - } - } - } - externalNativeBuild { - ndkBuild { - path 'jni/Android.mk' - } - } -} -afterEvaluate { - - android.libraryVariants.all { variant -> - def nameCapped = variant.name.capitalize() - def nameLowered = variant.name.toLowerCase() - - def zipTask = task("zip${nameCapped}", type: Exec, dependsOn: ":Bridge:makeAndCopy${nameCapped}") { - workingDir '..' - commandLine 'sh', 'build.sh', \ - project.name, \ - "${project.version}-${nameLowered}", \ - "${project.extensions['module_name']}" - } - - def pushTask = task("push${nameCapped}", type: Exec) { - workingDir 'release' - def commands = ["adb", "push", "magisk-${project.extensions['module_name']}" + - "-${project.version}-${nameLowered}.zip", "/sdcard/"] - if (OperatingSystem.current().isWindows()) { - commandLine 'cmd', '/c', commands.join(" ") - } else { - commandLine commands - } - } - - pushTask.dependsOn(zipTask) - } - -} diff --git a/Core/jni/main/include/config.h b/Core/jni/main/include/config.h deleted file mode 100644 index 8921a95e..00000000 --- a/Core/jni/main/include/config.h +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#ifndef CONFIG_H -#define CONFIG_H - -//#define LOG_DISABLED -//#define DEBUG - -#define INJECT_DEX_PATH \ -"/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex" - -#define ENTRY_CLASS_NAME "com.elderdrivers.riru.xposed.Main" - -#endif //CONFIG_H \ No newline at end of file diff --git a/Core/src/main/AndroidManifest.xml b/Core/src/main/AndroidManifest.xml deleted file mode 100644 index 6dcea510..00000000 --- a/Core/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Core/template_override/system/framework/eddalvikdx.dex b/Core/template_override/system/framework/eddalvikdx.dex deleted file mode 100644 index d733ee64..00000000 Binary files a/Core/template_override/system/framework/eddalvikdx.dex and /dev/null differ diff --git a/Core/template_override/system/framework/eddexmaker.dex b/Core/template_override/system/framework/eddexmaker.dex deleted file mode 100644 index 6d194a63..00000000 Binary files a/Core/template_override/system/framework/eddexmaker.dex and /dev/null differ diff --git a/Core/template_override/system/lib/libwhale.so b/Core/template_override/system/lib/libwhale.so deleted file mode 100755 index 227fcf31..00000000 Binary files a/Core/template_override/system/lib/libwhale.so and /dev/null differ diff --git a/Core/template_override/system/lib64/libwhale.so b/Core/template_override/system/lib64/libwhale.so deleted file mode 100755 index c3ebe73f..00000000 Binary files a/Core/template_override/system/lib64/libwhale.so and /dev/null differ diff --git a/Core/template_override/system_x86/lib/libwhale.so b/Core/template_override/system_x86/lib/libwhale.so deleted file mode 100755 index 15ae68bf..00000000 Binary files a/Core/template_override/system_x86/lib/libwhale.so and /dev/null differ diff --git a/Core/template_override/system_x86/lib64/libwhale.so b/Core/template_override/system_x86/lib64/libwhale.so deleted file mode 100755 index d685cdd0..00000000 Binary files a/Core/template_override/system_x86/lib64/libwhale.so and /dev/null differ diff --git a/README.md b/README.md index 7a90408c..61c153ad 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,9 @@ and zip binaries can be downloaded from [here](http://gnuwin32.sourceforge.net/p ## Build -1. run `:Bridge:makeAndCopyRelease` in Gradle window to build `edxposed.dex` -2. run `:Core:zipRelease` to build Magisk Riru module flashable zip file -3. find the flashable under `Core/release/` -4. flash the zip in recovery mode or in Magisk Manager +1. run `./gradlew :edxp-core:zipRelease` to build flashable zip +2. find the flashable under `edxp-core/release/` +3. flash the zip in recovery mode or in Magisk Manager ## Install diff --git a/build.gradle b/build.gradle index 7d4bf63d..55d04099 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,14 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - + repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' - + classpath 'com.android.tools.build:gradle:3.3.2' + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -16,6 +16,15 @@ buildscript { } allprojects { + ext { + templateRootPath = project(":edxp-core").projectDir.path + "/template_override/" + templateSystemPath = templateRootPath + "/system/" + templateSystemx86Path = templateRootPath + "/system_x86/" + templateFrameworkPath = templateRootPath + "/system/framework/" + templateLibPath = templateRootPath + "/system/lib/" + templateLib64Path = templateRootPath + "/system/lib64/" + templateEtcPath = templateRootPath + "/system/etc/" + } repositories { google() jcenter() diff --git a/dalvikdx/build.gradle b/dalvikdx/build.gradle index 68bb7760..5d64c3a3 100644 --- a/dalvikdx/build.gradle +++ b/dalvikdx/build.gradle @@ -6,3 +6,21 @@ dependencies { sourceCompatibility = "7" targetCompatibility = "7" + + +task dexInJar(type: Jar) { + dependsOn jar + doFirst { + exec { + workingDir jar.destinationDir + executable "dx" + args "--dex", "--output", "classes.dex", "${jar.archiveName}" + } + } + from "${jar.destinationDir}/classes.dex" + destinationDir jar.destinationDir + baseName "eddalvikdx" + onlyIf { + !jar.state.upToDate || !file(archiveName).exists() + } +} \ No newline at end of file diff --git a/dexmaker/build.gradle b/dexmaker/build.gradle index 9bc0f36d..319198e1 100644 --- a/dexmaker/build.gradle +++ b/dexmaker/build.gradle @@ -1,15 +1,3 @@ -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13" - } -} - -apply plugin: "net.ltgt.errorprone" apply plugin: 'java' description = "A utility for doing compile or runtime code generation targeting Android's Dalvik VM" @@ -21,10 +9,23 @@ repositories { jcenter() } -tasks.withType(JavaCompile) { - options.compilerArgs += ["-Xep:StringSplitter:OFF"] -} - dependencies { compileOnly project(':dalvikdx') } + +task dexInJar(type: Jar) { + dependsOn jar + doFirst { + exec { + workingDir jar.destinationDir + executable "dx" + args "--dex", "--output", "classes.dex", "${jar.archiveName}" + } + } + from "${jar.destinationDir}/classes.dex" + destinationDir jar.destinationDir + baseName "eddexmaker" + onlyIf { + !jar.state.upToDate || !file(archiveName).exists() + } +} diff --git a/dexmaker/src/main/java/external/com/android/dx/DexMaker.java b/dexmaker/src/main/java/external/com/android/dx/DexMaker.java index 3f151489..62efd845 100644 --- a/dexmaker/src/main/java/external/com/android/dx/DexMaker.java +++ b/dexmaker/src/main/java/external/com/android/dx/DexMaker.java @@ -230,7 +230,7 @@ public final class DexMaker { * Modifier#FINAL} and {@link Modifier#ABSTRACT}. */ public void declare(TypeId type, String sourceFile, int flags, - TypeId supertype, TypeId... interfaces) { + TypeId supertype, TypeId... interfaces) { TypeDeclaration declaration = getTypeDeclaration(type); int supportedFlags = Modifier.PUBLIC | Modifier.FINAL | Modifier.ABSTRACT | AccessFlags.ACC_SYNTHETIC; @@ -471,8 +471,23 @@ public final class DexMaker { } } + public ClassLoader loadClassDirect(ClassLoader parent, File dexCache, String dexFileName) { + File result = new File(dexCache, dexFileName); + // Check that the file exists. If it does, return a DexClassLoader and skip all + // the dex bytecode generation. + if (result.exists()) { + return generateClassLoader(result, dexCache, parent); + } else { + return null; + } + } + public ClassLoader generateAndLoad(ClassLoader parent, File dexCache) throws IOException { - return generateAndLoad(parent, dexCache, null); + return generateAndLoad(parent, dexCache, generateFileName(), false); + } + + public ClassLoader generateAndLoad(ClassLoader parent, File dexCache, String dexFileName) throws IOException { + return generateAndLoad(parent, dexCache, dexFileName, false); } /** @@ -500,9 +515,8 @@ public final class DexMaker { * @param dexCache the destination directory where generated and optimized * dex files will be written. If null, this class will try to guess the * application's private data dir. - * @param fileName the name of dex file */ - public ClassLoader generateAndLoad(ClassLoader parent, File dexCache, String fileName) throws IOException { + public ClassLoader generateAndLoad(ClassLoader parent, File dexCache, String dexFileName, boolean deleteOld) throws IOException { if (dexCache == null) { String property = System.getProperty("dexmaker.dexcache"); if (property != null) { @@ -516,16 +530,18 @@ public final class DexMaker { } } - if (fileName == null || fileName.isEmpty()) - fileName = generateFileName(); - File result = new File(dexCache, fileName); - // Check that the file exists. If it does, return a DexClassLoader and skip all - // the dex bytecode generation. - if (result.exists()) { - return generateClassLoader(result, dexCache, parent); - } + File result = new File(dexCache, dexFileName); - byte[] dex = generate(); + if (result.exists()) { + if (deleteOld) { + try { + deleteOldDex(result); + } catch (Throwable throwable) { + } + } else { + return generateClassLoader(result, dexCache, parent); + } + } /* * This implementation currently dumps the dex to the filesystem. It @@ -534,9 +550,17 @@ public final class DexMaker { * * TODO: load the dex from memory where supported. */ + + File parentDir = result.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + result.createNewFile(); + JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result)); JarEntry entry = new JarEntry(DexFormat.DEX_IN_JAR_NAME); + byte[] dex = generate(); entry.setSize(dex.length); jarOut.putNextEntry(entry); jarOut.write(dex); @@ -545,6 +569,32 @@ public final class DexMaker { return generateClassLoader(result, dexCache, parent); } + public void deleteOldDex(File dexFile) { + dexFile.delete(); + String dexDir = dexFile.getParent(); + File oatDir = new File(dexDir, "/oat/"); + File oatDirArm = new File(oatDir, "/arm/"); + File oatDirArm64 = new File(oatDir, "/arm64/"); + if (!oatDir.exists()) + return; + String nameStart = dexFile.getName().replaceAll(".jar", ""); + doDeleteOatFiles(oatDir, nameStart); + doDeleteOatFiles(oatDirArm, nameStart); + doDeleteOatFiles(oatDirArm64, nameStart); + } + + private void doDeleteOatFiles(File dir, String nameStart) { + if (!dir.exists()) + return; + File[] oats = dir.listFiles(); + if (oats == null) + return; + for (File oatFile:oats) { + if (oatFile.isFile() && oatFile.getName().startsWith(nameStart)) + oatFile.delete(); + } + } + DexFile getDexFile() { if (outputDex == null) { DexOptions options = new DexOptions(); diff --git a/Bridge/.gitignore b/edxp-common/.gitignore similarity index 100% rename from Bridge/.gitignore rename to edxp-common/.gitignore diff --git a/edxp-common/build.gradle b/edxp-common/build.gradle new file mode 100644 index 00000000..36d6440f --- /dev/null +++ b/edxp-common/build.gradle @@ -0,0 +1,48 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + 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(':xposed-bridge') + compileOnly project(':dexmaker') +} + + +preBuild.doLast { + def imlFile = file(project.name + ".iml") + 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") + } +} \ No newline at end of file diff --git a/Bridge/libs/framework-stub.jar b/edxp-common/libs/framework-stub.jar similarity index 100% rename from Bridge/libs/framework-stub.jar rename to edxp-common/libs/framework-stub.jar diff --git a/Bridge/proguard-rules.pro b/edxp-common/proguard-rules.pro similarity index 100% rename from Bridge/proguard-rules.pro rename to edxp-common/proguard-rules.pro diff --git a/edxp-common/src/main/AndroidManifest.xml b/edxp-common/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d879e9df --- /dev/null +++ b/edxp-common/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/Bridge/src/main/java/com/elderdrivers/riru/common/KeepAll.java b/edxp-common/src/main/java/com/elderdrivers/riru/common/KeepAll.java similarity index 100% rename from Bridge/src/main/java/com/elderdrivers/riru/common/KeepAll.java rename to edxp-common/src/main/java/com/elderdrivers/riru/common/KeepAll.java diff --git a/Bridge/src/main/java/com/elderdrivers/riru/common/KeepMembers.java b/edxp-common/src/main/java/com/elderdrivers/riru/common/KeepMembers.java similarity index 100% rename from Bridge/src/main/java/com/elderdrivers/riru/common/KeepMembers.java rename to edxp-common/src/main/java/com/elderdrivers/riru/common/KeepMembers.java diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/ConfigManager.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java similarity index 90% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/config/ConfigManager.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java index 784cdfb1..bfee37ed 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/ConfigManager.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/ConfigManager.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.config; +package com.elderdrivers.riru.edxp.config; import java.util.Collections; import java.util.HashMap; @@ -6,8 +6,8 @@ import java.util.Set; import de.robv.android.xposed.SELinuxHelper; -import static com.elderdrivers.riru.xposed.config.InstallerChooser.INSTALLER_DATA_BASE_DIR; -import static com.elderdrivers.riru.xposed.config.InstallerChooser.INSTALLER_PACKAGE_NAME; +import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_DATA_BASE_DIR; +import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME; public class ConfigManager { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java similarity index 84% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java index f0aeb624..9e829296 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/config/InstallerChooser.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/config/InstallerChooser.java @@ -1,32 +1,34 @@ -package com.elderdrivers.riru.xposed.config; +package com.elderdrivers.riru.edxp.config; import android.annotation.SuppressLint; import android.os.Build; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.util.Utils; import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.SELinuxHelper; import de.robv.android.xposed.services.BaseService; -import static com.elderdrivers.riru.xposed.Main.getInstallerPkgName; - public class InstallerChooser { private static final AtomicBoolean hasSet = new AtomicBoolean(false); + @SuppressLint("SdCardPath") private static final String DATA_DIR_PATH_PREFIX = - Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? "/data/user_de/0/" : "/data/data/"; + Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? "/data/user_de/0/" : "/data/user/0/"; public static final String PRIMARY_INSTALLER_PACKAGE_NAME = "com.solohsu.android.edxp.manager"; public static final String SECONDARY_INSTALLER_PACKAGE_NAME = "org.meowcat.edxposed.manager"; public static final String LEGACY_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer"; - public static String INSTALLER_PACKAGE_NAME = getInstallerPkgName(); - @SuppressLint("SdCardPath") - public static String INSTALLER_DATA_BASE_DIR = DATA_DIR_PATH_PREFIX + INSTALLER_PACKAGE_NAME + "/"; + public static String INSTALLER_PACKAGE_NAME; + public static String INSTALLER_DATA_BASE_DIR; + public static void setInstallerPackageName(String packageName) { + INSTALLER_PACKAGE_NAME = packageName; + INSTALLER_DATA_BASE_DIR = DATA_DIR_PATH_PREFIX + INSTALLER_PACKAGE_NAME + "/"; + } public static void setup() { if (!hasSet.compareAndSet(false, true)) { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ClassLoaderUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java similarity index 93% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ClassLoaderUtils.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java index 49712d72..af7dd803 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ClassLoaderUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ClassLoaderUtils.java @@ -1,9 +1,9 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.util; import android.os.Build; import android.util.ArrayMap; -import com.elderdrivers.riru.xposed.BuildConfig; +import com.elderdrivers.riru.edxp.BuildConfig; import java.lang.reflect.Field; import java.util.ArrayList; @@ -11,10 +11,11 @@ import java.util.HashSet; import java.util.List; import dalvik.system.PathClassLoader; +import de.robv.android.xposed.XposedHelpers; public class ClassLoaderUtils { - public static final String DEXPATH = "/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex"; + public static final String DEXPATH = "/system/framework/edxp.jar:/system/framework/eddalvikdx.jar:/system/framework/eddexmaker.jar"; public static void replaceParentClassLoader(ClassLoader appClassLoader) { if (appClassLoader == null) { @@ -91,7 +92,7 @@ public class ClassLoaderUtils { try { PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - baseDexClassLoader.addDexPath(DEXPATH); + XposedHelpers.callMethod(baseDexClassLoader, "addDexPath", DEXPATH); } else { DexUtils.injectDexAtFirst(DEXPATH, baseDexClassLoader); } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/DexUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/DexUtils.java similarity index 97% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/DexUtils.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/DexUtils.java index 7ef4ebec..eea9f75c 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/DexUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/DexUtils.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.util; import android.annotation.TargetApi; import android.os.Build; @@ -8,7 +8,6 @@ import java.lang.reflect.Field; import dalvik.system.BaseDexClassLoader; import dalvik.system.DexClassLoader; -import dalvik.system.PathClassLoader; /** * For 6.0 only. diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java similarity index 95% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java index 4443380a..d7802db0 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/FileUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/FileUtils.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.util; import android.annotation.SuppressLint; import android.os.Build; @@ -12,7 +12,7 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; -import static com.elderdrivers.riru.xposed.util.ProcessUtils.PER_USER_RANGE; +import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE; public class FileUtils { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProcessUtils.java similarity index 90% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProcessUtils.java index 3021b38f..b0e8edaa 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/ProcessUtils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/ProcessUtils.java @@ -1,10 +1,8 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.util; import android.os.Process; import android.text.TextUtils; -import com.elderdrivers.riru.xposed.Main; - import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -16,8 +14,7 @@ public class ProcessUtils { public static final int PER_USER_RANGE = 100000; public static final int USER_SYSTEM = 0; - public static String getCurrentProcessName() { - String prettyName = Main.appProcessName; + public static String getCurrentProcessName(String prettyName) { if (!TextUtils.isEmpty(prettyName)) { return prettyName; } @@ -26,8 +23,6 @@ public class ProcessUtils { /** * a common solution from https://stackoverflow.com/a/21389402 - *

- * use {@link com.elderdrivers.riru.xposed.Main#appProcessName} to get current process name */ public static String getProcessName(int pid) { BufferedReader cmdlineReader = null; diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/Utils.java b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/Utils.java similarity index 91% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/Utils.java rename to edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/Utils.java index 46f25e1b..bb3598fb 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/Utils.java +++ b/edxp-common/src/main/java/com/elderdrivers/riru/edxp/util/Utils.java @@ -1,8 +1,8 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.util; import android.util.Log; -import com.elderdrivers.riru.xposed.BuildConfig; +import com.elderdrivers.riru.edxp.BuildConfig; public class Utils { diff --git a/edxp-core/.gitignore b/edxp-core/.gitignore new file mode 100644 index 00000000..bb940433 --- /dev/null +++ b/edxp-core/.gitignore @@ -0,0 +1,8 @@ +/.externalNativeBuild +/build +/libs +/obj +/release +/template_override/system +/template_override/system_x86 +*.iml \ No newline at end of file diff --git a/Core/build-module.sh b/edxp-core/build-module.sh similarity index 100% rename from Core/build-module.sh rename to edxp-core/build-module.sh diff --git a/edxp-core/build.gradle b/edxp-core/build.gradle new file mode 100644 index 00000000..0b8ab926 --- /dev/null +++ b/edxp-core/build.gradle @@ -0,0 +1,117 @@ +import org.gradle.internal.os.OperatingSystem + +apply plugin: 'com.android.library' + +version "v0.3.1.8_beta-SNAPSHOT" + +ext { + module_name = "EdXposed" + jar_dest_dir = "${projectDir}/template_override/system/framework/" + is_windows = OperatingSystem.current().isWindows() + backends = ["Yahfa", "Sandhook", "Whale"] +} + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + + externalNativeBuild { + ndkBuild { + abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' + arguments "NDK_PROJECT_PATH=jni/" + } + } + } + externalNativeBuild { + ndkBuild { + path 'jni/Android.mk' + } + } +} + +task copyDalvikdxJar { + def jarTask = tasks.getByPath(':dalvikdx:dexInJar') + dependsOn jarTask + doLast { + copy { + from jarTask + into jar_dest_dir + } + } + onlyIf { + !jarTask.state.upToDate || !file(jar_dest_dir + jarTask.archiveName).exists() + } +} + +task copyDexmakerJar { + def jarTask = tasks.getByPath(':dexmaker:dexInJar') + dependsOn jarTask + doLast { + copy { + from jarTask + into jar_dest_dir + } + } + onlyIf { + !jarTask.state.upToDate || !file(jar_dest_dir + jarTask.archiveName).exists() + } +} + +task cleanTemplate(type: Delete) { + delete file(templateSystemPath), file(templateSystemx86Path) +} + +afterEvaluate { + + android.libraryVariants.all { variant -> + + def variantCapped = variant.name.capitalize() + def variantLowered = variant.name.toLowerCase() + + backends.each { backend -> + + def backendCapped = backend.capitalize() + def backendLowered = backend.toLowerCase() + + def zipTask = task("zip${backendCapped}${variantCapped}", type: Exec) { + dependsOn cleanTemplate, copyDalvikdxJar, copyDexmakerJar + dependsOn tasks.getByPath(":edxp-${backendLowered}:makeAndCopy${variantCapped}") + workingDir '..' + commandLine 'sh', 'build.sh', project.name, + "${backendLowered}-${project.version}-${variantLowered}", "${module_name}" + doFirst { + copy { + from "${projectDir}/edconfig.tpl" + into templateFrameworkPath + rename "edconfig.tpl", "edconfig.jar" + expand(backend: "$backendCapped") + } + } + } + + task("push${backendCapped}${variantCapped}", type: Exec) { + dependsOn zipTask + workingDir "${projectDir}/release" + def commands = ["adb", "push", + "magisk-${module_name}-${backendLowered}-${project.version}-${variantLowered}.zip", + "/sdcard/"] + if (is_windows) { + commandLine 'cmd', '/c', commands.join(" ") + } else { + commandLine commands + } + } + } + + // backward compatible + task("zip${variantCapped}") { + dependsOn "zipYahfa${variantCapped}" + } + task("push${variantCapped}") { + dependsOn "pushYahfa${variantCapped}" + } + } + +} \ No newline at end of file diff --git a/Core/template_override/system/framework/edconfig.dex b/edxp-core/edconfig.tpl similarity index 53% rename from Core/template_override/system/framework/edconfig.dex rename to edxp-core/edconfig.tpl index ce0a3ce2..5fe6d093 100644 --- a/Core/template_override/system/framework/edconfig.dex +++ b/edxp-core/edconfig.tpl @@ -1,4 +1,4 @@ -version=90.0-0.3.1.6-beta-SNAPSHOT +version=90.0-0.3.1.8-beta-SNAPSHOT ($backend) arch=arm64 minsdk=23 maxsdk=28 diff --git a/Core/jni/.gitattributes b/edxp-core/jni/.gitattributes similarity index 100% rename from Core/jni/.gitattributes rename to edxp-core/jni/.gitattributes diff --git a/Core/jni/Android.mk b/edxp-core/jni/Android.mk similarity index 100% rename from Core/jni/Android.mk rename to edxp-core/jni/Android.mk diff --git a/Core/jni/Application.mk b/edxp-core/jni/Application.mk similarity index 100% rename from Core/jni/Application.mk rename to edxp-core/jni/Application.mk diff --git a/Core/jni/external/Android.mk b/edxp-core/jni/external/Android.mk similarity index 100% rename from Core/jni/external/Android.mk rename to edxp-core/jni/external/Android.mk diff --git a/Core/jni/external/include/xhook/xhook.h b/edxp-core/jni/external/include/xhook/xhook.h similarity index 100% rename from Core/jni/external/include/xhook/xhook.h rename to edxp-core/jni/external/include/xhook/xhook.h diff --git a/Core/jni/external/xhook/queue.h b/edxp-core/jni/external/xhook/queue.h similarity index 100% rename from Core/jni/external/xhook/queue.h rename to edxp-core/jni/external/xhook/queue.h diff --git a/Core/jni/external/xhook/tree.h b/edxp-core/jni/external/xhook/tree.h similarity index 100% rename from Core/jni/external/xhook/tree.h rename to edxp-core/jni/external/xhook/tree.h diff --git a/Core/jni/external/xhook/xh_core.c b/edxp-core/jni/external/xhook/xh_core.c similarity index 100% rename from Core/jni/external/xhook/xh_core.c rename to edxp-core/jni/external/xhook/xh_core.c diff --git a/Core/jni/external/xhook/xh_core.h b/edxp-core/jni/external/xhook/xh_core.h similarity index 100% rename from Core/jni/external/xhook/xh_core.h rename to edxp-core/jni/external/xhook/xh_core.h diff --git a/Core/jni/external/xhook/xh_elf.c b/edxp-core/jni/external/xhook/xh_elf.c similarity index 100% rename from Core/jni/external/xhook/xh_elf.c rename to edxp-core/jni/external/xhook/xh_elf.c diff --git a/Core/jni/external/xhook/xh_elf.h b/edxp-core/jni/external/xhook/xh_elf.h similarity index 100% rename from Core/jni/external/xhook/xh_elf.h rename to edxp-core/jni/external/xhook/xh_elf.h diff --git a/Core/jni/external/xhook/xh_errno.h b/edxp-core/jni/external/xhook/xh_errno.h similarity index 100% rename from Core/jni/external/xhook/xh_errno.h rename to edxp-core/jni/external/xhook/xh_errno.h diff --git a/Core/jni/external/xhook/xh_jni.c b/edxp-core/jni/external/xhook/xh_jni.c similarity index 100% rename from Core/jni/external/xhook/xh_jni.c rename to edxp-core/jni/external/xhook/xh_jni.c diff --git a/Core/jni/external/xhook/xh_log.c b/edxp-core/jni/external/xhook/xh_log.c similarity index 100% rename from Core/jni/external/xhook/xh_log.c rename to edxp-core/jni/external/xhook/xh_log.c diff --git a/Core/jni/external/xhook/xh_log.h b/edxp-core/jni/external/xhook/xh_log.h similarity index 100% rename from Core/jni/external/xhook/xh_log.h rename to edxp-core/jni/external/xhook/xh_log.h diff --git a/Core/jni/external/xhook/xh_util.c b/edxp-core/jni/external/xhook/xh_util.c similarity index 100% rename from Core/jni/external/xhook/xh_util.c rename to edxp-core/jni/external/xhook/xh_util.c diff --git a/Core/jni/external/xhook/xh_util.h b/edxp-core/jni/external/xhook/xh_util.h similarity index 100% rename from Core/jni/external/xhook/xh_util.h rename to edxp-core/jni/external/xhook/xh_util.h diff --git a/Core/jni/external/xhook/xh_version.c b/edxp-core/jni/external/xhook/xh_version.c similarity index 100% rename from Core/jni/external/xhook/xh_version.c rename to edxp-core/jni/external/xhook/xh_version.c diff --git a/Core/jni/external/xhook/xh_version.h b/edxp-core/jni/external/xhook/xh_version.h similarity index 100% rename from Core/jni/external/xhook/xh_version.h rename to edxp-core/jni/external/xhook/xh_version.h diff --git a/Core/jni/external/xhook/xhook.c b/edxp-core/jni/external/xhook/xhook.c similarity index 100% rename from Core/jni/external/xhook/xhook.c rename to edxp-core/jni/external/xhook/xhook.c diff --git a/Core/jni/external/xhook/xhook.h b/edxp-core/jni/external/xhook/xhook.h similarity index 100% rename from Core/jni/external/xhook/xhook.h rename to edxp-core/jni/external/xhook/xhook.h diff --git a/Core/jni/main/Android.mk b/edxp-core/jni/main/Android.mk similarity index 100% rename from Core/jni/main/Android.mk rename to edxp-core/jni/main/Android.mk diff --git a/Core/jni/main/include/JNIHelper.h b/edxp-core/jni/main/include/JNIHelper.h similarity index 100% rename from Core/jni/main/include/JNIHelper.h rename to edxp-core/jni/main/include/JNIHelper.h diff --git a/Core/jni/main/include/android_build.h b/edxp-core/jni/main/include/android_build.h similarity index 100% rename from Core/jni/main/include/android_build.h rename to edxp-core/jni/main/include/android_build.h diff --git a/edxp-core/jni/main/include/config.h b/edxp-core/jni/main/include/config.h new file mode 100644 index 00000000..4efe8778 --- /dev/null +++ b/edxp-core/jni/main/include/config.h @@ -0,0 +1,19 @@ +#include +#include + +#ifndef CONFIG_H +#define CONFIG_H + +//#define LOG_DISABLED +//#define DEBUG + +#define INJECT_DEX_PATH \ +"/system/framework/edxp.jar:/system/framework/eddalvikdx.jar:/system/framework/eddexmaker.jar" + +#define ENTRY_CLASS_NAME "com.elderdrivers.riru.edxp.Main" + +#define CLASS_SAND_HOOK "com.swift.sandhook.SandHook" + +#define CLASS_NEVER_CALL "com.swift.sandhook.ClassNeverCall" + +#endif //CONFIG_H \ No newline at end of file diff --git a/Core/jni/main/include/fd_utils-inl.h b/edxp-core/jni/main/include/fd_utils-inl.h similarity index 100% rename from Core/jni/main/include/fd_utils-inl.h rename to edxp-core/jni/main/include/fd_utils-inl.h diff --git a/Core/jni/main/include/logging.h b/edxp-core/jni/main/include/logging.h similarity index 100% rename from Core/jni/main/include/logging.h rename to edxp-core/jni/main/include/logging.h diff --git a/Core/jni/main/include/misc.cpp b/edxp-core/jni/main/include/misc.cpp similarity index 100% rename from Core/jni/main/include/misc.cpp rename to edxp-core/jni/main/include/misc.cpp diff --git a/Core/jni/main/include/misc.h b/edxp-core/jni/main/include/misc.h similarity index 100% rename from Core/jni/main/include/misc.h rename to edxp-core/jni/main/include/misc.h diff --git a/Core/jni/main/include/riru.c b/edxp-core/jni/main/include/riru.c similarity index 100% rename from Core/jni/main/include/riru.c rename to edxp-core/jni/main/include/riru.c diff --git a/Core/jni/main/include/riru.h b/edxp-core/jni/main/include/riru.h similarity index 100% rename from Core/jni/main/include/riru.h rename to edxp-core/jni/main/include/riru.h diff --git a/Core/jni/main/inject/config_manager.cpp b/edxp-core/jni/main/inject/config_manager.cpp similarity index 100% rename from Core/jni/main/inject/config_manager.cpp rename to edxp-core/jni/main/inject/config_manager.cpp diff --git a/Core/jni/main/inject/config_manager.h b/edxp-core/jni/main/inject/config_manager.h similarity index 100% rename from Core/jni/main/inject/config_manager.h rename to edxp-core/jni/main/inject/config_manager.h diff --git a/Core/jni/main/inject/framework_hook.cpp b/edxp-core/jni/main/inject/framework_hook.cpp similarity index 100% rename from Core/jni/main/inject/framework_hook.cpp rename to edxp-core/jni/main/inject/framework_hook.cpp diff --git a/Core/jni/main/inject/framework_hook.h b/edxp-core/jni/main/inject/framework_hook.h similarity index 100% rename from Core/jni/main/inject/framework_hook.h rename to edxp-core/jni/main/inject/framework_hook.h diff --git a/Core/jni/main/java_hook/java_hook.cpp b/edxp-core/jni/main/java_hook/java_hook.cpp similarity index 89% rename from Core/jni/main/java_hook/java_hook.cpp rename to edxp-core/jni/main/java_hook/java_hook.cpp index 889a2a17..2e9194ec 100644 --- a/Core/jni/main/java_hook/java_hook.cpp +++ b/edxp-core/jni/main/java_hook/java_hook.cpp @@ -168,6 +168,29 @@ void loadDexAndInit(JNIEnv *env, const char *dexPath) { } else { LOGE("HookEntry class is null. %d", getpid()); } + + //load lib sandhook + void* lib_sandhook; + if (sizeof(void*) == 8) { + lib_sandhook = dlopen("/system/lib64/libsandhook.edxp.so", RTLD_NOW); + } else { + lib_sandhook = dlopen("/system/lib/libsandhook.edxp.so", RTLD_NOW); + } + if (!lib_sandhook) { + LOGW("libsandhook open failed. %s", dlerror()); + return; + } + bool* (*jni_load)(JNIEnv*, jclass, jclass) = reinterpret_cast(dlsym(lib_sandhook, "JNI_Load_Ex")); + + jclass sandhook_class = findClassFromLoader(env, myClassLoader, CLASS_SAND_HOOK); + jclass nevercall_class = findClassFromLoader(env, myClassLoader, CLASS_NEVER_CALL); + if (!sandhook_class || !nevercall_class) { // fail-fast + return; + } + if (!jni_load(env, sandhook_class, nevercall_class)) { + LOGE("SandHook: HookEntry class error. %d", getpid()); + } } jstring getThrowableMessage(JNIEnv *env, jobject throwable) { diff --git a/Core/jni/main/java_hook/java_hook.h b/edxp-core/jni/main/java_hook/java_hook.h similarity index 100% rename from Core/jni/main/java_hook/java_hook.h rename to edxp-core/jni/main/java_hook/java_hook.h diff --git a/Core/jni/main/main.cpp b/edxp-core/jni/main/main.cpp similarity index 100% rename from Core/jni/main/main.cpp rename to edxp-core/jni/main/main.cpp diff --git a/Core/jni/main/native_hook/native_hook.cpp b/edxp-core/jni/main/native_hook/native_hook.cpp similarity index 100% rename from Core/jni/main/native_hook/native_hook.cpp rename to edxp-core/jni/main/native_hook/native_hook.cpp diff --git a/Core/jni/main/native_hook/native_hook.h b/edxp-core/jni/main/native_hook/native_hook.h similarity index 97% rename from Core/jni/main/native_hook/native_hook.h rename to edxp-core/jni/main/native_hook/native_hook.h index 0a79f2c2..eb6f7a9a 100644 --- a/Core/jni/main/native_hook/native_hook.h +++ b/edxp-core/jni/main/native_hook/native_hook.h @@ -5,10 +5,10 @@ #if defined(__LP64__) static constexpr const char *kLibArtPath = "/system/lib64/libart.so"; -static constexpr const char *kLibWhalePath = "/system/lib64/libwhale.so"; +static constexpr const char *kLibWhalePath = "/system/lib64/libwhale.edxp.so"; #else static constexpr const char *kLibArtPath = "/system/lib/libart.so"; -static constexpr const char *kLibWhalePath = "/system/lib/libwhale.so"; +static constexpr const char *kLibWhalePath = "/system/lib/libwhale.edxp.so"; #endif #define XHOOK_REGISTER(NAME) \ diff --git a/Core/jni/main/native_hook/riru_hook.cpp b/edxp-core/jni/main/native_hook/riru_hook.cpp similarity index 100% rename from Core/jni/main/native_hook/riru_hook.cpp rename to edxp-core/jni/main/native_hook/riru_hook.cpp diff --git a/Core/jni/main/native_hook/riru_hook.h b/edxp-core/jni/main/native_hook/riru_hook.h similarity index 100% rename from Core/jni/main/native_hook/riru_hook.h rename to edxp-core/jni/main/native_hook/riru_hook.h diff --git a/Core/jni/main/yahfa/HookMain.c b/edxp-core/jni/main/yahfa/HookMain.c similarity index 100% rename from Core/jni/main/yahfa/HookMain.c rename to edxp-core/jni/main/yahfa/HookMain.c diff --git a/Core/jni/main/yahfa/HookMain.h b/edxp-core/jni/main/yahfa/HookMain.h similarity index 100% rename from Core/jni/main/yahfa/HookMain.h rename to edxp-core/jni/main/yahfa/HookMain.h diff --git a/Core/jni/main/yahfa/common.h b/edxp-core/jni/main/yahfa/common.h similarity index 100% rename from Core/jni/main/yahfa/common.h rename to edxp-core/jni/main/yahfa/common.h diff --git a/Core/jni/main/yahfa/env.h b/edxp-core/jni/main/yahfa/env.h similarity index 100% rename from Core/jni/main/yahfa/env.h rename to edxp-core/jni/main/yahfa/env.h diff --git a/Core/jni/main/yahfa/trampoline.c b/edxp-core/jni/main/yahfa/trampoline.c similarity index 100% rename from Core/jni/main/yahfa/trampoline.c rename to edxp-core/jni/main/yahfa/trampoline.c diff --git a/Core/jni/main/yahfa/trampoline.h b/edxp-core/jni/main/yahfa/trampoline.h similarity index 100% rename from Core/jni/main/yahfa/trampoline.h rename to edxp-core/jni/main/yahfa/trampoline.h diff --git a/edxp-core/src/main/AndroidManifest.xml b/edxp-core/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ac58c54b --- /dev/null +++ b/edxp-core/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/Core/template_override/META-INF/com/google/android/update-binary b/edxp-core/template_override/META-INF/com/google/android/update-binary similarity index 100% rename from Core/template_override/META-INF/com/google/android/update-binary rename to edxp-core/template_override/META-INF/com/google/android/update-binary diff --git a/Core/template_override/META-INF/com/google/android/updater-script b/edxp-core/template_override/META-INF/com/google/android/updater-script similarity index 100% rename from Core/template_override/META-INF/com/google/android/updater-script rename to edxp-core/template_override/META-INF/com/google/android/updater-script diff --git a/Core/template_override/common/post-fs-data.sh b/edxp-core/template_override/common/post-fs-data.sh similarity index 100% rename from Core/template_override/common/post-fs-data.sh rename to edxp-core/template_override/common/post-fs-data.sh diff --git a/Core/template_override/common/service.sh b/edxp-core/template_override/common/service.sh similarity index 100% rename from Core/template_override/common/service.sh rename to edxp-core/template_override/common/service.sh diff --git a/Core/template_override/common/system.prop b/edxp-core/template_override/common/system.prop similarity index 100% rename from Core/template_override/common/system.prop rename to edxp-core/template_override/common/system.prop diff --git a/Core/template_override/common/util_functions.sh b/edxp-core/template_override/common/util_functions.sh similarity index 98% rename from Core/template_override/common/util_functions.sh rename to edxp-core/template_override/common/util_functions.sh index 32e74e97..180310da 100644 --- a/Core/template_override/common/util_functions.sh +++ b/edxp-core/template_override/common/util_functions.sh @@ -1,6 +1,6 @@ #!/system/bin/sh -EDXP_VERSION="0.3.1.6_beta-SNAPSHOT (3160)" +EDXP_VERSION="0.3.1.8_beta-SNAPSHOT (3180)" ANDROID_SDK=`getprop ro.build.version.sdk` BUILD_DESC=`getprop ro.build.description` PRODUCT=`getprop ro.build.product` diff --git a/Core/template_override/config.sh b/edxp-core/template_override/config.sh similarity index 99% rename from Core/template_override/config.sh rename to edxp-core/template_override/config.sh index 299bbde4..9d02c8cd 100644 --- a/Core/template_override/config.sh +++ b/edxp-core/template_override/config.sh @@ -41,7 +41,7 @@ LATESTARTSERVICE=false print_modname() { ui_print "************************************" - ui_print " Riru - Ed Xposed v0.3.1.6 " + ui_print " Riru - Ed Xposed v0.3.1.8 " ui_print "************************************" } diff --git a/Core/template_override/module.prop b/edxp-core/template_override/module.prop similarity index 75% rename from Core/template_override/module.prop rename to edxp-core/template_override/module.prop index 5f43b227..fae2ae55 100644 --- a/Core/template_override/module.prop +++ b/edxp-core/template_override/module.prop @@ -1,7 +1,7 @@ id=riru_edxposed name=Riru - Ed Xposed -version=v0.3.1.6_beta-SNAPSHOT -versionCode=3160 +version=v0.3.1.8_beta-SNAPSHOT +versionCode=3180 author=solohsu & MlgmXyysd description=Magisk version of Xposed. Require Riru - Core installed. minMagisk=17000 diff --git a/Core/template_override/riru_module.prop b/edxp-core/template_override/riru_module.prop similarity index 69% rename from Core/template_override/riru_module.prop rename to edxp-core/template_override/riru_module.prop index d4c39dd3..d45abdd1 100644 --- a/Core/template_override/riru_module.prop +++ b/edxp-core/template_override/riru_module.prop @@ -1,5 +1,5 @@ name=Ed Xposed -version=v0.3.1.6_beta-SNAPSHOT -versionCode=3160 +version=v0.3.1.8_beta-SNAPSHOT +versionCode=3180 author=solohsu & MlgmXyysd description=Magisk version of Xposed. Require Riru - Core installed. diff --git a/edxp-sandhook/.gitignore b/edxp-sandhook/.gitignore new file mode 100644 index 00000000..845f9980 --- /dev/null +++ b/edxp-sandhook/.gitignore @@ -0,0 +1,2 @@ +/build +/template_override/system/framework/edxp.jar \ No newline at end of file diff --git a/edxp-sandhook/build.gradle b/edxp-sandhook/build.gradle new file mode 100644 index 00000000..a0bf289b --- /dev/null +++ b/edxp-sandhook/build.gradle @@ -0,0 +1,72 @@ +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.3.3' + compileOnly project(':dexmaker') +} + + +preBuild.doLast { + def imlFile = file(project.name + ".iml") + 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 variantNameCapped = variant.name.capitalize() + def variantNameLowered = variant.name.toLowerCase() + + def myTemplatePath = "${projectDir}/template_override/" + + task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { + from "${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}/out/" + destinationDir file(myTemplatePath + "system/framework/") + baseName "edxp" + doLast { + copy { + from file(myTemplatePath) + into file(templateRootPath) + } + } + outputs.upToDateWhen { false } + } + } +} \ No newline at end of file diff --git a/edxp-sandhook/genhookstubs.py b/edxp-sandhook/genhookstubs.py new file mode 100644 index 00000000..f3cd9b7a --- /dev/null +++ b/edxp-sandhook/genhookstubs.py @@ -0,0 +1,196 @@ +#!/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_32 = [10,20,30,30,30,30,30,20,10,10,5,5,3] +STUB_SIZES_64 = [10,20,30,30,30,30,50,50] +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 genStubInfo32(): + hasStub = "true" if HAS_BACKUP else "false" + stubSizes = "" + for args in range(len(STUB_SIZES_32)): + if (args != 0): + stubSizes += ", " + stubSizes += str(STUB_SIZES_32[args]) + return TEMP_STUB_INFO % (hasStub, stubSizes) + +def genStubInfo64(): + hasStub = "true" if HAS_BACKUP else "false" + stubSizes = "" + for args in range(len(STUB_SIZES_64)): + if (args != 0): + stubSizes += ", " + stubSizes += str(STUB_SIZES_64[args]) + return TEMP_STUB_INFO % (hasStub, stubSizes) + +def gen32Stub(packageDir): + class_content = genStubInfo32() + class_name = STUB_FILE_NAME + "32" + for args in range(len(STUB_SIZES_32)): + for index in range(STUB_SIZES_32[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 = genStubInfo64() + class_name = STUB_FILE_NAME + "64" + for args in range(len(STUB_SIZES_64)): + for index in range(STUB_SIZES_64[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..ba3214c2 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/Main.java @@ -0,0 +1,150 @@ +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.XposedCompat; +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.init(); + } + + public static void setAppDataDir(String appDataDir) { + Main.appDataDir = appDataDir; + XposedCompat.appDataDir = appDataDir; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // 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..f77dcfa6 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/config/SandHookProvider.java @@ -0,0 +1,57 @@ +package com.elderdrivers.riru.edxp.sandhook.config; + +import android.util.Log; + +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) { + if (SandHookXposedBridge.hooked(method) || DynamicBridge.hooked(method)) { + return; + } + if (method.getDeclaringClass() == Log.class) { + Log.e(XposedBridge.TAG, "some one hook Log!"); + return; + } + XposedCompat.hookMethod(method, additionalInfo); + } + + @Override + public Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args) throws Throwable { + if (SandHookXposedBridge.hooked(method)) { + try { + return SandHookXposedBridge.invokeOriginalMethod(method, thisObject, args); + } catch (Throwable throwable) { + throw new InvocationTargetException(throwable); + } + } else { + return DynamicBridge.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); + } + + @Override + public long getMethodId(Member member) { + return 0; + } +} 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/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMethodResolver.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java similarity index 97% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMethodResolver.java rename to edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java index ab97aba8..c5290914 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMethodResolver.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/core/HookMethodResolver.java @@ -1,10 +1,9 @@ -package com.elderdrivers.riru.xposed.core; +package com.elderdrivers.riru.edxp.sandhook.core; import android.os.Build; -import android.util.Log; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; import java.lang.reflect.Field; import java.lang.reflect.Method; 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..2437185f --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/dexmaker/DynamicBridge.java @@ -0,0 +1,135 @@ +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.ConcurrentHashMap; +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 ConcurrentHashMap hookedInfo = new ConcurrentHashMap<>(); + 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 boolean hooked(Member member) { + return hookedInfo.containsKey(member); + } + + 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..1240845e --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/Router.java @@ -0,0 +1,148 @@ +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.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.elderdrivers.riru.edxp.util.Utils; +import com.swift.sandhook.SandHookConfig; +import com.swift.sandhook.xposedcompat.XposedCompat; + +import java.util.concurrent.atomic.AtomicBoolean; + +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedInit; + +import static de.robv.android.xposed.XposedInit.startsSystemServer; + +public class Router { + + public volatile static boolean forkCompleted = false; + + private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); + + static boolean useSandHook = false; + + public static void prepare(boolean isSystem) { + // this flag is needed when loadModules + 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); + //SandHookConfig.compiler = !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) { + if (useSandHook) { + XposedCompat.addHookers(classLoader, SysBootstrapHookInfo.hookItems); + } else { + HookMain.doHookDefault( + Router.class.getClassLoader(), + classLoader, + SysBootstrapHookInfo.class.getName()); + } + } else { + if (useSandHook) { + XposedCompat.addHookers(classLoader, AppBootstrapHookInfo.hookItems); + } else { + HookMain.doHookDefault( + Router.class.getClassLoader(), + classLoader, + AppBootstrapHookInfo.class.getName()); + } + } + } + + public static void startSystemServerHook() { + if (useSandHook) { + XposedCompat.addHookers(SystemMainHooker.systemServerCL, SysInnerHookInfo.hookItems); + } else { + HookMain.doHookDefault( + Router.class.getClassLoader(), + SystemMainHooker.systemServerCL, + SysInnerHookInfo.class.getName()); + } + } + + public static void startWorkAroundHook() { + if (useSandHook) { + XposedCompat.addHookers(XposedBridge.BOOTCLASSLOADER, WorkAroundHookInfo.hookItems); + } else { + HookMain.doHookDefault( + Router.class.getClassLoader(), + XposedBridge.BOOTCLASSLOADER, + WorkAroundHookInfo.class.getName()); + } + } + + public static void onEnterChildProcess() { + forkCompleted = true; + DynamicBridge.onForkPost(); + //enable compile in child process + //SandHook.enableCompiler(!XposedInit.startsSystemServer); + } + + 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..ee352801 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/AppBootstrapHookInfo.java @@ -0,0 +1,20 @@ +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 = { + OnePlusWorkAroundHooker.class.getName(), + HandleBindAppHooker.class.getName(), + LoadedApkConstructorHooker.class.getName(), + }; + + public static Class[] hookItems = { + HandleBindAppHooker.class, + LoadedApkConstructorHooker.class, + OnePlusWorkAroundHooker.class + }; +} 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..c9b0fbc1 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysBootstrapHookInfo.java @@ -0,0 +1,23 @@ +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 = { + OnePlusWorkAroundHooker.class.getName(), + HandleBindAppHooker.class.getName(), + SystemMainHooker.class.getName(), + LoadedApkConstructorHooker.class.getName() + }; + + public static Class[] hookItems = { + HandleBindAppHooker.class, + SystemMainHooker.class, + LoadedApkConstructorHooker.class, + OnePlusWorkAroundHooker.class + }; +} 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..a89542ab --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/SysInnerHookInfo.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.StartBootstrapServicesHooker; + +public class SysInnerHookInfo implements KeepMembers { + public static String[] hookItemNames = { + StartBootstrapServicesHooker.class.getName() + }; + + public static Class[] hookItems = { + StartBootstrapServicesHooker.class + }; +} 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..7d255730 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/bootstrap/WorkAroundHookInfo.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.OnePlusWorkAroundHooker; + +public class WorkAroundHookInfo implements KeepMembers { + public static String[] hookItemNames = { + OnePlusWorkAroundHooker.class.getName() + }; + + public static Class[] hookItems = { + OnePlusWorkAroundHooker.class + }; +} 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..72c3099c --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/HandleBindAppHooker.java @@ -0,0 +1,105 @@ +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.Main; +import com.elderdrivers.riru.edxp.sandhook.entry.Router; +import com.elderdrivers.riru.edxp.util.Utils; +import com.swift.sandhook.SandHook; +import com.swift.sandhook.annotation.HookClass; +import com.swift.sandhook.annotation.HookMethod; +import com.swift.sandhook.annotation.HookMethodBackup; +import com.swift.sandhook.annotation.Param; +import com.swift.sandhook.annotation.SkipParamCheck; +import com.swift.sandhook.annotation.ThisObject; + +import java.lang.reflect.Method; + +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.sandhook.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; +import static com.elderdrivers.riru.edxp.util.ClassLoaderUtils.replaceParentClassLoader; + +// normal process initialization (for new Activity, Service, BroadcastReceiver etc.) +@HookClass(ActivityThread.class) +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"; + + @HookMethodBackup("handleBindApplication") + @SkipParamCheck + static Method backup; + + @HookMethod("handleBindApplication") + public static void hook(@ThisObject ActivityThread thiz, @Param("android.app.ActivityThread$AppBindData") Object bindData) throws Throwable { + 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) throws Throwable { + SandHook.callOriginByBackup(backup, thiz, 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..46daac80 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/LoadedApkConstructorHooker.java @@ -0,0 +1,110 @@ +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 com.swift.sandhook.SandHook; +import com.swift.sandhook.annotation.HookClass; +import com.swift.sandhook.annotation.HookMethod; +import com.swift.sandhook.annotation.HookMethodBackup; +import com.swift.sandhook.annotation.SkipParamCheck; +import com.swift.sandhook.annotation.ThisObject; + +import java.lang.reflect.Method; + +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 +@HookClass(LoadedApk.class) +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"; + + @HookMethodBackup + @SkipParamCheck + static Method backup; + + @HookMethod + public static void hook(@ThisObject Object thiz, ActivityThread activityThread, + ApplicationInfo aInfo, CompatibilityInfo compatInfo, + ClassLoader baseLoader, boolean securityViolation, + boolean includeCode, boolean registerPackage) throws Throwable { + + 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) throws Throwable { + SandHook.callOriginByBackup(backup, thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, 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..9066a112 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/OnePlusWorkAroundHooker.java @@ -0,0 +1,55 @@ +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 com.swift.sandhook.SandHook; +import com.swift.sandhook.annotation.HookClass; +import com.swift.sandhook.annotation.HookMethod; +import com.swift.sandhook.annotation.HookMethodBackup; +import com.swift.sandhook.annotation.SkipParamCheck; + +import java.lang.reflect.Method; + +import dalvik.system.BaseDexClassLoader; +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. + */ +@HookClass(BaseDexClassLoader.class) +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"; + + @HookMethodBackup("inCompatConfigList") + @SkipParamCheck + static Method backup; + + @HookMethod("inCompatConfigList") + public static boolean hook(int type, String packageName) throws Throwable { + if (XposedBridge.disableHooks || Router.forkCompleted) { + return backup(type, packageName); + } + Router.logD("BaseDexClassLoader#inCompatConfigList() starts"); + return false; + } + + public static boolean backup(int type, String packageName) throws Throwable { + return (boolean) SandHook.callOriginByBackup(backup, null, type, packageName); + } +} \ 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..082d0d36 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/StartBootstrapServicesHooker.java @@ -0,0 +1,81 @@ +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 com.swift.sandhook.SandHook; +import com.swift.sandhook.annotation.HookMethod; +import com.swift.sandhook.annotation.HookMethodBackup; +import com.swift.sandhook.annotation.HookMode; +import com.swift.sandhook.annotation.HookReflectClass; +import com.swift.sandhook.annotation.SkipParamCheck; +import com.swift.sandhook.annotation.ThisObject; + +import java.lang.reflect.Method; + +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; + +@HookReflectClass("com.android.server.SystemServer") +public class StartBootstrapServicesHooker implements KeepMembers { + public static String className = "com.android.server.SystemServer"; + public static String methodName = "startBootstrapServices"; + public static String methodSig = "()V"; + + @HookMethodBackup("startBootstrapServices") + @SkipParamCheck + static Method backup; + + @HookMethod("startBootstrapServices") + public static void hook(@ThisObject Object systemServer) throws Throwable { + + 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) throws Throwable { + SandHook.callOriginByBackup(backup, 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..c5d6d1fd --- /dev/null +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/SystemMainHooker.java @@ -0,0 +1,55 @@ +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 com.swift.sandhook.SandHook; +import com.swift.sandhook.annotation.HookClass; +import com.swift.sandhook.annotation.HookMethod; +import com.swift.sandhook.annotation.HookMethodBackup; +import com.swift.sandhook.annotation.HookMode; + +import java.lang.reflect.Method; + +import de.robv.android.xposed.XposedBridge; + + +// system_server initialization +// ed: only support sdk >= 21 for now +@HookClass(ActivityThread.class) +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; + + @HookMethodBackup("systemMain") + static Method backup; + + @HookMethod("systemMain") + public static ActivityThread hook() throws Throwable { + 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() throws Throwable { + return (ActivityThread) SandHook.callOriginByBackup(backup, null); + } +} \ No newline at end of file diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedBlackListHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java similarity index 87% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedBlackListHooker.java rename to edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java index 18c2be59..c86dddfc 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedBlackListHooker.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedBlackListHooker.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; import android.annotation.TargetApi; import android.app.Activity; @@ -6,7 +6,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.os.Build; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.util.Utils; import java.io.File; import java.util.Arrays; @@ -17,10 +17,10 @@ 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.xposed.config.InstallerChooser.INSTALLER_PACKAGE_NAME; -import static com.elderdrivers.riru.xposed.util.FileUtils.IS_USING_PROTECTED_STORAGE; -import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; +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 { @@ -62,7 +62,7 @@ public class XposedBlackListHooker { return; } try { - findAndHookMethod(ContextWrapper.class, "getSharedPreferences", String.class, int.class, new XC_MethodHook() { + 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 { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedInstallerHooker.java b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java similarity index 69% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedInstallerHooker.java rename to edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java index 9eeb6bcc..e3b83a77 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/XposedInstallerHooker.java +++ b/edxp-sandhook/src/main/java/com/elderdrivers/riru/edxp/sandhook/entry/hooker/XposedInstallerHooker.java @@ -1,6 +1,6 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.sandhook.entry.hooker; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.util.Utils; import java.io.File; import java.io.FileInputStream; @@ -9,43 +9,39 @@ 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.xposed.config.InstallerChooser.LEGACY_INSTALLER_PACKAGE_NAME; -import static de.robv.android.xposed.XposedHelpers.callStaticMethod; -import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; -import static de.robv.android.xposed.XposedHelpers.findClass; -import static de.robv.android.xposed.XposedHelpers.getObjectField; -import static de.robv.android.xposed.XposedHelpers.setObjectField; +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 = findClass(LEGACY_INSTALLER_PACKAGE_NAME + final Class InstallZipUtil = XposedHelpers.findClass(LEGACY_INSTALLER_PACKAGE_NAME + ".util.InstallZipUtil", classLoader); - findAndHookMethod(xposedAppClass, classLoader, "getActiveXposedVersion", + XposedHelpers.findAndHookMethod(xposedAppClass, classLoader, "getActiveXposedVersion", XC_MethodReplacement.returnConstant(XposedBridge.getXposedVersion())); - findAndHookMethod(xposedAppClass, classLoader, + 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 (getObjectField(thisObject, propFieldName) != null) { + if (XposedHelpers.getObjectField(thisObject, propFieldName) != null) { param.setResult(null); Utils.logD("reloadXposedProp already done, skip..."); return; } - File file = new File("/system/framework/edconfig.dex"); + File file = new File("/system/framework/edconfig.jar"); FileInputStream is = null; try { is = new FileInputStream(file); - Object props = callStaticMethod(InstallZipUtil, + Object props = XposedHelpers.callStaticMethod(InstallZipUtil, "parseXposedProp", is); synchronized (thisObject) { - setObjectField(thisObject, propFieldName, props); + XposedHelpers.setObjectField(thisObject, propFieldName, props); } Utils.logD("reloadXposedProp done..."); param.setResult(null); 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..fec53890 --- /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.setAppDataDir(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..10d97ec2 --- /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.setAppDataDir(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.setAppDataDir(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..d3f8e893 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/XposedCompat.java @@ -0,0 +1,109 @@ +package com.swift.sandhook.xposedcompat; + +import android.annotation.SuppressLint; +import android.os.Process; +import android.text.TextUtils; + +import com.swift.sandhook.SandHook; +import com.swift.sandhook.xposedcompat.classloaders.ComposeClassLoader; +import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge; +import com.swift.sandhook.xposedcompat.utils.ApplicationUtils; +import com.swift.sandhook.xposedcompat.utils.FileUtils; +import com.swift.sandhook.xposedcompat.utils.ProcessUtils; + +import java.io.File; +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE; +import static com.swift.sandhook.xposedcompat.utils.FileUtils.IS_USING_PROTECTED_STORAGE; + +public class XposedCompat { + + public static volatile String appDataDir; + + // TODO initialize these variables + public static volatile File cacheDir; + public static volatile ClassLoader classLoader; + + //try to use internal stub hooker & backup method to speed up hook + public static volatile boolean useInternalStub = true; + public static volatile boolean useNewCallBackup = true; + public static volatile boolean retryWhenCallOriginError = false; + + private static ClassLoader sandHookXposedClassLoader; + + public static void addHookers(ClassLoader classLoader, Class[] hookers) { + if (hookers == null) + return; + for (Class hooker:hookers) { + try { + SandHook.addHookClass(classLoader, hooker); + } catch (Throwable throwable) {} + } + } + + public static File getCacheDir() { + if (cacheDir == null) { + String fixedAppDataDir = getDataPathPrefix() + getPackageName(appDataDir) + "/"; + cacheDir = new File(fixedAppDataDir, "/cache/sandhook/" + + ProcessUtils.getProcessName().replace(":", "_") + "/"); + } + return cacheDir; + } + + public static ClassLoader getClassLoader() { + if (classLoader == null) { + classLoader = getSandHookXposedClassLoader(ApplicationUtils.currentApplication().getClassLoader(), XposedCompat.class.getClassLoader()); + } + return classLoader; + } + + 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(getCacheDir()); + getCacheDir().mkdirs(); + return true; + } catch (Throwable throwable) { + return false; + } + } + + public static void clearOatCache() { + SandHookXposedBridge.clearOatFile(); + } + + public static String getPackageName(String dataDir) { + if (TextUtils.isEmpty(dataDir)) { + return ""; + } + int lastIndex = dataDir.lastIndexOf("/"); + if (lastIndex < 0) { + return dataDir; + } + return dataDir.substring(lastIndex + 1); + } + + // FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet. + @SuppressLint("SdCardPath") + public static String getDataPathPrefix() { + int userId = Process.myUid() / PER_USER_RANGE; + String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/"; + return String.format(format, userId); + } + +} 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..571b8ba5 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/HookStubManager.java @@ -0,0 +1,412 @@ +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.XposedCompat; +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 volatile boolean is64Bit; + //64bits arg0 - arg7 is in reg x1 - x7 and > 7 is in stack, but can not match + public final static int MAX_64_ARGS = 7; + + public static int MAX_STUB_ARGS = 0; + + public static int[] stubSizes; + + public static boolean hasStubBackup; + + 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 { + is64Bit = SandHook.is64Bit(); + Class stubClass = is64Bit ? MethodHookerStubs64.class : MethodHookerStubs32.class; + stubSizes = (int[]) XposedHelpers.getStaticObjectField(stubClass, "stubSizes"); + Boolean hasBackup = (Boolean) XposedHelpers.getStaticObjectField(stubClass, "hasStubBackup"); + hasStubBackup = hasBackup != null && (hasBackup && !XposedCompat.useNewCallBackup); + 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; + if (is64Bit && needStubArgCount > MAX_64_ARGS) + return null; + for (Class par:parType) { + if (!ParamWrapper.support(par)) + return null; + } + } else { + parType = new Class[0]; + } + + synchronized (HookStubManager.class) { + StubMethodsInfo stubMethodInfo = getStubMethodPair(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 = 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) { + 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) { + 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) { + 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) { + 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..4cdaff80 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/hookstub/MethodHookerStubs64.java @@ -0,0 +1,1515 @@ +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, 50, 50}; + + + //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 6, index 30 + public static long stub_hook_30(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 30), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 31 + public static long stub_hook_31(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 31), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 32 + public static long stub_hook_32(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 32), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 33 + public static long stub_hook_33(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 33), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 34 + public static long stub_hook_34(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 34), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 35 + public static long stub_hook_35(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 35), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 36 + public static long stub_hook_36(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 36), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 37 + public static long stub_hook_37(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 37), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 38 + public static long stub_hook_38(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 38), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 39 + public static long stub_hook_39(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 39), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 40 + public static long stub_hook_40(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 40), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 41 + public static long stub_hook_41(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 41), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 42 + public static long stub_hook_42(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 42), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 43 + public static long stub_hook_43(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 43), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 44 + public static long stub_hook_44(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 44), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 45 + public static long stub_hook_45(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 45), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 46 + public static long stub_hook_46(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 46), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 47 + public static long stub_hook_47(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 47), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 48 + public static long stub_hook_48(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 48), null , a0, a1, a2, a3, a4, a5); + } + + + //stub of arg size 6, index 49 + public static long stub_hook_49(long a0, long a1, long a2, long a3, long a4, long a5) throws Throwable { + return hookBridge(getMethodId(6, 49), 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 7, index 20 + public static long stub_hook_20(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 20), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 21 + public static long stub_hook_21(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 21), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 22 + public static long stub_hook_22(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 22), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 23 + public static long stub_hook_23(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 23), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 24 + public static long stub_hook_24(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 24), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 25 + public static long stub_hook_25(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 25), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 26 + public static long stub_hook_26(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 26), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 27 + public static long stub_hook_27(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 27), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 28 + public static long stub_hook_28(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 28), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 29 + public static long stub_hook_29(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 29), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 30 + public static long stub_hook_30(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 30), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 31 + public static long stub_hook_31(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 31), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 32 + public static long stub_hook_32(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 32), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 33 + public static long stub_hook_33(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 33), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 34 + public static long stub_hook_34(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 34), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 35 + public static long stub_hook_35(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 35), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 36 + public static long stub_hook_36(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 36), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 37 + public static long stub_hook_37(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 37), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 38 + public static long stub_hook_38(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 38), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 39 + public static long stub_hook_39(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 39), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 40 + public static long stub_hook_40(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 40), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 41 + public static long stub_hook_41(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 41), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 42 + public static long stub_hook_42(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 42), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 43 + public static long stub_hook_43(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 43), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 44 + public static long stub_hook_44(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 44), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 45 + public static long stub_hook_45(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 45), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 46 + public static long stub_hook_46(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 46), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 47 + public static long stub_hook_47(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 47), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 48 + public static long stub_hook_48(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 48), null , a0, a1, a2, a3, a4, a5, a6); + } + + + //stub of arg size 7, index 49 + public static long stub_hook_49(long a0, long a1, long a2, long a3, long a4, long a5, long a6) throws Throwable { + return hookBridge(getMethodId(7, 49), null , a0, a1, a2, a3, a4, a5, a6); + } + +} 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..465b2533 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMaker.java @@ -0,0 +1,707 @@ +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.io.IOException; +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 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.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.loadClassDirect(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. + try { + loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName, true); + } catch (IOException e) { + //can not write file + byte[] dexBytes = mDexMaker.generate(); + loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); + } + 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..a6aa08a4 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/HookerDexMakerNew.java @@ -0,0 +1,307 @@ +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.io.IOException; +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 dalvik.system.InMemoryDexClassLoader; +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.loadClassDirect(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. + try { + loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName, true); + } catch (IOException e) { + //can not write file + byte[] dexBytes = mDexMaker.generate(); + loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); + } + 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..44a807da --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/methodgen/SandHookXposedBridge.java @@ -0,0 +1,134 @@ +package com.swift.sandhook.xposedcompat.methodgen; + +import android.os.Process; +import android.os.Trace; + +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.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import de.robv.android.xposed.XposedBridge; + +public final class SandHookXposedBridge { + + private static final Map hookedInfo = new ConcurrentHashMap<>(); + private static HookMaker hookMaker = XposedCompat.useNewCallBackup ? new HookerDexMakerNew() : new HookerDexMaker(); + private static final AtomicBoolean dexPathInited = new AtomicBoolean(false); + private static File dexDir; + + public static Map entityMap = new ConcurrentHashMap<>(); + + public static boolean hooked(Member member) { + return hookedInfo.containsKey(member) || entityMap.containsKey(member); + } + + 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 { + if (dexPathInited.compareAndSet(false, true)) { + try { + String fixedAppDataDir = XposedCompat.getCacheDir().getAbsolutePath(); + dexDir = new File(fixedAppDataDir, "/hookers/"); + if (!dexDir.exists()) + dexDir.mkdirs(); + } catch (Throwable throwable) { + DexLog.e("error when init dex path", throwable); + } + } + Trace.beginSection("SandXposed"); + 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, + hookMethod.getDeclaringClass().getClassLoader(), 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); + } + } + + public static void clearOatFile() { + String fixedAppDataDir = XposedCompat.getCacheDir().getAbsolutePath(); + File dexOatDir = new File(fixedAppDataDir, "/hookers/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 { + return SandHook.callOriginMethod(method, thisObject, args); + } + + public static void init() { + if (Process.is64Bit()) { + SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so"; + } else { + SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so"; + } + SandHookConfig.libLoader = new SandHookConfig.LibLoader() { + @Override + public void loadLib() { + //do it in loadDexAndInit + } + }; + SandHookConfig.DEBUG = true; + //in zygote disable compile + } +} + + 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..be45ace5 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/DexLog.java @@ -0,0 +1,53 @@ +package com.swift.sandhook.xposedcompat.utils; + +import android.util.Log; + +import java.lang.reflect.Member; + + +public class DexLog { + + public static final String TAG = "SandXposed"; + + public static volatile boolean DEBUG = false; + + 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 (DEBUG) { + return Log.d(TAG, s); + } else { + return 0; + } + } + + public static void printMethodHookIn(Member member) { + if (DEBUG && member != null) { + Log.d("SandHook", "method <" + member.toString() + "> hook in"); + } + } + + public static void printCallOriginError(Member member) { + Log.e("SandHook", "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..11d80101 --- /dev/null +++ b/edxp-sandhook/src/main/java/com/swift/sandhook/xposedcompat/utils/ProcessUtils.java @@ -0,0 +1,95 @@ +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.os.Process; +import android.text.TextUtils; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +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() { + if (!TextUtils.isEmpty(processName)) + return processName; + processName = getProcessName(Process.myPid()); + 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 String getProcessName(int pid) { + BufferedReader cmdlineReader = null; + try { + cmdlineReader = new BufferedReader(new InputStreamReader( + new FileInputStream( + "/proc/" + pid + "/cmdline"), + "iso-8859-1")); + int c; + StringBuilder processName = new StringBuilder(); + while ((c = cmdlineReader.read()) > 0) { + processName.append((char) c); + } + return processName.toString(); + } catch (Throwable throwable) { + DexLog.w("getProcessName: " + throwable.getMessage()); + } finally { + try { + if (cmdlineReader != null) { + cmdlineReader.close(); + } + } catch (Throwable throwable) { + DexLog.e("getProcessName: " + throwable.getMessage()); + } + } + return ""; + } + + public static boolean isMainProcess(Context context) { + String processName = getProcessName(); + 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-sandhook/template_override/system/lib/libsandhook.edxp.so b/edxp-sandhook/template_override/system/lib/libsandhook.edxp.so new file mode 100755 index 00000000..18596562 Binary files /dev/null and b/edxp-sandhook/template_override/system/lib/libsandhook.edxp.so differ diff --git a/edxp-sandhook/template_override/system/lib/libwhale.edxp.so b/edxp-sandhook/template_override/system/lib/libwhale.edxp.so new file mode 100755 index 00000000..187d0495 Binary files /dev/null and b/edxp-sandhook/template_override/system/lib/libwhale.edxp.so differ diff --git a/edxp-sandhook/template_override/system/lib64/libsandhook.edxp.so b/edxp-sandhook/template_override/system/lib64/libsandhook.edxp.so new file mode 100755 index 00000000..d0c13135 Binary files /dev/null and b/edxp-sandhook/template_override/system/lib64/libsandhook.edxp.so differ diff --git a/edxp-sandhook/template_override/system/lib64/libwhale.edxp.so b/edxp-sandhook/template_override/system/lib64/libwhale.edxp.so new file mode 100755 index 00000000..3c2cd0d8 Binary files /dev/null and b/edxp-sandhook/template_override/system/lib64/libwhale.edxp.so differ diff --git a/edxp-sandhook/template_override/system_x86/lib/libwhale.edxp.so b/edxp-sandhook/template_override/system_x86/lib/libwhale.edxp.so new file mode 100755 index 00000000..d1653bcc Binary files /dev/null and b/edxp-sandhook/template_override/system_x86/lib/libwhale.edxp.so differ diff --git a/edxp-sandhook/template_override/system_x86/lib64/libwhale.edxp.so b/edxp-sandhook/template_override/system_x86/lib64/libwhale.edxp.so new file mode 100755 index 00000000..f5bcdc5a Binary files /dev/null and b/edxp-sandhook/template_override/system_x86/lib64/libwhale.edxp.so differ diff --git a/edxp-whale/.gitignore b/edxp-whale/.gitignore new file mode 100644 index 00000000..845f9980 --- /dev/null +++ b/edxp-whale/.gitignore @@ -0,0 +1,2 @@ +/build +/template_override/system/framework/edxp.jar \ No newline at end of file diff --git a/edxp-whale/build.gradle b/edxp-whale/build.gradle new file mode 100644 index 00000000..8ca2d21f --- /dev/null +++ b/edxp-whale/build.gradle @@ -0,0 +1,70 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "com.elderdrivers.riru.edxp.whale" + 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') +} + + +preBuild.doLast { + def imlFile = file(project.name + ".iml") + 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 variantNameCapped = variant.name.capitalize() + def variantNameLowered = variant.name.toLowerCase() + + def myTemplatePath = "${projectDir}/template_override/" + + task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { + from "${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}/out/" + destinationDir file(myTemplatePath + "system/framework/") + baseName "edxp" + doLast { + copy { + from file(myTemplatePath) + into file(templateRootPath) + } + } + outputs.upToDateWhen { false } + } + } +} \ No newline at end of file diff --git a/edxp-whale/libs/framework-stub.jar b/edxp-whale/libs/framework-stub.jar new file mode 100644 index 00000000..36cd86b3 Binary files /dev/null and b/edxp-whale/libs/framework-stub.jar differ diff --git a/edxp-whale/proguard-rules.pro b/edxp-whale/proguard-rules.pro new file mode 100644 index 00000000..1d01a7a1 --- /dev/null +++ b/edxp-whale/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.lody.** {*;} \ No newline at end of file diff --git a/edxp-whale/src/main/AndroidManifest.xml b/edxp-whale/src/main/AndroidManifest.xml new file mode 100644 index 00000000..38b7acf3 --- /dev/null +++ b/edxp-whale/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/Main.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/Main.java new file mode 100644 index 00000000..78741c92 --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/Main.java @@ -0,0 +1,143 @@ +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.BuildConfig; +import com.elderdrivers.riru.edxp.config.InstallerChooser; +import com.elderdrivers.riru.edxp.yahfa.core.HookMethodResolver; +import com.elderdrivers.riru.edxp.yahfa.entry.Router; +import com.elderdrivers.riru.edxp.yahfa.proxy.BlackWhiteListProxy; +import com.elderdrivers.riru.edxp.yahfa.proxy.NormalProxy; +import com.elderdrivers.riru.edxp.util.Utils; +import com.lody.whale.WhaleRuntime; + +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()); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // 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-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleEdxpConfig.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleEdxpConfig.java new file mode 100644 index 00000000..60f364bd --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleEdxpConfig.java @@ -0,0 +1,23 @@ +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.Main; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.XposedBlackListHooker; + +public class WhaleEdxpConfig 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-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleHookProvider.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleHookProvider.java new file mode 100644 index 00000000..cb94160b --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/WhaleHookProvider.java @@ -0,0 +1,37 @@ +package com.elderdrivers.riru.edxp.yahfa.config; + +import com.elderdrivers.riru.edxp.hook.HookProvider; +import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; +import com.lody.whale.WhaleRuntime; + +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +public class WhaleHookProvider implements HookProvider { + + @Override + public void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo) { + WhaleRuntime.hookMethodNative(method.getDeclaringClass(), method, additionalInfo); + } + + @Override + public Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args) throws Throwable { + return WhaleRuntime.invokeOriginalMethodNative(methodId, thisObject, args); + } + + @Override + public Member findMethodNative(Member hookMethod) { + return hookMethod; + } + + @Override + public void deoptMethods(String packageName, ClassLoader classLoader) { + PrebuiltMethodsDeopter.deoptMethods(packageName, classLoader); + } + + @Override + public long getMethodId(Member member) { + return WhaleRuntime.getMethodSlot(member); + } +} diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java similarity index 95% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java index 7faa9186..13da190a 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/core/HookMain.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java @@ -1,8 +1,8 @@ -package com.elderdrivers.riru.xposed.core; +package com.elderdrivers.riru.edxp.yahfa.core; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.util.Utils; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -14,8 +14,8 @@ import java.util.Set; import de.robv.android.xposed.XposedHelpers; -import static com.elderdrivers.riru.xposed.Main.backupAndHookNative; -import static com.elderdrivers.riru.xposed.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-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java new file mode 100644 index 00000000..d8f616b5 --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java @@ -0,0 +1,155 @@ +package com.elderdrivers.riru.edxp.yahfa.core; + +import android.os.Build; + +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.util.Utils; + +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/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexLog.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java similarity index 86% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexLog.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java index 3802e49c..f7729737 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexLog.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java @@ -1,8 +1,8 @@ -package com.elderdrivers.riru.xposed.dexmaker; +package com.elderdrivers.riru.edxp.yahfa.dexmaker; import android.util.Log; -import com.elderdrivers.riru.xposed.BuildConfig; +import com.elderdrivers.riru.edxp.BuildConfig; public class DexLog { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/MethodInfo.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java similarity index 98% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/MethodInfo.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java index 03d141c7..27ea86e0 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/MethodInfo.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.dexmaker; +package com.elderdrivers.riru.edxp.yahfa.dexmaker; import java.lang.reflect.Constructor; import java.lang.reflect.Member; diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java similarity index 62% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java index 5510caa9..0a3347b3 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/Router.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java @@ -1,15 +1,20 @@ -package com.elderdrivers.riru.xposed.entry; +package com.elderdrivers.riru.edxp.yahfa.entry; +import android.app.AndroidAppHelper; import android.text.TextUtils; -import com.elderdrivers.riru.xposed.core.HookMain; -import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge; -import com.elderdrivers.riru.xposed.entry.bootstrap.AppBootstrapHookInfo; -import com.elderdrivers.riru.xposed.entry.bootstrap.SysBootstrapHookInfo; -import com.elderdrivers.riru.xposed.entry.bootstrap.SysInnerHookInfo; -import com.elderdrivers.riru.xposed.entry.bootstrap.WorkAroundHookInfo; -import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.yahfa.config.WhaleHookProvider; +import com.elderdrivers.riru.edxp.yahfa.config.WhaleEdxpConfig; +import com.elderdrivers.riru.edxp.yahfa.core.HookMain; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.AppBootstrapHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysBootstrapHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysInnerHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.WorkAroundHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.SystemMainHooker; + +import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedInit; @@ -18,6 +23,9 @@ 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; @@ -43,6 +51,10 @@ public class Router { 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); @@ -91,6 +103,20 @@ public class Router { public static void onEnterChildProcess() { forkCompleted = true; - DynamicBridge.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 WhaleEdxpConfig(); + EdXpConfigGlobal.sHookProvider = new WhaleHookProvider(); } } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/AppBootstrapHookInfo.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java similarity index 52% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/AppBootstrapHookInfo.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java index 714ea2fc..24aa7c29 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/AppBootstrapHookInfo.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java @@ -1,9 +1,9 @@ -package com.elderdrivers.riru.xposed.entry.bootstrap; +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.hooker.HandleBindAppHooker; -import com.elderdrivers.riru.xposed.entry.hooker.LoadedApkConstructorHooker; -import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; public class AppBootstrapHookInfo implements KeepMembers { public static String[] hookItemNames = { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysBootstrapHookInfo.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java similarity index 50% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysBootstrapHookInfo.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java index cca1e6b8..2cb7e02e 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysBootstrapHookInfo.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java @@ -1,10 +1,10 @@ -package com.elderdrivers.riru.xposed.entry.bootstrap; +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.hooker.HandleBindAppHooker; -import com.elderdrivers.riru.xposed.entry.hooker.LoadedApkConstructorHooker; -import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; -import com.elderdrivers.riru.xposed.entry.hooker.SystemMainHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.SystemMainHooker; public class SysBootstrapHookInfo implements KeepMembers { public static String[] hookItemNames = { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysInnerHookInfo.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java similarity index 60% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysInnerHookInfo.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java index c08293d7..a185c0df 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/SysInnerHookInfo.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java @@ -1,7 +1,7 @@ -package com.elderdrivers.riru.xposed.entry.bootstrap; +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.hooker.StartBootstrapServicesHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.StartBootstrapServicesHooker; public class SysInnerHookInfo implements KeepMembers { public static String[] hookItemNames = { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/WorkAroundHookInfo.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java similarity index 61% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/WorkAroundHookInfo.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java index 58ffcb99..f0c5f065 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/bootstrap/WorkAroundHookInfo.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java @@ -1,7 +1,7 @@ -package com.elderdrivers.riru.xposed.entry.bootstrap; +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; public class WorkAroundHookInfo implements KeepMembers { public static String[] hookItemNames = { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/HandleBindAppHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java similarity index 63% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/HandleBindAppHooker.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java index 0f7aa822..12d7ef2c 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/HandleBindAppHooker.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import android.app.ActivityThread; import android.app.LoadedApk; @@ -7,20 +7,18 @@ import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.util.Utils; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.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.xposed.config.InstallerChooser.INSTALLER_PACKAGE_NAME; -import static com.elderdrivers.riru.xposed.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; -import static com.elderdrivers.riru.xposed.util.ClassLoaderUtils.replaceParentClassLoader; -import static de.robv.android.xposed.XposedHelpers.getObjectField; -import static de.robv.android.xposed.XposedHelpers.setObjectField; -import static de.robv.android.xposed.XposedInit.loadedPackagesInProcess; -import static de.robv.android.xposed.XposedInit.logD; -import static de.robv.android.xposed.XposedInit.logE; +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.yahfa.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; // normal process initialization (for new Activity, Service, BroadcastReceiver etc.) public class HandleBindAppHooker implements KeepMembers { @@ -35,39 +33,39 @@ public class HandleBindAppHooker implements KeepMembers { return; } try { - logD("ActivityThread#handleBindApplication() starts"); + Router.logD("ActivityThread#handleBindApplication() starts"); ActivityThread activityThread = (ActivityThread) thiz; - ApplicationInfo appInfo = (ApplicationInfo) getObjectField(bindData, "appInfo"); + ApplicationInfo appInfo = (ApplicationInfo) XposedHelpers.getObjectField(bindData, "appInfo"); // save app process name here for later use - Main.appProcessName = (String) getObjectField(bindData, "processName"); + Main.appProcessName = (String) XposedHelpers.getObjectField(bindData, "processName"); String reportedPackageName = appInfo.packageName.equals("android") ? "system" : appInfo.packageName; - Utils.logD("processName=" + Main.appProcessName + + Utils.logD("processName=" + Main.appProcessName + ", packageName=" + reportedPackageName + ", appDataDir=" + Main.appDataDir); if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) { return; } - ComponentName instrumentationName = (ComponentName) getObjectField(bindData, "instrumentationName"); + ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName"); if (instrumentationName != null) { - logD("Instrumentation detected, disabling framework for"); + Router.logD("Instrumentation detected, disabling framework for"); XposedBridge.disableHooks = true; return; } - CompatibilityInfo compatInfo = (CompatibilityInfo) getObjectField(bindData, "compatInfo"); + CompatibilityInfo compatInfo = (CompatibilityInfo) XposedHelpers.getObjectField(bindData, "compatInfo"); if (appInfo.sourceDir == null) { return; } - setObjectField(activityThread, "mBoundApplication", bindData); - loadedPackagesInProcess.add(reportedPackageName); + 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) getObjectField(bindData, "processName"); + lpparam.processName = (String) XposedHelpers.getObjectField(bindData, "processName"); lpparam.classLoader = loadedApk.getClassLoader(); lpparam.appInfo = appInfo; lpparam.isFirstApplication = true; @@ -80,7 +78,7 @@ public class HandleBindAppHooker implements KeepMembers { XposedBlackListHooker.hook(lpparam.classLoader); } } catch (Throwable t) { - logE("error when hooking bindApp", t); + Router.logE("error when hooking bindApp", t); } finally { backup(thiz, bindData); } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/LoadedApkConstructorHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java similarity index 74% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/LoadedApkConstructorHooker.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java index 01ccbab7..ce2f7605 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/LoadedApkConstructorHooker.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import android.app.ActivityThread; import android.app.AndroidAppHelper; @@ -8,16 +8,14 @@ import android.content.res.CompatibilityInfo; import android.util.Log; import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.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.xposed.util.ClassLoaderUtils.replaceParentClassLoader; -import static de.robv.android.xposed.XposedHelpers.getBooleanField; -import static de.robv.android.xposed.XposedHelpers.getObjectField; -import static de.robv.android.xposed.XposedInit.loadedPackagesInProcess; -import static de.robv.android.xposed.XposedInit.logD; -import static de.robv.android.xposed.XposedInit.logE; +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 @@ -40,40 +38,40 @@ public class LoadedApkConstructorHooker implements KeepMembers { return; } - logD("LoadedApk# starts"); + Router.logD("LoadedApk# starts"); backup(thiz, activityThread, aInfo, compatInfo, baseLoader, securityViolation, includeCode, registerPackage); try { LoadedApk loadedApk = (LoadedApk) thiz; String packageName = loadedApk.getPackageName(); - Object mAppDir = getObjectField(thiz, "mAppDir"); - logD("LoadedApk# ends: " + mAppDir); + Object mAppDir = XposedHelpers.getObjectField(thiz, "mAppDir"); + Router.logD("LoadedApk# ends: " + mAppDir); if (XposedBlackListHooker.shouldDisableHooks(packageName)) { return; } if (packageName.equals("android")) { - logD("LoadedApk# is android, skip: " + mAppDir); + Router.logD("LoadedApk# is android, skip: " + mAppDir); return; } // mIncludeCode checking should go ahead of loadedPackagesInProcess added checking - if (!getBooleanField(loadedApk, "mIncludeCode")) { - logD("LoadedApk# mIncludeCode == false: " + mAppDir); + if (!XposedHelpers.getBooleanField(loadedApk, "mIncludeCode")) { + Router.logD("LoadedApk# mIncludeCode == false: " + mAppDir); return; } - if (!loadedPackagesInProcess.add(packageName)) { - logD("LoadedApk# has been loaded before, skip: " + mAppDir); + 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")) { - logD("LoadedApk# maybe oneplus's custom opt, skip"); + Router.logD("LoadedApk# maybe oneplus's custom opt, skip"); return; } @@ -87,7 +85,7 @@ public class LoadedApkConstructorHooker implements KeepMembers { lpparam.isFirstApplication = false; XC_LoadPackage.callAll(lpparam); } catch (Throwable t) { - logE("error when hooking LoadedApk.", t); + Router.logE("error when hooking LoadedApk.", t); } } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/OnePlusWorkAroundHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java similarity index 83% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/OnePlusWorkAroundHooker.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java index f545da8e..f3261f9d 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/OnePlusWorkAroundHooker.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java @@ -1,12 +1,11 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.Router; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.entry.Router; import de.robv.android.xposed.XposedBridge; -import static de.robv.android.xposed.XposedInit.logD; - /** * On OnePlus stock roms (Android Pie), {@link dalvik.system.BaseDexClassLoader#findClass(String)} * will open /dev/binder to communicate with PackageManagerService to check whether @@ -14,7 +13,7 @@ import static de.robv.android.xposed.XposedInit.logD; * 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 com.elderdrivers.riru.xposed.Main#forkAndSpecializePre}, where in zygote process, + * {@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 @@ -32,7 +31,7 @@ public class OnePlusWorkAroundHooker implements KeepMembers { if (XposedBridge.disableHooks || Router.forkCompleted) { return backup(type, packageName); } - logD("BaseDexClassLoader#inCompatConfigList() starts"); + Router.logD("BaseDexClassLoader#inCompatConfigList() starts"); return false; } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/StartBootstrapServicesHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java similarity index 83% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/StartBootstrapServicesHooker.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java index 9ab4a1e3..7bc1c542 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/StartBootstrapServicesHooker.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java @@ -1,19 +1,19 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import android.os.Build; import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.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.xposed.util.ClassLoaderUtils.replaceParentClassLoader; -import static com.elderdrivers.riru.xposed.util.Utils.logD; +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; -import static de.robv.android.xposed.XposedInit.loadedPackagesInProcess; -import static de.robv.android.xposed.XposedInit.logE; public class StartBootstrapServicesHooker implements KeepMembers { public static String className = "com.android.server.SystemServer"; @@ -30,7 +30,7 @@ public class StartBootstrapServicesHooker implements KeepMembers { logD("SystemServer#startBootstrapServices() starts"); try { - loadedPackagesInProcess.add("android"); + XposedInit.loadedPackagesInProcess.add("android"); replaceParentClassLoader(SystemMainHooker.systemServerCL); @@ -54,7 +54,7 @@ public class StartBootstrapServicesHooker implements KeepMembers { } catch (XposedHelpers.ClassNotFoundError | NoSuchMethodError ignored) { } } catch (Throwable t) { - logE("error when hooking startBootstrapServices", t); + Router.logE("error when hooking startBootstrapServices", t); } finally { backup(systemServer); } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/SystemMainHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java similarity index 74% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/SystemMainHooker.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java index 1f51c3d2..2478f2e6 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/entry/hooker/SystemMainHooker.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java @@ -1,16 +1,13 @@ -package com.elderdrivers.riru.xposed.entry.hooker; +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; import android.app.ActivityThread; import com.elderdrivers.riru.common.KeepMembers; -import com.elderdrivers.riru.xposed.entry.Router; -import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter; +import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; +import com.elderdrivers.riru.edxp.yahfa.entry.Router; import de.robv.android.xposed.XposedBridge; -import static de.robv.android.xposed.XposedInit.logD; -import static de.robv.android.xposed.XposedInit.logE; - // system_server initialization // ed: only support sdk >= 21 for now @@ -26,7 +23,7 @@ public class SystemMainHooker implements KeepMembers { if (XposedBridge.disableHooks) { return backup(); } - logD("ActivityThread#systemMain() starts"); + Router.logD("ActivityThread#systemMain() starts"); ActivityThread activityThread = backup(); try { // get system_server classLoader @@ -35,7 +32,7 @@ public class SystemMainHooker implements KeepMembers { PrebuiltMethodsDeopter.deoptSystemServerMethods(systemServerCL); Router.startSystemServerHook(); } catch (Throwable t) { - logE("error when hooking systemMain", t); + Router.logE("error when hooking systemMain", t); } return activityThread; } diff --git a/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java new file mode 100644 index 00000000..7261f63b --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java @@ -0,0 +1,87 @@ +package com.elderdrivers.riru.edxp.yahfa.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-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java new file mode 100644 index 00000000..07931306 --- /dev/null +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java @@ -0,0 +1,64 @@ +package com.elderdrivers.riru.edxp.yahfa.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/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java similarity index 88% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java index c0c5ab1b..ba9842d9 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java @@ -1,18 +1,18 @@ -package com.elderdrivers.riru.xposed.proxy.yahfa; +package com.elderdrivers.riru.edxp.yahfa.proxy; import android.text.TextUtils; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.config.ConfigManager; -import com.elderdrivers.riru.xposed.entry.Router; -import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter; -import com.elderdrivers.riru.xposed.util.ProcessUtils; -import com.elderdrivers.riru.xposed.util.Utils; +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; +import com.elderdrivers.riru.edxp.util.ProcessUtils; +import com.elderdrivers.riru.edxp.util.Utils; import de.robv.android.xposed.XposedBridge; -import static com.elderdrivers.riru.xposed.Main.isAppNeedHook; -import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; +import static com.elderdrivers.riru.edxp.Main.isAppNeedHook; +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; /** * 1. Non dynamic mode @@ -112,7 +112,7 @@ public class BlackWhiteListProxy { boolean needHook; if (TextUtils.isEmpty(appDataDir)) { Utils.logE("niceName:" + niceName + ", procName:" - + ProcessUtils.getCurrentProcessName() + ", appDataDir is null, blacklisted!"); + + 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 diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java similarity index 89% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java index b60e9e0c..9c1d3dba 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java @@ -1,11 +1,11 @@ -package com.elderdrivers.riru.xposed.proxy.yahfa; +package com.elderdrivers.riru.edxp.yahfa.proxy; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.config.ConfigManager; -import com.elderdrivers.riru.xposed.entry.Router; -import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter; +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; -import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; public class NormalProxy { diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/InlinedMethodCallers.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java similarity index 97% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/InlinedMethodCallers.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java index eb8a29cc..15fffeb0 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/InlinedMethodCallers.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java @@ -1,4 +1,4 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.yahfa.util; import java.util.HashMap; diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/PrebuiltMethodsDeopter.java b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java similarity index 77% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/util/PrebuiltMethodsDeopter.java rename to edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java index 7ef0fff6..ecd8813d 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/util/PrebuiltMethodsDeopter.java +++ b/edxp-whale/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java @@ -1,13 +1,14 @@ -package com.elderdrivers.riru.xposed.util; +package com.elderdrivers.riru.edxp.yahfa.util; -import com.elderdrivers.riru.xposed.Main; +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.xposed.util.InlinedMethodCallers.KEY_BOOT_IMAGE; -import static com.elderdrivers.riru.xposed.util.InlinedMethodCallers.KEY_SYSTEM_SERVER; +import static com.elderdrivers.riru.edxp.yahfa.util.InlinedMethodCallers.KEY_BOOT_IMAGE; +import static com.elderdrivers.riru.edxp.yahfa.util.InlinedMethodCallers.KEY_SYSTEM_SERVER; public class PrebuiltMethodsDeopter { diff --git a/edxp-whale/src/main/java/com/lody/whale/VMHelper.java b/edxp-whale/src/main/java/com/lody/whale/VMHelper.java new file mode 100644 index 00000000..392d7fef --- /dev/null +++ b/edxp-whale/src/main/java/com/lody/whale/VMHelper.java @@ -0,0 +1,105 @@ +package com.lody.whale; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.HashMap; + +/** + * @author Lody + */ +class VMHelper { + + // Holds a mapping from Java type names to native type codes. + private static final HashMap, String> PRIMITIVE_TO_SIGNATURE; + + static { + PRIMITIVE_TO_SIGNATURE = new HashMap<>(9); + PRIMITIVE_TO_SIGNATURE.put(byte.class, "B"); + PRIMITIVE_TO_SIGNATURE.put(char.class, "C"); + PRIMITIVE_TO_SIGNATURE.put(short.class, "S"); + PRIMITIVE_TO_SIGNATURE.put(int.class, "I"); + PRIMITIVE_TO_SIGNATURE.put(long.class, "J"); + PRIMITIVE_TO_SIGNATURE.put(float.class, "F"); + PRIMITIVE_TO_SIGNATURE.put(double.class, "D"); + PRIMITIVE_TO_SIGNATURE.put(void.class, "V"); + PRIMITIVE_TO_SIGNATURE.put(boolean.class, "Z"); + } + + /** + * Returns the internal name of {@code clazz} (also known as the + * descriptor). + */ + private static String getSignature(final Class clazz) { + final String primitiveSignature = PRIMITIVE_TO_SIGNATURE.get(clazz); + if (primitiveSignature != null) { + return primitiveSignature; + } else if (clazz.isArray()) { + return "[" + getSignature(clazz.getComponentType()); + } else { + return "L" + clazz.getName().replace('.', '/') + ";"; + } + } + + /** + * Returns the native type codes of {@code clazz}. + */ + private static String getShortyType(final Class clazz) { + final String primitiveSignature = PRIMITIVE_TO_SIGNATURE.get(clazz); + if (primitiveSignature != null) { + return primitiveSignature; + } + return "L"; + } + + // @SuppressWarnings("ConstantConditions") + private static String getSignature(final Class retType, + final Class[] parameterTypes) { + final StringBuilder result = new StringBuilder(); + + result.append('('); + for (final Class parameterType : parameterTypes) { + result.append(getSignature(parameterType)); + } + result.append(")"); + result.append(getSignature(retType)); + + return result.toString(); + } + + private static String getShorty(final Class retType, + final Class[] parameterTypes) { + final StringBuilder result = new StringBuilder(); + + result.append(getShortyType(retType)); + for (final Class parameterType : parameterTypes) { + result.append(getShortyType(parameterType)); + } + + return result.toString(); + } + + static String getSignature(final Member m) { + if (m instanceof Method) { + final Method md = (Method) m; + return getSignature(md.getReturnType(), md.getParameterTypes()); + } + if (m instanceof Constructor) { + final Constructor c = (Constructor) m; + return getSignature(void.class, c.getParameterTypes()); + } + return null; + } + + static String getShorty(final Member m) { + if (m instanceof Method) { + final Method md = (Method) m; + return getShorty(md.getReturnType(), md.getParameterTypes()); + } + if (m instanceof Constructor) { + final Constructor c = (Constructor) m; + return getShorty(void.class, c.getParameterTypes()); + } + return null; + } +} diff --git a/edxp-whale/src/main/java/com/lody/whale/WhaleRuntime.java b/edxp-whale/src/main/java/com/lody/whale/WhaleRuntime.java new file mode 100644 index 00000000..2c0904e4 --- /dev/null +++ b/edxp-whale/src/main/java/com/lody/whale/WhaleRuntime.java @@ -0,0 +1,74 @@ +package com.lody.whale; + +import android.os.Build; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import de.robv.android.xposed.XposedBridge; + +/** + * @author Lody + *

+ * NOTICE: Do not move or rename any methods in this class. + */ +public class WhaleRuntime { + + static { + System.loadLibrary("whale.edxp"); + } + + private static String getShorty(Member member) { + return VMHelper.getShorty(member); + } + + public static long[] countInstancesOfClasses(Class[] classes, boolean assignable) { + if (Build.VERSION.SDK_INT < 27) { + throw new UnsupportedOperationException("Not support countInstancesOfClasses on your device yet."); + } + try { + Class clazz = Class.forName("dalvik.system.VMDebug"); + Method method = clazz.getDeclaredMethod("countInstancesOfClasses", Class[].class, boolean.class); + return (long[]) method.invoke(null, classes, assignable); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + public static Object[][] getInstancesOfClasses(Class[] classes, boolean assignable) { + if (Build.VERSION.SDK_INT < 28) { + throw new UnsupportedOperationException("Not support getInstancesOfClasses on your device yet."); + } + try { + Class clazz = Class.forName("dalvik.system.VMDebug"); + Method method = clazz.getDeclaredMethod("getInstancesOfClasses", Class[].class, boolean.class); + return (Object[][]) method.invoke(null, classes, assignable); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + public static Object handleHookedMethod(Member member, long slot, Object additionInfo, Object thisObject, Object[] args) throws Throwable { + return XposedBridge.handleHookedMethod(member, slot, additionInfo, thisObject, args); + } + + public static native Object invokeOriginalMethodNative(long slot, Object thisObject, Object[] args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException; + + public static native long getMethodSlot(Member member) throws IllegalArgumentException; + + public static native long hookMethodNative(Class declClass, Member method, Object additionInfo); + + public static native void setObjectClassNative(Object object, Class parent); + + public static native Object cloneToSubclassNative(Object object, Class subClass); + + public static native void removeFinalFlagNative(Class cl); + + public static native void enforceDisableHiddenAPIPolicy(); + + private static native void reserved0(); + + private static native void reserved1(); +} diff --git a/edxp-whale/template_override/system/etc/public.libraries-edxp.txt b/edxp-whale/template_override/system/etc/public.libraries-edxp.txt new file mode 100644 index 00000000..55a4cc17 --- /dev/null +++ b/edxp-whale/template_override/system/etc/public.libraries-edxp.txt @@ -0,0 +1 @@ +libwhale.edxp.so diff --git a/edxp-whale/template_override/system/lib/libwhale.edxp.so b/edxp-whale/template_override/system/lib/libwhale.edxp.so new file mode 100755 index 00000000..187d0495 Binary files /dev/null and b/edxp-whale/template_override/system/lib/libwhale.edxp.so differ diff --git a/edxp-whale/template_override/system/lib64/libwhale.edxp.so b/edxp-whale/template_override/system/lib64/libwhale.edxp.so new file mode 100755 index 00000000..3c2cd0d8 Binary files /dev/null and b/edxp-whale/template_override/system/lib64/libwhale.edxp.so differ diff --git a/edxp-whale/template_override/system_x86/lib/libwhale.edxp.so b/edxp-whale/template_override/system_x86/lib/libwhale.edxp.so new file mode 100755 index 00000000..d1653bcc Binary files /dev/null and b/edxp-whale/template_override/system_x86/lib/libwhale.edxp.so differ diff --git a/edxp-whale/template_override/system_x86/lib64/libwhale.edxp.so b/edxp-whale/template_override/system_x86/lib64/libwhale.edxp.so new file mode 100755 index 00000000..f5bcdc5a Binary files /dev/null and b/edxp-whale/template_override/system_x86/lib64/libwhale.edxp.so differ diff --git a/edxp-yahfa/.gitignore b/edxp-yahfa/.gitignore new file mode 100644 index 00000000..845f9980 --- /dev/null +++ b/edxp-yahfa/.gitignore @@ -0,0 +1,2 @@ +/build +/template_override/system/framework/edxp.jar \ No newline at end of file diff --git a/edxp-yahfa/build.gradle b/edxp-yahfa/build.gradle new file mode 100644 index 00000000..b3dff3ed --- /dev/null +++ b/edxp-yahfa/build.gradle @@ -0,0 +1,71 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId "com.elderdrivers.riru.edxp.yahfa" + 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') + compileOnly project(':dexmaker') +} + + +preBuild.doLast { + def imlFile = file(project.name + ".iml") + 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 variantNameCapped = variant.name.capitalize() + def variantNameLowered = variant.name.toLowerCase() + + def myTemplatePath = "${projectDir}/template_override/" + + task("makeAndCopy${variantNameCapped}", type: Jar, dependsOn: "assemble${variantNameCapped}") { + from "${buildDir}/intermediates/dex/${variantNameLowered}/mergeDex${variantNameCapped}/out/" + destinationDir file(myTemplatePath + "system/framework/") + baseName "edxp" + doLast { + copy { + from file(myTemplatePath) + into file(templateRootPath) + } + } + outputs.upToDateWhen { false } + } + } +} \ No newline at end of file diff --git a/edxp-yahfa/libs/framework-stub.jar b/edxp-yahfa/libs/framework-stub.jar new file mode 100644 index 00000000..36cd86b3 Binary files /dev/null and b/edxp-yahfa/libs/framework-stub.jar differ diff --git a/edxp-yahfa/proguard-rules.pro b/edxp-yahfa/proguard-rules.pro new file mode 100644 index 00000000..721fdf5c --- /dev/null +++ b/edxp-yahfa/proguard-rules.pro @@ -0,0 +1,31 @@ +# 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 { *; } \ No newline at end of file diff --git a/edxp-yahfa/src/main/AndroidManifest.xml b/edxp-yahfa/src/main/AndroidManifest.xml new file mode 100644 index 00000000..7998b31b --- /dev/null +++ b/edxp-yahfa/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java similarity index 91% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java rename to edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java index 2d535039..d6bb5997 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/Main.java @@ -1,16 +1,18 @@ -package com.elderdrivers.riru.xposed; +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.xposed.core.HookMethodResolver; -import com.elderdrivers.riru.xposed.proxy.yahfa.BlackWhiteListProxy; -import com.elderdrivers.riru.xposed.proxy.yahfa.NormalProxy; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.BuildConfig; +import com.elderdrivers.riru.edxp.config.InstallerChooser; +import com.elderdrivers.riru.edxp.yahfa.core.HookMethodResolver; +import com.elderdrivers.riru.edxp.yahfa.entry.Router; +import com.elderdrivers.riru.edxp.yahfa.proxy.BlackWhiteListProxy; +import com.elderdrivers.riru.edxp.yahfa.proxy.NormalProxy; +import com.elderdrivers.riru.edxp.util.Utils; -import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Arrays; @@ -26,6 +28,8 @@ public class Main implements KeepAll { static { init(Build.VERSION.SDK_INT); HookMethodResolver.init(); + Router.injectConfig(); + InstallerChooser.setInstallerPackageName(getInstallerPkgName()); } /////////////////////////////////////////////////////////////////////////////////////////////// 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 new file mode 100644 index 00000000..352f0c05 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaEdxpConfig.java @@ -0,0 +1,23 @@ +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.Main; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.XposedBlackListHooker; + +public class YahfaEdxpConfig 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-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 new file mode 100644 index 00000000..cf51c5f5 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/config/YahfaHookProvider.java @@ -0,0 +1,37 @@ +package com.elderdrivers.riru.edxp.yahfa.config; + +import com.elderdrivers.riru.edxp.hook.HookProvider; +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.Member; + +import de.robv.android.xposed.XposedBridge; + +public class YahfaHookProvider implements HookProvider { + @Override + public void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo) { + DynamicBridge.hookMethod(method, additionalInfo); + } + + @Override + public Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args) throws Throwable { + return DynamicBridge.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); + } + + @Override + public long getMethodId(Member member) { + return 0; + } +} 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 new file mode 100644 index 00000000..13da190a --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMain.java @@ -0,0 +1,186 @@ +package com.elderdrivers.riru.edxp.yahfa.core; + +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.util.Utils; + +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-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 new file mode 100644 index 00000000..d8f616b5 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/core/HookMethodResolver.java @@ -0,0 +1,155 @@ +package com.elderdrivers.riru.edxp.yahfa.core; + +import android.os.Build; + +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.util.Utils; + +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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java new file mode 100644 index 00000000..f7729737 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexLog.java @@ -0,0 +1,37 @@ +package com.elderdrivers.riru.edxp.yahfa.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/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexMakerUtils.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java similarity index 93% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexMakerUtils.java rename to edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java index 9f99619f..7ca85d47 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DexMakerUtils.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DexMakerUtils.java @@ -1,12 +1,14 @@ -package com.elderdrivers.riru.xposed.dexmaker; +package com.elderdrivers.riru.edxp.yahfa.dexmaker; import android.app.AndroidAppHelper; import android.os.Build; import android.text.TextUtils; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.config.ConfigManager; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.config.ConfigManager; +import com.elderdrivers.riru.edxp.yahfa.core.HookMain; +import java.lang.reflect.Member; import java.security.MessageDigest; import java.util.HashMap; import java.util.Map; @@ -243,4 +245,17 @@ public class DexMakerUtils { } 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/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java similarity index 90% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/DynamicBridge.java rename to edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/DynamicBridge.java index 22039ee3..b998a29e 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/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.xposed.dexmaker; +package com.elderdrivers.riru.edxp.yahfa.dexmaker; -import com.elderdrivers.riru.xposed.Main; +import com.elderdrivers.riru.edxp.Main; import java.io.File; import java.lang.reflect.Constructor; @@ -13,10 +13,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import de.robv.android.xposed.XposedBridge; -import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.shouldUseInMemoryHook; -import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; -import static com.elderdrivers.riru.xposed.util.FileUtils.getPackageName; -import static com.elderdrivers.riru.xposed.util.ProcessUtils.getCurrentProcessName; +import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.shouldUseInMemoryHook; +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 DynamicBridge { @@ -76,7 +76,7 @@ public final class DynamicBridge { // in case some app is installing hooks before phone is unlocked String fixedAppDataDir = getDataPathPrefix() + getPackageName(Main.appDataDir) + "/"; dexDir = new File(fixedAppDataDir, "/cache/edhookers/" - + getCurrentProcessName().replace(":", "_") + "/"); + + getCurrentProcessName(Main.appProcessName).replace(":", "_") + "/"); dexOptDir = new File(dexDir, "oat"); dexDir.mkdirs(); DexLog.d(Main.appProcessName + " deleting dir: " + dexOptDir.getAbsolutePath()); diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/HookerDexMaker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java similarity index 98% rename from Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/HookerDexMaker.java rename to edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java index 39507c75..56695e55 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/dexmaker/HookerDexMaker.java +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/HookerDexMaker.java @@ -1,11 +1,11 @@ -package com.elderdrivers.riru.xposed.dexmaker; +package com.elderdrivers.riru.edxp.yahfa.dexmaker; import android.annotation.TargetApi; import android.os.Build; import android.text.TextUtils; -import com.elderdrivers.riru.xposed.Main; -import com.elderdrivers.riru.xposed.core.HookMain; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.core.HookMain; import java.io.File; import java.lang.reflect.Constructor; @@ -29,10 +29,10 @@ import external.com.android.dx.Local; import external.com.android.dx.MethodId; import external.com.android.dx.TypeId; -import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.autoBoxIfNecessary; -import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.autoUnboxIfNecessary; -import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.createResultLocals; -import static com.elderdrivers.riru.xposed.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive; +import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoBoxIfNecessary; +import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.autoUnboxIfNecessary; +import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.createResultLocals; +import static com.elderdrivers.riru.edxp.yahfa.dexmaker.DexMakerUtils.getObjTypeIdIfPrimitive; public class HookerDexMaker { diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java new file mode 100644 index 00000000..27ea86e0 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/dexmaker/MethodInfo.java @@ -0,0 +1,94 @@ +package com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java new file mode 100644 index 00000000..980ca8f5 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/Router.java @@ -0,0 +1,124 @@ +package com.elderdrivers.riru.edxp.yahfa.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.yahfa.config.YahfaEdxpConfig; +import com.elderdrivers.riru.edxp.yahfa.config.YahfaHookProvider; +import com.elderdrivers.riru.edxp.yahfa.core.HookMain; +import com.elderdrivers.riru.edxp.yahfa.dexmaker.DynamicBridge; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.AppBootstrapHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysBootstrapHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.SysInnerHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.bootstrap.WorkAroundHookInfo; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.SystemMainHooker; + +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(); + } + + 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 YahfaEdxpConfig(); + EdXpConfigGlobal.sHookProvider = new YahfaHookProvider(); + } +} diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java new file mode 100644 index 00000000..24aa7c29 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/AppBootstrapHookInfo.java @@ -0,0 +1,14 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java new file mode 100644 index 00000000..2cb7e02e --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysBootstrapHookInfo.java @@ -0,0 +1,16 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.HandleBindAppHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.LoadedApkConstructorHooker; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; +import com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java new file mode 100644 index 00000000..a185c0df --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/SysInnerHookInfo.java @@ -0,0 +1,10 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.StartBootstrapServicesHooker; + +public class SysInnerHookInfo implements KeepMembers { + public static String[] hookItemNames = { + StartBootstrapServicesHooker.class.getName() + }; +} diff --git a/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java new file mode 100644 index 00000000..f0c5f065 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/bootstrap/WorkAroundHookInfo.java @@ -0,0 +1,10 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.bootstrap; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.entry.hooker.OnePlusWorkAroundHooker; + +public class WorkAroundHookInfo implements KeepMembers { + public static String[] hookItemNames = { + OnePlusWorkAroundHooker.class.getName() + }; +} 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 new file mode 100644 index 00000000..12d7ef2c --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/HandleBindAppHooker.java @@ -0,0 +1,89 @@ +package com.elderdrivers.riru.edxp.yahfa.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.yahfa.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.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java new file mode 100644 index 00000000..ce2f7605 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/LoadedApkConstructorHooker.java @@ -0,0 +1,98 @@ +package com.elderdrivers.riru.edxp.yahfa.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.yahfa.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-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 new file mode 100644 index 00000000..f3261f9d --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/OnePlusWorkAroundHooker.java @@ -0,0 +1,41 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.Main; +import com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java new file mode 100644 index 00000000..7bc1c542 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/StartBootstrapServicesHooker.java @@ -0,0 +1,66 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; + +import android.os.Build; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java new file mode 100644 index 00000000..2478f2e6 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/SystemMainHooker.java @@ -0,0 +1,43 @@ +package com.elderdrivers.riru.edxp.yahfa.entry.hooker; + +import android.app.ActivityThread; + +import com.elderdrivers.riru.common.KeepMembers; +import com.elderdrivers.riru.edxp.yahfa.util.PrebuiltMethodsDeopter; +import com.elderdrivers.riru.edxp.yahfa.entry.Router; + +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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java new file mode 100644 index 00000000..7261f63b --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedBlackListHooker.java @@ -0,0 +1,87 @@ +package com.elderdrivers.riru.edxp.yahfa.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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java new file mode 100644 index 00000000..07931306 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/entry/hooker/XposedInstallerHooker.java @@ -0,0 +1,64 @@ +package com.elderdrivers.riru.edxp.yahfa.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-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 new file mode 100644 index 00000000..ba9842d9 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/BlackWhiteListProxy.java @@ -0,0 +1,132 @@ +package com.elderdrivers.riru.edxp.yahfa.proxy; + +import android.text.TextUtils; + +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; +import com.elderdrivers.riru.edxp.util.ProcessUtils; +import com.elderdrivers.riru.edxp.util.Utils; + +import de.robv.android.xposed.XposedBridge; + +import static com.elderdrivers.riru.edxp.Main.isAppNeedHook; +import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix; + +/** + * 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-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 new file mode 100644 index 00000000..9c1d3dba --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/proxy/NormalProxy.java @@ -0,0 +1,70 @@ +package com.elderdrivers.riru.edxp.yahfa.proxy; + +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; + +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-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java new file mode 100644 index 00000000..15fffeb0 --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/InlinedMethodCallers.java @@ -0,0 +1,49 @@ +package com.elderdrivers.riru.edxp.yahfa.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-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 new file mode 100644 index 00000000..ecd8813d --- /dev/null +++ b/edxp-yahfa/src/main/java/com/elderdrivers/riru/edxp/yahfa/util/PrebuiltMethodsDeopter.java @@ -0,0 +1,41 @@ +package com.elderdrivers.riru.edxp.yahfa.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.yahfa.util.InlinedMethodCallers.KEY_BOOT_IMAGE; +import static com.elderdrivers.riru.edxp.yahfa.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-yahfa/template_override/system/lib/libwhale.edxp.so b/edxp-yahfa/template_override/system/lib/libwhale.edxp.so new file mode 100755 index 00000000..187d0495 Binary files /dev/null and b/edxp-yahfa/template_override/system/lib/libwhale.edxp.so differ diff --git a/edxp-yahfa/template_override/system/lib64/libwhale.edxp.so b/edxp-yahfa/template_override/system/lib64/libwhale.edxp.so new file mode 100755 index 00000000..3c2cd0d8 Binary files /dev/null and b/edxp-yahfa/template_override/system/lib64/libwhale.edxp.so differ diff --git a/edxp-yahfa/template_override/system_x86/lib/libwhale.edxp.so b/edxp-yahfa/template_override/system_x86/lib/libwhale.edxp.so new file mode 100755 index 00000000..d1653bcc Binary files /dev/null and b/edxp-yahfa/template_override/system_x86/lib/libwhale.edxp.so differ diff --git a/edxp-yahfa/template_override/system_x86/lib64/libwhale.edxp.so b/edxp-yahfa/template_override/system_x86/lib64/libwhale.edxp.so new file mode 100755 index 00000000..f5bcdc5a Binary files /dev/null and b/edxp-yahfa/template_override/system_x86/lib64/libwhale.edxp.so differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9a4163a4..4e974715 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/hiddenapistubs/.gitignore b/hiddenapi-stubs/.gitignore similarity index 100% rename from hiddenapistubs/.gitignore rename to hiddenapi-stubs/.gitignore diff --git a/hiddenapistubs/build.gradle b/hiddenapi-stubs/build.gradle similarity index 100% rename from hiddenapistubs/build.gradle rename to hiddenapi-stubs/build.gradle diff --git a/hiddenapistubs/src/main/AndroidManifest.xml b/hiddenapi-stubs/src/main/AndroidManifest.xml similarity index 100% rename from hiddenapistubs/src/main/AndroidManifest.xml rename to hiddenapi-stubs/src/main/AndroidManifest.xml diff --git a/hiddenapistubs/src/main/java/android/app/ActivityThread.java b/hiddenapi-stubs/src/main/java/android/app/ActivityThread.java similarity index 100% rename from hiddenapistubs/src/main/java/android/app/ActivityThread.java rename to hiddenapi-stubs/src/main/java/android/app/ActivityThread.java diff --git a/hiddenapistubs/src/main/java/android/app/LoadedApk.java b/hiddenapi-stubs/src/main/java/android/app/LoadedApk.java similarity index 100% rename from hiddenapistubs/src/main/java/android/app/LoadedApk.java rename to hiddenapi-stubs/src/main/java/android/app/LoadedApk.java diff --git a/hiddenapistubs/src/main/java/android/content/pm/PackageParser.java b/hiddenapi-stubs/src/main/java/android/content/pm/PackageParser.java similarity index 100% rename from hiddenapistubs/src/main/java/android/content/pm/PackageParser.java rename to hiddenapi-stubs/src/main/java/android/content/pm/PackageParser.java diff --git a/hiddenapistubs/src/main/java/android/content/res/AssetManager.java b/hiddenapi-stubs/src/main/java/android/content/res/AssetManager.java similarity index 100% rename from hiddenapistubs/src/main/java/android/content/res/AssetManager.java rename to hiddenapi-stubs/src/main/java/android/content/res/AssetManager.java diff --git a/hiddenapistubs/src/main/java/android/content/res/CompatibilityInfo.java b/hiddenapi-stubs/src/main/java/android/content/res/CompatibilityInfo.java similarity index 100% rename from hiddenapistubs/src/main/java/android/content/res/CompatibilityInfo.java rename to hiddenapi-stubs/src/main/java/android/content/res/CompatibilityInfo.java diff --git a/hiddenapistubs/src/main/java/android/content/res/Resources.java b/hiddenapi-stubs/src/main/java/android/content/res/Resources.java similarity index 100% rename from hiddenapistubs/src/main/java/android/content/res/Resources.java rename to hiddenapi-stubs/src/main/java/android/content/res/Resources.java diff --git a/hiddenapistubs/src/main/java/android/content/res/TypedArray.java b/hiddenapi-stubs/src/main/java/android/content/res/TypedArray.java similarity index 100% rename from hiddenapistubs/src/main/java/android/content/res/TypedArray.java rename to hiddenapi-stubs/src/main/java/android/content/res/TypedArray.java diff --git a/hiddenapistubs/src/main/java/android/os/SELinux.java b/hiddenapi-stubs/src/main/java/android/os/SELinux.java similarity index 100% rename from hiddenapistubs/src/main/java/android/os/SELinux.java rename to hiddenapi-stubs/src/main/java/android/os/SELinux.java diff --git a/hiddenapistubs/src/main/java/android/os/ServiceManager.java b/hiddenapi-stubs/src/main/java/android/os/ServiceManager.java similarity index 100% rename from hiddenapistubs/src/main/java/android/os/ServiceManager.java rename to hiddenapi-stubs/src/main/java/android/os/ServiceManager.java diff --git a/hiddenapistubs/src/main/java/com/android/internal/os/RuntimeInit.java b/hiddenapi-stubs/src/main/java/com/android/internal/os/RuntimeInit.java similarity index 100% rename from hiddenapistubs/src/main/java/com/android/internal/os/RuntimeInit.java rename to hiddenapi-stubs/src/main/java/com/android/internal/os/RuntimeInit.java diff --git a/hiddenapistubs/src/main/java/com/android/internal/os/ZygoteInit.java b/hiddenapi-stubs/src/main/java/com/android/internal/os/ZygoteInit.java similarity index 100% rename from hiddenapistubs/src/main/java/com/android/internal/os/ZygoteInit.java rename to hiddenapi-stubs/src/main/java/com/android/internal/os/ZygoteInit.java diff --git a/hiddenapistubs/src/main/java/com/android/internal/util/XmlUtils.java b/hiddenapi-stubs/src/main/java/com/android/internal/util/XmlUtils.java similarity index 100% rename from hiddenapistubs/src/main/java/com/android/internal/util/XmlUtils.java rename to hiddenapi-stubs/src/main/java/com/android/internal/util/XmlUtils.java diff --git a/hiddenapistubs/src/main/java/dalvik/system/BaseDexClassLoader.java b/hiddenapi-stubs/src/main/java/dalvik/system/BaseDexClassLoader.java similarity index 100% rename from hiddenapistubs/src/main/java/dalvik/system/BaseDexClassLoader.java rename to hiddenapi-stubs/src/main/java/dalvik/system/BaseDexClassLoader.java diff --git a/hiddenapistubs/src/main/java/xposed/dummy/XResourcesSuperClass.java b/hiddenapi-stubs/src/main/java/xposed/dummy/XResourcesSuperClass.java similarity index 100% rename from hiddenapistubs/src/main/java/xposed/dummy/XResourcesSuperClass.java rename to hiddenapi-stubs/src/main/java/xposed/dummy/XResourcesSuperClass.java diff --git a/hiddenapistubs/src/main/java/xposed/dummy/XTypedArraySuperClass.java b/hiddenapi-stubs/src/main/java/xposed/dummy/XTypedArraySuperClass.java similarity index 100% rename from hiddenapistubs/src/main/java/xposed/dummy/XTypedArraySuperClass.java rename to hiddenapi-stubs/src/main/java/xposed/dummy/XTypedArraySuperClass.java diff --git a/settings.gradle b/settings.gradle index d61f9317..c40d4f51 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':Core', ':Bridge', ':hiddenapistubs', ':dexmaker', ':dalvikdx' \ No newline at end of file +include ':edxp-core', ':xposed-bridge', ':hiddenapi-stubs', ':dexmaker', ':dalvikdx', ':edxp-common', ':edxp-yahfa', ':edxp-sandhook', ':edxp-whale' \ No newline at end of file diff --git a/xposed-bridge/.gitignore b/xposed-bridge/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/xposed-bridge/.gitignore @@ -0,0 +1 @@ +/build diff --git a/xposed-bridge/build.gradle b/xposed-bridge/build.gradle new file mode 100644 index 00000000..08f13feb --- /dev/null +++ b/xposed-bridge/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + buildToolsVersion '28.0.3' + + defaultConfig { + multiDexEnabled false + minSdkVersion 23 + } + + sourceSets { + main { + java.srcDirs += ['src/main/apacheCommonsLang'] + } + } + + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +// Make sure that hiddenapistubs are placed before the Android SDK in xposed-bridge.iml +// as there doesn't seem to be any way to configure this in Android Studio. +preBuild.doLast { + def imlFile = file(project.name + ".iml") + 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 + } +} + +dependencies { + compileOnly files("libs/framework-stub.jar") + compileOnly project(':dexmaker') +} + +afterEvaluate { + + tasks.withType(JavaCompile) { + options.compilerArgs.add("-Xbootclasspath/p:${projectDir.absolutePath}/libs/framework-stub.jar") + } + +} \ No newline at end of file diff --git a/xposed-bridge/libs/framework-stub.jar b/xposed-bridge/libs/framework-stub.jar new file mode 100644 index 00000000..36cd86b3 Binary files /dev/null and b/xposed-bridge/libs/framework-stub.jar differ diff --git a/xposed-bridge/proguard-rules.pro b/xposed-bridge/proguard-rules.pro new file mode 100644 index 00000000..e72d685a --- /dev/null +++ b/xposed-bridge/proguard-rules.pro @@ -0,0 +1,25 @@ +# 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.** { *; } \ No newline at end of file diff --git a/Bridge/src/main/AndroidManifest.xml b/xposed-bridge/src/main/AndroidManifest.xml similarity index 59% rename from Bridge/src/main/AndroidManifest.xml rename to xposed-bridge/src/main/AndroidManifest.xml index 4208d992..cd2f6ed7 100644 --- a/Bridge/src/main/AndroidManifest.xml +++ b/xposed-bridge/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ - diff --git a/Bridge/src/main/apacheCommonsLang/LICENSE.txt b/xposed-bridge/src/main/apacheCommonsLang/LICENSE.txt similarity index 100% rename from Bridge/src/main/apacheCommonsLang/LICENSE.txt rename to xposed-bridge/src/main/apacheCommonsLang/LICENSE.txt diff --git a/Bridge/src/main/apacheCommonsLang/MODIFICATIONS.txt b/xposed-bridge/src/main/apacheCommonsLang/MODIFICATIONS.txt similarity index 100% rename from Bridge/src/main/apacheCommonsLang/MODIFICATIONS.txt rename to xposed-bridge/src/main/apacheCommonsLang/MODIFICATIONS.txt diff --git a/Bridge/src/main/apacheCommonsLang/NOTICE.txt b/xposed-bridge/src/main/apacheCommonsLang/NOTICE.txt similarity index 100% rename from Bridge/src/main/apacheCommonsLang/NOTICE.txt rename to xposed-bridge/src/main/apacheCommonsLang/NOTICE.txt diff --git a/Bridge/src/main/apacheCommonsLang/RELEASE-NOTES.txt b/xposed-bridge/src/main/apacheCommonsLang/RELEASE-NOTES.txt similarity index 100% rename from Bridge/src/main/apacheCommonsLang/RELEASE-NOTES.txt rename to xposed-bridge/src/main/apacheCommonsLang/RELEASE-NOTES.txt diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ArrayUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ArrayUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ArrayUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ArrayUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharSequenceUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharSequenceUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharSequenceUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharSequenceUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/CharUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ClassUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ClassUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ClassUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ClassUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/JavaVersion.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/JavaVersion.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/JavaVersion.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/JavaVersion.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ObjectUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ObjectUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ObjectUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/ObjectUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/StringUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/StringUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/StringUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/StringUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/SystemUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/SystemUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/SystemUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/SystemUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/Validate.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/Validate.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/Validate.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/Validate.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/Builder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/Builder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/Builder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/Builder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/CompareToBuilder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/CompareToBuilder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/CompareToBuilder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/CompareToBuilder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/EqualsBuilder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/EqualsBuilder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/EqualsBuilder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/EqualsBuilder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/HashCodeBuilder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/HashCodeBuilder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/HashCodeBuilder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/HashCodeBuilder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/IDKey.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/IDKey.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/IDKey.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/IDKey.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ReflectionToStringBuilder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringBuilder.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringBuilder.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringBuilder.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringBuilder.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringStyle.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringStyle.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringStyle.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/ToStringStyle.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/builder/package.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/CloneFailedException.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/CloneFailedException.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/CloneFailedException.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/CloneFailedException.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/exception/package.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/Mutable.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/Mutable.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/Mutable.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/Mutable.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/MutableInt.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/MutableInt.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/MutableInt.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/MutableInt.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/mutable/package.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/overview.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/overview.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/overview.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/overview.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/package.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MemberUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MemberUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MemberUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MemberUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MethodUtils.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MethodUtils.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MethodUtils.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/MethodUtils.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/reflect/package.html diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/ImmutablePair.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/ImmutablePair.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/ImmutablePair.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/ImmutablePair.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/Pair.java b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/Pair.java similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/Pair.java rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/Pair.java diff --git a/Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/package.html b/xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/package.html similarity index 100% rename from Bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/package.html rename to xposed-bridge/src/main/apacheCommonsLang/external/org/apache/commons/lang3/tuple/package.html diff --git a/Bridge/src/main/java/android/app/AndroidAppHelper.java b/xposed-bridge/src/main/java/android/app/AndroidAppHelper.java similarity index 100% rename from Bridge/src/main/java/android/app/AndroidAppHelper.java rename to xposed-bridge/src/main/java/android/app/AndroidAppHelper.java diff --git a/Bridge/src/main/java/android/app/package-info.java b/xposed-bridge/src/main/java/android/app/package-info.java similarity index 100% rename from Bridge/src/main/java/android/app/package-info.java rename to xposed-bridge/src/main/java/android/app/package-info.java diff --git a/Bridge/src/main/java/android/content/res/XModuleResources.java b/xposed-bridge/src/main/java/android/content/res/XModuleResources.java similarity index 100% rename from Bridge/src/main/java/android/content/res/XModuleResources.java rename to xposed-bridge/src/main/java/android/content/res/XModuleResources.java diff --git a/Bridge/src/main/java/android/content/res/XResForwarder.java b/xposed-bridge/src/main/java/android/content/res/XResForwarder.java similarity index 100% rename from Bridge/src/main/java/android/content/res/XResForwarder.java rename to xposed-bridge/src/main/java/android/content/res/XResForwarder.java diff --git a/Bridge/src/main/java/android/content/res/XResources.java b/xposed-bridge/src/main/java/android/content/res/XResources.java similarity index 100% rename from Bridge/src/main/java/android/content/res/XResources.java rename to xposed-bridge/src/main/java/android/content/res/XResources.java diff --git a/Bridge/src/main/java/android/content/res/package-info.java b/xposed-bridge/src/main/java/android/content/res/package-info.java similarity index 100% rename from Bridge/src/main/java/android/content/res/package-info.java rename to xposed-bridge/src/main/java/android/content/res/package-info.java diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java new file mode 100644 index 00000000..9ec66244 --- /dev/null +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfig.java @@ -0,0 +1,12 @@ +package com.elderdrivers.riru.edxp.config; + +public interface EdXpConfig { + + + String getInstallerBaseDir(); + + String getBlackListModulePackageName(); + + boolean isDynamicModulesMode(); + +} diff --git a/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java new file mode 100644 index 00000000..cc88f03f --- /dev/null +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/config/EdXpConfigGlobal.java @@ -0,0 +1,77 @@ +package com.elderdrivers.riru.edxp.config; + +import com.elderdrivers.riru.edxp.hook.HookProvider; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +public class EdXpConfigGlobal { + + public static volatile EdXpConfig sConfig; + public static volatile HookProvider sHookProvider; + + public static EdXpConfig getConfig() { + if (sConfig == null) { + return defaultConfig; + } + return sConfig; + } + + public static HookProvider getHookProvider() { + if (sHookProvider == null) { + return defaultHookProvider; + } + return sHookProvider; + } + + + private static final EdXpConfig defaultConfig = new EdXpConfig() { + + @Override + public String getInstallerBaseDir() { + return ""; + } + + @Override + public String getBlackListModulePackageName() { + return ""; + } + + @Override + public boolean isDynamicModulesMode() { + return false; + } + }; + + + private static final HookProvider defaultHookProvider = new HookProvider() { + + @Override + public void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo) { + + } + + @Override + public Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + return null; + } + + @Override + public Member findMethodNative(Member hookMethod) { + return hookMethod; + } + + @Override + public void deoptMethods(String packageName, ClassLoader classLoader) { + + } + + @Override + public long getMethodId(Member member) { + return 0; + } + }; +} 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 new file mode 100644 index 00000000..9e630e78 --- /dev/null +++ b/xposed-bridge/src/main/java/com/elderdrivers/riru/edxp/hook/HookProvider.java @@ -0,0 +1,18 @@ +package com.elderdrivers.riru.edxp.hook; + +import java.lang.reflect.Member; + +import de.robv.android.xposed.XposedBridge; + +public interface HookProvider { + + void hookMethod(Member method, XposedBridge.AdditionalHookInfo additionalInfo); + + Object invokeOriginalMethod(Member method, long methodId, Object thisObject, Object[] args) throws Throwable; + + Member findMethodNative(Member hookMethod); + + void deoptMethods(String packageName, ClassLoader classLoader); + + long getMethodId(Member member); +} diff --git a/Bridge/src/main/java/de/robv/android/xposed/DexCreator.java b/xposed-bridge/src/main/java/de/robv/android/xposed/DexCreator.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/DexCreator.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/DexCreator.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/IXposedHookCmdInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookCmdInit.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/IXposedHookCmdInit.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookCmdInit.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/IXposedHookInitPackageResources.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookInitPackageResources.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/IXposedHookInitPackageResources.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookInitPackageResources.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/IXposedHookLoadPackage.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookLoadPackage.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/IXposedHookLoadPackage.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookLoadPackage.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/IXposedHookZygoteInit.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/IXposedMod.java b/xposed-bridge/src/main/java/de/robv/android/xposed/IXposedMod.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/IXposedMod.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/IXposedMod.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java b/xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/SELinuxHelper.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/XC_MethodHook.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodHook.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/XC_MethodHook.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodHook.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XC_MethodReplacement.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XSharedPreferences.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/XposedBridge.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java similarity index 93% rename from Bridge/src/main/java/de/robv/android/xposed/XposedBridge.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java index 82972fed..204a0b04 100644 --- a/Bridge/src/main/java/de/robv/android/xposed/XposedBridge.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedBridge.java @@ -3,9 +3,7 @@ package de.robv.android.xposed; import android.annotation.SuppressLint; import android.util.Log; -import com.elderdrivers.riru.xposed.core.HookMain; -import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge; -import com.elderdrivers.riru.xposed.dexmaker.MethodInfo; +import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import java.io.File; import java.io.IOException; @@ -62,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<>(); @@ -198,15 +196,7 @@ public final class XposedBridge { } AdditionalHookInfo additionalInfo = new AdditionalHookInfo(callbacks, parameterTypes, returnType); - MethodInfo methodInfo = new MethodInfo(hookMethod); - declaringClass = methodInfo.getClassForSure(); - Member reflectMethod = (Member) HookMain.findMethod( - declaringClass, methodInfo.methodName, methodInfo.methodSig); - if (reflectMethod == null) { - Log.e(TAG, "method not found: name=" - + methodInfo.methodName + ", sig=" + methodInfo.methodSig); - reflectMethod = hookMethod; - } + Member reflectMethod = EdXpConfigGlobal.getHookProvider().findMethodNative(hookMethod); hookMethodNative(reflectMethod, declaringClass, slot, additionalInfo); } @@ -270,7 +260,7 @@ public final class XposedBridge { /** * This method is called as a replacement for hooked methods. */ - private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj, + public static Object handleHookedMethod(Member method, long originalMethodId, Object additionalInfoObj, Object thisObject, Object[] args) throws Throwable { AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj; @@ -405,15 +395,15 @@ public final class XposedBridge { */ private synchronized static void hookMethodNative(final Member method, Class declaringClass, int slot, final Object additionalInfoObj) { - DynamicBridge.hookMethod(method, (AdditionalHookInfo) additionalInfoObj); + EdXpConfigGlobal.getHookProvider().hookMethod(method, (AdditionalHookInfo) additionalInfoObj); } - private static Object invokeOriginalMethodNative(Member method, int methodId, + private static Object invokeOriginalMethodNative(Member method, long methodId, Class[] parameterTypes, Class returnType, Object thisObject, Object[] args) - throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { - return DynamicBridge.invokeOriginalMethod(method, thisObject, args); + throws Throwable { + return EdXpConfigGlobal.getHookProvider().invokeOriginalMethod(method, methodId, thisObject, args); } /** @@ -442,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; } @@ -462,7 +452,8 @@ public final class XposedBridge { throw new IllegalArgumentException("method must be of type Method or Constructor"); } - return invokeOriginalMethodNative(method, 0, parameterTypes, returnType, thisObject, args); + long methodId = EdXpConfigGlobal.getHookProvider().getMethodId(method); + return invokeOriginalMethodNative(method, methodId, parameterTypes, returnType, thisObject, args); } /*package*/ static void setObjectClass(Object obj, Class clazz) { diff --git a/Bridge/src/main/java/de/robv/android/xposed/XposedHelpers.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedHelpers.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/XposedHelpers.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XposedHelpers.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java similarity index 86% rename from Bridge/src/main/java/de/robv/android/xposed/XposedInit.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java index 20700ebb..bba953fd 100644 --- a/Bridge/src/main/java/de/robv/android/xposed/XposedInit.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/XposedInit.java @@ -1,15 +1,11 @@ package de.robv.android.xposed; -import android.app.AndroidAppHelper; import android.os.Build; import android.text.TextUtils; import android.util.Log; import com.android.internal.os.ZygoteInit; -import com.elderdrivers.riru.xposed.BuildConfig; -import com.elderdrivers.riru.xposed.config.ConfigManager; -import com.elderdrivers.riru.xposed.entry.Router; -import com.elderdrivers.riru.xposed.util.Utils; +import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import java.io.BufferedReader; import java.io.File; @@ -25,8 +21,6 @@ import dalvik.system.DexFile; import dalvik.system.PathClassLoader; import de.robv.android.xposed.services.BaseService; -import static com.elderdrivers.riru.xposed.config.InstallerChooser.INSTALLER_DATA_BASE_DIR; -import static com.elderdrivers.riru.xposed.entry.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME; import static de.robv.android.xposed.XposedHelpers.closeSilently; import static de.robv.android.xposed.XposedHelpers.findClass; import static de.robv.android.xposed.XposedHelpers.findFieldIfExists; @@ -46,18 +40,11 @@ public final class XposedInit { private XposedInit() { } - private static volatile AtomicBoolean bootstrapHooked = new AtomicBoolean(false); - /** * Hook some methods which we want to create an easier interface for developers. */ /*package*/ public static void initForZygote(boolean isSystem) throws Throwable { - if (!bootstrapHooked.compareAndSet(false, true)) { - return; - } - Router.startBootstrapHook(isSystem); - // TODO Are these still needed for us? // MIUI if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) { @@ -91,12 +78,12 @@ public final class XposedInit { public static void loadModules(boolean isInZygote) throws IOException { boolean hasLoaded = !modulesLoaded.compareAndSet(false, true); // dynamic module list mode doesn't apply to loading in zygote - if (hasLoaded && (isInZygote || !ConfigManager.isDynamicModulesMode())) { + if (hasLoaded && (isInZygote || !EdXpConfigGlobal.getConfig().isDynamicModulesMode())) { return; } // FIXME module list is cleared but never could be reload again when using dynamic-module-list under multi-user environment XposedBridge.clearLoadedPackages(); - final String filename = INSTALLER_DATA_BASE_DIR + "conf/modules.list"; + final String filename = EdXpConfigGlobal.getConfig().getInstallerBaseDir() + "conf/modules.list"; BaseService service = SELinuxHelper.getAppDataFileService(); if (!service.checkFileExists(filename)) { Log.e(TAG, "Cannot load any modules because " + filename + " was not found"); @@ -126,7 +113,10 @@ public final class XposedInit { private static void loadModule(String apk, ClassLoader topClassLoader) { Log.i(TAG, "Loading modules from " + apk); - if (!TextUtils.isEmpty(apk) && apk.contains(BLACK_LIST_PACKAGE_NAME)) { + // todo remove this legacy logic + String blackListModulePackageName = EdXpConfigGlobal.getConfig().getBlackListModulePackageName(); + if (!TextUtils.isEmpty(apk) && !TextUtils.isEmpty(blackListModulePackageName) + && apk.contains(blackListModulePackageName)) { Log.i(TAG, "We are going to take over black list's job..."); return; } @@ -234,14 +224,4 @@ public final class XposedInit { } public final static HashSet loadedPackagesInProcess = new HashSet<>(1); - - 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); - } } diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/IXUnhook.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/IXUnhook.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/IXUnhook.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/IXUnhook.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_InitPackageResources.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LayoutInflated.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LayoutInflated.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LayoutInflated.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LayoutInflated.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XC_LoadPackage.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java similarity index 95% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java index 4de87157..b8976e57 100644 --- a/Bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java +++ b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/XCallback.java @@ -2,8 +2,7 @@ package de.robv.android.xposed.callbacks; import android.os.Bundle; -import com.elderdrivers.riru.xposed.entry.Router; -import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter; +import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal; import java.io.Serializable; @@ -106,7 +105,7 @@ public abstract class XCallback implements Comparable { // deopt methods in system apps or priv-apps, this would be not necessary // only if we found out how to recompile their apks XC_LoadPackage.LoadPackageParam lpp = (XC_LoadPackage.LoadPackageParam) param; - PrebuiltMethodsDeopter.deoptMethods(lpp.packageName, lpp.classLoader); + EdXpConfigGlobal.getHookProvider().deoptMethods(lpp.packageName, lpp.classLoader); } if (param.callbacks == null) diff --git a/Bridge/src/main/java/de/robv/android/xposed/callbacks/package-info.java b/xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/package-info.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/callbacks/package-info.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/callbacks/package-info.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/package-info.java b/xposed-bridge/src/main/java/de/robv/android/xposed/package-info.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/package-info.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/package-info.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/BaseService.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/BaseService.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/BaseService.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/BaseService.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/BinderService.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/BinderService.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/BinderService.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/BinderService.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/DirectAccessService.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/DirectAccessService.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/DirectAccessService.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/DirectAccessService.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/FileResult.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/FileResult.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/FileResult.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/FileResult.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/ZygoteService.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/ZygoteService.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/ZygoteService.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/ZygoteService.java diff --git a/Bridge/src/main/java/de/robv/android/xposed/services/package-info.java b/xposed-bridge/src/main/java/de/robv/android/xposed/services/package-info.java similarity index 100% rename from Bridge/src/main/java/de/robv/android/xposed/services/package-info.java rename to xposed-bridge/src/main/java/de/robv/android/xposed/services/package-info.java