
आपको Android native library का अनुकरण करने की अनुमति देता है, और एक प्रायोगिक iOS अनुकरण
यह आपको एक Android नेटिव लाइब्रेरी को एमुलेट करने की सुविधा देता है, साथ ही एक प्रायोगिक iOS एमुलेशन भी।
यह ELF/MachO फ़ाइल प्रारूप और ARM असेंबली के बारे में अधिक सीखने के लिए एक शैक्षिक परियोजना है।
इसे अपने जोखिम पर उपयोग करें!
unidbg AI-सहायता प्राप्त डिबगिंग के लिए Model Context Protocol (MCP) का समर्थन करता है। जब डिबगर सक्रिय हो, तो कंसोल में mcp टाइप करें ताकि एक MCP सर्वर शुरू हो सके, जिससे AI टूल्स (जैसे Cursor) कनेक्ट हो सकें।
unidbg MCP के दो ऑपरेटिंग मोड हैं:
मोड 1: ब्रेकपॉइंट डिबग — डिबगर को अटैच करें और अपना कोड चलाएँ। जब कोई ब्रेकपॉइंट हिट होता है, Breaker.debug() एमुलेटर को रोक देता है — MCP सर्वर शुरू करने के लिए कंसोल में mcp टाइप करें और AI को विश्लेषण में सहायता करने दें। सभी डिबगिंग टूल्स उपलब्ध हैं (रजिस्टर, मेमोरी, डिसअसेंबली, स्टेपिंग, ट्रेसिंग, आदि)। फिर से शुरू करने के बाद, यदि कोई अन्य ब्रेकपॉइंट हिट होता है तो डिबगर फिर से रुक जाता है। एक बार ब्रेकपॉइंट हिट किए बिना निष्पादन पूरा हो जाने पर, प्रक्रिया समाप्त हो जाती है और MCP बंद हो जाता है।
Debugger debugger = emulator.attach();
debugger.addBreakPoint(address);
// run your emulation logic — debugger pauses when breakpoint is hit
मोड 2: कस्टम टूल्स (दोहराने योग्य) — McpToolkit का उपयोग करके कस्टम टूल्स पंजीकृत करें और AI को विभिन्न पैरामीटरों के साथ लक्षित फ़ंक्शनों को फिर से चलाने दें। नेटिव लाइब्रेरी एक बार लोड होती है; प्रत्येक निष्पादन के बाद प्रक्रिया सक्रिय रहती है और अगले रन के लिए MCP सक्रिय रहता है।
McpToolkit toolkit = new McpToolkit();
toolkit.addTool(new McpTool() {
@Override public String name() { return "encrypt"; }
@Override public String description() { return "Run encryption"; }
@Override public String[] paramNames() { return new String[]{"input"}; }
@Override public void execute(String[] params) {
String input = params.length > 0 ? params[0] : "default";
// call encryption with input
}
});
toolkit.run(emulator.attach());
जब डिबगर रुकता है, तो कंसोल में mcp (या पोर्ट निर्दिष्ट करने के लिए mcp 9239) टाइप करें। फिर Cursor MCP सेटिंग्स में जोड़ें:
{
"mcpServers": {
"unidbg-mcp-server": {
"url": "http://localhost:9239/sse"
}
}
}
स्थिति और जानकारी
रजिस्टर और डिसअसेंबली
मेमोरी
ब्रेकपॉइंट और निष्पादन
ट्रेसिंग
| Tool | Description |
|---|---|
trace_code | रजिस्टर रीड/राइट मानों (regs_read, prev_write) के साथ इंस्ट्रक्शनों को ट्रेस करें |
trace_read / trace_write | पता सीमा में मेमोरी रीड/राइट को ट्रेस करें |
फ़ंक्शन कॉल
| Tool | Description |
|---|---|
call_function | टाइप किए गए आर्ग्युमेंट्स (hex, string, bytes, null) के साथ पते द्वारा नेटिव फ़ंक्शन कॉल करें। सिंबल रिज़ॉल्यूशन और मेमोरी प्रीव्यू के साथ मान लौटाता है |
call_symbol | मॉड्यूल + सिंबल नाम द्वारा निर्यातित फ़ंक्शन कॉल करें, जैसे libc.so + malloc |
केवल iOS (Family=iOS होने पर उपलब्ध)
McpToolkit का उपयोग करके कस्टम टूल्स पंजीकृत करें, जिनमें से प्रत्येक McpTool इंटरफ़ेस को लागू करता है। यह मैन्युअल if-else डिस्पैच को साफ, स्व-निहित टूल क्लासों से बदल देता है। इस बिंदु तक नेटिव लाइब्रेरी पूरी तरह से लोड हो चुकी होती है (JNI_OnLoad / एंट्री पॉइंट पहले ही निष्पादित हो चुका होता है), इसलिए प्रत्येक टूल के execute() के अंदर का कोड विश्लेषण हेतु लक्षित फ़ंक्शन तर्क होता है। AI किसी कस्टम टूल को ट्रिगर करने से पहले ब्रेकपॉइंट और ट्रेस सेट कर सकता है, फिर प्रक्रिया को पुनः आरंभ किए बिना विभिन्न इनपुटों पर निष्पादन परिणामों का निरीक्षण कर सकता है।
Android उदाहरण — कस्टम MCP टूल्स के साथ Android JNI उदाहरण के लिए Utilities64.java देखें:
DalvikModule dm = vm.loadLibrary(new File("libtmessages.29.so"), true);
dm.callJNI_OnLoad(emulator);
cUtilities = vm.resolveClass("org/telegram/messenger/Utilities");
McpToolkit toolkit = new McpToolkit();
toolkit.addTool(new McpTool() {
@Override public String name() { return "aesCbc"; }
@Override public String description() { return "Run AES-CBC encryption on input data"; }
@Override public String[] paramNames() { return new String[]{"input"}; }
@Override public void execute(String[] params) {
byte[] input = params.length > 0 ? params[0].getBytes() : new byte[16];
aesCbcEncryptionByteArray(input);
}
});
toolkit.addTool(new McpTool() {
@Override public String name() { return "aesCtr"; }
@Override public String description() { return "Run AES-CTR decryption on input data"; }
@Override public String[] paramNames() { return new String[]{"input"}; }
@Override public void execute(String[] params) {
byte[] input = params.length > 0 ? params[0].getBytes() : new byte[16];
aesCtrDecryptionByteArray(input);
}
});
toolkit.addTool(new McpTool() {
@Override public String name() { return "pbkdf2"; }
@Override public String description() { return "Run PBKDF2 key derivation"; }
@Override public String[] paramNames() { return new String[]{"password", "iterations"}; }
@Override public void execute(String[] params) {
String password = params.length > 0 ? params[0] : "123456";
int iterations = params.length > 1 ? Integer.parseInt(params[1]) : 100000;
pbkdf2(password.getBytes(), iterations);
}
});
toolkit.run(emulator.attach());
iOS उदाहरण — कस्टम MCP टूल्स के साथ iOS IPA लोडिंग उदाहरण के लिए IpaLoaderTest.java देखें:
IpaLoader ipaLoader = new IpaLoader64(ipa, new File("target/rootfs/ipa"));
LoadedIpa loader = ipaLoader.load(this);
emulator = loader.getEmulator();
loader.callEntry();
module = loader.getExecutable();
McpToolkit toolkit = new McpToolkit();
toolkit.addTool(new McpTool() {
@Override public String name() { return "dumpClass"; }
@Override public String description() { return "Dump an ObjC class definition by name"; }
@Override public String[] paramNames() { return new String[]{"className"}; }
@Override public void execute(String[] params) {
String className = params.length > 0 ? params[0] : "AppDelegate";
IClassDumper classDumper = ClassDumper.getInstance(emulator);
System.out.println("dumpClass(" + className + "):\n" + classDumper.dumpClass(className));
}
});
toolkit.addTool(new McpTool() {
@Override public String name() { return "readVersion"; }
@Override public String description() { return "Read the TelegramCoreVersionString from the executable"; }
@Override public void execute(String[] params) {
Symbol sym = module.findSymbolByName("_TelegramCoreVersionString");
if (sym != null) {
Pointer pointer = UnidbgPointer.pointer(emulator, sym.getAddress());
if (pointer != null) {
System.out.println("_TelegramCoreVersionString=" + pointer.getString(0));
}
}
}
});
toolkit.run(emulator.attach());
MCP सर्वर शुरू होने के बाद, AI इन टूल्स को MCP के माध्यम से कॉल करके कस्टम पैरामीटरों के साथ एमुलेशन चला सकता है, ब्रेकपॉइंट सेट कर सकता है, निष्पादन को ट्रेस कर सकता है, और परिणामों का निरीक्षण कर सकता है — यह सब प्रक्रिया को पुनः आरंभ किए बिना।
लो-लेवल API: आप पूर्ण नियंत्रण के लिए सीधे
Debugger.addMcpTool()+Debugger.run(DebugRunnable)का भी उपयोग कर सकते हैं।McpToolkitएक उच्च-स्तरीय रैपर है जो if-else डिस्पैच को समाप्त करता है।
एमुलेटेड नेटिव कोड में लीक का पता लगाने के लिए गेस्ट-साइड मेमोरी आवंटन (mmap/munmap/brk) को ट्रैक करें। try-with-resources का उपयोग करें — ट्रैकिंग निर्माण पर शुरू होती है, और लीक रिपोर्ट बंद करने पर स्वतः प्रिंट होती है।
try (MemoryTracker tracker = emulator.traceMemoryLeaks()) {
module.callFunction(emulator, "targetFunction", arg1, arg2);
}
प्रत्येक लीक हुआ ब्लॉक गेस्ट ARM बैकट्रेस (मॉड्यूल+ऑफ़सेट+सिंबल) और होस्ट Java स्टैक ट्रेस शामिल करता है। नमूना आउटपुट:
=== Memory Leak Report ===
Tracking duration: 42ms
Total allocations: 5
Total deallocations: 3
Leaked blocks: 2
Total leaked size: 32768 bytes (32.0 KB)
--- Leak #1 ---
Address: 0x40001000, Size: 16384 (16.0 KB), Perms: rw-
Guest Backtrace:
#0 0x40123456 libexample.so+0x3456 (malloc+0x12)
#1 0x40124000 libexample.so+0x4000 (doSomething+0x48)
Host Stack Trace:
com.github.unidbg.linux.AndroidElfLoader.mmap2(AndroidElfLoader.java:785)
...
आप रिपोर्ट को बंद करने से पहले प्रोग्रामेटिक रूप से भी एक्सेस कर सकते हैं:
try (MemoryTracker tracker = emulator.traceMemoryLeaks()) {
module.callFunction(emulator, "targetFunction", arg1, arg2);
List<AllocationRecord> leaks = tracker.getLeaks();
assert leaks.isEmpty() : "Memory leak detected!";
}
एक थ्रेड-सुरक्षित ऑब्जेक्ट पूल जो कई थ्रेड्स में एमुलेटर इंस्टेंसों को पुनः उपयोग करने के लिए है, बार-बार आरंभीकरण के ओवरहेड से बचता है।
public class MyWorker implements Worker {
private final AndroidEmulator emulator;
public MyWorker() {
emulator = AndroidEmulatorBuilder.for64Bit().build();
// load .so, call JNI_OnLoad, etc.
}
@Override
public void destroy() {
emulator.close();
}
public byte[] doWork(byte[] input) {
// call native methods and return the result
}
}
// Create a worker pool (max = CPU cores, lazy-initialized)
WorkerPool pool = WorkerPoolFactory.create(MyWorker::new);
// Or specify max workers explicitly
// WorkerPool pool = WorkerPoolFactory.create(MyWorker::new, 4);
// Optional: customize idle timeout (default 10 minutes, minimum 1 minute)
pool.setIdleTimeout(30); // idle workers destroyed after 30 minutes
// Optional: customize minimum kept-alive workers (default 1, minimum 1)
pool.setMinIdle(2); // always keep at least 2 workers alive
// Optional: pre-create workers eagerly (default 0, fully lazy)
pool.setInitialSize(4); // eagerly create 4 workers on startup
// Concurrent invocation from multiple threads
ExecutorService executor = Executors.newFixedThreadPool(100);
for (int i = 0; i < 100; i++) {
executor.submit(() -> {
try (WorkerLoan<MyWorker> loan = pool.borrow(1, TimeUnit.MINUTES)) {
if (loan != null) {
byte[] result = loan.get().doWork(input);
}
} // worker is automatically returned to the pool
});
}
executor.shutdown();
executor.awaitTermination(10, TimeUnit.MINUTES);
pool.close(); // destroy all workers and release resources
एक संपूर्ण उदाहरण के लिए TTEncryptWorker.java देखें।
src/test निर्देशिका के अंतर्गत सरल परीक्षण:

