Source-linked AI summary

JANUS: Agentic Cross-Language Fuzzing Harness Generation for Android Native Libraries

Xiangyu Zhang, Yucheng Su, Lingling Fan, Yinan Li, Sen Chen

arXiv:2610.30218v1cs.SEcs.CR

TL;DR

JANUS addresses the difficulty of generating JNI-aware fuzzing harnesses for closed-source Android libraries, where prior tools struggle with cross-language usage patterns and composite arguments. It iteratively recovers dependencies and builds arguments bottom-up; across 21,386 JNI methods, it produced 7.4×/5.9× more valid harnesses than Atlas++ and POIROT, respectively.

  • Problem

    Closed-source Android libraries use app-specific JNI conventions, while existing approaches struggle to recover cross-language invocation context and construct complex composite arguments.

    Source: 1) Hidden App-Specific Invocation… · p. 3, 2) Missing Object-Construction Semantics · p. 3
  • Method

    JANUS iteratively resolves explicit and implicit call dependencies and recursively assembles composite arguments from primitive objects in a bottom-up manner.

    Source: §I · p. 2
  • Results

    7.4×/5.9× more valid harnesses than Atlas++ and POIROT, respectively, across 21,386 JNI methods; JANUS also uncovered 6 previously unknown memory-corruption vulnerabilities.

    Source: §I · p. 2
  • Takeaways & Limitations

    The confirmed crashes corresponded to 6 vulnerabilities in closed-source vendor libraries, which JANUS reported to CVE for review.

    Source: 2) Result · p. 9

    JANUS uses a linear execution model and may miss state dependencies established by asynchronous calls and concurrency-related vulnerabilities.

    Source: 1) Limitations · p. 10

Abstract

from arXiv · show

Modern Android apps extensively rely on native libraries, bridging Java/Kotlin and C/C++ through the Java Native Interface (JNI). This cross-language interoperation, however, exposes the memory-safe Android Runtime to the unsafe C/C++ world, creating an attack surface that has been repeatedly exploited for full device compromise. While fuzzing is a proven technique for vetting native libraries, state-of-the-art harness generation tools struggle to faithfully capture closed-source cross-language API usage: (i) precise program analysis across the JNI boundary does not scale, whereas lightweight approximations miss critical invocation patterns; and (ii) none tackles the construction of complex composite objects consumed by JNI methods. In this paper, we propose JANUS, the first agentic approach to synthesizing cross-language JNI-aware fuzzing harnesses for Android native libraries. JANUS iteratively resolves both explicit and implicit cross-language call dependencies to recover app-specific runtime context, and recursively assembles cross-language argument objects in a bottom-up manner. JANUS leverages an autonomous agentic workflow to reduce reliance on hand-crafted heuristics, capturing the vast landscape of hidden API usage knowledge embedded in closed-source native libraries. Evaluation on 44 popular real-world apps (such as Google and YouTube Music, covering 21,386 JNI methods total) shows that JANUS produces over 5.9 times as many valid harnesses (6,094) as state-of-the-art automatic harnessing tools. On pre-installed apps from five mainstream Android vendors (e.g., Xiaomi, Vivo, Samsung), JANUS further uncovers 6 previously unknown vulnerabilities in closed-source native libraries.

I. INTRODUCTION

JANUS targets the difficulty of generating valid fuzzing harnesses for closed-source Android native libraries, where JNI usage conventions are app-specific and complex argument construction remains unaddressed. It uses an agentic workflow to recover cross-language invocation context and construct composite arguments, producing more valid harnesses and uncovering previously unknown vulnerabilities.

Problem

  • JNI harnessing requires app-specific call dependencies and argument-construction knowledge that is difficult to recover across languages and is not portable across apps.Closed-source libraries lack official documentation or portable usage examples, so each app’s private conventions must be recovered anew.Source: §I · p. 1
  • Prior tools face a precision–scalability trade-off, and neither addresses construction of the complex composite objects JNI methods consume.Atlas uses cross-language analysis that does not scale well, while POIROT’s Java-only analysis is more scalable but less precise.Source: §I · pp. 1–2

Approach

  • JANUS iteratively resolves explicit and implicit invocation context, then recursively decomposes composite arguments and rebuilds them bottom-up.Its LLM-powered workflow captures JNI usage knowledge and parameter relationships while reducing reliance on hand-crafted heuristics.Source: §I · p. 2
  • JANUS uses an agentic workflow with structure-aware retrieval, persistent verified artifacts, and validation-guided refinement to address exploration, context drift, and hallucinations.Failures are attributed to the responsible synthesis stage for targeted refinement.Source: §I · p. 2

