This commit is contained in:
Shauli Bracha 2019-03-26 09:00:21 +02:00
commit 7504dd878f
316 changed files with 11306 additions and 575 deletions

View File

@ -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"
// }
}
}

View File

@ -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;
}
}

7
Core/.gitignore vendored
View File

@ -1,7 +0,0 @@
/.externalNativeBuild
/build
/libs
/obj
/release
/template_override/system/framework/edxposed.dex
*.iml

View File

@ -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)
}
}

View File

@ -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

View File

@ -1 +0,0 @@
<manifest package="com.elderdrivers.riru.xposed" />

View File

@ -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

View File

@ -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()

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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();

48
edxp-common/build.gradle Normal file
View File

@ -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")
}
}

View File

@ -0,0 +1 @@
<manifest package="com.elderdrivers.riru.edxp.common" />

View File

@ -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 {

View File

@ -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)) {

View File

@ -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);
}

View File

@ -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.

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

8
edxp-core/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
/.externalNativeBuild
/build
/libs
/obj
/release
/template_override/system
/template_override/system_x86
*.iml

117
edxp-core/build.gradle Normal file
View File

@ -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}"
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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) \

View File

@ -0,0 +1 @@
<manifest package="com.elderdrivers.riru.edxp" />

View File

@ -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`

View File

@ -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 "************************************"
}

View File

@ -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

View File

@ -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.

2
edxp-sandhook/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
/template_override/system/framework/edxp.jar

View File

@ -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 }
}
}
}

View File

@ -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.

33
edxp-sandhook/proguard-rules.pro vendored Normal file
View File

@ -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.** {*;}

View File

@ -0,0 +1 @@
<manifest package="com.elderdrivers.riru.edxp.sandhook" />

View File

@ -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