
Android JNI RegisterNatives का स्वचालित पुनर्प्राप्ति, stripped ARM64 .so प्रकार का पुनर्निर्माण, OLLVM BR X8 डीऑब्फस्केटर, और Jadx, Ghidra तथा IDA Pro 9.0 के लिए सार्वभौमिक LLM/MCP ब्रिज।
Android रिवर्स इंजीनियरिंग में Java-to-Native की खाई को पाटें।
स्वचालित RegisterNatives रिकवरी, स्ट्रिप्ड ARM64 .so टाइप पुनर्निर्माण, और AI-सहायता प्राप्त मैलवेयर विश्लेषण के लिए एक एकीकृत Jadx + Ghidra या IDA MCP सर्वर।
क्विकस्टार्ट • यह कैसे काम करता है • MCP टूल्स • स्टेल्थ Dobby एजेंट • रोडमैप
आधुनिक Android मैलवेयर, बैंकिंग ट्रोजन, स्पाईवेयर और व्यावसायिक पैकर्स अपने मुख्य लॉजिक (C2 एन्क्रिप्शन, की डेरिवेशन, एनवायरनमेंट चेक और एक्सप्लॉइट रूटीन) को स्ट्रिप्ड C/C++ नेटिव लाइब्रेरीज़ (lib*.so) के अंदर छिपाते हैं।
JNI सीमा के पार रिवर्सिंग करते समय विश्लेषकों को तीन बाधाओं का सामना करना पड़ता है:
classes.dex में घोषित native मेथड्स मानक Java_com_pkg_Class_method सिंबल्स का उपयोग नहीं करते। इसके बजाय, वे रनटाइम पर एक ऑब्फस्केटेड JNI_OnLoad के अंदर JNIEnv->RegisterNatives() के माध्यम से गतिशील रूप से बाइंड होते हैं।.so खोलने पर हज़ारों अनाम sub_XXXX फ़ंक्शन दिखाई देते हैं जहाँ JNIEnv* vtable कॉल्स कच्चे पॉइंटर अंकगणित ((**(code **)(*param_1 + 0x538))(param_1, param_2)) की तरह दिखते हैं।BroadcastReceiver से लेकर libnative-lib.so में ARM64 एन्क्रिप्शन रूटीन तक डेटा फ़्लो का पता नहीं लगा सकता।JNISleuth-MCP कॉन्टेक्स्ट स्विच को समाप्त करता है। यह स्वचालित रूप से स्टैटिक और डायनामिक RegisterNatives बाइंडिंग्स को रिकवर करता है, Ghidra में स्ट्रिप्ड ARM64 फ़ंक्शन्स को पुनः टाइप करता है, और DEX बाइटकोड को नेटिव असेंबली से जोड़ने वाला एक एकल एकीकृत Model Context Protocol (MCP) सर्वर प्रदान करता है।
| क्षमता | मानक Jadx / Ghidra MCPs | JNISleuth-MCP |
|---|---|---|
मानक Java_* एक्सपोर्ट्स को रिज़ॉल्व करें | ✅ | ✅ |
स्ट्रिप्ड RegisterNatives स्ट्रक्ट एरेज़ को स्टैटिक रूप से रिकवर करें (.rodata / .data.rel.ro + JNI_OnLoad CFG) | ❌ | ✅ |
Dobby के माध्यम से डिवाइस पर स्टेल्थ RegisterNatives हार्वेस्टिंग (anti-Frida चेक्स को बायपास करता है) | ❌ | ✅ |
Ghidra में JNIEnv* vtable टाइप्स को स्वतः लागू करें और Call*Method / GetStringUTFChars का पुनर्निर्माण करें | ❌ | ✅ |
सिंगल-कॉल क्रॉस-बाउंड्री डेटाफ़्लो (Java Caller ➔ JNI Bridge ➔ Decompiled ARM64 C++) | ❌ | ✅ |
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
RegisterNatives रिकवरीstripped native लाइब्रेरीज़ वाले APK के विरुद्ध jnisleuth scan चलाएँ:
$ 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
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;
}
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;
}
JNISleuth-MCP 100% मॉडल-अज्ञेयवादी है। आप इसे मानक Model Context Protocol (stdio JSON-RPC 2.0) के माध्यम से किसी भी क्लाउड या स्थानीय LLM से जोड़ सकते हैं या मूल OpenAI / Gemini / Ollama function-calling schemas निर्यात कर सकते हैं:
google-genai के लिए सीधा टूल-स्कीमा निर्यात (jnisleuth llm-tools --format openai|gemini|mcp)।