
Mágica do LD_PRELOAD para o AssetManager do Android
(A)AssetHook é uma biblioteca de hooking baseada em LD_PRELOAD que permite substituir arquivos de assets de APK dinamicamente, sem modificar o APK. Também é escrita em rust. Ela redireciona o carregamento de arquivos de assets para um caminho em um dispositivo Android sob /data/local/tmp/assethook/com.pkg.name. Escusado será dizer que, devido a isso (na verdade, o esquema DRM ridículo do SEAndroid que agora bloqueia o acesso de aplicativos a /data/local/tmp), o AssetHook atualmente exige que o modo SELinux esteja definido como permissivo. Se o caminho bruto do asset (normalmente assets/path/to/file.name) existir sob o caminho do AssetHook do respectivo pacote, a substituição será carregada em seu lugar. O AssetHook consiste em duas implementações de hook LD_PRELOAD separadas, uma para a API C "pública" e outra para a API C++ interna. Em geral, use o hook C++, mas se ele quebrar em uma nova versão do Android, tente o hook C (apenas observe as limitações dele descritas abaixo).
Porque coisas como o React Native usam a API nativa do gerenciador de assets, que não pode ser interceptada por coisas como o Xposed.
cppapi_assethook)Um hook "relativamente estável" baseado em LD_PRELOAD que intercepta a implementação de assets em C++ subjacente, chamada pela API C pública e pelas APIs Java, entre outras coisas. Como essa API de nível mais baixo é ocasionalmente usada por outro código interno do Android para carregar/verificar outros recursos estáticos de APKs, ela também pode ser usada para substituir esses arquivos (se lidos por meio dessa API) colocando as substituições em caminhos do APK que não sejam assets/.
Nota: Embora arquivos como res/layout/activity_main.xml sejam pelo menos abertos por meio dessa API, eles não são lidos com ela e não podem ser substituídos em tempo de execução com o AssetHook.
capi_aassethook)(Nota: observe os dois 'a' em "aasset")
Um hook "conservador" baseado em LD_PRELOAD que não intercepta o android.content.res.AssetManager no nível Java. Como a API C que ele intercepta (AAsset*) é pública, este é um hook estável para ser usado se novas alterações na implementação interna em C++ quebrarem o hook da API C++. Usando este hook, apenas arquivos sob /data/local/tmp/assethook/com.example.name/assets/ podem ser interceptados.
Instale o AAssetHook e ative-o para um pacote de aplicativo específico
Envie (como shell para garantir que o arquivo seja legível por todos) os arquivos de substituição:
adb push index.android.bundle.mod /data/local/tmp/assethook/com.pkg.name/assets/index.android.bundle
Reinicie o aplicativo com hook
Nota: Os objetos compartilhados para arm de 32 e 64 bits estão embutidos no repositório.
Nota: O hook da API C AAssetHook usa algumas extensões de sintaxe do rust para reduzir uma quantidade enorme de código repetitivo e, portanto, precisa ser compilado usando o rust nightly. Sabe-se que ele compila com rust no commit daf8c1dfc de 2016-12-05 (caso alterações internas no compilador rust quebrem a compilação).
Instale o Android NDK
Instale o rust via rustup (https://github.com/rust-lang-nursery/rustup.rs)
Execute os seguintes 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`
Adicione o seguinte 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: O script build.sh no diretório cppapi executa os últimos três comandos.
Nota: Se estiver recorrendo à implementação capi, substitua todas as ocorrências de cppapi por capi.
Primeiro instale o SELinuxModeChanger pelo F-Droid ou MrBIMC/SELinuxModeChanger, e defina-o para o modo permissivo.
Nota: Você também pode simplesmente executar /system/bin/setenforce 0 após cada inicialização.
cd cppapi
./install.sh
Nota: Se estiver recorrendo à implementação capi, substitua todas as ocorrências 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