
Magie de LD_PRELOAD pour l'AssetManager d'Android
(A)AssetHook est une bibliothèque de hooking basée sur LD_PRELOAD qui permet de remplacer dynamiquement les fichiers d'assets de l'APK sans modifier l'APK. Elle est également écrite en rust. Elle redirige le chargement des fichiers d'assets vers un chemin de fichier sur un appareil Android sous /data/local/tmp/assethook/com.pkg.name. Inutile de préciser qu'en raison de cela (en réalité l'absurde schéma DRM de SEAndroid qui bloque désormais l'accès des applications à /data/local/tmp), AssetHook exige actuellement que le mode SELinux soit réglé sur permissif. Si le chemin d'asset brut (typiquement assets/path/to/file.name) existe sous le chemin AssetHook du paquet correspondant, le remplacement sera chargé à la place. AssetHook se compose de deux implémentations de hook LD_PRELOAD distinctes, l'une pour l'API C « publique », et l'autre pour l'API C++ interne. En général, utilisez le hook C++, mais s'il casse sur une nouvelle version d'Android, essayez le hook C (en notant simplement ses limitations décrites ci-dessous).
Parce que des choses comme React Native utilisent l'API native du gestionnaire d'assets, qui ne peut pas être hookée via des outils comme Xposed.
cppapi_assethook)Un hook « relativement stable » basé sur LD_PRELOAD qui hooke l'implémentation C++ sous-jacente des assets, appelée par l'API C publique et les API Java, entre autres. Comme cette API de plus bas niveau est parfois utilisée par d'autres codes internes d'Android pour charger/vérifier d'autres ressources statiques depuis les APK, elle peut également être utilisée pour remplacer ces fichiers (s'ils sont lus via cette API) en plaçant les remplacements sous des chemins d'APK autres que assets/.
Remarque : Bien que des fichiers tels que res/layout/activity_main.xml soient au moins ouverts via cette API, ils ne sont pas lus avec elle et ne peuvent pas être remplacés à l'exécution avec AssetHook.
capi_aassethook)(Remarquez les deux « a » dans « aasset »)
Un hook « conservateur » basé sur LD_PRELOAD qui ne hookera pas l'android.content.res.AssetManager de niveau Java. Comme l'API C qu'il hooke (AAsset*) est publique, c'est un hook stable à utiliser si de nouveaux changements dans l'implémentation C++ interne cassent le hook de l'API C++. Avec ce hook, seuls les fichiers sous /data/local/tmp/assethook/com.example.name/assets/ peuvent être hookés.
Installez AAssetHook et activez-le pour un paquet d'application spécifique
Poussez (en tant que shell pour vous assurer que le fichier est lisible par tous) les fichiers de remplacement :
adb push index.android.bundle.mod /data/local/tmp/assethook/com.pkg.name/assets/index.android.bundle
Redémarrez l'application hookée
Remarque : Les objets partagés pour arm 32 bits et 64 bits sont inclus dans le dépôt.
Remarque : Le hook de l'API C AAssetHook utilise quelques extensions de syntaxe rust pour réduire considérablement le code répétitif (boilerplate), et doit donc être compilé avec rust nightly. Il est connu pour se compiler avec rust au commit daf8c1dfc du 2016-12-05 (au cas où des changements internes du compilateur rust casseraient la compilation).
Installez le NDK Android
Installez rust via rustup (https://github.com/rust-lang-nursery/rustup.rs)
Exécutez les commandes suivantes :
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`
Ajoutez ce qui suit à ~/.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"
Remarque : Le script build.sh dans le répertoire cppapi exécute les trois dernières commandes.
Remarque : En cas de repli sur l'implémentation capi, remplacez toutes les occurrences de cppapi par capi.
Installez d'abord SELinuxModeChanger depuis F-Droid ou MrBIMC/SELinuxModeChanger, et réglez-le en mode permissif.
Remarque : Vous pouvez aussi simplement exécuter /system/bin/setenforce 0 après chaque démarrage.
cd cppapi
./install.sh
Remarque : En cas de repli sur l'implémentation capi, remplacez toutes les occurrences de cppapi par 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