diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/android-malware-post-exploitation.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/android-malware-post-exploitation.md index 4e0b627567c..921362ab2de 100644 --- a/src/generic-methodologies-and-resources/basic-forensic-methodology/android-malware-post-exploitation.md +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/android-malware-post-exploitation.md @@ -145,6 +145,56 @@ Triage ideas: - fake media/font assets later passed into `ZipInputStream`, `DexClassLoader`, or custom RC4 helpers - reflection on `pathList`, `dexElements`, `ContextImpl`, or `LoadedApk` close to asset decryption +### Manifest-declared components resolved only at runtime + +A useful dropper hunting pattern is when `AndroidManifest.xml` declares activities/services that are **missing from the root `classes.dex`**. The visible APK often keeps the real implementations inside an encrypted asset (`*.ttf`, `*.dat`, `*.jar`, `*.base`), decrypts it into private storage, and only then exposes the missing classes through `DexClassLoader` or reflective `DexPathList` injection.[[19]](#references) + +Practical workflow: + +1. Extract every class name referenced by `AndroidManifest.xml`. +2. Compare them against all packaged `classes*.dex` files, not just the first DEX. +3. Treat unresolved components as a strong signal for staged code loading. +4. Hook asset reads, private-file writes, and class-loader APIs to recover the hidden module at runtime. + +High-signal events to correlate: +- `AssetManager.open()` / `Resources.openRawResource()` on non-media assets with high entropy +- `FileOutputStream` / `openFileOutput()` writing `*.dex`, `*.jar`, `*.apk` under app-private paths +- `DexClassLoader`, `PathClassLoader`, `InMemoryDexClassLoader`, or reflection touching `pathList` / `dexElements` +- `adb logcat` entries revealing generated payload paths or class-loading failures + +Quick triage: + +```bash +# Manifest vs DEX diff +apkanalyzer manifest print app.apk | rg 'service|activity|receiver' +unzip -l app.apk | rg 'classes.*\.dex|assets/|res/raw/' + +# Recover runtime payloads from the app sandbox +adb shell run-as sh -c 'find . -type f \( -name "*.dex" -o -name "*.jar" -o -name "*.apk" -o -name "*.json" -o -name "*.db" -o -name "*.xml" \) 2>/dev/null' +adb logcat | rg 'DexClassLoader|ClassNotFoundException|PackageInstaller|app_' +``` + +### Asset-to-`PackageInstaller` staging and nested child payloads + +Another useful evasion pattern is to hide stage 2 inside `assets/` and **stream it directly into a `PackageInstaller` session** instead of first dropping a plainly named APK in shared storage. After the child package is installed, that second package may generate another `DEX`/`JAR` under `/data/user/0//app_*` and dynamically load the final module.[[19]](#references) + +Hunting ideas: +- correlate `ACTION_MANAGE_UNKNOWN_APP_SOURCES` / `REQUEST_INSTALL_PACKAGES` with `PackageInstaller.createSession` -> `openWrite` -> `fsync` -> `commit` +- watch for the parent package stopping a temporary service (often VPN / overlay / lure UI) immediately after install, then launching the new package +- inspect `PACKAGE_ADDED` / `PACKAGE_REPLACED` receivers, private `app_*` directories, and follow-on `DexClassLoader` activity in the child app + +### `AccountManager` + Sync Adapter persistence + +A less common but very useful Android persistence primitive is to register a **fake account** and attach a **Sync Adapter** to it. The malware then uses `ContentResolver.setSyncAutomatically()`, `addPeriodicSync()`, or `requestSync()` so Android wakes it on a schedule even when no long-running service is visible.[[19]](#references) + +What to look for: +- authenticator XML/resources plus code calling `AccountManager.addAccountExplicitly` +- a sync adapter service with `android.content.SyncAdapter` metadata +- suspicious sync intervals (for example every 30 minutes) or forced immediate sync right after connectivity returns +- boot receivers / WorkManager jobs whose only purpose is to re-register the account or reschedule sync + +This is especially useful in samples that already store queue/state locally (SQLite + SharedPreferences): periodic sync becomes the exfil/reconnect trigger for offline-collected SMS, credential captures, contacts, or phishing results. + ### Anti-analysis kill-switch Packed loaders often **self-terminate** when emulator or analysis checks fail (e.g., `CPU_ABI` validation) by calling: @@ -880,5 +930,6 @@ struct Header { - [16] [Rokarolla : Android Banker with Complete Device Takeover Capabilities](https://zimperium.com/blog/rokarolla-android-banker-with-complete-device-takeover-capabilities) - [17] [Zimperium IOC – Rokarolla commands](https://github.com/Zimperium/IOC/blob/master/2026-06-Rokarolla/commands.md) - [18] [Kimwolf Android TV Botnet: ENS-Based C2 Evasion, TLS+ECDSA C2 Protocol, and Large-Scale Proxy/DDoS Operations](https://blog.xlab.qianxin.com/kimwolf-botnet-en/) +- [19] [Octagon: Technical Analysis of a Fake Bahrain Civil Defense Application](https://labs.k7computing.com/index.php/octagon-technical-analysis-of-a-fake-bahrain-civil-defense-application/) {{#include ../../banners/hacktricks-training.md}}