Results

  • JANUS produced 7.4×/5.9× more valid harnesses and achieved 5.8×/6.5× the bitmap coverage of Atlas++ and POIROT, respectively.The evaluation covered 21,386 JNI methods across 44 real-world apps; JANUS also uncovered 6 previously unknown memory-corruption vulnerabilities in vendor libraries.Source: §I · p. 2

II. PRELIMINARIES

The preliminaries explain how JNI mediates Java–native interaction and use a motivating example to expose app-specific invocation dependencies, complex object construction, and the limits of unconstrained LLM harness generation.

A. Java Native Interface in Android

  • JNI native methods bind statically through naming conventions or dynamically through RegisterNatives, and use JNIEnv reflection calls to access fields and create objects.Nested composite types require reflective lookups to be chained layer by layer.Source: A. Java Native Interface in Android · p. 2

B. Motivating Example

  • The motivating example illustrates two runtime-context challenges and shows why naive delegation to an LLM agent does not resolve them.The section identifies a further challenge introduced by unconstrained agent reasoning.Source: B. Motivating Example · p. 2

1) Hidden App-Specific Invocation Context:

  • nativeProcess requires both a Java-initialized ProcOpts object and a prior nativeInit call that sets g_init; otherwise it returns before reaching core logic.A Java-only call-chain analysis can omit nativeInit because it resides in a separate onCreate entry point.Source: 1) Hidden App-Specific Invocation… · p. 3

2) Missing Object-Construction Semantics:

  • Constructing ProcOpts requires selecting its constructor, recursively creating its nested SubConf object, and supplying a legal alg string.Existing methods described here do not synthesize such complex Java objects.Source: 2) Missing Object-Construction Semantics · p. 3

3) LLM Agents Are Not a Silver Bullet:

  • In a study of 1,247 JNI methods across 10 APKs, an off-the-shelf agent generated no buildable JNI-aware harness without manual intervention.Its failure modes included aimless exploration, long-horizon inconsistency, and hallucinations without validity refinement; an apparent no-crash run could still execute only shallow steps.Source: 3) LLM Agents Are Not a Silver Bullet · p. 3

III. APPROACH

JANUS divides harness generation into cross-language parsing, harness synthesis, and feedback-driven refinement. Its synthesis combines cross-language retrieval with dependency recovery and recursive argument construction, while memory and validation support longer reasoning chains.

III. APPROACH

  • JANUS parses an APK into DEX files and native libraries, then uses a parser, harness synthesizer, and feedback-driven refiner to generate harnesses.The refiner sends compilation errors, runtime exceptions, and coverage signals to the upstream stage responsible for repair.Source: §III · pp. 3–4

A. Phase 1: Cross-Language Parser

  • The parser recovers Java–native interaction structure, including method and call relationships, native function bodies, argument constraints, and runtime JNI bindings.Its binding table records method signatures, types, owning libraries, and relative offsets for static and dynamic registration.Source: A. Phase 1: Cross-Language Parser · p. 4

B. Phase 2: Harness Synthesizer

  • The Harness Synthesizer recovers each JNI method’s precursor call sequence and argument-construction scheme, while memory retains verified artifacts across methods.Its four components include a structure-aware retriever, dependency-driven sequence extractor, recursive argument constructor, and harness memory manager.Source: B. Phase 2: Harness Synthesizer · p. 4

1) Structure-Aware Code Retriever:

  • A JNI-aware language server links Java and native symbol indexes, while AST-Grep templates identify structural patterns such as object propagation and JNI field access.The retriever returns source locations, symbol information, and code snippets; tool choices remain traceable to source locations.Source: 1) Structure-Aware Code Retriever · pp. 4–5

2) Dependency-Driven Call Sequence Extractor:

JANUS builds prerequisite call sequences by iteratively resolving explicit and implicit dependencies in app-specific Java and native context. It annotates calls and accepts sequences only after their dependencies are resolved and the sequence passes a global review.

