
Магия LD_PRELOAD для Android AssetManager
(A)AssetHook — это библиотека перехвата на основе LD_PRELOAD, которая позволяет динамически заменять файлы ресурсов APK без изменения самого APK. Она также написана на Rust. Она перенаправляет загрузку файлов ресурсов на путь на Android-устройстве: /data/local/tmp/assethook/com.pkg.name. Само собой разумеется, из-за этого (точнее, из-за нелепой DRM-схемы SEAndroid, которая теперь блокирует доступ приложений к /data/local/tmp) AssetHook в настоящее время требует, чтобы режим SELinux был установлен в permissive. Если исходный путь ресурса (обычно assets/path/to/file.name) существует в соответствующем пути AssetHook для пакета, вместо него будет загружена замена. AssetHook состоит из двух отдельных реализаций перехвата LD_PRELOAD: одна для «публичного» C API, другая для внутреннего C++ API. В целом используйте C++ hook, но если он сломается на новой версии Android, попробуйте C (просто учтите описанные ниже ограничения).
Потому что такие технологии, как React Native, используют нативный API менеджера ресурсов (asset manager), который нельзя перехватить такими средствами, как Xposed.
cppapi_assethook)«Относительно стабильный» перехват на основе LD_PRELOAD, который перехватывает нижележащую C++ реализацию работы с ресурсами, вызываемую публичным C API и Java API, среди прочего. Поскольку этот низкоуровневый API иногда используется другим внутренним кодом Android для загрузки/проверки других статических ресурсов из APK, его также можно использовать для замены этих файлов (если они читаются через этот API), размещая замены по путям APK вне assets/.
Примечание: Хотя такие файлы, как res/layout/activity_main.xml, по крайней мере открываются через этот API, они не читаются через него и не могут быть заменены во время выполнения с помощью AssetHook.
capi_aassethook)(Обратите внимание на две буквы 'a' в слове "aasset")
«Консервативный» перехват на основе LD_PRELOAD, который не перехватывает Java-уровневый android.content.res.AssetManager. Поскольку C API, который он перехватывает (AAsset*), является публичным, это стабильный перехват для использования, если новые изменения во внутренней C++ реализации сломают C++ API 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
Перезапустите перехватываемое приложение
Примечание: Собранные библиотеки (shared objects) для 32-битной и 64-битной ARM уже включены в репозиторий.
Примечание: Перехват C API AAssetHook использует некоторые синтаксические расширения Rust, чтобы избавиться от огромного количества шаблонного кода, и поэтому его нужно компилировать с помощью nightly-версии Rust. Известно, что он собирается с Rust на коммите daf8c1dfc от 2016-12-05 (на случай, если внутренние изменения в компиляторе Rust сломают сборку).
Установите Android NDK
Установите Rust через rustup (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"
Примечание: Скрипт build.sh в каталоге cppapi выполняет последние три команды.
Примечание: Если вы переходите на реализацию capi, замените все вхождения cppapi на capi.
Сначала установите SELinuxModeChanger из F-Droid или MrBIMC/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/cppapi
cargo build --target=arm-linux-androideabi --release
cargo build --target=aarch64-linux-android --release
cargo build --target=i686-linux-android --release