
Plugin do Binary Ninja que sincroniza a análise bidirecionalmente com um repositório do Ghidra Server, por meio de um subprocesso de ponte Java.
Um plugin do Binary Ninja que se conecta a um repositório do Ghidra Server e importa sua análise — símbolos, nomes de funções e comentários — diretamente para uma binary view aberta no Binary Ninja.
Ghidra e Binary Ninja têm pontos fortes distintos. Este plugin permite usar ambos no mesmo binário sem copiar nomes ou comentários manualmente entre eles. Conecte-se a um Ghidra Server em execução, navegue por seus repositórios e dê um duplo clique em qualquer arquivo de projeto para trazer sua análise para a view do BN atualmente aberta.
A sincronização é bidirecional.
| BN ← Ghidra (importação) | BN → Ghidra (checkin) | |
|---|---|---|
| Símbolos (rótulos, nomes de funções) | ✓ | ✓ |
| Comentários (EOL/PRE/POST/PLATE/REP) | ✓ | ✓ |
| Assinaturas de funções (tipo de retorno, convenção de chamada) | ✓ | ✓ |
| Parâmetros de funções (renomear, retipar, adicionar) | ✓ | ✓ |
| Tipos de dados (struct/union/enum/typedef + ponteiro/array) | ✓ | ✓ |
| Equates (nomes de constantes + referências) | ✓ | ✓ |
| Bookmarks | ✓ | ✓ |
| Itens de dados tipados | ✓ | ✓ |
| Flags de funções (thunk, no-return, inline) | ✓ como tags do BN | — |
| Variáveis locais (cientes de storage) | ✓ | parcial — mapeamento de register-storage não implementado |
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)
O plugin inicia um subprocesso Java (a "bridge") ao carregar. A bridge mantém a conexão RMI com o Ghidra Server e fala um protocolo JSON simples de volta ao plugin através de um socket TCP local. Isso mantém todo o código Java/RMI fora do processo C++ e permite que a JVM inicie em segundo plano enquanto o BN termina de carregar.
A JVM da bridge também inicializa o framework Application do Ghidra na inicialização, para que o caminho de escrita possa usar as APIs de alto nível do modelo de programa do Ghidra (ProgramDB, DataTypeManager, SymbolTable, FunctionManager) em vez de escritas cruas via db.Table.putRecord() — veja Checkin write path abaixo.
| Caminho | Linguagem | Papel |
|---|---|---|
plugin/ | C++ / Qt6 | Plugin de sidebar do Binary Ninja |
bridge/ | Java 17 | Cliente RMI do Ghidra + servidor bridge JSON |
Plugin (C++):
plugin.cpp — registra configurações e o widget da sidebar; inicia a JVM da bridge antecipadamente ao carregarGhidraConnection.cpp — singleton; gerencia o ciclo de vida da bridge e todas as operações baseadas em RMIBridgeProcess.cpp — lança o JAR da bridge como subprocesso com pipes de stdout/stderr; lê a linha de handshake READY port=NBridgeClient.cpp — cliente TCP; envia requisições JSON, recebe respostas, despacha eventos assíncronosSyncEngine.cpp — aplica um GhidraDbExport a uma BinaryView (símbolos, comentários, flags)ui/ProjectPanel.cpp — widget da sidebar: árvore de repositórios, diálogo de conexão, log de atividadesui/ConnectDialog.cpp — diálogo de host/porta/usuário/senhaBridge (Java):
BridgeMain.java — parsing de argumentos; inicializa UniversalIdGenerator e o framework Application do Ghidra; inicia o servidor TCP; imprime READY port=N em stdoutBridgeServer.java — aceita uma conexão de cliente TCP e entrega a ela uma BridgeConnectionBridgeConnection.java — despachante de requisições JSON; serializa respostas da API do Ghidra para JSON; trata opCheckin (cria uma nova versão do programa no servidor)GhidraSession.java — sessão RMI autenticada; encapsula RemoteRepositoryServerHandleEventStreamer.java — thread em segundo plano por repositório aberto; envia RepositoryChangeEvents ao plugin como eventos JSON assíncronosDatabaseExporter.java — caminho de leitura: extrai tabelas de símbolos/comentários/flags de funções/tipos de dados/equates/bookmarks de um ManagedBufferFileHandle (buffer de DB remoto do Ghidra) via acesso cru ao db.jarProgramApplier.java — caminho de escrita: abre o arquivo de buffer como um ProgramDB real e aplica todas as mudanças do lado do BN através das APIs de alto nível do Ghidra (veja Checkin write path abaixo)DatabaseImporter.java — helpers legados de escrita crua mantidos apenas como ponto de teste; o apply(...) de produção delega para ProgramApplieropCheckin abre o arquivo de buffer gerenciado do programa em modo de escrita, constrói um ProgramDB sobre ele e aplica as mudanças do lado do BN através das APIs de modelo de programa do Ghidra. Escritas cruas via db.Table.putRecord() são evitadas — elas foram a fonte de todos os bugs de corrupção de checkin que já encontramos:
| Escrita em camada errada | Modo de falha |
|---|---|
setIntValue(col, longTypeId) na tabela Function Data | IntField.setLongValue trunca silenciosamente com l2i → StackPurge corrompido em toda atualização de assinatura |
setByteValue(col, isUnion) em V5V6 Composite Data Types | a coluna é BooleanField no Ghidra 12.x → IllegalFieldAccessException ("Illegal field access") |
setIntValue(col, 0) na coluna V2 Typedef Flags | a coluna é ShortField → mesmo crash, schema diferente |
| Escrever cabeçalho de composite sem linhas de component-settings | CompositeEditorModel.cloneAllComponentSettings lança ArrayIndexOutOfBoundsException quando a struct é aberta no Ghidra |
Escrever símbolo PARAMETER com SYM_ADDR_COL = endereço RAM | Address is not a VariableAddress lançado por FunctionDB.loadSymbolBasedVariables em qualquer acesso à função |
Passar DBChangeSet null para DBHandle.save() | o servidor grava um arquivo de change-data de 0 bytes → o próximo checkout falha com EOFException em ProgramContentHandler.loadProgramChangeSet |
ProgramApplier não tem essas armadilhas porque roteia através de DataTypeManager.addDataType, SymbolTable.createLabel, Listing.setComment, Function.setReturnType, etc. — APIs que mantêm automaticamente as invariantes das tabelas interligadas do Ghidra. Ele também executa uma passagem cleanupBadVariableSymbols no início de cada checkin para limpar corrupções deixadas no banco de dados por versões mais antigas da bridge.
server-package/CleanupBadVariableSymbols.java é um GhidraScript autônomo que executa a mesma limpeza via analyzeHeadless — útil quando um arquivo está corrompido demais para abrir na GUI do 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)
A suíte está organizada em cinco tiers. Os tiers 2–4 existem para provar uma propriedade: os mesmos dados compatíveis acabam armazenados tanto no .bndb quanto no banco de dados de programa do Ghidra (a matriz de compatibilidade no topo deste README).