2) Dependency-Driven Call Sequence Extractor:

  • JANUS resolves explicit Java-side and implicit native-side dependencies needed to reconstruct the runtime context of each target JNI method.Explicit dependencies include Java object construction and field writes; implicit dependencies may require preceding JNI calls to produce values or state.Source: 2) Dependency-Driven Call Sequence… · p. 5
  • The algorithm represents a target’s prerequisite calls as S_m, with annotations recording each call’s role, supporting code, and downstream bindings.Bindings capture return-value flow and side effects that establish dependency state for later calls or the target JNI method.Source: 2) Dependency-Driven Call Sequence… · p. 5
  • An agentic iterative loop identifies unmet dependencies, retrieves JNI-related code, converts results into candidate calls, and adds them with structured annotations.JANUS uses LLM agents rather than handcrafted heuristics to identify missing dependencies and calls that satisfy them.Source: 2) Dependency-Driven Call Sequence… · p. 5
  • Previously recorded sequences that cover a current dependency are reused, and the search returns failure if its budget runs out before dependency closure.Once dependencies are satisfied, a global review checks call ordering, dependency consistency, and bindings before accepting the sequence.Source: 2) Dependency-Driven Call Sequence… · p. 6
  • The accepted prerequisite calls and their supporting code provide the invocation context for the subsequent argument-synthesis stage.Source: 2) Dependency-Driven Call Sequence… · p. 6

3) Recursive Argument Constructor:

JANUS recursively constructs argument objects when JNI type signatures alone do not reveal how complex objects should be initialized. It selects construction paths, recurses into sub-arguments, and checks generated code before reuse.

3) Recursive Argument Constructor:

  • Primitive inputs and reference types such as strings or primitive arrays are synthesized directly from fuzzer bytes, while compatible constructions in memory are reused.Direct synthesis terminates recursion; primitive bytes are decoded into values, and reference types are materialized through JNI APIs.Source: 3) Recursive Argument Constructor · p. 6
  • For composite types, JANUS considers constructors, factory methods, and observed instantiation sites, selecting a path based on app usage and native-read fields.For ProcOpts, it selects ProcOpts(int, SubConf) because that constructor initializes the nested field read by native code.Source: 3) Recursive Argument Constructor · p. 6
  • JANUS recursively constructs each selected path’s sub-arguments, backtracks if one cannot be built, and emits JNI calls to assemble the object.The example recursively constructs SubConf and then its String and int arguments.Source: 3) Recursive Argument Constructor · p. 6
  • Generated construction code is checked for valid code references and smoke-tested for instantiation, field writes, and Java exceptions before being stored for reuse.Source: 3) Recursive Argument Constructor · p. 6
  • Construction snippets sourced from the fuzzer byte stream combine with the prerequisite call sequence to form the target method’s invocation context.Source: 3) Recursive Argument Constructor · p. 6

4) Harness Memory Manager:

JANUS uses a Harness Memory Manager to retain verified components during long-horizon synthesis. Later requirements can reuse matching components already in the global store.

4) Harness Memory Manager:

  • The Harness Memory Manager maintains a global store of verified harness components to support long-horizon synthesis.Verified call sequences and argument construction plans are examples of components committed to memory.Source: 4) Harness Memory Manager · pp. 6–7
  • When a component passes its validation check, JANUS commits it to memory for subsequent synthesis rounds.Source: 4) Harness Memory Manager · p. 7
  • For a new requirement, the manager queries memory and directly reuses a matching component when one is available.Source: 4) Harness Memory Manager · p. 7

C. Phase 3: Feedback-driven Harness Refiner

JANUS assembles synthesized call sequences and argument plans into runnable harnesses for fuzzers such as AFL++. The passage identifies strict harness constraints and shallow execution as distinct challenges to harness generation and validation.

C. Phase 3: Feedback-driven Harness Refiner

1) App-Specific Harness Template:

JANUS structures harness synthesis with a fixed template, then validates and repairs generated harnesses using compilation, runtime, and coverage feedback. Its evaluation spans commercial Android apps and vendor-preinstalled apps with system-level permissions.

1) App-Specific Harness Template:

2) Validation-Guided Iterative Refinement:

IV. EFFECTIVENESS EVALUATION

  • The evaluation asks whether JANUS generates effective harnesses, how its components contribute, and whether it discovers previously unknown bugs.Source: §IV · p. 7
  • Experiments use GLM-5, Android API 31 emulators, and Frida-driven AFL++ within a customized OpenCode implementation.Source: §IV · p. 7
  • POIROT-44 contains 44 popular apps, including 16 with over 500 million downloads, and 21,386 JNI methods; it supports RQ1 and RQ2.Source: Dataset · p. 7
  • Vendor-20 comprises 20 pre-installed apps from Xiaomi, Vivo, Samsung, OnePlus, and OPPO, with diverse native-library-heavy functions and system privileges.Source: Dataset · p. 7