अधिक परीक्षण:
| Tool | Description |
|---|
check_connection | एमुलेटर स्थिति: Family, architecture, backend क्षमताएँ, isRunning, लोड किए गए मॉड्यूल |
list_modules / get_module_info | लोड किए गए मॉड्यूलों की सूची बनाएँ, निर्यातित सिंबल गणना और निर्भरताओं सहित विवरण प्राप्त करें |
list_exports | वैकल्पिक फ़िल्टर और C++ डिमैंगलिंग के साथ एक मॉड्यूल के निर्यातित/डायनामिक सिंबलों की सूची बनाएँ |
find_symbol | नाम से सिंबल खोजें या पते पर निकटतम सिंबल खोजें |
get_threads | एमुलेटर में सभी थ्रेड/कार्यों की सूची बनाएँ |
| Tool | Description |
|---|
get_registers / get_register / set_register | CPU रजिस्टर पढ़ें/लिखें |
disassemble | पते पर मौजूद इंस्ट्रक्शनों को डिसअसेंबल करें (ब्रांच टारगेट सिंबल नामों के साथ स्वतः एनोटेट होते हैं) |
assemble | इंस्ट्रक्शन टेक्स्ट को मशीन कोड में असेंबल करें |
get_callstack | वर्तमान कॉल स्टैक (बैकट्रेस) प्राप्त करें |
| Tool | Description |
|---|
read_memory / write_memory | कच्चे मेमोरी बाइट्स पढ़ें/लिखें |
read_string / read_std_string | C स्ट्रिंग या C++ std::string पढ़ें (SSO पहचान के साथ) |
read_pointer | सिंबल रिज़ॉल्यूशन के साथ पॉइंटर श्रृंखला पढ़ें |
read_typed | मेमोरी को टाइप किए गए मानों के रूप में पढ़ें (int8–int64, float, double, pointer) |
search_memory | स्कोप/अनुमति फ़िल्टर के साथ मेमोरी में बाइट पैटर्न खोजें |
list_memory_map | अनुमतियों के साथ सभी मेमोरी मैपिंग की सूची बनाएँ |
allocate_memory / free_memory / list_allocations | वैकल्पिक प्रारंभिक डेटा के साथ आवंटित करें (malloc/mmap), मुक्त करें, और मेमोरी ब्लॉकों को ट्रैक करें |
patch | असेंबल किए गए इंस्ट्रक्शनों को मेमोरी में लिखें |
| Tool | Description |
|---|
add_breakpoint / add_breakpoint_by_symbol / add_breakpoint_by_offset | पते, सिंबल, या मॉड्यूल+ऑफ़सेट द्वारा ब्रेकपॉइंट जोड़ें |
remove_breakpoint / list_breakpoints | ब्रेकपॉइंट हटाएँ या सूचीबद्ध करें (डिसअसेंबली के साथ) |
continue_execution | निष्पादन फिर से शुरू करें। breakpoint_hit या execution_completed के लिए प्रतीक्षा हेतु poll_events का उपयोग करें |
step_over / step_into / step_out | फ़ंक्शन के ऊपर से, अंदर (N इंस्ट्रक्शन), या बाहर स्टेप करें |
next_block | अगले बेसिक ब्लॉक पर रुकें (केवल Unicorn) |
step_until_mnemonic | मेमोनिक से मेल खाने वाले अगले इंस्ट्रक्शन पर रुकें, जैसे bl, ret (केवल Unicorn) |
poll_events | breakpoint_hit, execution_completed, trace इवेंट्स के लिए पोल करें |
| Tool | Description |
|---|
inspect_objc_msg | objc_msgSend कॉल का निरीक्षण करें: रिसीवर क्लास का नाम और सेलेक्टर दिखाएँ, जैसे -[NSString length] |
get_objc_class_name | दिए गए पते पर ऑब्जेक्ट का ObjC क्लास नाम प्राप्त करें (शुद्ध मेमोरी पार्सिंग, कोई स्टेट परिवर्तन नहीं) |
dump_objc_class | ObjC क्लास परिभाषा डंप करें (properties, methods, protocols, ivars) |
dump_gpb_protobuf | GPB protobuf मैसेज स्कीमा को .proto प्रारूप में डंप करें (केवल 64-बिट) |