SkillAgentSearch skills...

JNISleuth-MCP

Automated Android JNI RegisterNatives recovery, stripped ARM64 .so type reconstruction, OLLVM BR X8 deobfuscator, and universal LLM/MCP bridge for Jadx, Ghidra & IDA Pro 9.0.

Install / Use

claude mcp add nighthawkk -- npx -y github:nighthawkk/JNISleuth-MCP

If the server publishes to npm under a different name, use that package instead — check the repo README.

About this skill
🔌

MCP Server

Model Context Protocol server

Quality Score

84/100

Category

Security

Supported Platforms

Claude Code
Claude Desktop

Our assessment of JNISleuth-MCP

JNISleuth-MCP scores 84/100 on our quality scale, 834th of 1,105 Security skills we index.

Its MCP Server is 12 KB long, well organised into 18 sections with 7 code examples: a thorough specification that gives an agent plenty to work with.

It has 10 GitHub stars, so there is little community track record yet; judge it on its content.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
4/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 7 days ago, so JNISleuth-MCP is actively maintained.
  • No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
  • Its trust signals score 85/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

JNISleuth-MCP compared with similar skills

All 4 of these similar skills score higher than JNISleuth-MCP; compare them before choosing.

SkillScoreStarsUpdatedFormat
JNISleuth-MCP (this skill)by nighthawkk84107d agoMCP Server
Agent-Reachby Panniantong100108.6ktodayCLAUDE.md
headroomby headroomlabs-ai10078.8ktodayCLAUDE.md
CowAgentby zhayujie10047.8ktodayCLAUDE.md
Scraplingby D4Vinci10096.0ktodayMCP Server

Frequently asked questions

How do I install JNISleuth-MCP?
Run claude mcp add nighthawkk -- npx -y github:nighthawkk/JNISleuth-MCP. The install tabs above show the steps for each supported agent.
Which AI agents does JNISleuth-MCP work with?
It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
Is JNISleuth-MCP safe to use?
It declares no license and scores 85/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is JNISleuth-MCP still maintained?
The repository was last updated 7 days ago, so JNISleuth-MCP is actively maintained.
<div align="center">

🕵️‍♂️ JNISleuth-MCP

Bridge the Java-to-Native Chasm in Android Reverse Engineering.
Automated RegisterNatives Recovery, Stripped ARM64 .so Type Reconstruction, and a Unified Jadx + Ghidra or IDA MCP Server for AI-Assisted Malware Analysis.

Platform Ghidra MCP Native Engine License

Quickstart • How It Works • MCP Tools • Stealth Dobby Agent • Roadmap

</div>

⚡ Why JNISleuth-MCP?

Modern Android malware, banking trojans, spyware, and commercial packers hide their core logic (C2 encryption, key derivation, environment checks, and exploit routines) inside stripped C/C++ native libraries (lib*.so).

When reversing across the JNI boundary, analysts hit three walls:

  1. Broken Cross-References: native methods declared in classes.dex do not use standard Java_com_pkg_Class_method symbols. Instead, they are dynamically bound at runtime inside an obfuscated JNI_OnLoad via JNIEnv->RegisterNatives().
  2. Blind Decompilation: Opening a stripped .so in Ghidra or IDA shows thousands of unnamed sub_XXXX functions where JNIEnv* vtable calls look like raw pointer arithmetic ((**(code **)(*param_1 + 0x538))(param_1, param_2)).
  3. Disconnected AI Context: Existing Ghidra MCP and Jadx MCP servers live in silos—an LLM cannot trace data flow from an Android BroadcastReceiver in Java straight into an ARM64 encryption routine in libnative-lib.so.

JNISleuth-MCP eliminates the context switch. It automatically recovers static and dynamic RegisterNatives bindings, re-types stripped ARM64 functions in Ghidra, and exposes a single unified Model Context Protocol (MCP) server connecting DEX bytecode to native assembly.

| Capability | Standard Jadx / Ghidra MCPs | JNISleuth-MCP | | :--- | :---: | :---: | | Resolve standard Java_* exports | ✅ | ✅ | | Recover stripped RegisterNatives struct arrays statically (.rodata / .data.rel.ro + JNI_OnLoad CFG) | ❌ | ✅ | | Stealth on-device RegisterNatives harvesting via Dobby (bypasses anti-Frida checks) | ❌ | ✅ | | Auto-apply JNIEnv* vtable types & reconstruct Call*Method / GetStringUTFChars in Ghidra | ❌ | ✅ | | Single-call cross-boundary dataflow (Java Caller ➔ JNI Bridge ➔ Decompiled ARM64 C++) | ❌ | ✅ |


🏗️ Architecture & How It Works

