Phase 9: Android line completion (multi-.so / MANIFEST-010 / MASVS / symbol attribution) - #23
Merged
Conversation
Extract every .so under the selected ABI when --apk-lib all is passed, run lief on each, and correlate JNI bridges against the union of every analysed library's exports. Native string hints are now built from the merged string pool so URLs / paths / crypto tokens embedded in secondary libraries (libssl.so, libsqlcipher.so, etc.) are no longer silently dropped. The primary .so still fills so_meta / extracted_so_path for backward compat; the rest goes into new fields: AndroidAnalysis.additional_so_metas: list[BinaryMeta] AndroidAnalysis.additional_so_paths: list[str] Also adds AndroidAnalysis.all_so_metas convenience property. Per-extra-lib parse failure is downgraded to a warning so one bad .so doesn't abort the whole report. The "X siblings skipped — re-run with --apk-lib X" warning is suppressed in multi-lib mode (it would be incorrect there). apk_extractor gains extract_all_native_libs() returning every .so path under an ABI, sorted lex. analysis_cache schema bumps 2 → 3 so an older single-lib payload can't satisfy a multi-lib request from cache. CLI accepts --apk-lib all (case-insensitive); cache_replay_blocker forces a fresh run when multi-lib data is missing from the hit. Tests +12: extract_all_native_libs (3), TestAnalyzeApkMultiLib (5) covering populate, union exports, warning suppression, single-lib warning preserved, graceful degradation; round-trip preserves additional_so_metas; existing 747 tests untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se 9-2) NetworkSecurityConfigMeta.base_trusts_user_certs was captured by Phase 7-3 but no rule fired on it — apps that opt user-installed CAs into the trust chain are MITM-able with a mitmproxy CA install + Wi-Fi proxy, no root or app patch required, and that gate was being silently ignored. MANIFEST-010 (high) surfaces the flag with an actionable description and a five-step PoC bundled into the same .sh export as the other mitmproxy recipes: 1. mitmproxy --listen-port 8080 2. adb push ~/.mitmproxy/mitmproxy-ca-cert.cer to /sdcard/ 3. install via Settings > Security > Install from device storage 4. set device Wi-Fi manual proxy to host:8080 5. am start the app and observe TLS-decrypted traffic PoC notes warn that Android 7+ defaults user-CA trust to OFF, so this rule only fires on explicit opt-in (almost always a debug NSC that slipped into release). Tests +5: positive trigger (high severity, NSC config), false flag ignored, no NSC object => no fire, NSC field default => no fire, PoC artifact shape (mitmproxy + cer push + am start). PER_RULE_BUILDERS coverage matrix updated to include MANIFEST-010 alongside 001..006. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a single-source-of-truth rule taxonomy and a category overview
panel to the HTML audit report.
src/venomhook/rule_taxonomy.py is the new module — every audit rule
maps to a category dataclass (key + label + framework). Today the
mapping covers all 10 manifest rules (001..010) and all 6 code rules
into nine MASVS buckets:
MASVS-NETWORK-1 MANIFEST-002, MANIFEST-010, CODE-001
MASVS-PLATFORM-1 MANIFEST-004, 005, 006
MASVS-PLATFORM-2 CODE-002 (WebView)
MASVS-STORAGE-1 MANIFEST-003, CODE-005, CODE-006
MASVS-CRYPTO-1 CODE-003
MASVS-PRIVACY-1 MANIFEST-007 (perms)
MASVS-PRIVACY-2 CODE-004 (cred logs)
MASVS-ARCH-9 MANIFEST-008, 009 (sdk)
MASVS-RESILIENCE-1 MANIFEST-001 (debug)
categorize_findings() takes any iterable of objects with rule_id +
severity attrs (duck-typed so Phase 8 PE-* findings reuse the same
helper without a models.py dependency cycle), returns CategoryGroup
records sorted by category key with each group's pills sorted by
severity rank.
audit_html_report inlines a new ``.taxonomy`` grid CSS block and
renders the overview panel right after warnings, before the per-rule
findings cards. Each card shows framework / category key / human
label / per-rule pills coloured by severity. The section auto-omits
when no rule has a mapping (clean app or a future rule set with no
taxonomy entries yet).
A coverage test locks every shipped MANIFEST-001..010 + CODE-001..006
rule_id into CATEGORY_BY_RULE so adding a future rule without an
entry fails the build rather than silently disappearing from the
overview.
Tests +17:
- test_rule_taxonomy.py (13): mapping presence, unknown→None, group
sort, severity sort, malformed object handling, dataclass hash
- test_audit_html_report.py (5): taxonomy section presence/absence,
pill severity class, ordering before findings, code-rule contribution
- Two pre-existing tests (finding-card order, zero-poc card lookup)
updated to anchor their searches inside findings-section since the
taxonomy pills now mention every rule_id earlier in the document
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-locality heuristic that surfaces "this exported native is in the
same category as embedded artefacts" — a first-pass operator hint
that points at high-yield Frida targets without claiming static xref
accuracy.
True per-symbol RVA-based attribution requires disassembling .text
(ADRP+ADD on ARM64, RIP-rel LEA on x86-64) — a Capstone-class task
that's out of scope. We deliver the pragmatic alternative instead:
classify_symbol_name(name) -> frozenset[str]
Tokenize JNI / camelCase names, match against per-bucket needles
("crypt"/"aes" -> crypto, "log"/"trace" -> debug, etc.). Returns
empty when the name is opaque (single-char ProGuard outputs,
Java_a_b_c stripping, generic names) — safer to under-attribute
than mislead.
attribute_strings_by_symbol_name(symbols, hints, cap=12)
For every classifiable symbol, collect the subset of hint strings
whose buckets intersect the symbol's name buckets. Capped per
symbol so the report stays compact.
Pipeline integration:
- AndroidAnalysis.strings_by_symbol: dict[str, list[str]]
- Populated at the end of analyze_apk when so_meta + hints exist
- Bridge-matched JNI symbols are the primary candidate set;
falls back to every Java_* export when no bridges (caller used
--no-jadx)
HTML rendering:
- Bridges section header reports "{N}개 브리지에 문자열 단서 첨부"
- Each bridge row shows up to 3 attributed strings as inline pills
so triage is one screen, not two clicks
Cache schema bumps 3 -> 4 (v3 payloads have empty strings_by_symbol;
replaying v3 for a fresh request would mis-represent the report).
Tests +15:
test_native_strings.py (13): symbol classification, word-boundary
safety (key vs monkey), camelCase split, ProGuard returns empty,
co-locality crypto/url separation, cap respected, multi-category
symbols collect from each matching bucket.
test_android_pipeline.py (2): pipeline populates strings_by_symbol
when bridges match crypto-named exports; empty when hints are
irrelevant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--apk-lib allextracts every .so under the selected ABI and runs lief on each; JNI bridge correlation now matches against the union of every analysed library's exports so symbols in libssl.so / libsqlcipher.so / etc. no longer show as unmatchedbase_trusts_user_certsflag (high) with a five-step mitmproxy CA install PoCrule_taxonomy.pymaps every shipped rule to an OWASP MASVS bucket; HTML report renders a category overview between the severity bar and the per-finding cards (framework key is generic so Phase 8 PE / CWE buckets can reuse the same grid)NativeStringHintsbuckets, attach up to 12 evidence strings per symbol; HTML bridges table shows up to 3 chips per row with a header countTest plan
to_dict/from_dictfor new fields (additional_so_metas,additional_so_paths,strings_by_symbol)analysis_cache.SCHEMA_VERSIONbumped 2 → 4 so multi-lib and symbol-attribution payloads cannot be replayed by older cachesfindings-sectionso taxonomy pills no longer interfereapk-batch-auditskill againstsample/apk/after merge to validate behavior on real APKs (--apk-lib allparity, MANIFEST-010 zero-fire on release builds, MASVS grouping, attributed-string chips on JNI exports)🤖 Generated with Claude Code