Merge remote-tracking branch 'origin/master'

This commit is contained in:
ganyao114 2020-04-27 13:18:31 +08:00
commit 30b18e0d51
61 changed files with 1207 additions and 1178 deletions

View File

@ -1,18 +1,22 @@
# EdXposed
# EdXposed Framework
Latest builds: [![Build status](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master)
[![Latest builds](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master) [![中文说明文档](art/README_CN.png)](README_CN.md)
A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework.
## Introduction
## Supported versions
A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework, supports Android 8.0 ~ **10**.
- Android Oreo (8.x)
- Android Pie (9.0)
- Android 10
> Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo. As all changes are done in the memory, you just need to deactivate the module and reboot to get your original system back. There are many other advantages, but here is just one more: Multiple modules can do changes to the same part of the system or app. With modified APKs, you to decide for one. No way to combine them, unless the author builds multiple APKs with different combinations.
## Supported Versions
- Android Q (10)[sdk29]
- Android Pie (9)[sdk28]
- Android Oreo (8.x)[sdk26/27]
For Android Nougat (7.x) and lower, please use the original Xposed Framework.
## Build requirements
## Build Requirements
Same as [Riru-Core's](https://github.com/RikkaApps/Riru/blob/master/README.md#build-requirements)
and zip binaries can be downloaded from [here](http://gnuwin32.sourceforge.net/packages/zip.htm).
@ -25,41 +29,63 @@ and zip binaries can be downloaded from [here](http://gnuwin32.sourceforge.net/p
## Install
1. Install Magisk v19.0+ (for latest EdXposed or Huawei devices, use our custom Magisk: Change Magisk update channel to [this](http://edxp.meowcat.org/repo/version.json)).
1. Install Magisk v19+ (for Huawei/Honor or OnePlus 7T/7TPro device, need Magisk v20.2+)
2. Install [Riru-Core](https://github.com/RikkaApps/Riru/releases) v19+ from Magisk repo.
3. Download [EdXposed](https://github.com/solohsu/EdXposed/releases) and install it in Magisk Manager or recovery mode.
3. [Download](#download) and install EdXposed in Magisk Manager or recovery mode.
4. Install [companion application](#companion-applications).
4. Reboot.
5. Have fun! :)
## Companion applications
## Download
Edxposed has three different builds
- StableStable version after passing the test, suitable for general users, update slowly.
***Download Stable version in Magisk Manager's [Downloads] tab***
- Alpha: Test version with multiple commits.
***Download Alpha version in [[Github Releases](https://github.com/ElderDrivers/EdXposed/releases)]***
- Canary: Debug version. Automatically build by CI.
***Download Canary version in [[EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)]***
## Companion Applications
> Both Xposed Installer and EdXposed Installer are deprecated. Support will be stopped for later versions. Please use [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)
- For v0.2.9.5 and before: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller).
- For v0.2.9.6 and v0.2.9.7: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller) + [EdXp Manager](https://github.com/solohsu/EdXpManager)(optional).
- For v0.2.9.8 and later: [EdXposed Installer](https://github.com/solohsu/XposedInstaller) and [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager).
- For the latest version, we recommend to use [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager).
## Useful links
## Useful Links
- [List of Xposed Modules For Android Pie Working With EdXposed](https://forum.xda-developers.com/xposed/list-xposed-modules-android-pie-ed-t3892768) (thanks to Uraniam9 @ xda-developers)
## Known issues
## Known Issues
- May not be compatible with all ART devices.
- File access services are not implemented yet, now EdXp simply uses magiskpolicy to enable needed SELinux policies.
- Dynamic modules not work, caused by SELinux.
See [Wiki: Known issues or bugs](https://github.com/ElderDrivers/EdXposed/wiki/Known-issues-or-bugs)
## Get help
## Get Help
- GitHub issues: [Issues](https://github.com/solohsu/EdXposed/issues/)
- GitHub issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/)
Notice(for Chinese): 鉴于部分用户提交的Issues质量过低对于中文用户反馈请先阅读[EdXposed错误提交说明_cn](https://raw.githubusercontent.com/ElderDrivers/Repository-Website/gh-pages/repo/EdXposedIssuesReport_cn.txt)(不看说明提交的Issue会有很大可能被close)
- Notice(for Chinese): In view of the low quality of issues submitted, please read the Chinese user report first[EdXposedIssuesReport_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(If you don't read the instructions, the submitted issue is likely to be closed)
## Community
## For Developers
Developers are welcomed to write Xposed modules with hooks based on EdXposed Framework. Module written based on EdXposed framework is fully compatible with the original Xposed Framework, so contrary a Xposed Framework-based module will work well with the EdXposed framework too.
- [Xposed Framework API](https://api.xposed.info/)
We use the module repository of the original Xposed, so you simply upload the module to repository, then you can download your module in EdXposed.
- [Xposed Module Repository](https://repo.xposed.info/)
## Community Discussion
- QQ Group: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f)
- Telegram: [Code_of_MeowCat](http://t.me/Code_of_MeowCat)
- Discord (not recommended): [Code_of_MeowCat](https://discord.gg/Hag6gNh)
- Telegram: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat)
Notice: These community group don't accept any bug report, please use [Get help](#get-help) to report.

96
README_CN.md Normal file
View File

@ -0,0 +1,96 @@
# EdXposed Framework
[![最新构建](https://ci.appveyor.com/api/projects/status/qu3vj1d64nqia1b8/branch/master?svg=true)](https://ci.appveyor.com/project/ElderDrivers/edxposed/branch/master) [![English](art/README_EN.png)](README.md)
## Introduction
基于 Riru 的 ART hook 框架 (最初用于 Android Pie) ,提供与原版 Xposed 相同的 API, 使用 YAHFA (或 SandHook) 进行 hook, supports Android 8.0 ~ **10**.
> Xposed 框架是一套开放源代码的、在Android高权限模式下运行的框架服务可以在不修改APK文件的情况下修改程序的运行基于它可以制作出许多功能强大的模块且在功能不冲突的情况下同时运作
## 支持的版本
- Android Oreo (8.x, sdk26/27)
- Android Pie (9, sdk28)
- Android Q (10, sdk29)
如果你使用 Android Nougat (7.x) 或更低版本, 请使用原版的 Xposed 框架
## 编译需求
见 [Riru-Core 的编译需求](https://github.com/RikkaApps/Riru/blob/master/README.md#build-requirements)
zip 可执行文件可以在 [这里](http://gnuwin32.sourceforge.net/packages/zip.htm) 下载
## 编译和使用
1. 执行 `:edxp-core:[zip|push][Yahfa|Sandhook]Release` 来构建对应分支的可刷入的 zip 文件
2. 在 `edxp-core/release/` 中找到可刷入的 zip 文件
3. 经由 Magisk Manager 或在恢复模式(Recovery)中刷入
## 安装
1. 安装 Magisk v19+ (对于 华为 / 荣耀 或 一加 7T / 7TPro 设备, 需要 Magisk v20.2+)
2. 在 Magisk 仓库中安装 [Riru-Core](https://github.com/RikkaApps/Riru/releases) v19 或更高版本.
3. [下载](#下载)并在恢复模式(Recovery)或经由 Magisk Manager 安装 EdXposed.
4. 安装 [框架管理应用](#框架管理应用).
4. 重启手机.
5. 完成 :)
## 下载
Edxposed 拥有三个不同的版本
- Stable经过测试的稳定版, 适合一般用户,更新缓慢.
***在 [Magisk Manager] 中的 [下载] 页中下载 Stable 版本***
- Alpha: 多次提交更新的测试版.
***在 [[Github Releases](https://github.com/ElderDrivers/EdXposed/releases)] 中下载 Alpha 版本***
- Canary: 由 CI 自动生成的测试版.
***在 [[EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)] 中下载 Canary 版本***
## 框架管理应用
> Xposed Installer 和 EdXposed Installer 均已停更,后续版本将取消支持,请使用 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager)
- 对于 v0.2.9.5 或更低版本: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller).
- 对于 v0.2.9.6 和 v0.2.9.7: [Xposed Installer](https://github.com/DVDAndroid/XposedInstaller) + [EdXp Manager](https://github.com/solohsu/EdXpManager)(optional).
- 对于 v0.2.9.8 或更高版本: [EdXposed Installer](https://github.com/solohsu/XposedInstaller) 或者 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager).
- 对于最新版,我们建议使用 [EdXposed Manager](https://github.com/ElderDrivers/EdXposedManager).
## 外部链接
- [List of Xposed Modules For Android Pie Working With EdXposed](https://forum.xda-developers.com/xposed/list-xposed-modules-android-pie-ed-t3892768) (感谢 Uraniam9 @ xda-developers)
## 已知问题
见 [Wiki: 已知问题和漏洞](https://github.com/ElderDrivers/EdXposed/wiki/已知问题和漏洞)
## 获取帮助
- GitHub issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/)
- 注意: 鉴于部分用户提交的Issues质量过低对于中文用户反馈请先阅读[EdXposed错误提交说明_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(不看说明提交的Issue会有很大可能被close)
## 社区交流
- QQ 群组: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f)
- Telegram 电报: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat)
注意: 这些社区群组不接收问题反馈, 请使用 [获取帮助](#获取帮助) 进行反馈.
## 贡献
- 显然框架还不够稳定欢迎使用PR贡献代码. :)
- 如果你愿意,可以[请我喝杯咖啡](https://www.paypal.me/givin2u).
## 鸣谢
- [YAHFA](https://github.com/rk700/YAHFA): ART hook 核心框架
- [Magisk](https://github.com/topjohnwu/Magisk/): 让一切成为可能
- [Riru](https://github.com/RikkaApps/Riru): 提供一种将代码注入 zygote 进程的方法
- [XposedBridge](https://github.com/rovo89/XposedBridge): 原版 xposed 框架的 API
- [dexmaker](https://github.com/linkedin/dexmaker) 和 [dalvikdx](https://github.com/JakeWharton/dalvik-dx): 动态生成 YAHFA hook 类
- [Whale](https://github.com/asLody/whale): 用于 hook 内联方法
- [SandHook](https://github.com/ganyao114/SandHook/): SandHook 分支的 ART hooking 框架

View File

@ -1,4 +1,4 @@
version: '0.4.6.0_beta({build})'
version: '0.4.6.3 ({build})'
environment:
ANDROID_HOME: C:\android-sdk-windows

BIN
art/README_CN.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
art/README_EN.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -8,7 +8,6 @@ import android.content.res.CompatibilityInfo;
import android.content.res.XResources;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
import com.elderdrivers.riru.edxp.util.Hookers;
import com.elderdrivers.riru.edxp.util.Utils;
@ -22,9 +21,6 @@ public class HandleBindApp extends XC_MethodHook {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (XposedBlackListHooker.shouldDisableHooks("")) {
return;
}
try {
Hookers.logD("ActivityThread#handleBindApplication() starts");
ActivityThread activityThread = (ActivityThread) param.thisObject;
@ -36,10 +32,6 @@ public class HandleBindApp extends XC_MethodHook {
Utils.logD("processName=" + ConfigManager.appProcessName +
", packageName=" + reportedPackageName + ", appDataDir=" + ConfigManager.appDataDir);
if (XposedBlackListHooker.shouldDisableHooks(reportedPackageName)) {
return;
}
ComponentName instrumentationName = (ComponentName) XposedHelpers.getObjectField(bindData, "instrumentationName");
if (instrumentationName != null) {
Hookers.logD("Instrumentation detected, disabling framework for");

View File

@ -5,7 +5,6 @@ import android.app.LoadedApk;
import android.content.res.XResources;
import android.util.Log;
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
import com.elderdrivers.riru.edxp.util.Hookers;
import de.robv.android.xposed.XC_MethodHook;
@ -18,10 +17,6 @@ public class LoadedApkCstr extends XC_MethodHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (XposedBlackListHooker.shouldDisableHooks("")) {
return;
}
Hookers.logD("LoadedApk#<init> starts");
try {
@ -32,10 +27,6 @@ public class LoadedApkCstr extends XC_MethodHook {
XResources.setPackageNameForResDir(packageName, loadedApk.getResDir());
if (XposedBlackListHooker.shouldDisableHooks(packageName)) {
return;
}
if (packageName.equals("android")) {
Hookers.logD("LoadedApk#<init> is android, skip: " + mAppDir);
return;

View File

@ -2,8 +2,8 @@ package com.elderdrivers.riru.edxp._hooker.impl;
import android.app.LoadedApk;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.hooker.SliceProviderFix;
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
import com.elderdrivers.riru.edxp.hooker.XposedInstallerHooker;
import com.elderdrivers.riru.edxp.util.Hookers;
@ -12,10 +12,7 @@ import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME;
import static com.elderdrivers.riru.edxp.hooker.SliceProviderFix.SYSTEMUI_PACKAGE_NAME;
import static com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
public class LoadedApkGetCL extends XC_MethodHook {
@ -38,10 +35,6 @@ public class LoadedApkGetCL extends XC_MethodHook {
try {
if (XposedBlackListHooker.shouldDisableHooks("")) {
return;
}
Hookers.logD("LoadedApk#getClassLoader starts");
LoadedApk loadedApk = (LoadedApk) param.thisObject;
@ -67,12 +60,9 @@ public class LoadedApkGetCL extends XC_MethodHook {
lpparam.isFirstApplication = this.isFirstApplication;
XC_LoadPackage.callAll(lpparam);
if (this.packageName.equals(INSTALLER_PACKAGE_NAME)) {
if (this.packageName.equals(ConfigManager.getInstallerPackageName())) {
XposedInstallerHooker.hookXposedInstaller(lpparam.classLoader);
}
if (this.packageName.equals(BLACK_LIST_PACKAGE_NAME)) {
XposedBlackListHooker.hook(lpparam.classLoader);
}
if (this.packageName.equals(SYSTEMUI_PACKAGE_NAME)) {
SliceProviderFix.hook();
}

View File

@ -1,17 +1,35 @@
package com.elderdrivers.riru.edxp.config;
import com.elderdrivers.riru.edxp.hooker.XposedBlackListHooker;
import android.text.TextUtils;
public class BaseEdxpConfig implements EdxpConfig {
@Override
public String getInstallerBaseDir() {
return InstallerChooser.INSTALLER_DATA_BASE_DIR;
public String getInstallerConfigPath(String suffix) {
return ConfigManager.getInstallerConfigPath(suffix != null ? suffix : "");
}
@Override
public String getBlackListModulePackageName() {
return XposedBlackListHooker.BLACK_LIST_PACKAGE_NAME;
public String getDataPathPrefix() {
return ConfigManager.getDataPathPrefix();
}
@Override
public String getInstallerPackageName() {
return ConfigManager.getInstallerPackageName();
}
@Override
public String getXposedPropPath() {
return ConfigManager.getXposedPropPath();
}
@Override
public String getLibSandHookName() {
return ConfigManager.getLibSandHookName();
}
@Override
public String getLibWhaleName() {
return ConfigManager.getLibWhaleName();
}
@Override
@ -24,6 +42,11 @@ public class BaseEdxpConfig implements EdxpConfig {
return ConfigManager.isResourcesHookEnabled();
}
@Override
public boolean isNoModuleLogEnabled() {
return ConfigManager.isNoModuleLogEnabled();
}
@Override
public boolean isBlackWhiteListMode() {
return ConfigManager.isBlackWhiteListEnabled();

View File

@ -4,15 +4,12 @@ import java.util.HashMap;
import de.robv.android.xposed.SELinuxHelper;
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_DATA_BASE_DIR;
public class ConfigManager {
public static String appDataDir = "";
public static String niceName = "";
public static String appProcessName = "";
private static final String COMPAT_LIST_PATH = INSTALLER_DATA_BASE_DIR + "conf/compatlist/";
private static final HashMap<String, Boolean> compatModeCache = new HashMap<>();
public static boolean shouldUseCompatMode(String packageName) {
@ -21,7 +18,7 @@ public class ConfigManager {
&& (result = compatModeCache.get(packageName)) != null) {
return result;
}
result = isFileExists(COMPAT_LIST_PATH + packageName);
result = isFileExists(getInstallerConfigPath("compatlist/" + packageName));
compatModeCache.put(packageName, result);
return result;
}
@ -34,11 +31,23 @@ public class ConfigManager {
public static native boolean isDynamicModulesEnabled();
public static native boolean isNoModuleLogEnabled();
public static native boolean isResourcesHookEnabled();
public static native boolean isDeoptBootImageEnabled();
public static native String getInstallerPackageName();
public static native String getXposedPropPath();
public static native String getLibSandHookName();
public static native String getLibWhaleName();
public static native String getInstallerConfigPath(String suffix);
public static native String getDataPathPrefix();
public static native boolean isAppNeedHook(String appDataDir);
}

View File

@ -1,68 +0,0 @@
package com.elderdrivers.riru.edxp.config;
import android.annotation.SuppressLint;
import android.os.Build;
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;
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/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;
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)) {
// init once
return;
}
String dataBaseDir;
if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + PRIMARY_INSTALLER_PACKAGE_NAME + "/")) {
INSTALLER_PACKAGE_NAME = PRIMARY_INSTALLER_PACKAGE_NAME;
INSTALLER_DATA_BASE_DIR = dataBaseDir;
Utils.logI("using " + PRIMARY_INSTALLER_PACKAGE_NAME + "as installer app");
return;
}
if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + SECONDARY_INSTALLER_PACKAGE_NAME + "/")) {
INSTALLER_PACKAGE_NAME = SECONDARY_INSTALLER_PACKAGE_NAME;
INSTALLER_DATA_BASE_DIR = dataBaseDir;
Utils.logI("using " + SECONDARY_INSTALLER_PACKAGE_NAME + "as installer app");
return;
}
if (checkDataDirValid(dataBaseDir = DATA_DIR_PATH_PREFIX + LEGACY_INSTALLER_PACKAGE_NAME + "/")) {
INSTALLER_PACKAGE_NAME = LEGACY_INSTALLER_PACKAGE_NAME;
INSTALLER_DATA_BASE_DIR = dataBaseDir;
Utils.logI("using " + LEGACY_INSTALLER_PACKAGE_NAME + "as installer app");
return;
}
Utils.logE("no supported installer app found");
}
/**
* For some reason checkFileExists(dirPath) is not reliable when forkSystemServerPre
*/
private static boolean checkDataDirValid(String dirPath) {
BaseService fileService = SELinuxHelper.getAppDataFileService();
return fileService.checkFileExists(dirPath + "code_cache")
|| fileService.checkFileExists(dirPath + "cache");
}
}

View File

@ -1,87 +0,0 @@
package com.elderdrivers.riru.edxp.hooker;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.Build;
import com.elderdrivers.riru.edxp.util.Utils;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import static com.elderdrivers.riru.edxp.config.InstallerChooser.INSTALLER_PACKAGE_NAME;
import static com.elderdrivers.riru.edxp.util.FileUtils.IS_USING_PROTECTED_STORAGE;
public class XposedBlackListHooker {
public static final String BLACK_LIST_PACKAGE_NAME = "com.flarejune.xposedblacklist";
private static final String BLACK_LIST_PREF_NAME = "list";
private static final String PREF_KEY_BLACK_LIST = "blackList";
public static final String PREF_FILE_PATH = (IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data")
+ BLACK_LIST_PACKAGE_NAME + "/shared_prefs/" + BLACK_LIST_PREF_NAME + ".xml";
private static final XSharedPreferences PREFERENCES = new XSharedPreferences(new File(PREF_FILE_PATH));
// always white list. empty string is to make sure blackList does not contain empty packageName
private static final List<String> WHITE_LIST = Arrays.asList(INSTALLER_PACKAGE_NAME, BLACK_LIST_PACKAGE_NAME, "");
static {
try {
PREFERENCES.makeWorldReadable();
} catch (Throwable throwable) {
Utils.logE("error making pref worldReadable", throwable);
}
}
public static boolean shouldDisableHooks(String packageName) {
return XposedBridge.disableHooks || getBlackList().contains(packageName);
}
public static Set<String> getBlackList() {
try {
PREFERENCES.reload();
Set<String> result = PREFERENCES.getStringSet(PREF_KEY_BLACK_LIST, new HashSet<String>());
if (result != null) result.removeAll(WHITE_LIST);
return result;
} catch (Throwable throwable) {
Utils.logE("error when reading black list", throwable);
return new HashSet<>();
}
}
public static void hook(ClassLoader classLoader) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return;
}
try {
XposedHelpers.findAndHookMethod(ContextWrapper.class, "getSharedPreferences", String.class, int.class, new XC_MethodHook() {
@TargetApi(Build.VERSION_CODES.N)
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
try {
String prefName = (String) param.args[0];
if (!prefName.equals(BLACK_LIST_PREF_NAME)) {
return;
}
Activity activity = (Activity) param.thisObject;
Context context = activity.createDeviceProtectedStorageContext();
context.moveSharedPreferencesFrom(activity, prefName);
param.setResult(context.getSharedPreferences(prefName, (int) param.args[1]));
} catch (Throwable throwable) {
Utils.logE("error hooking Xposed BlackList", throwable);
}
}
});
} catch (Throwable throwable) {
Utils.logE("error hooking Xposed BlackList", throwable);
}
}
}

View File

@ -1,5 +1,6 @@
package com.elderdrivers.riru.edxp.hooker;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.Utils;
import java.io.File;
@ -11,10 +12,10 @@ import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import static com.elderdrivers.riru.edxp.config.InstallerChooser.LEGACY_INSTALLER_PACKAGE_NAME;
public class XposedInstallerHooker {
private static final String LEGACY_INSTALLER_PACKAGE_NAME = "de.robv.android.xposed.installer";
public static void hookXposedInstaller(ClassLoader classLoader) {
try {
final String xposedAppClass = LEGACY_INSTALLER_PACKAGE_NAME + ".XposedApp";
@ -29,12 +30,15 @@ public class XposedInstallerHooker {
Utils.logD("before reloadXposedProp...");
final String propFieldName = "mXposedProp";
final Object thisObject = param.thisObject;
if (thisObject == null) {
return;
}
if (XposedHelpers.getObjectField(thisObject, propFieldName) != null) {
param.setResult(null);
Utils.logD("reloadXposedProp already done, skip...");
return;
}
File file = new File("/system/framework/edconfig.jar");
File file = new File(ConfigManager.getXposedPropPath());
FileInputStream is = null;
try {
is = new FileInputStream(file);

View File

@ -145,7 +145,7 @@ public abstract class BaseRouter implements Router {
XposedHelpers.findAndHookMethod(OnePlusWorkAroundHooker.className,
classLoader, OnePlusWorkAroundHooker.methodName,
int.class, String.class, new OneplusWorkaround());
} catch (Throwable throwable) {
} catch (Throwable ignored) {
}
} else {
HookMain.doHookDefault(

View File

@ -3,6 +3,8 @@ package com.elderdrivers.riru.edxp.proxy;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
import de.robv.android.xposed.SELinuxHelper;
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
public class NormalProxy extends BaseProxy {
@ -18,6 +20,7 @@ public class NormalProxy extends BaseProxy {
String appDataDir) {
// mainly for secondary zygote
mRouter.onForkStart();
SELinuxHelper.initOnce();
mRouter.initResourcesHook();
// call this to ensure the flag is set to false ASAP
mRouter.prepare(false);
@ -36,6 +39,7 @@ public class NormalProxy extends BaseProxy {
public void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
mRouter.onForkStart();
SELinuxHelper.initOnce();
mRouter.initResourcesHook();
// set startsSystemServer flag used when loadModules
mRouter.prepare(true);

View File

@ -64,9 +64,9 @@ public class ClassLoaderUtils {
}
}
public static ClassLoader createComposeClassLoader(ClassLoader appClassLoader) {
public static ClassLoader createProxyClassLoader(ClassLoader appClassLoader) {
ClassLoader current = ClassLoaderUtils.class.getClassLoader();
return appClassLoader == null ? current : new ComposeClassLoader(appClassLoader, current);
return appClassLoader == null ? current : new ProxyClassLoader(appClassLoader, current);
}
public static List<ClassLoader> getAppClassLoader() {

View File

@ -1,35 +0,0 @@
package com.elderdrivers.riru.edxp.util;
/**
* Created by weishu on 17/11/30.
*/
public class ComposeClassLoader extends ClassLoader {
private final ClassLoader mAppClassLoader;
public ComposeClassLoader(ClassLoader parent, ClassLoader appClassLoader) {
super(parent);
mAppClassLoader = appClassLoader;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = null;
try {
clazz = mAppClassLoader.loadClass(name);
} catch (ClassNotFoundException e) {
// IGNORE.
}
if (clazz == null) {
clazz = super.loadClass(name, resolve);
}
if (clazz == null) {
throw new ClassNotFoundException();
}
return clazz;
}
}

View File

@ -1,10 +1,9 @@
package com.elderdrivers.riru.edxp.util;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Process;
import android.text.TextUtils;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@ -12,12 +11,8 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE;
public class FileUtils {
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
/**
* Delete a file or a directory and its children.
*
@ -52,8 +47,9 @@ public class FileUtils {
public static void writeLine(File file, String line) {
try {
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
} catch (IOException ex) {
} catch (IOException ignored) {
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(line);
@ -75,11 +71,7 @@ public class FileUtils {
return dataDir.substring(lastIndex + 1);
}
// FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet.
@SuppressLint("SdCardPath")
public static String getDataPathPrefix() {
int userId = Process.myUid() / PER_USER_RANGE;
String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/";
return String.format(format, userId);
return ConfigManager.getDataPathPrefix();
}
}

View File

@ -0,0 +1,30 @@
package com.elderdrivers.riru.edxp.util;
public class ProxyClassLoader extends ClassLoader {
private final ClassLoader mClassLoader;
public ProxyClassLoader(ClassLoader parentCL, ClassLoader appCL) {
super(parentCL);
mClassLoader = appCL;
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = null;
try {
clazz = mClassLoader.loadClass(name);
} catch (ClassNotFoundException ignored) {
}
if (clazz == null) {
clazz = super.loadClass(name, resolve);
if (clazz == null) {
throw new ClassNotFoundException();
}
}
return clazz;
}
}

View File

@ -4,7 +4,5 @@
/obj
/release
/template_override/module.prop
/template_override/riru_module.prop
/template_override/system
/template_override/system_x86
*.iml

View File

@ -4,8 +4,8 @@ import org.gradle.internal.os.OperatingSystem
apply plugin: 'com.android.library'
// Values set here will be overriden by AppVeyor, feel free to modify during development.
def buildVersionName = 'v0.4.6.0_beta'
def buildVersionCode = 10000
def buildVersionName = 'v0.4.6.3'
def buildVersionCode = 233
if (System.env.APPVEYOR_BUILD_VERSION != null) {
buildVersionName = "v${System.getenv('appveyor_build_version')}"
@ -28,9 +28,9 @@ ext {
yahfa_module_id = "riru_edxposed"
sandhook_module_id = yahfa_module_id + "_sandhook"
whale_module_id = yahfa_module_id + "_whale"
yahfa_authors = "solohsu, rk700 & MlgmXyysd"
sandhook_authors = "solohsu, ganyao114 & MlgmXyysd"
whale_authors = "solohsu, asLody & MlgmXyysd"
yahfa_authors = "solohsu, MlgmXyysd & rk700"
sandhook_authors = "solohsu, MlgmXyysd & ganyao114"
whale_authors = "solohsu, MlgmXyysd & asLody"
riruModuleId = "edxp"
zipPathMagiskRelease = "$buildDir/tmp/release/magisk"
@ -107,7 +107,7 @@ task copyDexmakerJar {
}
task cleanTemplate(type: Delete) {
delete file(templateSystemPath), file(templateSystemx86Path)
delete file(templateSystemx86Path)
}
afterEvaluate {
@ -148,11 +148,6 @@ afterEvaluate {
versionCode: "$versionCode", authorList: "$authorList")
filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
}
copy {
from "${templateRootPath}/module.prop"
into templateRootPath
rename "module.prop", "riru_module.prop"
}
}
def libPathRelease = "${buildDir}/intermediates/cmake/${variantLowered}/obj"
doLast {
@ -160,19 +155,15 @@ afterEvaluate {
from "${projectDir}/template_override"
into zipPathMagiskRelease
}
copy {
from "${projectDir}/template_override/common/util_functions.sh"
into "${zipPathMagiskRelease}/common"
filter { line -> line
.replaceAll('%VERSION%', "$version")
.replaceAll('%VERSION_CODE%', "$versionCode")
.replaceAll('%BACKEND%', "$backendCapped") }
filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
}
copy {
from 'template_override/riru_module.prop'
into "$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}"
}
// copy {
// from "${projectDir}/template_override/util_functions.sh"
// into "${zipPathMagiskRelease}/"
// filter { line -> line
// .replaceAll('%VERSION%', "$version")
// .replaceAll('%VERSION_CODE%', "$versionCode")
// .replaceAll('%BACKEND%', "$backendCapped") }
// filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
// }
copy {
from "$libPathRelease/armeabi-v7a"
into "$zipPathMagiskRelease/system/lib"
@ -189,15 +180,12 @@ afterEvaluate {
from "$libPathRelease/x86_64"
into "$zipPathMagiskRelease/system_x86/lib64"
}
file("$zipPathMagiskRelease/riru_module.prop").delete()
file("$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}/riru_module.prop").renameTo("$zipPathMagiskRelease/data/misc/riru/modules/${riruModuleId}/module.prop")
}
}
def zipTask = task("zip${backendCapped}${variantCapped}", type: Zip) {
dependsOn prepareMagiskFilesTask
archiveName "magisk-${module_name}-${backend}-${project.version}-${variantLowered}.zip"
archiveName "${module_name}-${backend}-${project.version}-${variantLowered}.zip"
destinationDir file("$projectDir/release")
from "$zipPathMagiskRelease"
}
@ -206,7 +194,7 @@ afterEvaluate {
dependsOn zipTask
workingDir "${projectDir}/release"
def commands = ["adb", "push",
"magisk-${module_name}-${backend}-${project.version}-${variantLowered}.zip",
"${module_name}-${backend}-${project.version}-${variantLowered}.zip",
"/sdcard/"]
if (is_windows) {
commandLine 'cmd', '/c', commands.join(" ")

View File

@ -20,6 +20,7 @@ static int OFFSET_access_flags_in_ArtMethod;
static size_t ArtMethodSize;
static int kAccNative = 0x0100;
static int kAccCompileDontBother = 0x01000000;
static int kAccFastInterpreterToInterpreterInvoke = 0x40000000;
static inline uint16_t read16(void *addr) {
return *((uint16_t *) addr);
@ -29,8 +30,8 @@ static inline uint32_t read32(void *addr) {
return *((uint32_t *) addr);
}
static inline uint64_t read64(void *addr) {
return *((uint64_t *) addr);
static inline void write32(void *addr, uint32_t value) {
*((uint32_t *) addr) = value;
}
void Java_lab_galaxy_yahfa_HookMain_init(JNIEnv *env, jclass clazz, jint sdkVersion) {
@ -122,11 +123,7 @@ void setNonCompilable(void *method) {
int access_flags = read32((char *) method + OFFSET_access_flags_in_ArtMethod);
LOGI("setNonCompilable: access flags is 0x%x", access_flags);
access_flags |= kAccCompileDontBother;
memcpy(
(char *) method + OFFSET_access_flags_in_ArtMethod,
&access_flags,
4
);
write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags);
}
bool setNativeFlag(void *method, bool isNative) {
@ -135,15 +132,15 @@ bool setNativeFlag(void *method, bool isNative) {
int old_access_flags = access_flags;
if (isNative) {
access_flags |= kAccNative;
if (SDKVersion >= ANDROID_Q) {
// On API 29 whether to use the fast path or not is cached in the ART method structure
access_flags &= ~kAccFastInterpreterToInterpreterInvoke;
}
} else {
access_flags &= ~kAccNative;
}
if (access_flags != old_access_flags) {
memcpy(
(char *) method + OFFSET_access_flags_in_ArtMethod,
&access_flags,
4
);
write32((char *) method + OFFSET_access_flags_in_ArtMethod, access_flags);
return true;
}
return false;

View File

@ -17,7 +17,10 @@ namespace art {
if (api_level == ANDROID_P) {
HOOK_FUNC(SetOnlyUseSystemOatFiles,
"_ZN3art14OatFileManager24SetOnlyUseSystemOatFilesEv");
}
if (api_level == ANDROID_Q) {
HOOK_FUNC(SetOnlyUseSystemOatFiles,
"_ZN3art14OatFileManager24SetOnlyUseSystemOatFilesEbb");
}
};

View File

@ -29,6 +29,8 @@ namespace edxp {
static constexpr auto kLibArtName = "libart.so";
static constexpr auto kLibFwkName = "libandroid_runtime.so";
static constexpr auto kLibWhaleName = "libwhale.edxp.so";
static constexpr auto kLibSandHookName = "libsandhook.edxp.so";
static const auto kLibBasePath = std::string(LP_SELECT("/system/lib/", "/system/lib64/"));
static const auto kLibRuntimeBasePath = std::string(
@ -36,8 +38,9 @@ namespace edxp {
static const auto kLibArtPath =
(GetAndroidApiLevel() >= ANDROID_Q ? kLibRuntimeBasePath : kLibBasePath) + kLibArtName;
static const auto kLibWhalePath = kLibBasePath + "libwhale.edxp.so";
static const auto kLibSandHookPath = kLibBasePath + "libsandhook.edxp.so";
static const auto kLibWhalePath = kLibBasePath + kLibWhaleName;
static const auto kLibSandHookPath = kLibBasePath + kLibSandHookName;
static const auto kLibFwPath = kLibBasePath + "libandroidfw.so";
static const auto kLibDlPath = kLibBasePath + "libdl.so";
static const auto kLibFwkPath = kLibBasePath + kLibFwkName;

View File

@ -30,18 +30,12 @@ namespace edxp {
LOGI("using installer %s", kPrimaryInstallerPkgName);
return kPrimaryInstallerPkgName;
}
data_test_path = data_path_prefix_ + kSecondaryInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) {
LOGI("using installer %s", kSecondaryInstallerPkgName);
return kSecondaryInstallerPkgName;
}
data_test_path = data_path_prefix_ + kLegacyInstallerPkgName;
if (access(data_test_path.c_str(), F_OK) == 0) {
LOGI("using installer %s", kLegacyInstallerPkgName);
return kLegacyInstallerPkgName;
}
LOGE("no supported installer app found, using primary as default %s",
kPrimaryInstallerPkgName);
LOGE("no supported installer app found, using default: %s", kPrimaryInstallerPkgName);
return kPrimaryInstallerPkgName;
}
@ -53,7 +47,7 @@ namespace edxp {
while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name;
LOGI("whitelist: %s", fileName);
LOGI(" whitelist: %s", fileName);
white_list_default_.emplace_back(fileName);
}
}
@ -64,7 +58,7 @@ namespace edxp {
while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name;
LOGI("blacklist: %s", fileName);
LOGI(" blacklist: %s", fileName);
black_list_default_.emplace_back(fileName);
}
}
@ -72,37 +66,62 @@ namespace edxp {
}
}
void ConfigManager::InitOnce() {
if (!initialized_) {
use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N;
data_path_prefix_ = use_prot_storage_ ? "/data/user_de/0/" : "/data/user/0/";
void ConfigManager::UpdateConfigPath(const uid_t user) {
if (last_user_ != user) {
LOGI("updating config data paths from %u to %u...", last_user_, user);
last_user_ = user;
}
installer_pkg_name_ = RetrieveInstallerPkgName();
base_config_path_ = GetConfigPath("");
blacklist_path_ = GetConfigPath("blacklist/");
whitelist_path_ = GetConfigPath("whitelist/");
use_whitelist_path_ = GetConfigPath("usewhitelist");
const char *format = use_prot_storage_ ? "/data/user_de/%u/" : "/data/user/%u/";
char buff[PATH_MAX];
snprintf(buff, sizeof(buff), format, last_user_);
data_path_prefix_ = buff;
dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0;
black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0;
deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0;
resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0;
installer_pkg_name_ = RetrieveInstallerPkgName();
base_config_path_ = GetConfigPath("");
blacklist_path_ = GetConfigPath("blacklist/");
whitelist_path_ = GetConfigPath("whitelist/");
use_whitelist_path_ = GetConfigPath("usewhitelist");
// use_white_list snapshot
use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0;
LOGI("black/white list mode: %s, using whitelist: %s",
BoolToString(black_white_list_enabled_), BoolToString(use_white_list_snapshot_));
LOGI("dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_));
LOGI("resources hook: %s", BoolToString(resources_hook_enabled_));
LOGI("deopt boot image: %s", BoolToString(deopt_boot_image_enabled_));
if (black_white_list_enabled_) {
SnapshotBlackWhiteList();
}
initialized_ = true;
dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0;
black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0;
deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0;
resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0;
no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0;
hidden_api_bypass_enabled_ = access(GetConfigPath("disable_hidden_api_bypass").c_str(), F_OK) != 0;
// use_white_list snapshot
use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0;
LOGI("data path prefix: %s", data_path_prefix_.c_str());
LOGI(" application list mode: %s", BoolToString(black_white_list_enabled_));
LOGI(" using whitelist: %s", BoolToString(use_white_list_snapshot_));
LOGI(" dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_));
LOGI(" resources hook: %s", BoolToString(resources_hook_enabled_));
LOGI(" deopt boot image: %s", BoolToString(deopt_boot_image_enabled_));
LOGI(" no module log: %s", BoolToString(no_module_log_enabled_));
LOGI(" hidden api bypass: %s", BoolToString(hidden_api_bypass_enabled_));
if (black_white_list_enabled_) {
SnapshotBlackWhiteList();
}
}
bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) const {
bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) {
// zygote always starts with `uid == 0` and then fork into different user.
// so we have to check if we are the correct user or not.
uid_t user = 0;
char package_name[PATH_MAX];
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%u/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGE("can't parse %s", app_data_dir.c_str());
return false; // default to no hooking for safety
}
}
if (last_user_ != user) {
UpdateConfigPath(user);
}
if (!black_white_list_enabled_) {
return true;
}
@ -115,17 +134,7 @@ namespace edxp {
app_data_dir.c_str());
use_white_list = use_white_list_snapshot_;
}
int user = 0;
char package_name[PATH_MAX];
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%d/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGE("can't parse %s", app_data_dir.c_str());
return !use_white_list;
}
}
if (strcmp(package_name, kPrimaryInstallerPkgName) == 0
|| strcmp(package_name, kSecondaryInstallerPkgName) == 0
|| strcmp(package_name, kLegacyInstallerPkgName) == 0) {
// always hook installer apps
return true;
@ -164,6 +173,10 @@ namespace edxp {
return dynamic_modules_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsNoModuleLogEnabled() const {
return no_module_log_enabled_;
}
ALWAYS_INLINE bool ConfigManager::IsResourcesHookEnabled() const {
return resources_hook_enabled_;
}
@ -172,20 +185,38 @@ namespace edxp {
return deopt_boot_image_enabled_;
}
ALWAYS_INLINE std::string ConfigManager::GetInstallerPkgName() const {
ALWAYS_INLINE bool ConfigManager::IsHiddenAPIBypassEnabled() const {
return hidden_api_bypass_enabled_;
}
ALWAYS_INLINE std::string ConfigManager::GetInstallerPackageName() const {
return installer_pkg_name_;
}
ALWAYS_INLINE std::string ConfigManager::GetXposedPropPath() const {
return kXposedPropPath;
}
ALWAYS_INLINE std::string ConfigManager::GetLibSandHookName() const {
return kLibSandHookName;
}
ALWAYS_INLINE std::string ConfigManager::GetLibWhaleName() const {
return kLibWhaleName;
}
ALWAYS_INLINE std::string ConfigManager::GetDataPathPrefix() const {
return data_path_prefix_;
}
ALWAYS_INLINE std::string ConfigManager::GetConfigPath(const std::string &suffix) const {
return data_path_prefix_ + installer_pkg_name_ + "/conf/" + suffix;
};
ConfigManager::ConfigManager() {
InitOnce();
}
ConfigManager::~ConfigManager() {
initialized_ = false;
use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N;
last_user_ = 0;
UpdateConfigPath(last_user_);
}
}

View File

@ -8,9 +8,9 @@
namespace edxp {
static constexpr const char *kPrimaryInstallerPkgName = "com.solohsu.android.edxp.manager";
static constexpr const char *kSecondaryInstallerPkgName = "org.meowcat.edxposed.manager";
static constexpr const char *kPrimaryInstallerPkgName = "org.meowcat.edxposed.manager";
static constexpr const char *kLegacyInstallerPkgName = "de.robv.android.xposed.installer";
static constexpr auto kXposedPropPath = "/system/framework/edconfig.jar";
class ConfigManager {
public:
@ -30,13 +30,28 @@ namespace edxp {
bool IsDeoptBootImageEnabled() const;
std::string GetInstallerPkgName() const;
bool IsNoModuleLogEnabled() const;
bool IsAppNeedHook(const std::string &app_data_dir) const;
bool IsHiddenAPIBypassEnabled() const;
std::string GetInstallerPackageName() const;
std::string GetXposedPropPath() const;
std::string GetLibSandHookName() const;
std::string GetLibWhaleName() const;
std::string GetDataPathPrefix() const;
std::string GetConfigPath(const std::string &suffix) const;
bool IsAppNeedHook(const std::string &app_data_dir);
bool hidden_api_bypass_enabled_ = false;
private:
inline static ConfigManager *instance_;
bool initialized_ = false;
uid_t last_user_ = false;
bool use_prot_storage_ = true;
std::string data_path_prefix_;
std::string installer_pkg_name_;
@ -47,6 +62,7 @@ namespace edxp {
bool black_white_list_enabled_ = false;
bool dynamic_modules_enabled_ = false;
bool deopt_boot_image_enabled_ = false;
bool no_module_log_enabled_ = false;
bool resources_hook_enabled_ = true;
// snapshot at boot
bool use_white_list_snapshot_ = false;
@ -55,17 +71,12 @@ namespace edxp {
ConfigManager();
~ConfigManager();
void InitOnce();
void UpdateConfigPath(const uid_t user);
void SnapshotBlackWhiteList();
std::string RetrieveInstallerPkgName() const;
std::string GetConfigPath(const std::string &suffix) const;
};
} // namespace edxp

View File

@ -22,8 +22,36 @@ namespace edxp {
return (jboolean) ConfigManager::GetInstance()->IsDeoptBootImageEnabled();
}
static jboolean ConfigManager_isNoModuleLogEnabled(JNI_START) {
return (jboolean) ConfigManager::GetInstance()->IsNoModuleLogEnabled();
}
static jstring ConfigManager_getInstallerPackageName(JNI_START) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetInstallerPkgName().c_str());
return env->NewStringUTF(ConfigManager::GetInstance()->GetInstallerPackageName().c_str());
}
static jstring ConfigManager_getXposedPropPath(JNI_START) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetXposedPropPath().c_str());
}
static jstring ConfigManager_getLibWhaleName(JNI_START) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetLibWhaleName().c_str());
}
static jstring ConfigManager_getLibSandHookName(JNI_START) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetLibSandHookName().c_str());
}
static jstring ConfigManager_getDataPathPrefix(JNI_START) {
return env->NewStringUTF(ConfigManager::GetInstance()->GetDataPathPrefix().c_str());
}
static jstring ConfigManager_getInstallerConfigPath(JNI_START, jstring jSuffix) {
const char *suffix = env->GetStringUTFChars(jSuffix, JNI_FALSE);
auto result = ConfigManager::GetInstance()->GetConfigPath(suffix);
env->ReleaseStringUTFChars(jSuffix, suffix);
return env->NewStringUTF(result.c_str());
}
static jboolean ConfigManager_isAppNeedHook(JNI_START, jstring appDataDir) {
@ -38,7 +66,13 @@ namespace edxp {
NATIVE_METHOD(ConfigManager, isDynamicModulesEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, isResourcesHookEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, isDeoptBootImageEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, isNoModuleLogEnabled, "()Z"),
NATIVE_METHOD(ConfigManager, getInstallerPackageName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getXposedPropPath, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getLibSandHookName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getLibWhaleName, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getDataPathPrefix, "()Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, getInstallerConfigPath, "(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ConfigManager, isAppNeedHook, "(Ljava/lang/String;)Z"),
};

View File

@ -66,7 +66,7 @@ namespace edxp {
}
hook_func = reinterpret_cast<HookFunType>(hook_func_symbol);
if (api_level >= ANDROID_P) {
if (api_level > ANDROID_P) {
ScopedDlHandle dl_handle(kLibDlPath.c_str());
void *handle = dl_handle.Get();
HOOK_FUNC(mydlopen, "__loader_dlopen");
@ -83,7 +83,9 @@ namespace edxp {
if (art_hooks_installed) {
return;
}
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
if (ConfigManager::GetInstance() -> IsHiddenAPIBypassEnabled()) {
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
}
art::Runtime::Setup(art_handle, hook_func);
art::gc::Heap::Setup(art_handle, hook_func);
art::ClassLinker::Setup(art_handle, hook_func);

Binary file not shown.

View File

@ -1,12 +1,15 @@
#!/sbin/sh
TMPDIR=/dev/tmp
MOUNTPATH=/dev/magisk_img
#################
# Initialization
#################
# Default permissions
umask 022
# Initial cleanup
# Global vars
TMPDIR=/dev/tmp
PERSISTDIR=/sbin/.magisk/mirror/persist
rm -rf $TMPDIR 2>/dev/null
mkdir -p $TMPDIR
@ -14,20 +17,33 @@ mkdir -p $TMPDIR
ui_print() { echo "$1"; }
require_new_magisk() {
ui_print "***********************************"
ui_print " Please install the latest Magisk! "
ui_print "***********************************"
ui_print "*******************************"
ui_print " Please install Magisk v19.0+! "
ui_print "*******************************"
exit 1
}
imageless_magisk() {
[ $MAGISK_VER_CODE -gt 18100 ]
is_legacy_script() {
unzip -l "$ZIPFILE" install.sh | grep -q install.sh
return $?
}
##########################################################################################
print_modname() {
local len
len=`echo -n $MODNAME | wc -c`
len=$((len + 2))
local pounds=`printf "%${len}s" | tr ' ' '*'`
ui_print "$pounds"
ui_print " $MODNAME "
ui_print "$pounds"
ui_print "*******************"
ui_print " Powered by Magisk "
ui_print "*******************"
}
##############
# Environment
##########################################################################################
##############
OUTFD=$2
ZIPFILE=$3
@ -35,12 +51,9 @@ ZIPFILE=$3
mount /data 2>/dev/null
# Load utility functions
if [ -f /data/adb/magisk/util_functions.sh ]; then
. /data/adb/magisk/util_functions.sh
NVBASE=/data/adb
else
require_new_magisk
fi
[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
. /data/adb/magisk/util_functions.sh
[ $MAGISK_VER_CODE -gt 18100 ] || require_new_magisk
# Preperation for flashable zips
setup_flashable
@ -54,98 +67,107 @@ api_level_arch_detect
# Setup busybox and binaries
$BOOTMODE && boot_actions || recovery_actions
##########################################################################################
##############
# Preparation
##########################################################################################
##############
# Extract common files
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
[ ! -f $TMPDIR/install.sh ] && abort "! Unable to extract zip file!"
# Load install script
. $TMPDIR/install.sh
if imageless_magisk; then
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
MODULEROOT=$NVBASE/$MODDIRNAME
else
$BOOTMODE && IMGNAME=magisk_merge.img || IMGNAME=magisk.img
IMG=$NVBASE/$IMGNAME
request_zip_size_check "$ZIPFILE"
mount_magisk_img
MODULEROOT=$MOUNTPATH
fi
# Extract prop file
unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
[ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!"
$BOOTMODE && MODDIRNAME=modules_update || MODDIRNAME=modules
MODULEROOT=$NVBASE/$MODDIRNAME
MODID=`grep_prop id $TMPDIR/module.prop`
MODPATH=$MODULEROOT/$MODID
print_modname
ui_print "******************************"
ui_print "Powered by Magisk (@topjohnwu)"
ui_print "******************************"
##########################################################################################
# Install
##########################################################################################
MODNAME=`grep_prop name $TMPDIR/module.prop`
# Create mod paths
rm -rf $MODPATH 2>/dev/null
mkdir -p $MODPATH
on_install
##########
# Install
##########
# Remove placeholder
rm -f $MODPATH/system/placeholder 2>/dev/null
if is_legacy_script; then
unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
# Custom uninstaller
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
# Load install script
. $TMPDIR/install.sh
# Auto Mount
if imageless_magisk; then
# Callbacks
print_modname
on_install
# Custom uninstaller
[ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
# Skip mount
$SKIPMOUNT && touch $MODPATH/skip_mount
# prop file
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
# Module info
cp -af $TMPDIR/module.prop $MODPATH/module.prop
# post-fs-data scripts
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
# service scripts
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
ui_print "- Setting permissions"
set_permissions
else
$SKIPMOUNT || touch $MODPATH/auto_mount
fi
print_modname
# prop files
$PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
# Module info
cp -af $TMPDIR/module.prop $MODPATH/module.prop
if $BOOTMODE; then
# Update info for Magisk Manager
if imageless_magisk; then
mktouch $NVBASE/modules/$MODID/update
cp -af $TMPDIR/module.prop $NVBASE/modules/$MODID/module.prop
else
mktouch /sbin/.magisk/img/$MODID/update
cp -af $TMPDIR/module.prop /sbin/.magisk/img/$MODID/module.prop
if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
ui_print "- Extracting module files"
unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
# Default permissions
set_perm_recursive $MODPATH 0 0 0755 0644
fi
# Load customization script
[ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
fi
# post-fs-data mode scripts
$POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
# service mode scripts
$LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
# Handle replace folders
for TARGET in $REPLACE; do
ui_print "- Replace target: $TARGET"
mktouch $MODPATH$TARGET/.replace
done
ui_print "- Setting permissions"
set_permissions
if $BOOTMODE; then
# Update info for Magisk Manager
mktouch $NVBASE/modules/$MODID/update
cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop
fi
##########################################################################################
# Copy over custom sepolicy rules
if [ -f $MODPATH/sepolicy.rule -a -e $PERSISTDIR ]; then
ui_print "- Installing custom sepolicy patch"
PERSISTMOD=$PERSISTDIR/magisk/$MODID
mkdir -p $PERSISTMOD
cp -af $MODPATH/sepolicy.rule $PERSISTMOD/sepolicy.rule
fi
# Remove stuffs that don't belong to modules
rm -rf \
$MODPATH/system/placeholder $MODPATH/customize.sh \
$MODPATH/README.md $MODPATH/.git* 2>/dev/null
##############
# Finalizing
##########################################################################################
##############
cd /
imageless_magisk || unmount_magisk_img
$BOOTMODE || recovery_cleanup
rm -rf $TMPDIR $MOUNTPATH
rm -rf $TMPDIR
ui_print "- Done"
exit 0
exit 0

View File

@ -0,0 +1,47 @@
# EdXposed Framework
[简体中文](https://github.com/ElderDrivers/EdXposed/wiki/%E7%AE%80%E4%BB%8B)
## Introduction
A Riru module trying to provide an ART hooking framework (initially for Android Pie) which delivers consistent APIs with the OG Xposed, leveraging YAHFA (or SandHook) hooking framework, supports Android 8.0 ~ **10**.
> Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo. As all changes are done in the memory, you just need to deactivate the module and reboot to get your original system back. There are many other advantages, but here is just one more: Multiple modules can do changes to the same part of the system or app. With modified APKs, you to decide for one. No way to combine them, unless the author builds multiple APKs with different combinations.
What are the differences between EdXposed Framework and Xposed Framework?
1. EdXposed fully supports Android Pie and Q (even R)
2. EdXposed have App List mode. Only the apps you want to apply Xposed modules are hooked. Other apps in system run in a completely clean environment
3. EdXposed doesn't need to reboot system to active most modules
4. EdXposed is hard to detect. EdXposed use Riru to inject, doesn't modify the libart and app_process
## How to use ?
To put it simply, just follow these steps:
1. Install Magisk
2. Flash the Riru - Core Magisk module. You can find it in [Riru release page](https://github.com/RikkaApps/Riru/releases).
3. Flash the Riru - EdXposed Magisk module. You can find it in [EdXposed release page](https://github.com/ElderDrivers/EdXposed/releases).
4. Install EdXposed Manager. You can find it in [EdXposed Manager release page](https://github.com/ElderDrivers/EdXposedManager/releases).
5. Reboot :)
More informations in detail:
[**Official Website**](http://edxp.meowcat.org/)
[**Wiki**](https://github.com/ElderDrivers/EdXposed/wiki)
[**Telegram Channel**](https://t.me/EdXposed/)
## Community Discussion
- QQ Group: [855219808](http://shang.qq.com/wpa/qunwpa?idkey=fae42a3dba9dc758caf63e971be2564e67bf7edd751a2ff1c750478b0ad1ca3f)
- Telegram: [@Code_of_MeowCat](http://t.me/Code_of_MeowCat)
Notice: These community group don't accept any bug report, please use [Get help](#get-help) to report.
## Get Help
- GitHub Issues: [Issues](https://github.com/ElderDrivers/EdXposed/issues/)
- Notice(for Chinese): In view of the low quality of issues submitted, please read the Chinese user report first[EdXposedIssuesReport_cn](http://edxp.meowcat.org/assets/EdXposedIssuesReport_cn.txt)(If you don't read the instructions, the submitted issue is likely to be closed)

View File

@ -1,25 +0,0 @@
#!/system/bin/sh
# Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/...
# This will make your scripts compatible even if Magisk change its mount point in the future
MODDIR=${0%/*}
# This script will be executed in post-fs-data mode
# More info in the main Magisk thread
# necessary for using mmap in system_server process
#supolicy --live "allow system_server system_server process {execmem}"
# supolicy --live "allow system_server system_server memprotect {mmap_zero}"
# for built-in apps // TODO maybe narrow down the target classes
#supolicy --live "allow coredomain coredomain process {execmem}"
# read configs set in our app
#supolicy --live "allow coredomain app_data_file * *"
#supolicy --live "attradd {system_app platform_app} mlstrustedsubject"
# read module apk file in zygote
#supolicy --live "allow zygote apk_data_file * *"
. ${MODDIR}/util_functions.sh
start_log_catchers

View File

@ -1,7 +0,0 @@
#!/system/bin/sh
# Please don't hardcode /magisk/modname/... ; instead, please use $MODDIR/...
# This will make your scripts compatible even if Magisk change its mount point in the future
MODDIR=${0%/*}
# This script will be executed in late_start service mode
# More info in the main Magisk thread

View File

@ -1,97 +0,0 @@
#!/system/bin/sh
EDXP_VERSION="%VERSION% (%BACKEND%)"
ANDROID_SDK=`getprop ro.build.version.sdk`
BUILD_DESC=`getprop ro.build.description`
PRODUCT=`getprop ro.build.product`
MANUFACTURE=`getprop ro.product.manufacturer`
BRAND=`getprop ro.product.brand`
FINGERPRINT=`getprop ro.build.fingerprint`
ARCH=`getprop ro.product.cpu.abi`
DEVICE=`getprop ro.product.device`
ANDROID=`getprop ro.build.version.release`
BUILD=`getprop ro.build.id`
MAGISKV=`su -v`
MAGISKC=`su -V`
setup_log_path () {
EDXP_INSTALLER=com.solohsu.android.edxp.manager
EDXP_MANAGER=org.meowcat.edxposed.manager
XP_INSTALLER=de.robv.android.xposed.installer
PATH_PREFIX_PROT=/data/user_de/0/
PATH_PREFIX_LEGACY=/data/user/0/
if [[ ${ANDROID_SDK} -ge 24 ]]; then
PATH_PREFIX=${PATH_PREFIX_PROT}
else
PATH_PREFIX=${PATH_PREFIX_LEGACY}
fi
DEFAULT_BASE_PATH=${PATH_PREFIX}${EDXP_INSTALLER}
BASE_PATH=${DEFAULT_BASE_PATH}
if [[ ! -d ${BASE_PATH} ]]
then
BASE_PATH=${PATH_PREFIX}${EDXP_MANAGER}
if [[ ! -d ${BASE_PATH} ]]
then
BASE_PATH=${PATH_PREFIX}${XP_INSTALLER}
if [[ ! -d ${BASE_PATH} ]]
then
BASE_PATH=${DEFAULT_BASE_PATH}
fi
fi
fi
LOG_PATH=${BASE_PATH}/log
CONF_PATH=${BASE_PATH}/conf
DISABLE_VERBOSE_LOG_FILE=${CONF_PATH}/disable_verbose_log
LOG_VERBOSE=true
if [[ -f ${DISABLE_VERBOSE_LOG_FILE} ]]; then LOG_VERBOSE=false; fi
}
start_log_cather () {
LOG_FILE_NAME=$1
LOG_TAG_FILTERS=$2
CLEAN_OLD=$3
START_NEW=$4
LOG_FILE=${LOG_PATH}/${LOG_FILE_NAME}
mkdir -p ${LOG_PATH}
if [[ ${CLEAN_OLD} = true ]]; then
rm -rf ${LOG_FILE}
fi
if [[ ${START_NEW} = false ]]; then
return
fi
touch ${LOG_FILE}
chmod 777 ${LOG_FILE}
echo "--------- beginning of head">>${LOG_FILE}
echo "EdXposed Log">>${LOG_FILE}
echo "Powered by Log Catcher">>${LOG_FILE}
echo "QQ chat group 855219808">>${LOG_FILE}
echo "--------- beginning of system info">>${LOG_FILE}
echo "Android version: ${ANDROID}">>${LOG_FILE}
echo "Android sdk: ${ANDROID_SDK}">>${LOG_FILE}
echo "Android build: ${BUILD}">>${LOG_FILE}
echo "Fingerprint: ${FINGERPRINT}">>${LOG_FILE}
echo "ROM build description: ${BUILD_DESC}">>${LOG_FILE}
echo "EdXposed Version: ${EDXP_VERSION}">>${LOG_FILE}
echo "Architecture: ${ARCH}">>${LOG_FILE}
echo "Device: ${DEVICE}">>${LOG_FILE}
echo "Manufacture: ${MANUFACTURE}">>${LOG_FILE}
echo "Brand: ${BRAND}">>${LOG_FILE}
echo "Product: ${PRODUCT}">>${LOG_FILE}
echo "Magisk: ${MAGISKV}(${MAGISKC})">>${LOG_FILE}
logcat -f ${LOG_FILE} *:S ${LOG_TAG_FILTERS} &
}
start_verbose_log_catcher () {
start_log_cather all.log "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE}
}
start_bridge_log_catcher () {
start_log_cather error.log "XSharedPreferences:V EdXposed-Bridge:V" true true
}
start_log_catchers () {
start_bridge_log_catcher
start_verbose_log_catcher
}
setup_log_path

View File

@ -0,0 +1,350 @@
SKIPUNZIP=1
getRandomNameExist() {
RAND_PATH=$4
RAND_SUFFIX=$3
RAND_PREFIX=$2
RAND_DIGIT=$1
RAND_RAND="$(cat /proc/sys/kernel/random/uuid|md5sum|cut -c 1-"${RAND_DIGIT}")"
RAND_PATH_EXIST=false
for TARGET in ${RAND_PATH}; do
if [[ -e "${TARGET}/${RAND_PREFIX}${RAND_RAND}${RAND_SUFFIX}" ]]; then
RAND_PATH_EXIST=true
fi
done
if [[ "${RAND_PATH_EXIST}" == true ]]; then
getRandomNameExist "${RAND_DIGIT}" "${RAND_PREFIX}" "${RAND_SUFFIX}" "${RAND_PATH}"
else
echo "${RAND_RAND}"
fi
}
RIRU_PATH="/data/misc/riru"
RIRU_EDXP="$(getRandomNameExist 4 "libriru_" ".so" "
/system/lib
/system/lib64
")"
RIRU_MODULES="${RIRU_PATH}/modules"
RIRU_TARGET="${RIRU_MODULES}/${RIRU_EDXP}"
VERSION=$(grep_prop version "${TMPDIR}/module.prop")
RIRU_MIN_API_VERSION=$(grep_prop api "${TMPDIR}/module.prop")
PROP_MODEL=$(getprop ro.product.model)
PROP_DEVICE=$(getprop ro.product.device)
PROP_PRODUCT=$(getprop ro.build.product)
PROP_BRAND=$(getprop ro.product.brand)
PROP_MANUFACTURER=$(getprop ro.product.manufacturer)
JAR_EDXP="$(getRandomNameExist 8 "" ".jar" "
/system/framework
").jar"
JAR_EDDALVIKDX="$(getRandomNameExist 8 "" ".jar" "
/system/framework
").jar"
JAR_EDDEXMAKER="$(getRandomNameExist 8 "" ".jar" "
/system/framework
").jar"
JAR_EDCONFIG="$(getRandomNameExist 8 "" ".jar" "
/system/framework
").jar"
LIB_RIRU_EDXP="libriru_${RIRU_EDXP}.so"
LIB_WHALE_EDXP="lib$(getRandomNameExist 10 "lib" ".so" "
/system/lib
/system/lib64
").so"
LIB_SANDHOOK_EDXP="lib$(getRandomNameExist 13 "lib" ".so" "
/system/lib
/system/lib64
").so"
MODEL="
HD1900
HD1910
"
DEVICE="
OnePlus7T
OnePlus7TPro
"
PRODUCT="
OnePlus7T
OnePlus7TPro
"
BRAND="
HUAWEI
HONOR
"
MANUFACTURER="
HUAWEI
"
OLD_MAGISK=false
DETECTED_DEVICE=false
#NO_PERSIST=false
[[ "$(getenforce)" == "Enforcing" ]] && ENFORCE=true || ENFORCE=false
abortC() {
rm -rf "${MODPATH}"
abort "$1"
}
require_new_magisk() {
# if [[ "${NO_PERSIST}" == true ]]; then
# ui_print "******************************"
# ui_print "! Special device detected"
# ui_print "! But persist is not found in your device, SEPolicy rules will not take effect correctly"
# ui_print "! Deprecated custom Magisk v20.1 is required"
# ui_print "! Change Magisk update channel to http://edxp.meowcat.org/repo/version.json"
# ui_print "! And re-install Magisk"
# abortC "******************************"
# else
ui_print "******************************"
ui_print "! Special device detected"
ui_print "! Magisk v20.2+ or custom Magisk v20.1(Deprecated) is required"
ui_print "! You can update from 'Magisk Manager' or https://github.com/topjohnwu/Magisk/releases"
abortC "******************************"
# fi
}
update_new_magisk() {
ui_print "******************************"
ui_print "- Deprecated custom Magisk v20.1 detected"
ui_print "- We will still keep the rule file for you"
ui_print "- You can update to the latest Magisk directly from official update channel"
ui_print "******************************"
}
require_riru() {
ui_print "******************************"
ui_print "! Requirement module 'Riru - Core' is not installed"
ui_print "! You can download from 'Magisk Manager' or https://github.com/RikkaApps/Riru/releases"
abortC "******************************"
}
require_new_riru() {
ui_print "******************************"
ui_print "! Old Riru ${1} (below v19) detected"
ui_print "! The latest version of 'Riru - Core' is required"
ui_print "! You can download from 'Magisk Manager' or https://github.com/RikkaApps/Riru/releases"
abortC "******************************"
}
require_yahfa() {
ui_print "******************************"
ui_print "! Architecture x86 or x86_64 detected"
ui_print "! Only YAHFA variant supports x86 or x86_64 architecture devices"
ui_print "! You can download from 'Magisk Manager' or 'EdXposed Manager'"
abortC "******************************"
}
require_new_android() {
ui_print "******************************"
ui_print "! Old Android ${1} (below Oreo) detected"
ui_print "! Only the original Xposed Framework can be used under Android 8.0"
ui_print "! You can download from 'Xposed Installer' or 'Magisk Manager(Systemless-ly)'"
ui_print "! Learn more: https://github.com/ElderDrivers/EdXposed/wiki/Available-Android-versions"
abortC "******************************"
}
check_old_magisk_device() {
OLD_MAGISK=true
ui_print "******************************"
ui_print "- Old Magisk ${1} (below v20.2) detected"
ui_print "- The old Magisk may cause some problems (it may be fixed in new version)"
ui_print "- And support may be cancelled in subsequent versions"
ui_print "- In any case, you should update to the latest version in time"
ui_print "******************************"
if [[ "${DETECTED_DEVICE}" == true ]]; then
require_new_magisk
fi
}
check_magisk_version() {
for TARGET in ${MODEL}; do
if [[ "${PROP_MODEL}" == "${TARGET}" ]]; then
DETECTED_DEVICE=true
fi
done
for TARGET in ${DEVICE}; do
if [[ "${PROP_DEVICE}" == "${TARGET}" ]]; then
DETECTED_DEVICE=true
fi
done
for TARGET in ${PRODUCT}; do
if [[ "${PROP_PRODUCT}" == "${TARGET}" ]]; then
DETECTED_DEVICE=true
fi
done
for TARGET in ${BRAND}; do
if [[ "${PROP_BRAND}" == "${TARGET}" ]]; then
DETECTED_DEVICE=true
fi
done
for TARGET in ${MANUFACTURER}; do
if [[ "${PROP_MANUFACTURER}" == "${TARGET}" ]]; then
DETECTED_DEVICE=true
fi
done
if [[ "${DETECTED_DEVICE}" == true ]]; then
ui_print "- Special device detected"
fi
ui_print "- Magisk version: ${MAGISK_VER_CODE}"
[[ ${MAGISK_VER_CODE} -ge 20101 ]] || check_old_magisk_device "${MAGISK_VER_CODE}"
[[ ${MAGISK_VER_CODE} -eq 20101 ]] && update_new_magisk
}
check_riru_version() {
if [[ ! -f "${RIRU_PATH}/api_version" ]] && [[ ! -f "${RIRU_PATH}/api_version.new" ]]; then
require_riru
fi
RIRU_API_VERSION=$(cat "${RIRU_PATH}/api_version.new") || RIRU_API_VERSION=$(cat "${RIRU_PATH}/api_version") || RIRU_API_VERSION=0
[[ "${RIRU_API_VERSION}" -eq "${RIRU_API_VERSION}" ]] || RIRU_API_VERSION=0
ui_print "- Riru API version: ${RIRU_API_VERSION}"
if [[ "${RIRU_API_VERSION}" -lt ${RIRU_MIN_API_VERSION} ]]; then
require_new_riru ${RIRU_API_VERSION}
fi
}
check_architecture() {
if [[ "${MODID}" == "riru_edxposed_sandhook" ]]; then
VARIANTS="SandHook"
else
VARIANTS="YAHFA"
fi
ui_print "- EdXposed Variant: ${VARIANTS}"
if [[ "${ARCH}" != "arm" && "${ARCH}" != "arm64" && "${ARCH}" != "x86" && "${ARCH}" != "x64" ]]; then
abortC "! Unsupported platform: ${ARCH}"
else
ui_print "- Device platform: ${ARCH}"
if [[ "${ARCH}" == "x86" || "${ARCH}" == "x64" ]]; then
if [[ "${VARIANTS}" == "SandHook" ]]; then
require_yahfa
fi
fi
fi
}
check_android_version() {
if [[ ${API} -ge 26 ]]; then
ui_print "- Android sdk: ${API}"
else
require_new_android "${API}"
fi
}
#check_persist() {
# if [[ "$(cat /proc/mounts | grep /sbin/.magisk/mirror/persist)" == "" ]]; then
# NO_PERSIST=true
# fi
#}
ui_print "- EdXposed Version ${VERSION}"
#check_persist
check_magisk_version
check_riru_version
check_architecture
ui_print "- Extracting module files"
unzip -o "${ZIPFILE}" EdXposed.apk module.prop post-fs-data.sh sepolicy.rule system.prop uninstall.sh 'system/*' -d "${MODPATH}" >&2
if [[ "${ARCH}" == "x86" || "${ARCH}" == "x64" ]]; then
ui_print "- Replacing x86 and x86_64 libraries"
unzip -o "${ZIPFILE}" 'system_x86/*' -d "${MODPATH}" >&2
rm -rf "${MODPATH}/system/lib"
rm -rf "${MODPATH}/system/lib64"
mv "${MODPATH}/system_x86/lib" "${MODPATH}/system/lib"
mv "${MODPATH}/system_x86/lib64" "${MODPATH}/system/lib64"
rm -rf "${MODPATH}/system_x86"
fi
if [[ "${IS64BIT}" == false ]]; then
ui_print "- Removing 64-bit libraries"
rm -rf "${MODPATH}/system/lib64"
fi
if [[ "$(pm path org.meowcat.edxposed.manager)" == "" && "$(pm path de.robv.android.xposed.installer)" == "" ]]; then
NO_MANAGER=true
fi
if [[ ${BOOTMODE} == true && ${NO_MANAGER} == true ]]; then
ui_print "- Installing stub apk"
${ENFORCE} && setenforce 0
(pm install "${MODPATH}/EdXposed.apk" >/dev/null 2>&2) || ui_print " - Stub install failed! Do not forget install EdXposed Manager manually"
${ENFORCE} && setenforce 1
fi
if [[ "${OLD_MAGISK}" == true ]]; then
ui_print "- Removing SEPolicy rule for old Magisk"
rm "${MODPATH}"/sepolicy.rule
fi
#echo "- Mounted persist:" >&2
#mount | grep persist >&2
#if [[ "${NO_PERSIST}" == true ]]; then
# ui_print "- Persist not detected, remove SEPolicy rule"
# rm ${MODPATH}/sepolicy.rule
#fi
ui_print "- Copying framework libraries"
mv "${MODPATH}/system/framework/eddalvikdx.jar" "${MODPATH}/system/framework/${JAR_EDDALVIKDX}"
mv "${MODPATH}/system/framework/edxp.jar" "${MODPATH}/system/framework/${JAR_EDXP}"
mv "${MODPATH}/system/framework/eddexmaker.jar" "${MODPATH}/system/framework/${JAR_EDDEXMAKER}"
mv "${MODPATH}/system/framework/edconfig.jar" "${MODPATH}/system/framework/${JAR_EDCONFIG}"
mv "${MODPATH}/system/lib/libriru_edxp.so" "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
mv "${MODPATH}/system/lib/libwhale.edxp.so" "${MODPATH}/system/lib/${LIB_WHALE_EDXP}"
if [[ "${IS64BIT}" == true ]]; then
mv "${MODPATH}/system/lib64/libriru_edxp.so" "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
mv "${MODPATH}/system/lib64/libwhale.edxp.so" "${MODPATH}/system/lib64/${LIB_WHALE_EDXP}"
fi
if [[ "${VARIANTS}" == "SandHook" ]]; then
mv "${MODPATH}/system/lib/libsandhook.edxp.so" "${MODPATH}/system/lib/${LIB_SANDHOOK_EDXP}"
if [[ "${IS64BIT}" == true ]]; then
mv "${MODPATH}/system/lib64/libsandhook.edxp.so" "${MODPATH}/system/lib64/${LIB_SANDHOOK_EDXP}"
fi
fi
ui_print "- Resetting libraries path"
sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib/${LIB_RIRU_EDXP}"
if [[ "${IS64BIT}" == true ]]; then
sed -i 's:/system/framework/edxp.jar\:/system/framework/eddalvikdx.jar\:/system/framework/eddexmaker.jar:/system/framework/'"${JAR_EDXP}"'\:/system/framework/'"${JAR_EDDALVIKDX}"'\:/system/framework/'"${JAR_EDDEXMAKER}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:/system/framework/edconfig.jar:/system/framework/'"${JAR_EDCONFIG}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:libriru_edxp.so:'"${LIB_RIRU_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:libwhale.edxp.so:'"${LIB_WHALE_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
sed -i 's:libsandhook.edxp.so:'"${LIB_SANDHOOK_EDXP}"':g' "${MODPATH}/system/lib64/${LIB_RIRU_EDXP}"
fi
ui_print "- Removing old configuration"
if [[ -f "${RIRU_MODULES}/edxp.prop" ]]; then
OLD_CONFIG=$(cat "${RIRU_MODULES}/edxp.prop")
rm -rf "${RIRU_MODULES}/${OLD_CONFIG}"
fi
if [[ -e "${RIRU_MODULES}/edxp" ]]; then
rm -rf "${RIRU_MODULES}/edxp"
fi
ui_print "- Copying extra files"
[[ -d "${RIRU_TARGET}" ]] || mkdir -p "${RIRU_TARGET}" || abort "! Can't mkdir -p ${RIRU_TARGET}"
echo "${RIRU_EDXP}">"${RIRU_MODULES}/edxp.prop"
rm "${RIRU_TARGET}/module.prop"
cp "${MODPATH}/module.prop" "${RIRU_TARGET}/module.prop" || abort "! Can't create ${RIRU_TARGET}/module.prop"
set_perm_recursive "${MODPATH}" 0 0 0755 0644
ui_print "- Welcome to EdXposed ${VERSION}!"

View File

@ -1,186 +0,0 @@
##########################################################################################
#
# Magisk Module Installer Script
#
##########################################################################################
##########################################################################################
#
# Instructions:
#
# 1. Place your files into system folder (delete the placeholder file)
# 2. Fill in your module's info into module.prop
# 3. Configure and implement callbacks in this file
# 4. If you need boot scripts, add them into common/post-fs-data.sh or common/service.sh
# 5. Add your additional or modified system properties into common/system.prop
#
##########################################################################################
##########################################################################################
# Config Flags
##########################################################################################
# Set to true if you do *NOT* want Magisk to mount
# any files for you. Most modules would NOT want
# to set this flag to true
SKIPMOUNT=false
# Set to true if you need to load system.prop
PROPFILE=true
# Set to true if you need post-fs-data script
POSTFSDATA=true
# Set to true if you need late_start service script
LATESTARTSERVICE=false
##########################################################################################
# Replace list
##########################################################################################
# List all directories you want to directly replace in the system
# Check the documentations for more info why you would need this
# Construct your list in the following format
# This is an example
REPLACE_EXAMPLE="
/system/app/Youtube
/system/priv-app/SystemUI
/system/priv-app/Settings
/system/framework
"
# Construct your own list here
REPLACE="
"
##########################################################################################
#
# Function Callbacks
#
# The following functions will be called by the installation framework.
# You do not have the ability to modify update-binary, the only way you can customize
# installation is through implementing these functions.
#
# When running your callbacks, the installation framework will make sure the Magisk
# internal busybox path is *PREPENDED* to PATH, so all common commands shall exist.
# Also, it will make sure /data, /system, and /vendor is properly mounted.
#
##########################################################################################
##########################################################################################
#
# The installation framework will export some variables and functions.
# You should use these variables and functions for installation.
#
# ! DO NOT use any Magisk internal paths as those are NOT public API.
# ! DO NOT use other functions in util_functions.sh as they are NOT public API.
# ! Non public APIs are not guranteed to maintain compatibility between releases.
#
# Available variables:
#
# MAGISK_VER (string): the version string of current installed Magisk
# MAGISK_VER_CODE (int): the version code of current installed Magisk
# BOOTMODE (bool): true if the module is currently installing in Magisk Manager
# MODPATH (path): the path where your module files should be installed
# TMPDIR (path): a place where you can temporarily store files
# ZIPFILE (path): your module's installation zip
# ARCH (string): the architecture of the device. Value is either arm, arm64, x86, or x64
# IS64BIT (bool): true if $ARCH is either arm64 or x64
# API (int): the API level (Android version) of the device
#
# Availible functions:
#
# ui_print <msg>
# print <msg> to console
# Avoid using 'echo' as it will not display in custom recovery's console
#
# abort <msg>
# print error message <msg> to console and terminate installation
# Avoid using 'exit' as it will skip the termination cleanup steps
#
# set_perm <target> <owner> <group> <permission> [context]
# if [context] is empty, it will default to "u:object_r:system_file:s0"
# this function is a shorthand for the following commands
# chown owner.group target
# chmod permission target
# chcon context target
#
# set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
# if [context] is empty, it will default to "u:object_r:system_file:s0"
# for all files in <directory>, it will call:
# set_perm file owner group filepermission context
# for all directories in <directory> (including itself), it will call:
# set_perm dir owner group dirpermission context
#
##########################################################################################
##########################################################################################
# If you need boot scripts, DO NOT use general boot scripts (post-fs-data.d/service.d)
# ONLY use module scripts as it respects the module status (remove/disable) and is
# guaranteed to maintain the same behavior in future Magisk releases.
# Enable boot scripts by setting the flags in the config section above.
##########################################################################################
RIRU_PATH="/data/misc/riru"
print_modname() {
ui_print "*******************************"
ui_print "* Riru - EdXposed *"
ui_print "*******************************"
}
check_riru_version() {
[[ ! -f "$RIRU_PATH/api_version" ]] && abort "! Please Install Riru - Core v19 or above"
VERSION=$(cat "$RIRU_PATH/api_version")
ui_print "- Riru API version is $VERSION"
[[ "$VERSION" -ge 4 ]] || abort "! Please Install Riru - Core v19 or above"
}
check_architecture() {
if [[ "$ARCH" != "arm" && "$ARCH" != "arm64" && "$ARCH" != "x86" && "$ARCH" != "x64" ]]; then
abort "! Unsupported platform: $ARCH"
else
ui_print "- Device platform: $ARCH"
fi
}
on_install() {
check_architecture
check_riru_version
if [[ "$ARCH" == "x86" || "$ARCH" == "x64" ]]; then
ui_print "- Extracting x86/64 libraries"
unzip -o "$ZIPFILE" 'system_x86/*' -d $MODPATH >&2
mv "$MODPATH/system_x86/lib" "$MODPATH/system/lib"
mv "$MODPATH/system_x86/lib64" "$MODPATH/system/lib64"
else
ui_print "- Extracting arm/arm64 libraries"
unzip -o "$ZIPFILE" 'system/*' -d $MODPATH >&2
fi
if [[ "$IS64BIT" = false ]]; then
ui_print "- Removing 64-bit libraries"
rm -rf "$MODPATH/system/lib64"
fi
TARGET="$RIRU_PATH/modules"
ui_print "- Extracting extra files"
unzip -o "$ZIPFILE" 'data/*' -d "$TMPDIR" >&2
[[ -d "$TARGET" ]] || mkdir -p "$TARGET" || abort "! Can't mkdir -p $TARGET"
cp -af "$TMPDIR$TARGET/." "$TARGET" || abort "! Can't cp -af $TMPDIR$TARGET/. $TARGET"
cp -af "$TMPDIR/util_functions.sh" "$MODPATH/util_functions.sh" || abort "! Can't cp -af $TMPDIR/util_functions.sh $MODPATH/util_functions.sh"
ui_print "- Files copied"
}
set_permissions() {
# The following is the default rule, DO NOT remove
set_perm_recursive $MODPATH 0 0 0755 0644
# Here are some examples:
# set_perm_recursive $MODPATH/system/lib 0 0 0755 0644
# set_perm $MODPATH/system/bin/app_process32 0 2000 0755 u:object_r:zygote_exec:s0
# set_perm $MODPATH/system/bin/dex2oat 0 2000 0755 u:object_r:dex2oat_exec:s0
# set_perm $MODPATH/system/lib/libart.so 0 0 0644
}

View File

@ -0,0 +1,170 @@
#!/system/bin/sh
grep_prop() {
local REGEX="s/^$1=//p"
shift
local FILES=$@
[[ -z "$FILES" ]] && FILES='/system/build.prop'
sed -n "$REGEX" ${FILES} 2>/dev/null | head -n 1
}
MODDIR=${0%/*}
RIRU_PATH="/data/misc/riru"
TARGET="${RIRU_PATH}/modules"
[[ "$(getenforce)" == "Enforcing" ]] && ENFORCE=true || ENFORCE=false
EDXP_VERSION=$(grep_prop version "${MODDIR}/module.prop")
ANDROID_SDK=$(getprop ro.build.version.sdk)
BUILD_DESC=$(getprop ro.build.description)
PRODUCT=$(getprop ro.build.product)
MODEL=$(getprop ro.product.model)
MANUFACTURER=$(getprop ro.product.manufacturer)
BRAND=$(getprop ro.product.brand)
FINGERPRINT=$(getprop ro.build.fingerprint)
ARCH=$(getprop ro.product.cpu.abi)
DEVICE=$(getprop ro.product.device)
ANDROID=$(getprop ro.build.version.release)
BUILD=$(getprop ro.build.id)
RIRU_VERSION=$(cat "${RIRU_PATH}/version_name")
RIRU_VERCODE=$(cat "${RIRU_PATH}/version_code")
RIRU_APICODE=$(cat "${RIRU_PATH}/api_version")
MAGISK_VERSION=$(su -v)
MAGISK_VERCODE=$(su -V)
EDXP_MANAGER="org.meowcat.edxposed.manager"
XP_INSTALLER="de.robv.android.xposed.installer"
PATH_PREFIX="/data/user_de/0/"
#PATH_PREFIX_LEGACY="/data/user/0/"
sepolicy() {
# necessary for using mmap in system_server process
# read configs set in our app
# for built-in apps // TODO: maybe narrow down the target classes
# read module apk file in zygote
# TODO: remove coredomain sepolicy
supolicy --live "allow system_server system_server process { execmem }"\
"allow system_server system_server memprotect { mmap_zero }"\
"allow coredomain coredomain process { execmem }"\
"allow coredomain app_data_file * *"\
"attradd { system_app platform_app } mlstrustedsubject"\
"allow zygote apk_data_file * *"
}
#if [[ ${ANDROID_SDK} -ge 24 ]]; then
# PATH_PREFIX="${PATH_PREFIX_PROT}"
#else
# PATH_PREFIX="${PATH_PREFIX_LEGACY}"
#fi
DEFAULT_BASE_PATH="${PATH_PREFIX}${EDXP_MANAGER}"
BASE_PATH="${DEFAULT_BASE_PATH}"
if [[ ! -d ${BASE_PATH} ]]; then
BASE_PATH="${PATH_PREFIX}${XP_INSTALLER}"
if [[ ! -d ${BASE_PATH} ]]; then
BASE_PATH="${DEFAULT_BASE_PATH}"
fi
fi
LOG_PATH="${BASE_PATH}/log"
CONF_PATH="${BASE_PATH}/conf"
DISABLE_VERBOSE_LOG_FILE="${CONF_PATH}/disable_verbose_log"
LOG_VERBOSE=true
OLD_PATH=${PATH}
PATH=${PATH#*:}
PATH_INFO=$(ls -ldZ "${BASE_PATH}")
PATH=${OLD_PATH}
PATH_OWNER=$(echo "${PATH_INFO}" | awk -F " " '{print $3":"$4}')
PATH_CONTEXT=$(echo "${PATH_INFO}" | awk -F " " '{print $5}')
if [[ -f ${DISABLE_VERBOSE_LOG_FILE} ]]; then
LOG_VERBOSE=false
fi
start_log_cather () {
LOG_FILE_NAME=$1
LOG_TAG_FILTERS=$2
CLEAN_OLD=$3
START_NEW=$4
LOG_FILE="${LOG_PATH}/${LOG_FILE_NAME}.log"
PID_FILE="${LOG_PATH}/${LOG_FILE_NAME}.pid"
mkdir -p ${LOG_PATH}
if [[ ${CLEAN_OLD} == true ]]; then
rm "${LOG_FILE}.old"
mv "${LOG_FILE}" "${LOG_FILE}.old"
fi
rm "${LOG_PATH}/${LOG_FILE_NAME}.pid"
if [[ ${START_NEW} == false ]]; then
return
fi
touch ${LOG_FILE}
touch ${PID_FILE}
echo "--------- beginning of head">>${LOG_FILE}
echo "EdXposed Log">>${LOG_FILE}
echo "Powered by Log Catcher">>${LOG_FILE}
echo "QQ support group: 855219808">>${LOG_FILE}
echo "Telegram support group: @Code_Of_MeowCat">>${LOG_FILE}
echo "Telegram channel: @EdXposed">>${LOG_FILE}
echo "--------- beginning of information">>${LOG_FILE}
echo "Manufacturer: ${MANUFACTURER}">>${LOG_FILE}
echo "Brand: ${BRAND}">>${LOG_FILE}
echo "Device: ${DEVICE}">>${LOG_FILE}
echo "Product: ${PRODUCT}">>${LOG_FILE}
echo "Model: ${MODEL}">>${LOG_FILE}
echo "Fingerprint: ${FINGERPRINT}">>${LOG_FILE}
echo "ROM description: ${BUILD_DESC}">>${LOG_FILE}
echo "Architecture: ${ARCH}">>${LOG_FILE}
echo "Android build: ${BUILD}">>${LOG_FILE}
echo "Android version: ${ANDROID}">>${LOG_FILE}
echo "Android sdk: ${ANDROID_SDK}">>${LOG_FILE}
echo "EdXposed version: ${EDXP_VERSION}">>${LOG_FILE}
echo "EdXposed api: 91.0">>${LOG_FILE}
echo "Riru version: ${RIRU_VERSION} (${RIRU_VERCODE})">>${LOG_FILE}
echo "Riru api: ${RIRU_APICODE}">>${LOG_FILE}
echo "Magisk: ${MAGISK_VERSION%:*} (${MAGISK_VERCODE})">>${LOG_FILE}
logcat -f ${LOG_FILE} *:S ${LOG_TAG_FILTERS} &
LOG_PID=$!
echo "${LOG_PID}">"${LOG_PATH}/${LOG_FILE_NAME}.pid"
}
# Backup app_process to avoid bootloop caused by original Xposed replacement in Android Oreo
# TODO: Magisk mount replace
rm -rf "${MODDIR}/system/bin"
mkdir "${MODDIR}/system/bin"
cp -f "/system/bin/app_process32" "${MODDIR}/system/bin/app_process32"
[[ -f "/system/bin/app_process64" ]] && cp -f "/system/bin/app_process64" "${MODDIR}/system/bin/app_process64"
# install stub if manager not installed
if [[ "$(pm path org.meowcat.edxposed.manager)" == "" && "$(pm path de.robv.android.xposed.installer)" == "" ]]; then
NO_MANAGER=true
fi
if [[ ${NO_MANAGER} == true ]]; then
${ENFORCE} && setenforce 0
pm install "${MODDIR}/EdXposed.apk"
${ENFORCE} && setenforce 1
fi
# execute live patch if rule not found
[[ -f "${MODDIR}/sepolicy.rule" ]] || sepolicy
# start_verbose_log_catcher
start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE}
# start_bridge_log_catcher
start_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true
if [[ -f "/data/misc/riru/modules/edxp.prop" ]]; then
CONFIG=$(cat "/data/misc/riru/modules/edxp.prop")
[[ -d "${TARGET}/${CONFIG}" ]] || mkdir -p "${TARGET}/${CONFIG}"
cp "${MODDIR}/module.prop" "${TARGET}/${CONFIG}/module.prop"
fi
chcon -R u:object_r:system_file:s0 "${MODDIR}"
chcon -R ${PATH_CONTEXT} "${LOG_PATH}"
chown -R ${PATH_OWNER} "${LOG_PATH}"
chmod -R 666 "${LOG_PATH}"

View File

@ -0,0 +1,6 @@
allow system_server system_server process {execmem}
allow system_server system_server memprotect {mmap_zero}
allow coredomain coredomain process {execmem}
allow coredomain app_data_file * *
attradd {system_app platform_app} mlstrustedsubject
allow zygote apk_data_file * *

View File

@ -1,4 +1,24 @@
#!/sbin/sh
#rm -r -f /data/misc/riru/modules/edxposed/
#rm -r -f /data/misc/riru/modules/edxp/
MODDIR=${0%/*}
VARIANT="YAHFA"
REMOVE=false
[[ "$(echo ${MODDIR} | grep sandhook)" != "" ]] && VARIANT="SandHook"
if [[ "${VARIANT}" == "SandHook" ]]; then
[[ -f "${MODDIR}/../riru_edxposed/module.prop" ]] || REMOVE=true
else
[[ -f "${MODDIR}/../riru_edxposed_sandhook/module.prop" ]] || REMOVE=true
fi
if [[ "${REMOVE}" == true ]]; then
rm -rf /data/misc/riru/modules/edxp
if [[ -f "/data/misc/riru/modules/edxp.prop" ]]; then
OLD_CONFIG=$(cat "/data/misc/riru/modules/edxp.prop")
rm -rf "/data/misc/riru/modules/${OLD_CONFIG}"
rm "/data/misc/riru/modules/edxp.prop"
fi
fi

View File

@ -1,5 +1,5 @@
version=90.0-$version ($backend)
version=91.0-$version ($backend)
arch=arm64
minsdk=26
maxsdk=28
maxsdk=29
requires:fbe_aware=1

View File

@ -3,5 +3,5 @@ name=Riru - EdXposed
version=${versionName}
versionCode=${versionCode}
author=${authorList}
description=Magisk version of Xposed. Require Riru - Core v19+ installed. See change log in EdXposed Manager or Github Releases.
description=Another enhanced implementation of Xposed Framework. Supports Android 8.0, 8.1, 9, 10 or above. Requires Riru - Core v19 or above installed. Telegram: @EdXposed
api=4

View File

@ -2,8 +2,6 @@ package com.elderdrivers.riru.edxp.sandhook.core;
import android.os.Build;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.config.InstallerChooser;
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
import com.elderdrivers.riru.edxp.core.EdxpImpl;
import com.elderdrivers.riru.edxp.core.Main;
@ -36,9 +34,7 @@ public class SandHookEdxpImpl extends BaseEdxpImpl {
Yahfa.init(Build.VERSION.SDK_INT);
HookMethodResolver.init();
getRouter().injectConfig();
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
SandHookXposedBridge.init();
setInitialized();
}
}

View File

@ -1,24 +1,22 @@
package com.swift.sandhook.xposedcompat;
import android.annotation.SuppressLint;
import android.os.Process;
import android.text.TextUtils;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.ComposeClassLoader;
import com.elderdrivers.riru.edxp.util.FileUtils;
import com.elderdrivers.riru.edxp.util.ProcessUtils;
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
import com.swift.sandhook.wrapper.HookWrapper;
import com.swift.sandhook.xposedcompat.methodgen.SandHookXposedBridge;
import com.swift.sandhook.xposedcompat.utils.ApplicationUtils;
import com.swift.sandhook.xposedcompat.utils.FileUtils;
import com.swift.sandhook.xposedcompat.utils.ProcessUtils;
import java.io.File;
import java.lang.reflect.Member;
import de.robv.android.xposed.XposedBridge;
import static com.elderdrivers.riru.edxp.util.ProcessUtils.PER_USER_RANGE;
import static com.swift.sandhook.xposedcompat.utils.FileUtils.IS_USING_PROTECTED_STORAGE;
import static com.elderdrivers.riru.edxp.util.FileUtils.getDataPathPrefix;
public class XposedCompat {
@ -54,7 +52,7 @@ public class XposedCompat {
if (cacheDir == null) {
String fixedAppDataDir = getDataPathPrefix() + getPackageName(ConfigManager.appDataDir) + "/";
cacheDir = new File(fixedAppDataDir, "/cache/sandhook/"
+ ProcessUtils.getProcessName().replace(":", "_") + "/");
+ ProcessUtils.getProcessName(Process.myPid()).replace(":", "_") + "/");
}
return cacheDir;
}
@ -74,7 +72,7 @@ public class XposedCompat {
if (sandHookXposedClassLoader != null) {
return sandHookXposedClassLoader;
} else {
sandHookXposedClassLoader = new ComposeClassLoader(sandBoxHostClassLoader, appOriginClassLoader);
sandHookXposedClassLoader = new ProxyClassLoader(sandBoxHostClassLoader, appOriginClassLoader);
return sandHookXposedClassLoader;
}
}
@ -104,12 +102,4 @@ public class XposedCompat {
return dataDir.substring(lastIndex + 1);
}
// FIXME: Although multi-users is considered here, but compat mode doesn't support other users' apps on Oreo and later yet.
@SuppressLint("SdCardPath")
public static String getDataPathPrefix() {
int userId = Process.myUid() / PER_USER_RANGE;
String format = IS_USING_PROTECTED_STORAGE ? "/data/user_de/%d/" : "/data/user/%d/";
return String.format(format, userId);
}
}

View File

@ -244,6 +244,11 @@ public class HookStubManager {
args = entity.getArgs(stubArgs);
}
if (thiz == null)
{
thiz = originMethod.getDeclaringClass();
}
if (XposedBridge.disableHooks) {
if (hasStubBackup) {
return callOrigin.call(stubArgs);
@ -351,6 +356,7 @@ public class HookStubManager {
try {
((XC_MethodHook) snapshot[beforeIdx]).callBeforeHookedMethod(param);
} catch (Throwable t) {
XposedBridge.log(t);
// reset result (ignoring what the unexpectedly exiting callback did)
param.setResult(null);
param.returnEarly = false;

View File

@ -5,7 +5,9 @@ import android.os.Process;
import android.os.Trace;
import android.util.Log;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.ClassLoaderUtils;
import com.elderdrivers.riru.edxp.util.FileUtils;
import com.swift.sandhook.SandHook;
import com.swift.sandhook.SandHookConfig;
import com.swift.sandhook.blacklist.HookBlackList;
@ -14,7 +16,6 @@ import com.swift.sandhook.xposedcompat.XposedCompat;
import com.swift.sandhook.xposedcompat.hookstub.HookMethodEntity;
import com.swift.sandhook.xposedcompat.hookstub.HookStubManager;
import com.swift.sandhook.xposedcompat.utils.DexLog;
import com.swift.sandhook.xposedcompat.utils.FileUtils;
import java.io.File;
import java.lang.reflect.Constructor;
@ -84,7 +85,7 @@ public final class SandHookXposedBridge {
hookMaker = defaultHookMaker;
}
hookMaker.start(hookMethod, additionalHookInfo,
ClassLoaderUtils.createComposeClassLoader(
ClassLoaderUtils.createProxyClassLoader(
hookMethod.getDeclaringClass().getClassLoader()),
dexDir == null ? null : dexDir.getAbsolutePath());
hookedInfo.put(hookMethod, hookMaker.getCallBackupMethod());
@ -133,9 +134,11 @@ public final class SandHookXposedBridge {
public static void init() {
if (Process.is64Bit()) {
SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so";
// SandHookConfig.libSandHookPath = "/system/lib64/libsandhook.edxp.so";
SandHookConfig.libSandHookPath = "/system/lib64/" + ConfigManager.getLibSandHookName();
} else {
SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so";
// SandHookConfig.libSandHookPath = "/system/lib/libsandhook.edxp.so";
SandHookConfig.libSandHookPath = "/system/lib/" + ConfigManager.getLibSandHookName();
}
SandHookConfig.libLoader = new SandHookConfig.LibLoader() {
@Override

View File

@ -1,106 +0,0 @@
package com.swift.sandhook.xposedcompat.utils;
import android.os.Build;
import android.util.ArrayMap;
import com.elderdrivers.riru.edxp.sandhook.BuildConfig;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import dalvik.system.PathClassLoader;
public class ClassLoaderUtils {
public static final String DEXPATH = "/system/framework/edxposed.dex:/system/framework/eddalvikdx.dex:/system/framework/eddexmaker.dex";
public static void replaceParentClassLoader(ClassLoader appClassLoader) {
if (appClassLoader == null) {
DexLog.e("appClassLoader is null, you might be kidding me?");
return;
}
try {
ClassLoader curCL = ClassLoaderUtils.class.getClassLoader();
ClassLoader parent = appClassLoader;
ClassLoader lastChild = appClassLoader;
while (parent != null) {
ClassLoader tmp = parent.getParent();
if (tmp == curCL) {
DexLog.d("replacing has been done before, skip.");
return;
}
if (tmp == null) {
DexLog.d("before replacing =========================================>");
dumpClassLoaders(appClassLoader);
Field parentField = ClassLoader.class.getDeclaredField("parent");
parentField.setAccessible(true);
parentField.set(curCL, parent);
parentField.set(lastChild, curCL);
DexLog.d("after replacing ==========================================>");
dumpClassLoaders(appClassLoader);
}
lastChild = parent;
parent = tmp;
}
} catch (Throwable throwable) {
DexLog.e("error when replacing class loader.", throwable);
}
}
private static void dumpClassLoaders(ClassLoader classLoader) {
if (BuildConfig.DEBUG) {
while (classLoader != null) {
DexLog.d(classLoader + " =>");
classLoader = classLoader.getParent();
}
}
}
public static List<ClassLoader> getAppClassLoader() {
List<ClassLoader> cacheLoaders = new ArrayList<>(0);
try {
DexLog.d("start getting app classloader");
Class appLoadersClass = Class.forName("android.app.ApplicationLoaders");
Field loadersField = appLoadersClass.getDeclaredField("gApplicationLoaders");
loadersField.setAccessible(true);
Object loaders = loadersField.get(null);
Field mLoaderMapField = loaders.getClass().getDeclaredField("mLoaders");
mLoaderMapField.setAccessible(true);
ArrayMap<String, ClassLoader> mLoaderMap = (ArrayMap<String, ClassLoader>) mLoaderMapField.get(loaders);
DexLog.d("mLoaders size = " + mLoaderMap.size());
cacheLoaders = new ArrayList<>(mLoaderMap.values());
} catch (Exception ex) {
DexLog.e("error get app class loader.", ex);
}
return cacheLoaders;
}
private static HashSet<ClassLoader> classLoaders = new HashSet<>();
public static boolean addPathToClassLoader(ClassLoader classLoader) {
if (!(classLoader instanceof PathClassLoader)) {
DexLog.w(classLoader + " is not a BaseDexClassLoader!!!");
return false;
}
if (classLoaders.contains(classLoader)) {
DexLog.d(classLoader + " has been hooked before");
return true;
}
try {
PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//baseDexClassLoader.addDexPath(DEXPATH);
} else {
DexUtils.injectDexAtFirst(DEXPATH, baseDexClassLoader);
}
classLoaders.add(classLoader);
return true;
} catch (Throwable throwable) {
DexLog.e("error when addPath to ClassLoader: " + classLoader, throwable);
}
return false;
}
}

View File

@ -1,66 +0,0 @@
package com.swift.sandhook.xposedcompat.utils;
import android.annotation.TargetApi;
import android.os.Build;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import dalvik.system.BaseDexClassLoader;
import dalvik.system.DexClassLoader;
/**
* For 6.0 only.
*/
@TargetApi(Build.VERSION_CODES.M)
public class DexUtils {
public static void injectDexAtFirst(String dexPath, BaseDexClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
DexClassLoader dexClassLoader = new DexClassLoader(dexPath, null, dexPath, classLoader);
Object baseDexElements = getDexElements(getPathList(classLoader));
Object newDexElements = getDexElements(getPathList(dexClassLoader));
Object allDexElements = combineArray(newDexElements, baseDexElements);
Object pathList = getPathList(classLoader);
setField(pathList, pathList.getClass(), "dexElements", allDexElements);
}
private static Object getDexElements(Object paramObject)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException {
return getField(paramObject, paramObject.getClass(), "dexElements");
}
private static Object getPathList(Object baseDexClassLoader)
throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
return getField(baseDexClassLoader, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList");
}
private static Object combineArray(Object firstArray, Object secondArray) {
Class<?> localClass = firstArray.getClass().getComponentType();
int firstArrayLength = Array.getLength(firstArray);
int allLength = firstArrayLength + Array.getLength(secondArray);
Object result = Array.newInstance(localClass, allLength);
for (int k = 0; k < allLength; ++k) {
if (k < firstArrayLength) {
Array.set(result, k, Array.get(firstArray, k));
} else {
Array.set(result, k, Array.get(secondArray, k - firstArrayLength));
}
}
return result;
}
public static Object getField(Object obj, Class<?> cl, String field)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(obj);
}
public static void setField(Object obj, Class<?> cl, String field, Object value)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
localField.set(obj, value);
}
}

View File

@ -1,77 +0,0 @@
package com.swift.sandhook.xposedcompat.utils;
import android.os.Build;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtils {
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
/**
* Delete a file or a directory and its children.
*
* @param file The directory to delete.
* @throws IOException Exception when problem occurs during deleting the directory.
*/
public static void delete(File file) throws IOException {
for (File childFile : file.listFiles()) {
if (childFile.isDirectory()) {
delete(childFile);
} else {
if (!childFile.delete()) {
throw new IOException();
}
}
}
if (!file.delete()) {
throw new IOException();
}
}
public static String readLine(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
return reader.readLine();
} catch (Throwable throwable) {
return "";
}
}
public static void writeLine(File file, String line) {
try {
file.createNewFile();
} catch (IOException ex) {
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(line);
writer.flush();
} catch (Throwable throwable) {
DexLog.e("error writing line to file " + file + ": " + throwable.getMessage());
}
}
public static String getPackageName(String dataDir) {
if (TextUtils.isEmpty(dataDir)) {
DexLog.e("getPackageName using empty dataDir");
return "";
}
int lastIndex = dataDir.lastIndexOf("/");
if (lastIndex < 0) {
return dataDir;
}
return dataDir.substring(lastIndex + 1);
}
public static String getDataPathPrefix() {
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
}
}

View File

@ -1,90 +0,0 @@
package com.swift.sandhook.xposedcompat.utils;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* Created by swift_gan on 2017/11/23.
*/
public class ProcessUtils {
public static String getProcessName() {
return getProcessName(Process.myPid());
}
private static String doGetProcessName(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) {
if (proInfo.pid == android.os.Process.myPid()) {
if (proInfo.processName != null) {
return proInfo.processName;
}
}
}
return context.getPackageName();
}
public static String getProcessName(int pid) {
BufferedReader cmdlineReader = null;
try {
cmdlineReader = new BufferedReader(new InputStreamReader(
new FileInputStream(
"/proc/" + pid + "/cmdline"),
"iso-8859-1"));
int c;
StringBuilder processName = new StringBuilder();
while ((c = cmdlineReader.read()) > 0) {
processName.append((char) c);
}
return processName.toString();
} catch (Throwable throwable) {
DexLog.w("getProcessName: " + throwable.getMessage());
} finally {
try {
if (cmdlineReader != null) {
cmdlineReader.close();
}
} catch (Throwable throwable) {
DexLog.e("getProcessName: " + throwable.getMessage());
}
}
return "";
}
public static boolean isMainProcess(Context context) {
String processName = getProcessName();
String pkgName = context.getPackageName();
if (!TextUtils.isEmpty(processName) && !TextUtils.equals(processName, pkgName)) {
return false;
} else {
return true;
}
}
public static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
final PackageManager packageManager = context.getPackageManager();
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(packageName);
final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
return apps != null ? apps : new ArrayList<ResolveInfo>();
}
}

View File

@ -2,12 +2,9 @@ package com.elderdrivers.riru.edxp.whale.core;
import android.os.Build;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.config.InstallerChooser;
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
import com.elderdrivers.riru.edxp.core.EdxpImpl;
import com.elderdrivers.riru.edxp.core.Main;
import com.elderdrivers.riru.edxp.core.Proxy;
import com.elderdrivers.riru.edxp.core.Yahfa;
import com.elderdrivers.riru.edxp.core.yahfa.HookMethodResolver;
import com.elderdrivers.riru.edxp.proxy.Router;
@ -36,8 +33,6 @@ public class WhaleEdxpImpl extends BaseEdxpImpl {
Yahfa.init(Build.VERSION.SDK_INT);
HookMethodResolver.init();
getRouter().injectConfig();
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
setInitialized();
}

View File

@ -1,5 +1,6 @@
package com.elderdrivers.riru.edxp.whale.core;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import com.elderdrivers.riru.edxp.framework.Zygote;
import com.elderdrivers.riru.edxp.proxy.BaseRouter;
@ -16,8 +17,10 @@ public class WhaleRouter extends BaseRouter {
BaseRouter.useXposedApi = true;
EdXpConfigGlobal.sConfig = new WhaleEdxpConfig();
EdXpConfigGlobal.sHookProvider = new WhaleHookProvider();
Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so");
Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so");
// Zygote.allowFileAcrossFork("/system/lib/libwhale.edxp.so");
// Zygote.allowFileAcrossFork("/system/lib64/libwhale.edxp.so");
Zygote.allowFileAcrossFork("/system/lib/" + ConfigManager.getLibWhaleName());
Zygote.allowFileAcrossFork("/system/lib64/" + ConfigManager.getLibWhaleName());
Zygote.allowFileAcrossFork("/system/lib/libart.so");
Zygote.allowFileAcrossFork("/system/lib64/libart.so");
}

View File

@ -2,8 +2,6 @@ package com.elderdrivers.riru.edxp.yahfa.core;
import android.os.Build;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.config.InstallerChooser;
import com.elderdrivers.riru.edxp.core.BaseEdxpImpl;
import com.elderdrivers.riru.edxp.core.EdxpImpl;
import com.elderdrivers.riru.edxp.core.Main;
@ -34,8 +32,6 @@ public class YahfaEdxpImpl extends BaseEdxpImpl {
Yahfa.init(Build.VERSION.SDK_INT);
HookMethodResolver.init();
getRouter().injectConfig();
InstallerChooser.setInstallerPackageName(ConfigManager.getInstallerPackageName());
setInitialized();
}

View File

@ -6,7 +6,7 @@ import android.text.TextUtils;
import com.elderdrivers.riru.edxp.core.Yahfa;
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
import com.elderdrivers.riru.edxp.util.ComposeClassLoader;
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
import java.io.File;
import java.lang.reflect.Constructor;
@ -181,7 +181,7 @@ public class HookerDexMaker {
mAppClassLoader = getClass().getClassLoader();
} else {
mAppClassLoader = appClassLoader;
mAppClassLoader = new ComposeClassLoader(mAppClassLoader, getClass().getClassLoader());
mAppClassLoader = new ProxyClassLoader(mAppClassLoader, getClass().getClassLoader());
}
doMake();
}

View File

@ -8,6 +8,7 @@ import android.graphics.Movie;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.StrictMode;
import android.text.Html;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@ -115,8 +116,10 @@ public class XResources extends XResourcesSuperClass {
if (mResDir == null)
return false;
final StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads();
Long lastModification = new File(mResDir).lastModified();
Long oldModified = sResDirLastModified.get(mResDir);
StrictMode.setThreadPolicy(policy);
if (lastModification.equals(oldModified))
return false;

View File

@ -2,12 +2,22 @@ package com.elderdrivers.riru.edxp.config;
public interface EdxpConfig {
String getInstallerBaseDir();
String getInstallerConfigPath(String suffix);
String getBlackListModulePackageName();
String getDataPathPrefix();
String getInstallerPackageName();
String getXposedPropPath();
String getLibSandHookName();
String getLibWhaleName();
boolean isDynamicModulesMode();
boolean isNoModuleLogEnabled();
boolean isResourcesHookEnabled();
boolean isBlackWhiteListMode();

View File

@ -1,6 +1,11 @@
package de.robv.android.xposed;
import android.os.SELinux;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import de.robv.android.xposed.services.BaseService;
import de.robv.android.xposed.services.BinderService;
@ -28,7 +33,36 @@ public final class SELinuxHelper {
* @return A boolean indicating whether SELinux is enforcing.
*/
public static boolean isSELinuxEnforced() {
return sIsSELinuxEnabled && SELinux.isSELinuxEnforced();
if (!sIsSELinuxEnabled) {
return false;
}
boolean result = false;
final File SELINUX_STATUS_FILE = new File("/sys/fs/selinux/enforce");
if (SELINUX_STATUS_FILE.exists()) {
try {
FileInputStream fis = new FileInputStream(SELINUX_STATUS_FILE);
int status = fis.read();
switch (status) {
case 49:
result = true;
break;
case 48:
result = false;
break;
default:
XposedBridge.log("Unexpected byte " + status + " in /sys/fs/selinux/enforce");
}
fis.close();
} catch (IOException e) {
if (e.getMessage().contains("Permission denied")) {
result = true;
} else {
XposedBridge.log("Failed to read SELinux status: " + e.getMessage());
result = false;
}
}
}
return result;
}
/**
@ -56,14 +90,15 @@ public final class SELinuxHelper {
// ----------------------------------------------------------------------------
// TODO: SELinux status
private static boolean sIsSELinuxEnabled = false;
private static BaseService sServiceAppDataFile = new DirectAccessService(); // ed: initialized directly
/*package*/ static void initOnce() {
/*package*/ public static void initOnce() {
// ed: we assume all selinux policies have been added lively using magiskpolicy
// try {
// sIsSELinuxEnabled = SELinux.isSELinuxEnabled();
// } catch (NoClassDefFoundError ignored) {}
try {
sIsSELinuxEnabled = SELinux.isSELinuxEnabled();
} catch (NoClassDefFoundError ignored) {}
}
/*package*/ static void initForProcess(String packageName) {

View File

@ -29,6 +29,7 @@ public abstract class XC_MethodReplacement extends XC_MethodHook {
Object result = replaceHookedMethod(param);
param.setResult(result);
} catch (Throwable t) {
XposedBridge.log(t);
param.setThrowable(t);
}
}

View File

@ -24,6 +24,8 @@ import de.robv.android.xposed.services.FileResult;
* This class is basically the same as SharedPreferencesImpl from AOSP, but
* read-only and without listeners support. Instead, it is made to be
* compatible with all ROMs.
*
* @deprecated in Android Pie or later was lost by Google, will not remove
*/
public final class XSharedPreferences implements SharedPreferences {
private static final String TAG = "XSharedPreferences";
@ -128,11 +130,11 @@ public final class XSharedPreferences implements SharedPreferences {
map = mMap;
}
} catch (XmlPullParserException e) {
Log.w(TAG, "getSharedPreferences", e);
Log.w(TAG, "getSharedPreferences failed for: " + mFilename, e);
} catch (FileNotFoundException ignored) {
// SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist
} catch (IOException e) {
Log.w(TAG, "getSharedPreferences", e);
Log.w(TAG, "getSharedPreferences failed for: " + mFilename, e);
} finally {
if (result != null && result.stream != null) {
try {

View File

@ -143,11 +143,11 @@ public final class XposedBridge {
*/
public static int getXposedVersion() {
// ed: fixed value for now
return 90;
return 91;
}
/**
* Writes a message to the Xposed error log.
* Writes a message to the Xposed modules log.
*
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
* If you want to write information/debug messages, use logcat.
@ -155,11 +155,14 @@ public final class XposedBridge {
* @param text The log message.
*/
public synchronized static void log(String text) {
if (EdXpConfigGlobal.getConfig().isNoModuleLogEnabled()) {
return;
}
Log.i(TAG, text);
}
/**
* Logs a stack trace to the Xposed error log.
* Logs a stack trace to the Xposed modules log.
*
* <p class="warning"><b>DON'T FLOOD THE LOG!!!</b> This is only meant for error logging.
* If you want to write information/debug messages, use logcat.

View File

@ -10,7 +10,6 @@ import android.content.res.XResources;
import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@ -313,7 +312,7 @@ public final class XposedInit {
return false;
}
synchronized (moduleLoadLock) {
final String filename = EdXpConfigGlobal.getConfig().getInstallerBaseDir() + "conf/modules.list";
final String filename = EdXpConfigGlobal.getConfig().getInstallerConfigPath("modules.list");
BaseService service = SELinuxHelper.getAppDataFileService();
if (!service.checkFileExists(filename)) {
Log.e(TAG, "Cannot load any modules because " + filename + " was not found");
@ -399,14 +398,6 @@ public final class XposedInit {
private static boolean loadModule(String apk, ClassLoader topClassLoader, boolean callInitZygote) {
Log.i(TAG, "Loading modules from " + apk);
// todo remove this legacy logic
String blackListModulePackageName = EdXpConfigGlobal.getConfig().getBlackListModulePackageName();
if (!TextUtils.isEmpty(apk) && !TextUtils.isEmpty(blackListModulePackageName)
&& apk.contains(blackListModulePackageName)) {
Log.i(TAG, "We are going to take over black list's job...");
return false;
}
if (!new File(apk).exists()) {
Log.e(TAG, " File does not exist");
return false;