
AndroidのAssetManager向けLD_PRELOADマジック
(A)AssetHook は、APK を変更することなく APK アセットファイルを動的に置き換えることができる、LD_PRELOAD ベースのフッキングライブラリです。また、Rust で書かれています。
アセットファイルの読み込みを、Android デバイス上の
/data/local/tmp/assethook/com.pkg.name 配下のファイルパスへリダイレクトします。言うまでもなく、このため
(実際には、現在 /data/local/tmp へのアプリのアクセスをブロックしている SEAndroid の理不尽な DRM スキームが原因ですが)、AssetHook は現在、SELinux モードを permissive に設定する必要があります。対応するパッケージの AssetHook パス配下に元のアセットパス(通常は assets/path/to/file.name)
が存在する場合、代わりに置き換え後のファイルが読み込まれます。AssetHook は、2 つの独立した LD_PRELOAD フック
実装で構成されています。1 つは「公開」C API 用、もう 1 つは内部 C++ API 用です。
一般的には C++ フックを使用してください。ただし、新しいバージョンの Android で動作しなくなった場合は、
C の方をお試しください(後述の制限事項に注意してください)。
React Native などのフレームワークがネイティブアセットマネージャー API を使用しており、これは Xposed などではフックできないためです。
cppapi_assethook)フック公開 C API や Java API などから呼び出される基盤となる C++ アセット実装をフックする、「比較的安定した」LD_PRELOAD ベースのフックです。この低レベル API は、APK から他の静的リソースを読み込んだりチェックしたりするために Android の他の内部コードでも使用されることがあるため、assets/ 以外の APK パスに置き換えファイルを配置することで、(この API 経由で読み込まれる場合に)それらのファイルも置き換えることができます。
注: res/layout/activity_main.xml などのファイルはこの API 経由で少なくとも開かれますが、この API では読み込まれないため、AssetHook で実行時に置き換えることはできません。
capi_aassethook)フック("aasset" には 'a' が 2 つあることに注意)
Java レベルの android.content.res.AssetManager をフックしない「保守的な」LD_PRELOAD ベースのフックです。フック対象の C API(AAsset*)は公開されているため、内部 C++ 実装の新しい変更によって C++ API フックが動作しなくなった場合に備えた安定したフックです。このフックを使用すると、/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"
注: cppapi ディレクトリ内の build.sh スクリプトが最後の 3 つのコマンドを実行します。
注: 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>
cd /path/to/aassethook/cppapicargo build --target=arm-linux-androideabi --release
cargo build --target=aarch64-linux-android --release
cargo build --target=i686-linux-android --release