flowchart LR
    subgraph Input["📦 Target APK / Malware"]
        DEX["classes*.dex"]
        ELF["Stripped lib/*.so (ARM64)"]
    end

    subgraph Harvester["🔍 Stage 1: JNI Bridge Harvester"]
        StaticScan["Static ELF & DEX Scanner\n(LIEF + Capstone + Heuristic Triplets)"]
        DobbyAgent["Stealth Native Agent\n(C++ / NDK / Dobby Inline Hook)"]
    end

    subgraph GhidraEngine["⚙️ Stage 2: Ghidra Headless Reconstructor"]
        Renamer["Function Renamer & Signature Applier"]
        VTable["JNIEnv* VTable & Struct Propagator"]
    end

    subgraph MCPServer["🤖 Stage 3: Unified FastMCP Server"]
        CrossGraph["Cross-Boundary Callgraph\n(Jadx Java + Ghidra C/ARM64)"]
        CallbackTrace["Upcall Tracer\n(Native -> Java Reflection)"]
    end

    DEX --> StaticScan
    ELF --> StaticScan
    ELF -. "Packed / OLLVM?" .-> DobbyAgent
    StaticScan --> Renamer
    DobbyAgent -- "register_natives.json" --> Renamer
    Renamer --> VTable
    VTable --> CrossGraph
    VTable --> CallbackTrace

🎬 See It In Action

1. CLI Static + Dynamic RegisterNatives Recovery

Run jnisleuth scan against an APK with stripped native libraries:

$ jnisleuth scan --apk samples/banker_dropper.apk --arch arm64-v8a

[*] Parsing 3 DEX files... Found 14 declared `native` methods across 4 classes.
[*] Inspecting lib/arm64-v8a/libcore-crypto.so (Stripped ELF, 0 exported Java_* symbols)
[*] Running static JNINativeMethod triplet scanner on .rodata / .data.rel.ro...
    [+] Resolved 11/14 methods via static struct table @ 0x0004d210
[!] 3 methods unresolved (constructed dynamically on stack in JNI_OnLoad).
[*] Launching headless Dobby collector on device (emulator-5554)...

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ Java Class & Method                      ┃ JNI Signature        ┃ .so Offset (ARM64)  ┃ Resolution Mode  ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
│ com.dropper.Core#initEngine              │ (Landroid/content/.. │ libcore.so+0x001a40 │ Static (.rodata) │
│ com.dropper.Core#decryptPayload          │ ([BLjava/lang/Stri.. │ libcore.so+0x0023c8 │ Static (.rodata) │
│ com.dropper.Core#signC2Beacon            │ (Ljava/lang/String.. │ libcore.so+0x003f10 │ Dynamic (Dobby)  │
│ com.dropper.net.SocketBridge#connectRaw  │ (Ljava/lang/String.. │ libcore.so+0x004890 │ Dynamic (Dobby)  │
└──────────────────────────────────────────┴──────────────────────┴─────────────────────┴──────────────────┘
[+] Synced 14 function signatures and JNIEnv* types to Ghidra project: banker_dropper.gpr

2. Before vs. After in Ghidra

Before JNISleuth-MCP (FUN_000123c8):

long FUN_000123c8(long *param_1, undefined8 param_2, undefined8 param_3, undefined8 param_4) {
  char *pcVar1;
  long lVar2;
  pcVar1 = (char *)(**(code **)(*param_1 + 0x548))(param_1, param_4, 0);
  lVar2 = (**(code **)(*param_1 + 0x5c0))(param_1, param_3, 0);
  sub_00014a00(lVar2, pcVar1);
  (**(code **)(*param_1 + 0x550))(param_1, param_4, pcVar1);
  return param_3;
}

After JNISleuth-MCP (Java_com_dropper_Core_decryptPayload):

jbyteArray Java_com_dropper_Core_decryptPayload(
    JNIEnv *env, jobject thiz, jbyteArray encryptedData, jstring rc4KeyStr) 
{
  const char *key_utf = (*env)->GetStringUTFChars(env, rc4KeyStr, NULL);
  jbyte *payload_bytes = (*env)->GetByteArrayElements(env, encryptedData, NULL);
  rc4_crypt_buffer(payload_bytes, key_utf);
  (*env)->ReleaseStringUTFChars(env, rc4KeyStr, key_utf);
  return encryptedData;
}

🤖 Universal LLM & MCP Support (Works With Any Model)

JNISleuth-MCP is 100% model-agnostic. You can connect it to any cloud or local LLM via the standard Model Context Protocol (stdio JSON-RPC 2.0) or export native OpenAI / Gemini / Ollama function-calling schemas:

  • Cloud LLMs & Agents: Google Gemini CLI, OpenAI / ChatGPT Desktop / Codex CLI, Cursor, Windsurf, Cline, Roo Code, Claude Desktop / Claude Code
  • Local / Self-Hosted LLMs: Ollama, vLLM, LM Studio, OpenWebUI, Continue.dev (DeepSeek-R1, Qwen-2.5-Coder, Llama-3.3)
  • Custom Python Agent SDKs: Direct tool-schema export (jnisleuth llm-tools --format openai|gemini|mcp) for LangChain, LlamaIndex, LiteLLM, OpenAI SDK, or google-genai.

