Merge branch 'master' of https://github.com/ElderDrivers/EdXposed
This commit is contained in:
commit
7504dd878f
|
|
@ -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"
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
/.externalNativeBuild
|
||||
/build
|
||||
/libs
|
||||
/obj
|
||||
/release
|
||||
/template_override/system/framework/edxposed.dex
|
||||
*.iml
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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
|
||||
|
|
@ -1 +0,0 @@
|
|||
<manifest package="com.elderdrivers.riru.xposed" />
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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
|
||||
|
||||
|
|
|
|||
15
build.gradle
15
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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<manifest package="com.elderdrivers.riru.edxp.common" />
|
||||
|
|
@ -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 {
|
||||
|
||||
|
|
@ -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)) {
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -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 {
|
||||
|
||||
|
|
@ -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
|
||||
* <p>
|
||||
* use {@link com.elderdrivers.riru.xposed.Main#appProcessName} to get current process name
|
||||
*/
|
||||
public static String getProcessName(int pid) {
|
||||
BufferedReader cmdlineReader = null;
|
||||
|
|
@ -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 {
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/.externalNativeBuild
|
||||
/build
|
||||
/libs
|
||||
/obj
|
||||
/release
|
||||
/template_override/system
|
||||
/template_override/system_x86
|
||||
*.iml
|
||||
|
|
@ -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}"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#include <jni.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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<bool *(*)(JNIEnv *, jclass,
|
||||
jclass)>(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) {
|
||||
|
|
@ -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) \
|
||||
|
|
@ -0,0 +1 @@
|
|||
<manifest package="com.elderdrivers.riru.edxp" />
|
||||
|
|
@ -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`
|
||||
|
|
@ -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 "************************************"
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/build
|
||||
/template_override/system/framework/edxp.jar
|
||||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"))
|
||||
Binary file not shown.
|
|
@ -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.** {*;}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<manifest package="com.elderdrivers.riru.edxp.sandhook" />
|
||||
|
|
@ -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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue