Skip to content

Commit

Permalink
First submit
Browse files Browse the repository at this point in the history
  • Loading branch information
sanfengAndroid committed Feb 22, 2021
1 parent 5bf7744 commit 4e7cc18
Show file tree
Hide file tree
Showing 249 changed files with 22,341 additions and 0 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Android CI

on:
push:
branches: [ main ]

jobs:
build:
name: Build Apk on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest, macOS-latest ]

steps:
- name: Check out
uses: actions/checkout@v2
with:
submodules: 'recursive'
fetch-depth: 0

- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8

- name: Set up Python 3
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Set up GitHub env (Windows)
if: runner.os == 'Windows'
run: |
echo "ANDROID_SDK_ROOT=$env:ANDROID_SDK_ROOT" >> $env:GITHUB_ENV
- name: Set up GitHub env (Unix)
if: runner.os != 'Windows'
run: |
echo ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT >> $GITHUB_ENV
- name: Cache Gradle
uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle-

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build release
run: python build.py -vrm -f ${{ secrets.storeFileBase64 }} -s ${{ secrets.signConfig }} -l 3 all

- name: Build debug
run: python build.py -vm -f ${{ secrets.storeFileBase64 }} -s ${{ secrets.signConfig }} all

- name: Upload a Build Artifact
if: runner.os == 'Linux'
uses: actions/[email protected]
with:
name: ${{ github.sha }}
path: out
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.iml
.gradle
.idea
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "fake-linker"]
path = fake-linker
url = https://github.com/sanfengAndroid/fake-linker.git
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# FakeXposed
![License](https://img.shields.io/badge/License-Apache2-blue)

Chinese document click [here](README_CN.md)

## Project description
Use [fake-linker](https://github.com/sanfengAndroid/fake-linker) in combination with `Xposed` to provide `Java` and `Native` bidirectional shielding of `Xposed` detection, and also provide additional file redirection, `JNI` monitor, file access control, provide to other modules to dynamically add or modify the configuration in the process.

## Principle analysis introduction
View [FakeXposed principle analysis](https://sanfengandroid.github.io/2021/02/20/fakexposed-principle-analyze/)

## Supported Android
Android version: `Android 5.0` ~ `Android 11`+. Support instructions: `x86`, `x86_64`, `arm`, `arm64`.`Api 25` Because the new version of `NDK` is removed, you need to change the `NDK` version to adapt and compile

## Build
- Required build environment: Any platform that supports `Android Studio`, `Python 3.6+` (for script build)
- Build configuration: Edit [local.properties.sample](local.properties.sample) sample configuration and rename it to `local.properties` or pass the configuration path `-PconfigPath` to `gradle`
- Clone sources: `git clone --recurse-submodules https://github.com/sanfengAndroid/FakeXposed.git`
- Android Studio build: Import the source code into `Android Studio`, modify the configuration and compile
- Command line build
- Install Python 3.6+ (Windows platform only: add `Python` to the environment variable `PATH`, and run `pip install colorama`)
- Set `ANDROID_SDK_ROOT` to the system environment variable, and install `Android NDK 22.0.7026061`, which can be done in `Android Studio SDK Manager`
- Run `python build.py -vrm all` to execute a complete `Release` build
- Run `python build.py -vrm api 30` to compile only `Android Api level 30`
- For more options, please see the [build.py](build.py) script

## Download
[Download the latest Release version](https://github.com/sanfengAndroid/FakeXposed/releases/latest)

## Usage
1. This application is the `Xposed` module, not limited to the original `Xposed`, `Taichi`, `EdXposed`, `VirtualXposed`, you need to enable the module in the specified `Xposed manager` .Normal status is as follows ![home](capture/en/home.png)
2. Enable `Global Hook` and specify `Application Hook` as needed, and the module will determine whether to enable an application separately. Long press to turn on/off ![package_configuration](capture/en/package_configuration.png)
3. Configure different hook options for each application or globally, such as file blacklist, hidden `maps` rules, file redirection, access control, package visibility, etc. ![package_hidden](capture/en/package_hidden.png) ![dlsym_hidden](capture/en/dlsym_hidden.png)
4. `Android 7` The following data sharing uses `XSharedPreferences` without additional permissions. If you have `root` permissions on Android 7 and above, it is recommended to use `root` permissions to install configuration files to another path for other applications to access, otherwise you need to set This software has `self-start` permission, and uses `ContentProvider` to exchange data, which may significantly increase the start-up time

## Other module calls
- Get the `ClassLoader` of the module

Hook an unused method in the application `ClassLoader.defineClass`
```Java
XposedHelpers.findAndHookMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String name = (String) param.args[0];
if (TextUtils.equals(name, BuildConfig.APPLICATION_ID)){
LogUtil.d(TAG, "define class get self class");
param.setResult(NativeHook.class);
}
}
});
```
Obtain `NativeHook.class` by calling as follows. Note that `defineClass` has several overloaded methods. Only the ones that match the above signature can be obtained, otherwise you will get an exception
```Java
Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
Class<?> nativeHook = (Class<?>) method.invoke(getClassLoader(), BuildConfig.APPLICATION_ID, null, 0, 0);
```
Get the `NativeHook.class` to get the corresponding `ClassLoader`, and then call various functions through reflection to add or delete configurations

**Note: The loading order of Xposed modules is not controllable, so it is best to enter the application execution timing (such as the application Application.onCreate method) and then obtain `NativeHook.class`, and then use reflection operation, the source package name is `com.sanfengandroid.fakeinterface The classes under `will not be confused**
- Invoke interface

The data mainly involves `Java` and `Native` data, all of which contains the complete configuration in `Java` [GlobalConfig](app/src/main/java/com/sanfengandroid/fakeinterface/GlobalConfig.java), the core data is as follows
```Java
public class GlobalConfig {
private static final String TAG = GlobalConfig.class.getSimpleName();
private static final Map<String, ?>[] maps;
private static final Object EXIST = new Object();
private static final Map<String, String> classBlacklist = new HashMap<>();
private static final Map<String, String> stackClassBlacklist = new HashMap<>();
private static final Map<String, String> packageBlacklist = new HashMap<>();
private static final Map<Integer, Object> hookMethodModifierFilter = new HashMap<>();
private static final ObservableMap<String, String> propBlacklist = new ObservableMap<>();
private static final ObservableMap<String, EnvBean> envBlacklist = new ObservableMap<>();
private static final Map<String, String> globalPropertyBlacklist = new HashMap<>();
private static final Map<String, String> componentKeyBlacklist = new HashMap<>();
private static final Map<String, String> globalSettingsBlacklist = new HashMap<>();
private static final Map<String, ExecBean> runtimeBlackList = new HashMap<>();
private static final Map<String, String> fileBlacklist = new HashMap<>();
private static final Map<String, String> symbolBlacklist = new HashMap<>();
private static final Map<String, String> mapsBlacklist = new HashMap<>();
private static final Map<String, String> fileRedirectList = new HashMap<>();
private static final Map<String, String> fileAccessList = new HashMap<>();
}
```
-`Java Hook` data modification: directly reflect and modify the above `Map` object to take effect
-`Native Hook` data modification: In addition to modifying the above `Map` object, you need to call [NativeInit.nativeSync](app/src/main/java/com/sanfengandroid/fakeinterface/NativeInit.java#nativeSync), which will clear some `native` data (file blacklist, symbol blacklist, attribute replacement, etc.) and then re-synchronized to `native`, which means that some old data is still in effect (maps rule, file redirection, file access permission configuration), but It can be updated
```cpp
static void NativeHook_ClearAll(JNIEnv *env, jclass clazz) {
file_blacklist.clear();
file_path_blacklist.clear();
symbol_blacklist.clear();
properties.clear();
}
```
There are some other `Native` interfaces that can be viewed by themselves. [NativeHook](app/src/main/java/com/sanfengandroid/fakeinterface/NativeHook.java) Just call those public methods by reflection

**Note: This application may have compatibility issues, please make a backup when the Hook system is in progress**

**The application has not undergone a lot of testing. If you have any questions, you can leave a message on github, blog or wechat public**
## Reference
[RootCloak](https://github.com/devadvance/rootcloak)

[XposedChecker](https://github.com/w568w/XposedChecker)
103 changes: 103 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# FakeXposed
![License](https://img.shields.io/badge/License-Apache2-blue)

## 项目描述
使用 [fake-linker](https://github.com/sanfengAndroid/fake-linker)`Xposed` 结合,提供 `Java``Native` 双向屏蔽 `Xposed`检测,还提供额外的文件重定向、`JNI`监听、文件访问权限控制、提供给其它模块在进程内动态添加或修改配置。

## 原理分析介绍
查看 [FakeXposed原理分析](https://sanfengandroid.github.io/2021/02/20/fakexposed-principle-analyze/)

## 支持的Android版本
支持版本:`Android 5.0 ~ Android 11+`,支持架构:`x86``x86_64``arm``arm64``Api 25`由于新版本 `NDK` 移除需要自行改变 `NDK` 版本适配编译

## 构建
- 需要的编译环境:任何支持`Android Studio`的平台, `Python 3.6+`(脚本编译使用)
- 编译配置:编辑 [local.properties.sample](local.properties.sample) 示例配置,改名为 `local.properties` 或向 `gradle` 传递配置路径 `-PconfigPath`
- 克隆源码: `git clone --recurse-submodules https://github.com/sanfengAndroid/FakeXposed.git`
- Android Studio构建:导入源码到 `Android Studio`中 修改配置编译即可
- 命令行编译
- 安装Python 3.6+(Windows平台:添加 `Python` 到环境变量`PATH`中,并运行 `pip install colorama`
- 设置 `ANDROID_SDK_ROOT` 到系统环境变量,并安装`Android NDK 22.0.7026061`,可在`Android Studio SDK Manager`中完成
- 运行 `python build.py -vrm all` 执行完整 `Release` 编译
- 运行 `python build.py -vrm api 30`只编译`Android Api level 30`
- 更多选项请查看 [build.py](build.py) 脚本

## 下载
[最新Release版本下载](https://github.com/sanfengAndroid/FakeXposed/releases/latest)

## 使用介绍
1. 本软件是`Xposed`模块,不限于原版`Xposed``Taichi``EdXposed``VirtualXposed`,需到指定的 `Xposed管理器` 中启用该模块,状态正常则如下 ![home](capture/cn/home.png)
2. 根据需要开启`全局Hook` 和指定 `应用Hook`,模块内部会单独判断对某个应用是否启,长按开启/关闭 ![package_configuration](capture/cn/package_configuration.png)

3. 为每一个应用或全局配置不同的Hook选项,如文件黑名单、隐藏`maps`规则、文件重定向、访问控制、包可见性等 ![package_hidden](capture/cn/package_hidden.png) ![dlsym_hidden](capture/cn/dlsym_hidden.png)
4. `Android 7` 以下数据共享使用 `XSharedPreferences` 无需额外权限,`Android 7` 以上如果有 `root` 权限推荐使用 `root` 权限来安装配置文件到另外的路径以供其它应用访问,否者需要设置本软件 `自启动` 权限,使用 `ContentProvider` 交换数据,这可能会显著增加启动时长

## 其它模块调用
- 获取模块的 `ClassLoader`

应用内部Hook一个不被使用的方法 `ClassLoader.defineClass`
```Java
XposedHelpers.findAndHookMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String name = (String) param.args[0];
if (TextUtils.equals(name, BuildConfig.APPLICATION_ID)){
LogUtil.d(TAG, "define class get self class");
param.setResult(NativeHook.class);
}
}
});
```
通过如下调用获取 `NativeHook.class`,注意 `defineClass` 有几个重载方法,只有匹配上面签名的才可以获取,否者会得到异常
```Java
Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
Class<?> nativeHook = (Class<?>) method.invoke(getClassLoader(), BuildConfig.APPLICATION_ID, null, 0, 0);
```
获取到 `NativeHook.class` 就能够获取到对应的 `ClassLoader`,然后通过反射调用各种函数来添加或删除配置

**注意:Xposed 模块的加载顺序不可控制,因此最好进入应用执行时机(如应用Application.onCreate方法)后再获取`NativeHook.class`,然后通过反射操作,源码包名 `com.sanfengandroid.fakeinterface` 下的类都不会被混淆**
- 调用接口

数据主要涉及到 `Java` 和 `Native`数据,其中所有数据在 `Java` [GlobalConfig](app/src/main/java/com/sanfengandroid/fakeinterface/GlobalConfig.java) 中包含完整配置,核心数据如下
```Java
public class GlobalConfig {
private static final String TAG = GlobalConfig.class.getSimpleName();
private static final Map<String, ?>[] maps;
private static final Object EXIST = new Object();
private static final Map<String, String> classBlacklist = new HashMap<>();
private static final Map<String, String> stackClassBlacklist = new HashMap<>();
private static final Map<String, String> packageBlacklist = new HashMap<>();
private static final Map<Integer, Object> hookMethodModifierFilter = new HashMap<>();
private static final ObservableMap<String, String> propBlacklist = new ObservableMap<>();
private static final ObservableMap<String, EnvBean> envBlacklist = new ObservableMap<>();
private static final Map<String, String> globalPropertyBlacklist = new HashMap<>();
private static final Map<String, String> componentKeyBlacklist = new HashMap<>();
private static final Map<String, String> globalSettingsBlacklist = new HashMap<>();
private static final Map<String, ExecBean> runtimeBlackList = new HashMap<>();
private static final Map<String, String> fileBlacklist = new HashMap<>();
private static final Map<String, String> symbolBlacklist = new HashMap<>();
private static final Map<String, String> mapsBlacklist = new HashMap<>();
private static final Map<String, String> fileRedirectList = new HashMap<>();
private static final Map<String, String> fileAccessList = new HashMap<>();
}
```
- `Java Hook` 数据修改: 直接反射修改上面的 `Map` 对象即可生效
- `Native Hook` 数据修改:除了修改上面的 `Map` 对象还需要调用 [NativeInit.nativeSync](app/src/main/java/com/sanfengandroid/fakeinterface/NativeInit.java#nativeSync),这会清除部分 `native` 数据(文件黑名单,符号黑名单,属性替换等)然后重新同步至 `native`,这意味着有些旧数据还是在生效中(maps规则、文件重定向、文件访问权限配置),清除它们可能会引起不必要的问题,但是它可以被更新
```cpp
static void NativeHook_ClearAll(JNIEnv *env, jclass clazz) {
file_blacklist.clear();
file_path_blacklist.clear();
symbol_blacklist.clear();
properties.clear();
}
```
还有一些其它的 `Native` 接口可以自行查看 [NativeHook](app/src/main/java/com/sanfengandroid/fakeinterface/NativeHook.java) 反射调用那些公开的方法即可

**注意:本应用可能存在兼容性问题,在Hook系统进程时请做好备份**

**软件没有经过大量测试,有问题可以github、博客留言、公众号留言均可**
## 参考
[RootCloak](https://github.com/devadvance/rootcloak)

[XposedChecker](https://github.com/w568w/XposedChecker)
2 changes: 2 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/build
/src/main/libs
Loading

0 comments on commit 4e7cc18

Please sign in to comment.