A. RQ1: Effectiveness of JANUS’s Harness Generation

On POIROT-44, JANUS outperforms Atlas++ and POIROT in harness generation, execution, coverage, and crash discovery. Manual analysis also identifies execution failures and limits on interpreting crash findings.

2) Result:

Failure Analysis.

  • Among 1,163 non-runnable harnesses, 637 succeeded with a two-hour budget; remaining failures involved coarse crash feedback, unmet external state, or anti-emulation checks.Source: A. RQ1: Effectiveness of JANUS’s… · p. 8

Cost Analysis.

B. RQ2: Ablation Study of the Analysis Passes

The ablation study tests four JANUS components by replacing each stage with unguided agent behavior. Each component contributes to harness quality, while Vendor-20 separately supplies the RQ3 setting for vulnerability discovery.

1) Setup:

B. RQ2: Ablation Study of the Analysis Passes

1) Setup:

  • RQ3 applies the same harness-generation pipeline to Vendor-20 JNI methods and allocates 24 hours of fuzzing per successfully built harness.Source: 1) Setup · p. 9

2) Result:

JANUS’s evaluation confirmed six previously unknown vulnerabilities across four major vendors, including a Xiaomi Theme Manager case. The results also identify boundaries involving concurrent execution and deep Android system interactions.

2) Result:

  • The authors reported the vulnerabilities to the vendors and provided sanitized artifacts, withholding full technical details until the agreed embargo expires.The reports included harness artifacts and crash samples for manual validation.Source: 2) Result · pp. 9–10
  • A Xiaomi Theme Manager case exposed an unchecked stride-based write: attacker-controlled index and value yield a relative heap-write primitive reachable through crafted scenes.The app runs with system privileges, and a victim must be lured into applying the crafted scene file.Source: 2) Result · p. 10
  • 6 vulnerabilities across 4 major vendors were confirmed; JANUS’s 1,284 crashing inputs were deduplicated to 155 crashes for manual triage and reachability/root-cause analysis.Crashes unreachable from attacker-controllable production inputs were filtered out.Source: 2) Result · pp. 9–10

A. Choice of Base Model

  • JANUS adopts GLM-5 for its balance of instruction following, open weights, and low cost; Claude Opus 4.5 cost $7,225.8, 5.6× the cost of JANUS-backed GLM-5.The tested open models were insufficient for the agentic tasks, while closed proprietary models raised reproducibility concerns.Source: A. Choice of Base Model · p. 10

1) Limitations:

  • JANUS’s linear execution may miss asynchronous state dependencies and concurrency-related vulnerabilities; it may also fail on libraries relying heavily on deep Android or Binder interactions.The paper identifies real-time runtime context as a challenge for those system interactions.Source: 1) Limitations · p. 10

2) Threats to Validity:

The evaluation’s two app datasets broaden coverage but leave other app categories unexamined. Prior approaches also leave challenges in app-specific JNI usage and composite-object construction, while JANUS targets those gaps.

2) Threats to Validity:

  • POIROT-44 covers normal-permission commercial apps and Vendor-20 covers system-level vendor apps, but other app categories may remain unrepresented.The authors identify broader evaluation across more app types as future work.Source: 2) Threats to Validity · p. 10

A. Automated Harness Generation for Libraries

  • Prior harness-generation methods face app-specific call-dependency and object-construction challenges in closed-source Android libraries, where thorough API documentation or examples are often unavailable.The related-work discussion describes these constraints across general and cross-language harness-generation approaches.Source: A. Automated Harness Generation for… · p. 10

B. Android/JNI Vulnerability Detection

  • Android/JNI vulnerability research often centers on Java/Kotlin or information-flow analysis; Atlas and POIROT face precision-scalability trade-offs and do not recover complex-object construction knowledge.FANS assumes system-service source availability, while JNIFuzzer lacks Java-side context modeling.Source: B. Android/JNI Vulnerability Detection · p. 10

VII. CONCLUSION

  • JANUS is presented as the first agentic approach to JNI-aware Android native-library harness synthesis, yielding more valid harnesses and uncovering previously unknown vulnerabilities.Source: §VII · p. 11

VIII. DATA AVAILABILITY

  • The authors publicly release the JANUS prototype and artifacts.Source: §VIII · p. 11
Loading 2610.30218v1…