
Binary Ninja प्लगइन जो एक Java bridge subprocess के माध्यम से Ghidra Server repository के साथ विश्लेषण को द्विदिशात्मक रूप से सिंक करता है।
एक Binary Ninja प्लगइन जो Ghidra Server रिपॉज़िटरी से कनेक्ट होता है और उसके विश्लेषण — प्रतीकों, फ़ंक्शन नामों, और टिप्पणियों — को सीधे एक खुले Binary Ninja बाइनरी व्यू में आयात करता है।
Ghidra और Binary Ninja दोनों की अपनी-अपनी खूबियाँ हैं। यह प्लगइन आपको एक ही बाइनरी पर दोनों का उपयोग करने देता है, बिना मैन्युअल रूप से नाम या टिप्पणियाँ एक-दूसरे में कॉपी किए। एक चल रहे Ghidra Server से कनेक्ट करें, उसकी रिपॉज़िटरीज़ ब्राउज़ करें, और किसी भी प्रोजेक्ट फ़ाइल पर डबल-क्लिक करके उसका विश्लेषण वर्तमान में खुले BN व्यू में खींच लें।
सिंक दोनों दिशाओं में होता है।
| BN ← Ghidra (आयात) | BN → Ghidra (चेकइन) |
|---|
| प्रतीक (लेबल, फ़ंक्शन नाम) | ✓ | ✓ |
| टिप्पणियाँ (EOL/PRE/POST/PLATE/REP) | ✓ | ✓ |
| फ़ंक्शन सिग्नेचर (रिटर्न टाइप, कॉलिंग कन्वेंशन) | ✓ | ✓ |
| फ़ंक्शन पैरामीटर (नाम बदलें, टाइप बदलें, जोड़ें) | ✓ | ✓ |
| डेटा टाइप (struct/union/enum/typedef + pointer/array) | ✓ | ✓ |
| Equates (कॉन्स्टेंट नाम + संदर्भ) | ✓ | ✓ |
| बुकमार्क | ✓ | ✓ |
| टाइप्ड डेटा आइटम | ✓ | ✓ |
| फ़ंक्शन फ़्लैग (thunk, no-return, inline) | ✓ BN टैग के रूप में | — |
| लोकल वेरिएबल (स्टोरेज-अवेयर) | ✓ | आंशिक — रजिस्टर-स्टोरेज मैपिंग लागू नहीं है |
Binary Ninja (C++ plugin)
│ TCP / newline-delimited JSON
▼
ghidra-bridge-*.jar (Java, runs as a subprocess)
│ Java RMI / SSL
▼
Ghidra Server (ghidraSvr, running on the network)
प्लगइन लोड होने पर एक Java सबप्रोसेस (जिसे "bridge" कहा जाता है) शुरू करता है। ब्रिज Ghidra Server के साथ RMI कनेक्शन बनाए रखता है और एक लोकल TCP सॉकेट पर प्लगइन से सरल JSON प्रोटोकॉल में बात करता है। इससे सारा Java/RMI कोड C++ प्रोसेस से बाहर रहता है और JVM बैकग्राउंड में शुरू हो सकता है जबकि BN लोड होना पूरा करता है।
ब्रिज JVM स्टार्टअप पर Ghidra के Application फ़्रेमवर्क को भी इनिशियलाइज़ करता है ताकि राइट पाथ कच्चे db.Table.putRecord() राइट्स के बजाय Ghidra के हाई-लेवल प्रोग्राम-मॉडल APIs (ProgramDB, DataTypeManager, SymbolTable, FunctionManager) का उपयोग कर सके — नीचे Checkin write path देखें।
| पाथ | भाषा | भूमिका |
|---|---|---|
plugin/ | C++ / Qt6 | Binary Ninja साइडबार प्लगइन |
bridge/ | Java 17 | Ghidra RMI क्लाइंट + JSON ब्रिज सर्वर |
प्लगइन (C++):
plugin.cpp — सेटिंग्स और साइडबार विजेट रजिस्टर करता है; लोड पर ब्रिज JVM को तुरंत शुरू करता हैGhidraConnection.cpp — सिंगलटन; ब्रिज लाइफसाइकल और सभी RMI-आधारित ऑपरेशन्स प्रबंधित करता हैBridgeProcess.cpp — ब्रिज JAR को stdout/stderr पाइप्स के साथ सबप्रोसेस के रूप में लॉन्च करता है; READY port=N हैंडशेक लाइन पढ़ता हैBridgeClient.cpp — TCP क्लाइंट; JSON रिक्वेस्ट भेजता है, रिस्पॉन्स प्राप्त करता है, async इवेंट्स डिस्पैच करता हैSyncEngine.cpp — एक GhidraDbExport को BinaryView पर लागू करता है (प्रतीक, टिप्पणियाँ, फ़्लैग)ui/ProjectPanel.cpp — साइडबार विजेट: रेपो ट्री, कनेक्ट डायलॉग, एक्टिविटी लॉगui/ConnectDialog.cpp — होस्ट/पोर्ट/यूज़र/पासवर्ड डायलॉगब्रिज (Java):
BridgeMain.java — आर्गुमेंट पार्सिंग; UniversalIdGenerator और Ghidra Application फ़्रेमवर्क इनिशियलाइज़ करता है; TCP सर्वर शुरू करता है; stdout पर READY port=N प्रिंट करता हैBridgeServer.java — एक TCP क्लाइंट कनेक्शन स्वीकार करता है और उसे एक BridgeConnection सौंपता हैBridgeConnection.java — JSON रिक्वेस्ट डिस्पैचर; Ghidra API रिस्पॉन्स को JSON में सीरियलाइज़ करता है; opCheckin संभालता है (सर्वर पर एक नया प्रोग्राम वर्ज़न बनाता है)GhidraSession.java — ऑथेंटिकेटेड RMI सेशन; RemoteRepositoryServerHandle को रैप करता हैEventStreamer.java — प्रत्येक खुले रेपो के लिए बैकग्राउंड थ्रेड; RepositoryChangeEvents को async JSON इवेंट्स के रूप में प्लगइन को पुश करता हैDatabaseExporter.java — रीड पाथ: कच्चे db.jar एक्सेस के माध्यम से एक ManagedBufferFileHandle (Ghidra का रिमोट DB बफ़र) से symbol/comment/function-flag/data-type/equate/bookmark टेबल्स निकालता हैProgramApplier.java — राइट पाथ: बफ़र फ़ाइल को एक असली ProgramDB के रूप में खोलता है और Ghidra के हाई-लेवल APIs के माध्यम से सभी BN-साइड परिवर्तन लागू करता है (नीचे Checkin write path देखें)DatabaseImporter.java — लिगेसी रॉ-राइट हेल्पर्स केवल एक टेस्ट सीम के रूप में रखे गए हैं; प्रोडक्शन apply(...) ProgramApplier को डेलिगेट करता हैopCheckin प्रोग्राम की मैनेज्ड बफ़र फ़ाइल को राइट मोड में खोलता है, उसके ऊपर एक ProgramDB बनाता है, और Ghidra के प्रोग्राम-मॉडल APIs के माध्यम से BN-साइड परिवर्तन लागू करता है। कच्चे db.Table.putRecord() राइट्स से बचा जाता है — वे ही हर उस चेकइन-करप्शन बग का स्रोत थे जो हमने कभी देखा:
| गलत-टियर राइट | विफलता मोड |
|---|---|
Function Data टेबल पर setIntValue(col, longTypeId) | IntField.setLongValue चुपचाप l2i-ट्रंकेट करता है → हर सिग्नेचर अपडेट पर StackPurge करप्ट हो जाता है |
V5V6 Composite Data Types पर setByteValue(col, isUnion) | Ghidra 12.x में कॉलम BooleanField है → IllegalFieldAccessException ("Illegal field access") |
V2 Typedef Flags कॉलम पर setIntValue(col, 0) | कॉलम ShortField है → वही क्रैश, अलग स्कीमा |
| component-settings रो के बिना composite हेडर लिखना | Ghidra में struct खोलने पर CompositeEditorModel.cloneAllComponentSettings ArrayIndexOutOfBoundsException थ्रो करता है |
SYM_ADDR_COL = RAM एड्रेस के साथ PARAMETER प्रतीक लिखना | किसी भी फ़ंक्शन एक्सेस पर FunctionDB.loadSymbolBasedVariables द्वारा Address is not a VariableAddress थ्रो होता है |
DBHandle.save() को null DBChangeSet पास करना | सर्वर एक 0-बाइट change-data फ़ाइल लिखता है → अगला चेकआउट ProgramContentHandler.loadProgramChangeSet में EOFException के साथ विफल होता है |
ProgramApplier में ये जाल नहीं हैं क्योंकि यह DataTypeManager.addDataType, SymbolTable.createLabel, Listing.setComment, Function.setReturnType, आदि के माध्यम से रूट करता है — ऐसे APIs जो Ghidra के इंटरलॉकिंग-टेबल इनवेरिएंट्स को स्वचालित रूप से बनाए रखते हैं। यह हर चेकइन की शुरुआत में एक cleanupBadVariableSymbols पास भी चलाता है ताकि पुराने ब्रिज वर्ज़न द्वारा डेटाबेस में छोड़ी गई करप्शन को साफ़ किया जा सके।
server-package/CleanupBadVariableSymbols.java एक स्टैंडअलोन GhidraScript है जो analyzeHeadless के माध्यम से वही क्लीनअप चलाता है — तब उपयोगी होता है जब कोई फ़ाइल Ghidra GUI में खोलने के लिए बहुत करप्ट हो।
./test.sh # macOS / Linux: tiers 0-3 (C++ unit + BN-headless + Java)
test.bat # Windows equivalent
test.bat --parity # cross-DB parity tier only (C++ BN tests + gradlew parityTest)
test.bat --e2e # live Ghidra-server E2E (starts a local ghidraSvr)
सूट पाँच टियर में व्यवस्थित है। टियर 2–4 एक ही गुण सिद्ध करने के लिए हैं: वही संगत डेटा अंततः .bndb और Ghidra प्रोग्राम डेटाबेस दोनों में संग्रहीत होता है (इस README के शीर्ष पर दी गई संगतता मैट्रिक्स)।
| टियर | क्या | कहाँ | गेट |
|---|---|---|---|
| 0 | शुद्ध यूनिट टेस्ट | plugin/test/*.cpp (binja-ghidra-tests), ब्रिज *Test.java | हमेशा |
| 1 | Ghidra-DB राउंड-ट्रिप | ब्रिज *RoundTripTest.java (एक असली ProgramDB के विरुद्ध ProgramApplier) | ghidra.home / GHIDRA_HOME चाहिए |
| 2 | BN BinaryView/.bndb राउंड-ट्रिप | plugin/test/bn/ (binja-ghidra-bn-tests; headless binaryninjacore) | headless-सक्षम BN लाइसेंस के बिना साफ़ तौर पर SKIP होता है (BN_LICENSE env का सम्मान किया जाता है) |
| 3 | क्रॉस-DB पैरिटी | CanonicalParityTest (C++ और Java) testdata/parity/fixtures/ में साझा गोल्डन्स के विरुद्ध | टियर 1+2 के साथ |
| 4 | लाइव-सर्वर E2E | ब्रिज LiveServerE2ETest — एक टेम्प डिर में असली ghidraSvr बूट करता है, analyzeHeadless के माध्यम से सीड करता है, RMI पर checkout → export → checkin → re-export चलाता है | test.bat --e2e (GHIDRA_E2E=1 सेट करता है) |
पैरिटी ओरेकल (टियर 3)। दोनों पक्ष स्वतंत्र रूप से उसी चेक-इन किए गए कैनोनिकल JSON (ब्रिज DatabaseExporter शेप) के विरुद्ध सत्यापित करते हैं। आयात दिशा: गोल्डन एक ProgramDB (Java) में और SyncEngine (C++) के माध्यम से एक BinaryView में लोड होता है, और प्रत्येक re-export गोल्डन के बराबर होना चाहिए। चेकइन दिशा: स्क्रिप्टेड BN एडिट्स को ठीक fixtures/checkin/*/expected-preview.json (C++) उत्पन्न करना चाहिए, और उस प्रीव्यू को ProgramApplier के माध्यम से लागू करने पर expected-after.json (Java) के रूप में re-export होना चाहिए। यदि दोनों पक्ष साझा गोल्डन्स से मेल खाते हैं, तो दोनों डेटाबेस ट्रांज़िटिविटी द्वारा सहमत होते हैं। फ़ील्ड कंपेयर मोड्स और टाइप-नाम नॉर्मलाइज़ेशन टेबल testdata/parity/RULES.md में हैं; टेस्ट बाइनरी testdata/bin/parity_x64.bin है (लेआउट parity_x64.md में)।
Java पक्ष पर लंबे समय से चले आ रहे रिग्रेशन पिन्स:
DataTypesRoundTripTest.struct_cloneSettings_doesNotThrow — composite सेटिंग्स हेडर के साथ संगत रहनी चाहिए (cloneAllComponentSettings क्रैश)FunctionSignaturesRoundTripTest.returnType_doesNotCorruptStackPurge — IntField ट्रंकेशनParametersRoundTripTest.noParameterSymbol_endsUpAtRamAddress — VariableAddress इनवेरिएंटराउंड-ट्रिप और पैरिटी टेस्ट के लिए एक Ghidra इंस्टॉल चाहिए (रनटाइम पर भाषा सेवाओं के लिए उपयोग किया जाता है)। पाथ ghidra.home Gradle सिस्टम प्रॉपर्टी या GHIDRA_HOME env वेरिएबल से पढ़ा जाता है; build.gradle डिफ़ॉल्ट रूप से ghidraHome पास करता है। टियर-2/3 C++ टेस्ट को अतिरिक्त रूप से binaryninjacore लोड करने योग्य चाहिए (स्क्रिप्ट्स BN इंस्टॉल डिर को PATH पर डालती हैं)।
| निर्भरता | नोट्स |
|---|---|
| Binary Ninja (कमर्शियल) | BN इंस्टॉल में api_REVISION.txt से मेल खाने वाले वर्ज़न के विरुद्ध परीक्षित |
| Ghidra Server | Ghidra 12.0.4 के साथ परीक्षित। चल रहा होना चाहिए और RMI/SSL पर पहुँचने योग्य होना चाहिए |
| Java 17+ JDK | Eclipse Adoptium JDK 21 अनुशंसित |
| CMake 3.24+ | |
| Ninja | |
| C++ कंपाइलर | Windows पर MSVC 2022+; macOS पर clang; Linux पर gcc/clang |
| Qt 6.7+ | नीचे Qt setup देखें; बिल्ड समय पर qmake PATH पर होना चाहिए |
| Gradle (रैपर के माध्यम से) | ब्रिज Gradle रैपर का उपयोग करता है — अलग इंस्टॉल की आवश्यकता नहीं |
| Poetry (केवल Qt बिल्ड) | केवल तब आवश्यक जब qt-build सबमॉड्यूल से Qt बनाया जा रहा हो। pip install poetry या pipx install poetry से इंस्टॉल करें। |
| libclang 19 (केवल Qt बिल्ड) | Qt के बिल्ड सिस्टम द्वारा आवश्यक। डाउनलोड निर्देशों के लिए qt-build/README.md देखें। |
प्लगइन उसी Qt 6 बिल्ड के विरुद्ध लिंक करता है जिसका उपयोग Binary Ninja करता है। आपके पास दो विकल्प हैं:
विकल्प A — मौजूदा Qt इंस्टॉल का उपयोग करें (सबसे तेज़ यदि आपके पास पहले से Qt है)
अपने Qt CMake डिरेक्टरी की ओर इशारा करते हुए Qt6_DIR पास करें:
Qt6_DIR=/path/to/Qt/6.x.y/clang_64/lib/cmake/Qt6 ./build.sh
macOS पर बिल्ड स्क्रिप्ट Qt को स्वतः पहचान लेती है यदि इसे Qt ऑनलाइन इंस्टॉलर द्वारा /usr/local/Qt* के अंतर्गत इंस्टॉल किया गया था।
विकल्प B — qt-build सबमॉड्यूल से Qt बनाएँ (~1-2 घंटे, प्रति मशीन एक बार)
qt-build सबमॉड्यूल (Vector35 की Qt बिल्ड स्क्रिप्ट्स) Binary Ninja के पैच के साथ Qt 6 को कंपाइल करता है। इसके लिए Poetry और libclang 19 चाहिए (ऊपर पूर्वापेक्षाएँ और qt-build/README.md देखें)।
Qt रेपो के अंदर qt/<version>/<compiler>/ में इंस्टॉल होता है:
| प्लेटफ़ॉर्म | इंस्टॉल पाथ |
|---|---|
| macOS | qt/6.10.1/clang_64/ |
| Linux x86-64 | qt/6.10.1/gcc_64/ |
| Windows | qt/6.10.1/msvc2022_64/ |
# First time on a new machine:
./build.sh qt # compiles Qt — takes 1-2 hours
# All subsequent builds (Qt cached in qt/, reused automatically):
./build.sh
qt चरण केवल एक बार आवश्यक है। CMake और बिल्ड स्क्रिप्ट्स हर बाद के रन पर qt/ में बने Qt को पहचान लेती हैं और सबमॉड्यूल को पूरी तरह छोड़ देती हैं। qt/ डिरेक्टरी gitignored है।
git clone https://github.com/mutinylaboratories/ghidra_svr_bridge.git
cd ghidra_svr_bridge
git submodule update --init # populates binaryninja-api and qt-build (~seconds)
फिर ऊपर दिए गए Qt setup (विकल्प A या B) का पालन करें, और चलाएँ:
./build.sh install
# Incremental build of both components
./build.sh
# Full clean rebuild + install into BN plugins folder
./build.sh clean install
# Build only the C++ plugin
./build.sh plugin
# Build only the Java bridge
./build.sh bridge
# Build Qt once on a machine without Qt installed
./build.sh qt
एनवायरनमेंट वेरिएबल्स (सभी वैकल्पिक — स्क्रिप्ट उचित डिफ़ॉल्ट सेट करती है):
BN_INSTALL=/Applications/Binary\ Ninja.app/Contents/MacOS
Qt6_DIR=/usr/local/Qt-6.7.2/lib/cmake/Qt6
पहले उपयोग से पहले build.bat के शीर्ष पर दिए गए पाथ्स को अपने एनवायरनमेंट से मेल खाने के लिए संपादित करें:
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-21.0.11.10-hotspot"
set "VSDEVCMD=C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\Tools\VsDevCmd.bat"
set "Qt6_DIR=C:\qt\v6.7.2\lib\cmake\Qt6"
set "BN_INSTALL=C:\Program Files\Vector35\BinaryNinja"
rem Incremental build of both components
build.bat
rem Full clean rebuild + install into BN plugins folder
build.bat clean install
rem Build only the C++ plugin
build.bat plugin
rem Build only the Java bridge
build.bat bridge
rem Build Qt once on a machine without Qt installed
build.bat qt
C++ बिल्ड api_REVISION.txt में दर्ज सटीक कमिट पर binaryninja-api को क्लोन करने के लिए CMake FetchContent का उपयोग करता है, इसलिए प्लगइन ABI हमेशा इंस्टॉल किए गए BN वर्ज़न से मेल खाता है। यदि GHIDRA_HOME सेट नहीं है तो पहले कॉन्फ़िगर पर Ghidra CMake द्वारा स्वतः डाउनलोड हो जाता है।
इंस्टॉल करने के बाद, Binary Ninja की सेटिंग्स में ये सेट करें (Edit → Preferences → Settings, "Ghidra" खोजें):
| सेटिंग | विवरण |
|---|---|
ghidra.javaExe | java.exe का पूरा पाथ |
ghidra.ghidraHome | आपके Ghidra इंस्टॉलेशन का रूट (Ghidra/Framework/… शामिल है) |
ghidra.trustAllCerts | यदि आपका Ghidra Server स्व-हस्ताक्षरित प्रमाणपत्र का उपयोग करता है तो true सेट करें |
ghidra.defaultHost | Connect डायलॉग को पहले से भरता है |
ghidra.defaultPort | डिफ़ॉल्ट: 13100 |
ghidra.defaultUser | Connect डायलॉग को पहले से भरता है |
चरण 5 के लिए पूर्वापेक्षा: प्रोग्राम फ़ाइल Ghidra Server रिपॉज़िटरी में कमिट होनी चाहिए (केवल Ghidra में लोकली खुली हुई नहीं)। Ghidra में: Project विंडो में फ़ाइल पर राइट-क्लिक करें → Version Control → Add to Version Control…।
प्लगइन और ब्रिज न्यूलाइन-डेलिमिटेड JSON का उपयोग करते हुए एक लोकल TCP सॉकेट पर संवाद करते हैं। प्रत्येक रिक्वेस्ट में एक इंटीजर id और एक स्ट्रिंग op होती है; प्रत्येक रिस्पॉन्स id को वापस भेजता है। Async इवेंट्स (सर्वर-साइड रिपॉज़िटरी परिवर्तन) इसके बजाय एक "event" की रखते हैं।
| Op | दिशा | उद्देश्य |
|---|---|---|
ping, status, connect, disconnect | request/response | सेशन लाइफसाइकल |
list_repos, open_repo, close_repo | request/response | रेपो एन्यूमरेशन |
list_items, get_subfolders | request/response | रेपो ब्राउज़िंग |
get_versions, get_checkouts | request/response | वर्ज़न कंट्रोल स्टेट |
checkout, terminate_checkout | request/response | एक्सक्लूसिव राइट लॉक |
open_db | request/response | पूरा Ghidra DB पढ़ें → JSON (भारी) |
checkin | request/response | BN-साइड परिवर्तन लागू करें → नया रेपो वर्ज़न (भारी, ProgramApplier के माध्यम से) |
download_binary, upload_binary | request/response | मूल बाइनरी को अंदर/बाहर ले जाएँ |
delete_item | request/response | रेपो से फ़ाइल हटाएँ |
repo_changed | event (async) | सर्वर-साइड RepositoryChangeEvent पुश |
रिपॉज़िटरी में शुरू से फिर से बनाने के लिए आवश्यक सब कुछ है। प्रति-डेवलपर सेटअप जो git में नहीं है:
git clone https://github.com/mutinylaboratories/ghidra_svr_bridge.git
cd ghidra_svr_bridge
git submodule update --init --recursive
bridge/gradle.properties बनाएँ:
ghidraHome=C:/Users/<you>/ghidra/ghidra_12.0.4_PUBLIC
Qt6_DIR को मौजूदा इंस्टॉल पर पॉइंट करें या एक बार ./build.sh qt (Windows: build.bat qt) चलाएँ।binaryninja-api कमिट फ़ेच करती है:
./build.sh --channel stable # default — latest stable release (from GitHub)
./build.sh --channel dev # latest dev (dev branch head, from GitHub)
./build.sh --bn-api <commit> # explicit commit, no GitHub lookup (escape hatch)
--channel और --bn-api परस्पर अनन्य हैं; दोनों में से कोई न होने पर stable चैनल उपयोग होता है। --channel Vector35/binaryninja-api GitHub को क्वेरी करता है (नवीनतम stable/* रिलीज़, या dev ब्रांच हेड) इसलिए इसे नेटवर्क एक्सेस चाहिए। यदि आपका इंस्टॉल किया गया BN नवीनतम रिलीज़ से पीछे है, तो उस इंस्टॉल के api_REVISION.txt से सटीक SHA के साथ --bn-api पास करें।जब एक नया Claude Code सेशन खोलें, तो सर्वोत्तम ऑनबोर्डिंग संकेत यह README और dev पर वर्तमान स्थिति हैं:
bridge/src/main/java/com/ghidra_svr/bridge/ProgramApplier.javabridge/src/test/java/com/ghidra_svr/bridge/ProgramTestBase.javabridge/src/test/java/com/ghidra_svr/bridge/*RoundTripTest.javagit log --oneline — प्रत्येक सब्जेक्ट लाइन बताती है क्या बदला और क्यों