Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,34 @@ Also consider stubbing vendor methods such as `PluginVerifier.verifySignature()`
- Split APK / local-testing leftovers: official Play Core testing helpers obtain splits from a specified local directory, and `SplitCompat.install()` immediately exposes code/resources from installed splits. In production builds, any custom equivalent that trusts writable module directories, `split_id`-derived filenames, or leftover local-testing artefacts becomes a plugin-swap primitive. Historically this class of bug already led to Play Core code execution via path traversal (CVE-2020-8913); today you usually find the same idea as app-side misuse rather than the library bug itself.
- React Native / Web-based OTA content: if native bridges execute JS from OTA without strict signing, arbitrary code execution in the app context is possible (e.g., insecure CodePush-like flows). For Expo/EAS-style updaters, look for disabled or bypassable update signing before treating the JS bundle as trusted.

### 5.1 Platform changes that change exploitation
### 5.1 Trusted updater abuse: installing packages that do not exist yet

Do not test only replacement updates. A preinstalled or privileged updater may deserialize a remote Boolean/enum that decides whether the target package must already exist. If the backend can select an “install when absent” branch (for example, `installNotExists=true`), the update channel becomes an **arbitrary new-APK installation primitive**, even if the normal workflow appears limited to maintaining firmware packages. Trace the complete path from MQTT/push-message parsing through the package-existence check, download destination and `PackageInstaller`/PackageManager call.<sup>[[3]](#references)</sup>

Preserve the updater cache and correlate every newly introduced package with its recorded installer. Android's `pm list packages -i` option exposes the installer identity; on a rooted or forensic image, compare this with the APKs staged below the updater's external cache.<sup>[[3]](#references)[[4]](#references)</sup>

```bash
UPDATER=com.vendor.updater; SUSPECT=com.example.suspect
adb shell 'pm list packages -i | sort'
adb shell "find /sdcard/Android/data/$UPDATER/cache/push/apk -type f -ls 2>/dev/null"
adb shell "pm path $SUSPECT; dumpsys package $SUSPECT"
```

Treat the installer identity as provenance, not privilege inheritance: a downloaded APK normally executes under its **own UID and declared/granted permissions**. Do not report execution with the updater's system privileges unless shared UID, platform signing, an exported privileged bridge or another explicit escalation path proves it.<sup>[[3]](#references)</sup>

### 5.2 Recovering staged payload families

A downloaded file's extension is not a reliable type signal. Start from the loader's reads and deserializer: one observed staged format used a one-byte string key, a four-byte floating-point value reused as an XOR key, and then encrypted DEX bytes. Embedded droppers may also split ciphertext into blocks and derive each single-byte key linearly (`key_i = (key_0 + i * step) & 0xff`). Reimplement the exact loop, deserialize the recovered metadata, and validate output with DEX/ZIP magic before decompilation.<sup>[[3]](#references)</sup>

Predictable version strings in payload URLs are also an analysis surface. If a captured path contains a directly editable value such as `dex3.68.png`, enumerate nearby versions **only in an authorized sinkholed/lab copy**, then record HTTP status, hash, decoded magic and entry point. Diff recovered versions for header-layout, decoder, C2, class/method and capability changes; a decoder change in an older payload can reveal a previously unknown intermediate loader.<sup>[[3]](#references)</sup>

### 5.3 Configuration-driven reflective modules

Look beyond hard-coded command handlers. A compact implant can receive integer task IDs, fetch JSON definitions only for unknown or newer timestamped versions, and persist them in `SharedPreferences`; a field such as `tagName` then selects handlers for HTTP, WebView/JavaScript or module loading. During analysis, dump the preferences XML and correlate ID/version changes with descriptor-fetch requests and reflective calls.<sup>[[3]](#references)</sup>

For module loaders, trace attacker-controlled `url`, module name, entry class, factory/virtual method, typed arguments, cleanup list, thread and reload flags. An MD5/SHA value delivered in the **same attacker-controlled task object** as the payload URL detects corruption but does not authenticate code: the operator controls both values. Successful reflection gives replaceable code execution in the implant process and permission context.<sup>[[3]](#references)</sup>

### 5.4 Platform changes that change exploitation

- Apps targeting Android 14 (API 34+) must mark dynamically loaded DEX/JAR/APK files read-only as soon as they are opened and before content is written; otherwise the system throws an exception when the app later tries to load them.<sup>[[2]](#references)</sup>
- Apps targeting Android 17 (API 37+) extend the same Safer Dynamic Code Loading rule to native libraries loaded with `System.load()`; writable copied `.so` files now fail with `UnsatisfiedLinkError`.<sup>[[2]](#references)</sup>
Expand Down Expand Up @@ -279,5 +306,7 @@ Also consider stubbing vendor methods such as `PluginVerifier.verifySignature()`

- [1] [NowSecure – Remote Code Execution Discovered in Xtool AnyScan App](https://www.nowsecure.com/blog/2025/07/16/remote-code-execution-discovered-in-xtool-anyscan-app-risks-to-phones-and-vehicles/)
- [2] [Android Developers – Dynamic Code Loading (risks and mitigations)](https://developer.android.com/privacy-and-security/risks/dynamic-code-loading)
- [3] [MoYu Malware Turns Android Car Head Units into Proxy-Botnet Nodes](https://securelist.com/android-head-unit-malware/121106/)
- [4] [Android Debug Bridge – Package manager commands](https://developer.android.com/tools/adb#pm)

{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}