8000
Skip to content

Set DexTrace as the default core library - #967

Open
haeter525 wants to merge 10 commits into
ev-flow:masterfrom
haeter525:feat/dextrace-default-backend
Open

Set DexTrace as the default core library#967
haeter525 wants to merge 10 commits into
ev-flow:masterfrom
haeter525:feat/dextrace-default-backend

Conversation

@haeter525
Copy link
Copy Markdown
Member

Description

Changes Quark's default --core-library from androguard to dextrace, per the comparison results in #966.

Also makes rizin/radare2 optional extras instead of hard dependencies.

Adds a clear error message when a selected backend is unavailable.

Key Changes

  • Changed the default --core-library value (CLI and Quark.__init__) to dextrace.
  • Added CoreLibraryUnavailable exception in baseapkinfo.py.
    • cli.py now catches it and prints a clean error instead of a raw traceback.
  • Moved rzpipe/r2pipe from core install requirements into new extras:
    • pip install "quark-engine[rizin]"
    • pip install "quark-engine[radare2]"
  • Fixed a Level 4 sequence-check bug in quark/core/quark.py.
    • Previously: return on the first (first_api, second_api) pair with no mutual parent function aborted the whole rule check.
    • Now: continue, so remaining candidate pairs are still tried.
    • Side effect: fixed a PYTHONHASHSEED-dependent confidence-score flakiness.
  • Updated docs/source/install.rst for the new default and extras.
  • Minor backend-agnostic cleanup in r2apkinfo.py, rzapkinfo.py, shurikenapkinfo.py, dextraceapkinfo.py, axmlreader/__init__.py, script/__init__.py, report.py.

Motivation and Context

Closes part of #966.

A comparison between DexTrace and Androguard across 470 comparable samples from the malware-family corpus showed a 99.6% exact confidence-score match (468/470).

The 2 remaining mismatches trace to a known Androguard adapter bug, not to DexTrace:

  • Duplicate-class dedup miscount when an API is defined across multiple DEX files.

Blocked on: DexTrace#19.

  • Needs merging, then a new DexTrace release published to PyPI.
  • The dextrace version pin in setup.py needs bumping once that's out — until then CI here won't pass.

How Has This Been Tested?

  • Full accuracy run across all malware families: 468/470 comparable samples match exactly between DexTrace and Androguard.
  • Seed-bug fix verified separately on the 18 previously-diffing samples (35 sample-rule combos): 35/35 now match.

Checklist

  • DexTrace#19 merged and new DexTrace version released
  • Bump dextrace version pin in setup.py
  • CI passing on Linux/macOS/Windows
  • Quark-Script and Quark Report smoke-tested
  • Existing unit tests pass locally

haeter525 and others added 10 commits August 16, 2026 03:36
Classes referenced but not defined in the app's DEX (e.g. NetworkInfo,
ConnectivityManager) had no entry in superclass_relationships, so
find_api_usage()'s subtype walk dead-ended before reaching
Ljava/lang/Object;. Rules pairing such a class with a generic
Object.equals call as the second API could never reach full
combination/sequence confidence.

Every Java class ultimately extends Object, so default any class with
no DEX-derived hierarchy entry to that instead of a lookup dead end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JB4p3nzcxeJ16U7WQMEh3Q
- quark/cli.py, quark/core/quark.py, quark/report.py: default
  core_library changed from androguard to dextrace. quark/forensic/
  forensic.py intentionally left on androguard -- it has no dextrace
  branch and DexTraceImp.get_strings() is a stub returning an empty
  set, so switching its default would silently break string
  extraction rather than just swap backends.

- setup.py: move rzpipe and r2pipe==1.8.0 out of install_requires
  into new 'rizin' / 'radare2' extras. androguard and dextrace stay
  required. Shuriken was already optional (never in install_requires).

- quark/core/axmlreader/__init__.py: the module-level 'import rzpipe'
  / 'import r2pipe' transitively broke every backend, since
  BaseApkinfo (which all backends inherit) imports
  axmlreader.python, which runs axmlreader/__init__.py as a package
  side effect. Verified empirically that BaseApkinfo failed to import
  with rzpipe/r2pipe unavailable before this fix. Moved both imports
  into the rizin/radare2 branches of AxmlReader.__init__, guarded
  with try/except raising AxmlException (the file's own local
  exception -- can't import the new shared exception here without a
  circular import back through baseapkinfo.py -> axmlreader.python ->
  axmlreader/__init__.py).

