
Plugin Binary Ninja qui synchronise l'analyse de manière bidirectionnelle avec un dépôt Ghidra Server, via un sous-processus de pont Java.
Un plugin Binary Ninja qui se connecte à un dépôt Ghidra Server et importe son analyse — symboles, noms de fonctions et commentaires — directement dans une vue binaire Binary Ninja ouverte.
Ghidra et Binary Ninja ont chacun leurs forces. Ce plugin vous permet d'utiliser les deux sur le même binaire sans copier manuellement les noms ou les commentaires entre eux. Connectez-vous à un Ghidra Server en cours d'exécution, parcourez ses dépôts, et double-cliquez sur n'importe quel fichier de projet pour extraire son analyse dans la vue BN actuellement ouverte.
La synchronisation se fait dans les deux sens.
| BN ← Ghidra (import) | BN → Ghidra (checkin) | |
|---|---|---|
| Symboles (labels, noms de fonctions) | ✓ | ✓ |
| Commentaires (EOL/PRE/POST/PLATE/REP) | ✓ | ✓ |
| Signatures de fonctions (type de retour, convention d'appel) | ✓ | ✓ |
| Paramètres de fonctions (renommer, retyper, ajouter) | ✓ | ✓ |
| Types de données (struct/union/enum/typedef + pointeur/tableau) | ✓ | ✓ |
| Équates (noms de constantes + références) | ✓ | ✓ |
| Signets | ✓ | ✓ |
| Éléments de données typés | ✓ | ✓ |
| Indicateurs de fonctions (thunk, no-return, inline) | ✓ en tant que tags BN | — |
| Variables locales (sensibles au stockage) | ✓ | partiel — le mapping du stockage par registre n'est pas implémenté |
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)
Le plugin lance un sous-processus Java (le « bridge ») au chargement. Le bridge maintient la connexion RMI vers le Ghidra Server et parle un protocole JSON simple au plugin via un socket TCP local. Cela garde tout le code Java/RMI hors du processus C++ et permet à la JVM de démarrer en arrière-plan pendant que BN termine son chargement.
La JVM du bridge initialise également le framework Application de Ghidra au démarrage, afin que le chemin d'écriture puisse utiliser les API de haut niveau du modèle de programme de Ghidra (ProgramDB, DataTypeManager, SymbolTable, FunctionManager) plutôt que des écritures brutes db.Table.putRecord() — voir Checkin write path ci-dessous.
| Chemin | Langage | Rôle |
|---|---|---|
plugin/ | C++ / Qt6 | Plugin de barre latérale Binary Ninja |
bridge/ | Java 17 | Client RMI Ghidra + serveur bridge JSON |
Plugin (C++) :
plugin.cpp — enregistre les paramètres et le widget de barre latérale ; démarre la JVM du bridge au chargementGhidraConnection.cpp — singleton ; gère le cycle de vie du bridge et toutes les opérations basées sur RMIBridgeProcess.cpp — lance le JAR du bridge comme sous-processus avec des pipes stdout/stderr ; lit la ligne de handshake READY port=NBridgeClient.cpp — client TCP ; envoie des requêtes JSON, reçoit des réponses, distribue les événements asynchronesSyncEngine.cpp — applique un GhidraDbExport à un BinaryView (symboles, commentaires, indicateurs)ui/ProjectPanel.cpp — widget de barre latérale : arborescence des dépôts, boîte de dialogue de connexion, journal d'activitéui/ConnectDialog.cpp — boîte de dialogue hôte/port/utilisateur/mot de passeBridge (Java) :
BridgeMain.java — analyse des arguments ; initialise UniversalIdGenerator et le framework Application de Ghidra ; démarre le serveur TCP ; affiche READY port=N sur stdoutBridgeServer.java — accepte une connexion client TCP et lui attribue une BridgeConnectionBridgeConnection.java — répartiteur de requêtes JSON ; sérialise les réponses de l'API Ghidra en JSON ; gère opCheckin (crée une nouvelle version du programme sur le serveur)GhidraSession.java — session RMI authentifiée ; encapsule RemoteRepositoryServerHandleEventStreamer.java — thread d'arrière-plan par dépôt ouvert ; pousse les RepositoryChangeEvent vers le plugin sous forme d'événements JSON asynchronesDatabaseExporter.java — chemin de lecture : extrait les tables symboles/commentaires/indicateurs de fonctions/types de données/équates/signets d'un ManagedBufferFileHandle (le buffer de base de données distant de Ghidra) via un accès brut à db.jarProgramApplier.java — chemin d'écriture : ouvre le fichier buffer comme un véritable ProgramDB et applique tous les changements côté BN via les API de haut niveau de Ghidra (voir Checkin write path ci-dessous)DatabaseImporter.java — helpers d'écriture brute hérités conservés uniquement comme point de test ; la méthode apply(...) de production délègue à ProgramApplieropCheckin ouvre le fichier buffer managé du programme en mode écriture, construit un ProgramDB par-dessus, et applique les changements côté BN via les API du modèle de programme de Ghidra. Les écritures brutes db.Table.putRecord() sont évitées — elles étaient la source de tous les bugs de corruption de checkin que nous avons rencontrés :
| Écriture au mauvais niveau | Mode de défaillance |
|---|---|
setIntValue(col, longTypeId) sur la table Function Data | IntField.setLongValue tronque silencieusement via l2i → StackPurge corrompu à chaque mise à jour de signature |
setByteValue(col, isUnion) sur V5V6 Composite Data Types | la colonne est un BooleanField dans Ghidra 12.x → IllegalFieldAccessException (« Illegal field access ») |
setIntValue(col, 0) sur la colonne V2 Typedef Flags | la colonne est un ShortField → même crash, schéma différent |
| Écriture d'un en-tête composite sans lignes de paramètres de composants | CompositeEditorModel.cloneAllComponentSettings lève une ArrayIndexOutOfBoundsException quand la struct est ouverte dans Ghidra |
Écriture d'un symbole PARAMETER avec SYM_ADDR_COL = adresse RAM | Address is not a VariableAddress levée par FunctionDB.loadSymbolBasedVariables à tout accès à la fonction |
Passage d'un DBChangeSet null à DBHandle.save() | le serveur écrit un fichier de données de changement de 0 octet → le prochain checkout échoue avec EOFException dans ProgramContentHandler.loadProgramChangeSet |
ProgramApplier n'a pas ces pièges car il passe par DataTypeManager.addDataType, SymbolTable.createLabel, Listing.setComment, Function.setReturnType, etc. — des API qui maintiennent automatiquement les invariants des tables imbriquées de Ghidra. Il exécute également une passe cleanupBadVariableSymbols au début de chaque checkin pour purger la corruption laissée dans la base de données par les anciennes versions du bridge.
server-package/CleanupBadVariableSymbols.java est un GhidraScript autonome qui exécute le même nettoyage via analyzeHeadless — utile quand un fichier est trop corrompu pour être ouvert dans l'interface graphique de Ghidra.
./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)
La suite est organisée en cinq niveaux. Les niveaux 2 à 4 existent pour prouver une propriété : les mêmes données compatibles finissent stockées à la fois dans le .bndb et dans la base de données de programme Ghidra (la matrice de compatibilité en haut de ce README).