(A)AssetHook 是一个基于 LD_PRELOAD 的挂钩库,允许在不修改 APK 的情况下动态替换 APK 资源文件。它同样使用 rust 编写。它会将资源文件加载重定向到 Android 设备上的文件路径 /data/local/tmp/assethook/com.pkg.name。不用说,由于这一点(实际上是 SEAndroid 荒谬的 DRM 机制,现在阻止应用访问 /data/local/tmp),AssetHook 目前要求将 SELinux 模式设置为 permissive。如果原始资源路径(通常是 assets/path/to/file.name)存在于对应包的 AssetHook 路径下,则将加载替换文件。AssetHook 由两个独立的 LD_PRELOAD 挂钩实现组成,一个用于“公共”C API,另一个用于内部 C++ API。通常,使用 C++ hook,但如果它在新的 Android 版本上失效,请尝试 C hook(只需注意下面所述的局限性)。
因为 React Native 之类的东西使用原生 asset manager API,这些 API 无法通过 Xposed 之类的方式挂钩。
cppapi_assethook)Hook一个“相对稳定”的基于 LD_PRELOAD 的 hook,钩住公共 C API 和 Java API 等所调用的底层 C++ 资源实现。由于这一底层 API 有时会被 Android 其他内部代码用来加载/检查 APK 中的其他静态资源,因此也可以将替换文件放在非 assets/ APK 路径下,从而替换这些文件(如果通过此 API 读取的话)。
注意: 虽然 res/layout/activity_main.xml 等文件至少会通过此 API 打开,但并不会通过它读取,因此无法在运行时使用 AssetHook 替换。
capi_aassethook)Hook(注意 "aasset" 中有两个 'a')
一个“保守”的基于 LD_PRELOAD 的 hook,不会钩住 Java 层的 android.content.res.AssetManager。由于它挂钩的 C API(AAsset*)是公开的,当内部 C++ 实现的新变化导致 C++ API hook 失效时,这是一个稳定的 hook。使用此 hook,只能挂钩 /data/local/tmp/assethook/com.example.name/assets/ 下的文件。
安装 AAssetHook 并为特定应用包启用它
以 shell 身份推送(以确保文件全局可读)替换文件:
adb push index.android.bundle.mod /data/local/tmp/assethook/com.pkg.name/assets/index.android.bundle
重启被挂钩的应用
注意: 仓库中已包含 32 位和 64 位 arm 的共享对象。
注意: 用于 C API 的 AAssetHook 使用了一些 rust 语法扩展来减少大量样板代码,因此需要使用 rust nightly 编译。已知在 2016-12-05 的 daf8c1dfc 提交下可使用 rust 构建(以防 rust 编译器内部变化导致构建失败)。
安装 Android NDK
通过 rustup 安装 rust(https://github.com/rust-lang-nursery/rustup.rs)
运行以下命令:
rustup install nightly # C API hook only
rustup default nightly # C API hook only
rustup target add aarch64-linux-android
rustup target add arm-linux-androideabi
rustup target add i686-linux-android # AVD/HAXM
mkdir ~/.cargo/toolchains
cd ~/.cargo/toolchains
/path/to/ndk/build/tools/make-standalone-toolchain.sh \
--platform=android-22 --toolchain=arm-linux-android-4.9 \
--install-dir=android-22-arm-toolchain`
/path/to/ndk/build/tools/make-standalone-toolchain.sh \
--platform=android-22 --toolchain=aarch64-linux-android-4.9 \
--install-dir=android-22-aarch64-toolchain`
/path/to/ndk/build/tools/make-standalone-toolchain.sh \
--platform=android-22 --toolchain=x86-linux-android-4.9 \
--install-dir=android-22-x86-toolchain`
将以下内容添加到 ~/.cargo/config
[target.arm-linux-androideabi]
linker = "/path/to/home/.cargo/toolchains/android-22-arm-toolchain/bin/clang"
[target.aarch64-linux-android]
linker = "/path/to/home/.cargo/toolchains/android-22-aarch64-toolchain/bin/clang"
[target.i686-linux-android]
linker = "/path/to/home/.cargo/toolchains/android-22-x86-toolchain/bin/clang"
cd /path/to/aassethook/cppapi
注意: cppapi 目录中的 build.sh 脚本会执行最后三条命令。
注意: 如果回退到 capi 实现,请将所有的 cppapi 替换为 capi。
首先从 F-Droid 或 MrBIMC/SELinuxModeChanger 安装 SELinuxModeChanger,并将其设置为 permissive 模式。
注意: 你也可以在每次启动后直接运行 /system/bin/setenforce 0。
cd cppapi
./install.sh
注意: 如果回退到 capi 实现,请将所有的 cppapi 替换为 capi。
cd cppapi
./hook.sh <pkg.name> <32|64|unhook>
cargo build --target=arm-linux-androideabi --release
cargo build --target=aarch64-linux-android --release
cargo build --target=i686-linux-android --release