| Tool Name | Description | | :--- | :--- | | resolve_apk_jni_map(apk_path) | Extracts all native declarations from DEX and maps them to exact ELF file offsets in lib/*.so (via export symbols, static .rodata triplets, or dynamic trace import). | | get_cross_boundary_slice(java_method) | Returns the decompiled Java caller (via Jadx) and the typed, decompiled C/ARM64 implementation (via Ghidra/IDA) in a single unified response. | | trace_jni_upcalls(so_name, fn_offset) | Lists every Java reflection callback (FindClass, GetMethodID, CallObjectMethod, SetByteArrayRegion) invoked inside a native ARM64 function and its callees. | | sync_ghidra_jni_types(trace_json) | Applies JNIEnv*, JavaVM*, JNINativeMethod structs, and recovered function signatures directly into an active or headless Ghidra project. | | sync_ida_jni_types(trace_json) | Applies JNIEnv*, JavaVM*, JNINativeMethod C headers, recovered function prototypes, and OLLVM fl_JN code cross-references into IDA Pro 9.0 (idalib / idapyswitch / idat64). | | resolve_ollvm_indirect_branches(so_name, fn_offset) | Resolves OLLVM CSEL + BR X8 state-machine dispatchers and .rodata jump tables in JNI_OnLoad, and optionally patches the ELF binary with direct B.<cond> / B instructions. | | extract_jni_onload_strings(so_name) | Dumps stack-constructed and XOR-decrypted strings inside .init_array and JNI_OnLoad. |


🥷 Stealth Dobby Agent (Anti-RASP & Packer Mode)

Many wild Android malware families and commercial protectors immediately crash or exit if they detect frida-agent.so in /proc/self/maps, gum-js-loop threads, or modified function prologues in libc.so.

JNISleuth-MCP includes an optional zero-Frida native collector (agent-native/) written in C++20 and ARM64 assembly using Dobby:

  • Mid-Function Hooking: Places hooks inside the ArtMethod::RegisterNative / JNIEnvExt::RegisterNatives dispatch path rather than the first instruction of exported stubs, evading basic prologue integrity scanners.
  • Base-Address Normalization: Uses dladdr() and linker soinfo traversal to automatically subtract ASLR slide and record deterministic file offsets (libfoo.so + 0x23c8), even if the packer unmaps ELF section headers after JNI_OnLoad.

🚀 2-Minute Quickstart

Prerequisites

  • Python 3.10+ (pip install uv)
  • Ghidra 11.0+ (GHIDRA_INSTALL_DIR) or IDA Pro 9.0+ (IDA_INSTALL_DIR / idapyswitch)
  • Jadx CLI installed in $PATH
  • (Optional) Android NDK r26+ & ADB for dynamic Dobby collection

Installation

git clone https://github.com/<your-username>/JNISleuth-MCP.git
cd JNISleuth-MCP
uv sync

# 1. Scan the included obfuscated NDK crackme sample & sync with Ghidra / IDA Pro 9.0:
uv run jnisleuth scan --apk examples/obfuscated_jni_sample.apk --ghidra-headless --ida-headless

# 2. Resolve & patch OLLVM CSEL + BR X8 indirect branches in JNI_OnLoad:
uv run jnisleuth deobfuscate --so examples/libcore-crypto.so --offset 0x5200 --patch-out examples/libcore-crypto.deobf.so

Connect to Any LLM / IDE Agent (mcp.json / settings.json)

Works out of the box with Gemini CLI (~/.gemini/settings.json), Cursor (.cursor/mcp.json), Windsurf, Cline, Continue.dev (Ollama), ChatGPT Desktop, and Claude:

{
  "mcpServers": {
    "jnisleuth-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/JNISleuth-MCP", "jnisleuth-mcp"],
      "env": {
        "GHIDRA_INSTALL_DIR": "/opt/ghidra",
        "IDA_INSTALL_DIR": "/opt/idapro-9.0"
      }
    }
  }
}

Use with OpenAI / Gemini / Ollama Python SDKs Directly (No MCP Client Needed)

# Export function-calling tool schemas for OpenAI / Ollama / vLLM or Google Gemini:
uv run jnisleuth llm-tools --format openai > openai_tools.json
uv run jnisleuth llm-tools --format gemini > gemini_tools.json

🗺️ Roadmap

  • [x] Static DEX native method parser + ELF .rodata / .data.rel.ro JNINativeMethod triplet scanner
  • [x] Headless Ghidra JNIEnv* vtable auto-typing script for ARM64 & x86_64
  • [x] Unified FastMCP server bridging Jadx, Ghidra & IDA Pro 9.0
  • [x] On-device Dobby mid-function RegisterNatives + DexFile::OpenCommon unpacker module
  • [x] IDA Pro 9.0 (idapyswitch / idalib / headless idat64) backend support alongside Ghidra
  • [x] Automated OLLVM indirect-branch (BR X8) resolver & ELF patcher for JNI_OnLoad state machines

⚠️ Disclaimer

JNISleuth-MCP is developed for defensive malware analysis, mobile application security assessments, and reverse-engineering research. All

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars10
CategorySecurity
Updated7d ago
Forks2

Languages

Python

Trust signals

85/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

1 medium1 info