Files
apk-reverse/references/third-party-builds.md
T
inliver233 1a5cb6245f Broaden skill with unpacking, TLS triage, third-party build auditing, runtime probe
references: recon gains packer identification + unpacking workflow (payload/plaintext size mapping, dump validation, hash de-duplication, business-dex heuristic); repack-and-sign gains the de-shelled repack pipeline, why apktool over binary AXML, and the apksigner scheme-selection caveat; new tls-and-cert documents feature-scoped network failures, dual trust chains and the fix template; new third-party-builds covers auditing a cracked/modded APK before trusting it; dynamic-frida gains version pinning, remote-device path, the four-layer probe and hook-never-fires triage; environment gains UI automation pitfalls; ad-removal gains the single convergence point, dynamic-plugin SDKs and the global timestamp gate; pitfalls gains P13-P17; verification gains rung 7 and the three-signal ad check.

scripts: new frida_probe.js (four-layer runtime probe), run_probe.py and tls_check.py; repack.py fixes two crash-on-default bugs and a misleading META-INF note; datastore_inject.py, PatchMethodExample.java and build_scripts.py lose hardcoded values - the example class name did not match its file and could not compile.
2026-09-19 21:44:00 +08:00

140 lines
6.6 KiB
Markdown

# Third-party builds — auditing a "cracked" or "modded" APK before trusting it
## Why this exists
A modded build of the exact app you are targeting is the most tempting shortcut available:
it appears to prove the goal is achievable, and it may already contain the patch you were
about to write. It is also the single most common source of wasted hours and of real risk,
for two reasons.
1. **It is usually not editable.** Authors who redistribute mods protect them, often with
more layers than the original app ever had. You cannot treat someone else's build as a
patching workbench.
2. **Its target-audience behaviour is unverified.** The binary may carry injected components,
extra endpoints, or embedded credentials. "It runs and the ads are gone" tells you nothing
about what else it does.
Treat a third-party build as an **untrusted sample to be audited**, never as a baseline.
The useful output of an audit is a decision plus evidence — not a binary you start from.
## Step 1: Can you even edit it?
Find the app's own package prefix (the one that appears in its own class definitions, e.g.
`com/<vendor>/<app>/`) and count how many times it appears as a **defined class** in each
plaintext dex.
```
business-prefix hits per dex:
classes.dex 0 <- shell
classes2.dex 0
classes3.dex 0
classes4.dex 0
```
Zero everywhere means the business code has been **moved out of the plaintext dexes** — the
build is protected at a level you cannot patch directly, even though it launches and works.
Stop here and treat it as a black box.
Also check the reported dex count against the file count: a manifest-declared app with only
library classes present is the same signal.
## Step 2: How many protection layers does it carry?
Mods frequently stack protection from multiple vendors, sometimes because the author
re-protected an already-protected app. Look for independent, coexisting families:
| Layer kind | Typical static evidence |
|---|---|
| Commercial packer | shell `Application`/`appComponentFactory` in the manifest, a `lib*protect*.so`, encrypted assets, `assets/*.jar` with near-maximal entropy |
| DEX-to-native (dex2c) | a "stub" `lib*.so` containing the tool's name, `EntryPoint`/`protect`-style symbols, and **business class names as strings** alongside a near-empty dex layer |
| Anti-debugging / RASP | strings such as `TracerPid`, `ptrace`, `NoNewPrivs`, `CheckPtraceSelf`, `AntiFrida`, plus a self-protection log path |
| Generic hardening marker files | small text files under `assets/` naming a protection vendor and a protection timestamp |
The practical consequence of an anti-debugging layer is that Frida-based dynamic work will hit
a self-check before it hits your hook. Note it, and prefer static conclusions on such a sample.
## Step 3: What did the author ADD?
This is where the audit earns its keep. Diff against the **original build of the same version**
(referenced as `<original>` below).
### New components
Build the set difference of `activity` / `service` / `receiver` / `provider` declarations,
then check whether each new class name actually exists in the plaintext dexes.
- Class exists and is readable → you can judge its purpose.
- Class name appears **nowhere** in plaintext but shows up inside a native library's strings →
the logic is in the native/dex2c layer, purpose unknown. Say so.
- Nothing registered with an implicit-launch intent-filter (`BOOT_COMPLETED`, `MAIN`) → it cannot
be started implicitly, which limits (but does not eliminate) the risk.
- A provider with an `authorities` value containing a package-name rewrite (a suffix/prefix that
is not the current package) is a strong hint the build was produced by **repackaging or app
cloning**, not by editing the original.
### New outbound endpoints
Extract every URL/domain/IP from the modded build's `lib/*.so`, `assets/*`, and dex strings,
and subtract the original's set. Any domain that exists **only** in the modded build is the most
important finding in the audit.
Rank what you find:
- A domain that also serves install attribution or update checks is explainable.
- A domain paired with an authorization-looking path (e.g. a `GET...`-style endpoint name
nearby in the same string neighbourhood) is *not* explainable by de-ad work.
### Embedded secrets
Search native libraries and assets for private-key markers:
```
-----BEGIN ... PRIVATE KEY----- , PRIVATE KEY , PKCS#8 , RSA PRIVATE
```
A **private key shipped inside a client artifact** means its "authorization" or "integrity"
path is not a security boundary — anyone can extract the key. Report it as a red flag on the
build's trust claims, regardless of intent.
## Step 4: Capability picture — read both sides
A native library's import table is only half the story.
- **What it does not have** is meaningful: no `socket`/`connect`, no `execve`/`fork`/`system`,
no `ptrace`, no installer-session strings → no direct evidence of command execution or
silent install.
- **What it references** can override that impression: string references to Java-layer
`java/net/Socket`, `InetSocketAddress`, reflection entry points, or executor services mean the
capability exists **through the Java layer**, off the native import table.
State findings as "capability present / no evidence of use" rather than "safe" — an import table
is evidence of shape, not of intent.
## Step 5: The verdict
Do not hand back a binary. Hand back a decision with evidence and explicit unknowns.
```
VERDICT: use / use with caution / do not use
EVIDENCE:
- business code plaintext? yes/no (+ counts)
- protection layers list
- injected components list, each with purpose known/unknown
- endpoints present only in this build list
- embedded credentials yes/no
UNCONFIRMED:
- <each item you could not establish, stated plainly>
```
"Use with caution" is the honest answer whenever a build is un-analysable **and** carries new
endpoints or unknown injected components. Do not upgrade it to "safe" because it launches
cleanly, and do not call it malicious without evidence — both are guesses.
## Using the audit result
Two legitimate outcomes:
1. The audit shows the mod is an honest de-ad of the same version → you may use it to **learn the
approach** (diff its patch points against the original), but still rebuild from the original
yourself so the artifact you ship has a known provenance.
2. The audit shows it is re-protected, injected, or un-analysable → discard it and do the work on
the original. That is usually faster than reverse-engineering someone else's protection *and*
your target's at the same time.