
Magia LD_PRELOAD para el AssetManager de Android
(A)AssetHook es una biblioteca de hooking basada en LD_PRELOAD que permite reemplazar dinámicamente los archivos de recursos (assets) de un APK sin modificarlo. También está escrita en rust.
Redirige las cargas de archivos de recursos a una ruta en un dispositivo Android bajo /data/local/tmp/assethook/com.pkg.name. No hace falta decir que, debido a esto (en realidad, el ridículo esquema de DRM de SEAndroid que ahora bloquea el acceso de las aplicaciones a /data/local/tmp), AssetHook actualmente requiere que el modo SELinux esté configurado como permisivo. Si la ruta de recurso original (típicamente assets/path/to/file.name) existe en la ruta AssetHook del paquete correspondiente, se cargará el reemplazo en su lugar. AssetHook consta de dos implementaciones de hook LD_PRELOAD separadas: una para la API C «pública» y otra para la API C++ interna. En general, usa el hook de C++, pero si se rompe en una versión nueva de Android, prueba el de C (solo ten en cuenta las limitaciones descritas más abajo).
Porque proyectos como React Native usan la API nativa del administrador de recursos, que no se puede interceptar con cosas como Xposed.
cppapi_assethook)Un hook basado en LD_PRELOAD «relativamente estable» que engancha la implementación C++ de recursos subyacente, llamada por la API C pública y por las API de Java, entre otras cosas. Dado que esta API de más bajo nivel se usa ocasionalmente en otro código interno de Android para cargar/comprobar otros recursos estáticos de los APK, también se puede usar para reemplazar esos archivos (si se leen a través de esta API) colocando reemplazos en rutas del APK que no sean assets/.
Nota: Aunque archivos como res/layout/activity_main.xml se abren al menos a través de esta API, no se leen con ella y no se pueden reemplazar en tiempo de ejecución con AssetHook.
capi_aassethook)(Nótese las dos 'a' en "aasset")
Un hook basado en LD_PRELOAD «conservador» que no engancha el android.content.res.AssetManager a nivel de Java. Como la API C a la que engancha (AAsset*) es pública, es un hook estable para usar si los cambios nuevos en la implementación C++ interna rompen el hook de la API C++. Con este hook, solo se pueden interceptar archivos bajo /data/local/tmp/assethook/com.example.name/assets/.
Instala AAssetHook y actívalo para un paquete de aplicación concreto
Envía (como shell para asegurarte de que el archivo sea legible por todos) los archivos de reemplazo:
adb push index.android.bundle.mod /data/local/tmp/assethook/com.pkg.name/assets/index.android.bundle
Reinicia la aplicación hookeada
Nota: Los objetos compartidos para arm de 32 y 64 bits están incluidos en el repositorio.
Nota: El hook de la API C AAssetHook usa algunas extensiones de sintaxis de rust para reducir una enorme cantidad de código repetitivo y, por lo tanto, necesita compilarse con rust nightly. Se sabe que compila con rust en el commit daf8c1dfc del 2016-12-05 (por si los cambios internos en el compilador de rust rompen la compilación).
Instala el Android NDK
Instala rust mediante rustup (https://github.com/rust-lang-nursery/rustup.rs)
Ejecuta los siguientes comandos:
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`
Añade lo siguiente a ~/.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"
Nota: El script build.sh en el directorio cppapi ejecuta los últimos tres comandos.
Nota: Si se recurre a la implementación capi, sustituye todas las apariciones de cppapi por capi.
Primero instala SELinuxModeChanger desde F-Droid o MrBIMC/SELinuxModeChanger, y configúralo en modo permisivo.
Nota: También puedes simplemente ejecutar /system/bin/setenforce 0 después de cada arranque.
cd cppapi
./install.sh
Nota: Si se recurre a la implementación capi, sustituye todas las apariciones de cppapi por 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