leolovenet/Zygisk-FridaGadget
GitHub: leolovenet/Zygisk-FridaGadget
一个基于 Zygisk 的 Magisk 模块,用于在 frida-server 无法稳定运行的设备上,通过配置将 Frida Gadget 选择性注入目标 Android 进程。
Stars: 0 | Forks: 0
# Zygisk - Frida Gadget
这是一个通过配置驱动的 Zygisk 模块,用于将 Frida Gadget 注入到选定的 Android 应用进程中。
默认的示例目标是 `com.example.app`,但目标是在 `targets.conf` 中配置的,不需要修改 C++ 代码。
## 使用场景
当 `frida-server` 无法在设备上稳定运行时(例如由于厂商限制、进程隐藏、可执行文件映射策略或其他运行时限制),本模块旨在作为基于 Frida Gadget 的替代方案。
该模块不会启动全局的 `frida-server`,而是利用 Zygisk 进入选定的应用进程,并仅为已配置的目标加载 Frida Gadget。
## 负责任地使用
本项目适用于对您拥有或已获得明确授权的设备与应用程序,进行合法的安全研究、调试、兼容性分析以及防御性测试。
未经授权,请勿使用本项目访问、修改、埋点或监控任何应用程序、系统或数据。
## 运行环境要求
- Magisk 27001 / Kitsune Magisk(需启用 Zygisk)
## 构建要求
- Android NDK r26+
- `ndk-build`
- Python 3
## 在 macOS 上配置 NDK
```
export ANDROID_NDK_HOME=/path/to/android-ndk-r26d
export PATH="$ANDROID_NDK_HOME:$PATH"
```
## 下载 Frida Gadget
从 Frida 官方发布页面下载 Android Gadget:
```
https://github.com/frida/frida/releases
```
请使用与您的目标设备/应用相匹配的 ABI 文件:
```
frida-gadget--android-arm64.so.xz
frida-gadget--android-arm.so.xz
```
解压后,如果您愿意,可以保留源文件名中的版本号:
```
gadget/
arm64-v8a/
.gitkeep
libgadget-17.15.3.so
libgadget.so -> libgadget-17.15.3.so
armeabi-v7a/
.gitkeep
libgadget-17.15.3.so
libgadget.so -> libgadget-17.15.3.so
libgadget.config.so
```
这是发布版本的推荐目录结构,因为多个 Gadget 版本可以共存,同时由 `libgadget.so` 来选择要部署的版本。在部署期间,模块会解析所选的真实文件,并将其作为以下名称复制到目标应用的 native lib 目录中:
```
libgadget.so
```
保持部署后的文件名稳定是刻意为之的:Frida Gadget 会在已加载的 `libgadget.so` 旁边自动发现 `libgadget.config.so`。
`.gitkeep` 文件仅在克隆仓库时用于保持 ABI 目录的存在。它们在运行时不会被使用。
源文件名也可以是纯净的格式:
```
gadget/arm64-v8a/libgadget.so
gadget/armeabi-v7a/libgadget.so
```
每个 ABI 目录的选择规则:
```
1. If libgadget.so is a symlink, its target is used.
2. If libgadget.so is a small selector file, its contents are treated as the selected Gadget path.
3. If libgadget.so is a regular Gadget file, that file is used.
4. If libgadget.so is missing and exactly one versioned Gadget file exists, deployment creates libgadget.so as a symlink to it.
5. If multiple versioned Gadget files exist and libgadget.so is missing, deployment is skipped for that ABI and deploy.log records the ambiguity.
```
选择器文件适用于简短的相对路径名称(例如 `libgadget-17.15.3.so`),或者在您确实需要时使用绝对路径。大于 256 字节的文件将被视为真实的 `.so` 文件,而不是选择器。这使得选择器路径配置更加灵活,同时避免了意外将二进制文件误判为选择器。
要切换版本,请更新软链接并再次运行 `action.sh`:
```
adb shell su -c 'cd /data/adb/modules/zygisk_frida_gadget/gadget/arm64-v8a && ln -sf libgadget-17.15.3.so libgadget.so'
adb shell su -c '/data/adb/modules/zygisk_frida_gadget/action.sh'
```
## Gadget 配置
将 Gadget 配置文件放在项目根目录:
```
libgadget.config.so
```
您也可以将特定 ABI 的配置文件放在 Gadget 二进制文件旁边:
```
gadget/arm64-v8a/libgadget.config.so
gadget/armeabi-v7a/libgadget.config.so
```
特定 ABI 的配置优先于根目录的配置。
## 配置目标
编辑 `targets.conf`:
```
# package|process|match|abi
com.example.app|com.example.app|exact|auto
```
字段说明:
```
package: target Android package name, used for deployment under /data/app
process: optional target process name, compared with args->nice_name from Zygisk
match: optional process-name matching mode, defaults to exact
abi: optional Gadget ABI selection, defaults to auto
```
如果省略 `process` 或将其留空,则默认使用包名。以下形式是等价的:
```
com.example.app
com.example.app|
com.example.app|com.example.app
com.example.app|com.example.app|exact
com.example.app|com.example.app|exact|auto
```
支持的 `match` 值:
```
exact
prefix
suffix
contains
```
`match` 控制如何将配置的 `process` 值与真实的进程名称进行比较:
```
exact: load only when process name is exactly equal
prefix: load when process name starts with the configured value
suffix: load when process name ends with the configured value
contains: load when process name contains the configured value
```
对于大多数应用,建议从 `exact` 开始,以避免无意中注入子进程、沙箱或服务进程。仅当您有意要覆盖多个相关进程时,才使用 `prefix`、`suffix` 或 `contains`。
支持的 `abi` 值:
```
auto
arm64-v8a
armeabi-v7a
```
当配置为 `abi=auto` 时,如果 `lib/arm64` 目录存在,部署程序会将 arm64 Gadget 复制到该目录;如果 `lib/arm` 目录存在,则将 arm Gadget 复制到该目录。
在运行时,native loader 也会根据当前进程的位数选择已部署的 payload 路径。64 位进程会在 `lib/arm64` 下查找,而 32 位进程会在 `lib/arm` 下查找;仅当特定 ABI 目录中没有提供 `libgadget.so` 时,两者才会回退到 `lib` 目录。
`abi` 字段是可选的。如果省略,默认值为 `auto`:
```
com.example.app|com.example.app|exact
```
## 调试日志
编辑 `module.conf`:
```
debug=0
```
设置 `debug=1` 以记录非目标进程的检查信息以及其他详细的匹配细节。
重要日志将始终输出:
- 匹配到目标
- 已解析 payload 路径
- 开始加载 payload
- dlopen 成功/失败
## 构建
```
./build.sh
```
输出:
```
out/zygisk_frida_gadget.zip
```
`build.sh` 是一个围绕 `build.py` 的小型兼容性包装脚本。使用 Python 是为了实现确定性的 zip 打包,并在不依赖特定平台 `zip` 命令的情况下保留 Unix 文件模式/软链接。
默认情况下,如果缺少 Gadget 二进制文件或配置文件,只会产生警告,因此您可以先构建 loader,稍后再添加 Gadget。对于发布构建,请使用严格模式:
```
STRICT_BUILD=1 ./build.sh
```
## 更新
当 `module.prop` 包含以下内容时,兼容 Magisk 的模块管理器可以检查更新:
```
updateJson=https://raw.githubusercontent.com/leolovenet/Zygisk-FridaGadget/main/update.json
```
更新元数据发布在 `update.json` 中,并指向附加到相应 GitHub 发布标签的发布 zip 包。发布新版本时,请同时更新以下值:
```
module.prop: version, versionCode
update.json: version, versionCode, zipUrl
CHANGELOG.md: release notes
```
然后构建 `out/zygisk_frida_gadget.zip`,并将其上传到标签与 `zipUrl` 相匹配的 GitHub Release 中。
## 安装
在 Magisk 中安装:
```
Magisk -> Modules -> Install from storage
```
安装后请重启设备。
## 无需重启重新部署
native loader 会在每个应用进程启动时读取 `targets.conf`。如果您仅更改了进程匹配规则,并且该包已经部署过 Gadget,请强制停止并重启目标应用。
如果您添加了新包、更改了 Gadget 文件,或者需要重新部署到目标应用的 native lib 目录中,请运行:
```
adb shell su -c '/data/adb/modules/zygisk_frida_gadget/action.sh'
```
某些 Magisk 管理器会为提供 `action.sh` 的模块显示一个“操作”按钮。如果该按钮可用,点击它将运行相同的重新部署流程并打印 `deploy.log`。如果您的 Magisk/Kitsune 版本只显示“卸载”,请使用上述的 adb 命令。
然后强制停止并重启目标应用:
```
adb shell am force-stop com.example.app
```
## 工作原理
1. `customize.sh` 在模块安装期间运行。
2. `service.sh` 在开机后运行并重试部署。
3. `deploy_gadget.sh` 读取 `targets.conf`。
4. 对于每个目标,它使用 `pm path` 定位应用安装目录。
5. 它将 Frida Gadget 和配置文件复制到目标应用的 native library 目录中,例如:
```
/data/app//lib/arm64/libgadget.so
/data/app//lib/arm64/libgadget.config.so
```
6. 它会同步该目录中已有 `.so` 文件的 owner(所有者)、group(用户组)、mode(权限模式)和 SELinux context(上下文)。
7. Zygisk 模块读取 `targets.conf`,匹配当前进程名称,从 `/proc/self/maps` 或 `/data/app` 解析当前应用安装目录,检查 Gadget 是否已映射到进程中,并调用:
```
dlopen(payload_path, RTLD_NOW | RTLD_GLOBAL);
```
因为 Gadget 是从应用 native library 目录加载的,所以 Frida 可以从同一目录读取 `libgadget.config.so`,而无需向应用进程开放 `/data/adb` 的访问权限。
如果进程已经映射了配置的 payload 路径、`libgadget.so` 或带有版本号的 `libgadget-*.so`,loader 会记录 `payload already loaded, skip dlopen`,并且不会再次加载 Gadget。
## 限制
- 当前的部署路径是 `/data/app` 下的目标应用 native library 目录。
- 应用更新可能会替换安装目录,因此在更新目标应用后,请再次运行 `action.sh`。
- 当前的脚本仅处理 `arm64-v8a` 和 `armeabi-v7a` 架构的 Gadget 包。
- 该模块不尝试隐藏 Frida 的痕迹;它仅提供一种实用的 Gadget 加载途径。
## 日志
```
adb logcat -s ZygiskFridaGadget
adb logcat | grep -i Frida
```
部署日志写入到:
```
/data/adb/modules/zygisk_frida_gadget/deploy.log
```
## 验证部署
```
adb shell su -c 'find /data/app -name "libgadget*.so" -ls'
adb shell su -c 'ls -lZ /data/app/*/lib/arm64/libgadget* 2>/dev/null'
```
## 清理
移除 Magisk 模块时会运行 `uninstall.sh`,该脚本会从已配置的目标应用 native lib 目录中删除已部署的 `libgadget.so` 和 `libgadget.config.so`。
## 安全提示
该模块刻意避免扩大 `/data/adb` 的权限;相反,Gadget 和配置文件会被部署到目标应用的 native lib 目录中。
标签:Android, Docker支持, DSL, Frida, Zygisk, 云资产清单, 目录枚举, 移动安全, 逆向工具, 逆向工程