- quark/core/rzapkinfo.py, quark/core/r2apkinfo.py: same guard
  pattern already used by ShurikenImp (try/except ModuleNotFoundError
  around the top-level import, check-and-raise moved into __init__).
  Now raise the new shared CoreLibraryUnavailable exception.

- quark/core/interface/baseapkinfo.py: add CoreLibraryUnavailable, a
  shared exception for 'this --core-library backend's dependency
  isn't installed'. ShurikenImp now raises this too instead of a bare
  Exception.

- quark/cli.py: wrap both Quark(...)/ParallelQuark(...) construction
  sites in try/except CoreLibraryUnavailable, printing a clean
  one-line message via print_error() and exiting 1, instead of
  letting a raw traceback reach the user (previously true even for
  Shuriken's existing 'not installed' message).

- tests/core/test_quark.py, tests/agent/test_agentTools.py: pin the
  three Quark(...) call sites that relied on the implicit default to
  core_library="androguard" explicitly, since these fixtures test
  Quark's evaluation logic against Androguard-specific behavior, not
  'whatever the current default backend is'.

Verified: BaseApkinfo, quark.core.quark, RizinImp, and R2Imp all
import/construct correctly with rzpipe/r2pipe simulated missing
(RizinImp/R2Imp raise CoreLibraryUnavailable with install
instructions instead of ModuleNotFoundError at import time). CLI with
no --core-library flag now runs dextrace by default end-to-end;
--core-library androguard still works explicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JB4p3nzcxeJ16U7WQMEh3Q
install.rst's --core-library list was already stale (missing dextrace
before this change). Add it, mark it as the default, and document
pip install quark-engine[rizin]/[radare2] for the two backends that
moved out of install_requires.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JB4p3nzcxeJ16U7WQMEh3Q
- add _register_no_caller_callee_methods: walk all declared methods
  up front so a concrete method with no outgoing calls and no visible
  caller in-DEX (e.g. interface-callback overrides like
  HostnameVerifier.verify()) still lands in all_methods/android_apis/
  custom_methods, instead of only being discoverable via
  extract_api_calls (invoke targets) or _register_abstract_methods
  (code_off==0 declarations)
- wire extract_declared_methods and extract_strings into imports
- implement get_strings() via extract_strings instead of returning
  an empty set
- add debug logger gated on config.DEBUG
- sort per-caller calls by real invoke offset when all present;
  fall back to DexTrace's original call order (with a warning)
  when any offset is missing, instead of a stable-sort tiebreak
  that guessed order
- propagate the real offset into _calls_by_caller and
  _calls_by_caller_sig instead of always using enumerate() index
Drop "_from_cache" suffix — implementation detail, not part of
the name's meaning; caller doesn't care about caching.
- strip quotes and unescape smali string literals (const-string
  etc keep quotes; androguard's operand is the raw unquoted string)
- parse const/const-wide literal operands (decimal, 0x-hex, optional
  'L' wide suffix) into int to match androguard's int operand type
Method.get_upper_methods walked apkinfo.analysis.get_class_analysis,
an androguard-only API; DexTrace backend has no analysis object.
Derive class hierarchy from apkinfo.superclass_relationships instead,
which both backends provide.

superclass_relationships mixes extends+implements edges; first
parent is treated as the superclass edge since rules/backends
don't distinguish the two either.
- swap Dict/List/Set/Tuple/Optional[X] for dict/list/set/tuple/X | None
  builtin generics (PEP 585, PEP 604) throughout
- move Generator/Iterable imports to collections.abc
- drop empty parens on functools.lru_cache decorators
- drop unused second Generator type param (yields only)
@codecov
codecov Bot commented Aug 23, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 65.32258% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.48%. Comparing base (528c937) to head (b10d153).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
quark/core/dextraceapkinfo.py 57.97% 29 Missing ⚠️
quark/cli.py 57.14% 3 Missing ⚠️
quark/core/r2apkinfo.py 66.66% 3 Missing ⚠️
quark/core/rzapkinfo.py 66.66% 3 Missing ⚠️
quark/core/axmlreader/__init__.py 80.00% 2 Missing ⚠️
quark/core/quark.py 75.00% 1 Missing ⚠️
quark/core/shurikenapkinfo.py 50.00% 1 Missing ⚠️
setup.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master     #967   +/-   ##
=======================================
  Coverage   78.48%   78.48%           
=======================================
  Files          84       84           
  Lines        7692     7692           
=======================================
  Hits         6037     6037           
  Misses       1655     1655           
Flag Coverage Δ
unittests 78.48% <65.32%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0