feat(engine): add engine discovery and availability check

This commit is contained in:
Rodrigo Verdiani 2026-06-09 20:23:18 -03:00
parent f2ba9b2019
commit e01948b9e4
9 changed files with 145 additions and 42 deletions

View File

@ -1,4 +1,4 @@
# Pontos de Extração — IDA 5, IDA 7 e Ghidra
# Pontos de Extração — IDA 5, IDA 6.6, IDA 7 e Ghidra
Documento de referência sobre quais dados de análise estática são extraíveis via script de cada engine, com a utilidade de cada ponto e grau de dificuldade.
@ -6,30 +6,30 @@ Documento de referência sobre quais dados de análise estática são extraívei
## Tabela Resumo
| # | Dado | Utilidade | IDA 5 (IDC) | IDA 7+ (IDAPython) | Ghidra (Java/Python) |
|---|------|-----------|:-----------:|:------------------:|:--------------------:|
| 1 | Funções (nome, endereço, assembly) | Navegação básica do binário | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 2 | Code references / Labels | Resolver alvos de jump/call | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 3 | Xrefs de entrada (callers) | Grafo de chamadas reverso | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 4 | Entry point | Saber onde o binário inicia | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 5 | Tipo de xref (CALL vs JUMP vs DATA) | Diferencia saltos de chamadas | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 6 | Flags da função (library, thunk, far) | Classificar tipo de função | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 7 | Segmentos (.text, .data, .rdata) | Mapa de memória do binário | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 8 | Tamanho/fim da função | Delimitar escopo da função | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 9 | Strings referenciadas | Entender mensagens, nomes, paths | ✅ Médio | ✅ Fácil | ✅ Fácil |
| 10 | Imports / APIs externas (DLLs) | Saber quais libs externas são usadas | ✅ Médio | ✅ Fácil | ✅ Fácil |
| 11 | Frame da função (vars locais, args) | Estrutura da stack frame | ✅ Médio | ✅ Fácil | ✅ Fácil |
| 12 | Comentários do IDA/Ghidra | Anotações automáticas do disassembler | ✅ Médio | ✅ Fácil | ✅ Fácil |
| 13 | Data xrefs (leitura/escrita em globais) | Quem acessa cada variável global | ⚠️ Limitado | ✅ Médio | ✅ Médio |
| 14 | Tipos e assinaturas de funções | Parâmetros, retorno, calling convention | ❌ Não viável | ✅ Médio | ✅ Fácil |
| 15 | Estruturas e enums | Layout de structs usadas pelo binário | ❌ Não viável | ⚠️ Limitado | ✅ Médio |
| 16 | Decompilação (pseudocódigo) | Código de alto nível reconstruído | ❌ Não existe | ✅ Fácil | ✅ Fácil |
| 17 | Call graph / Fluxo de controle (CFG) | Visualização de blocos e branches | ⚠️ Limitado | ✅ Médio | ✅ Médio |
| 18 | Nomes de variáveis globais | Labels simbólicos de dados | ✅ Médio | ✅ Fácil | ✅ Fácil |
| # | Dado | Utilidade | IDA 5 (IDC) | IDA 6.6 (IDAPython) | IDA 7+ (IDAPython) | Ghidra (Java/Python) |
|---|------|-----------|:-----------:|:--------------------:|:------------------:|:--------------------:|
| 1 | Funções (nome, endereço, assembly) | Navegação básica do binário | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 2 | Code references / Labels | Resolver alvos de jump/call | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 3 | Xrefs de entrada (callers) | Grafo de chamadas reverso | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 4 | Entry point | Saber onde o binário inicia | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 5 | Tipo de xref (CALL vs JUMP vs DATA) | Diferencia saltos de chamadas | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 6 | Flags da função (library, thunk, far) | Classificar tipo de função | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 7 | Segmentos (.text, .data, .rdata) | Mapa de memória do binário | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 8 | Tamanho/fim da função | Delimitar escopo da função | ✅ **Implementado** | ✅ **Implementado** | ✅ Fácil | ✅ Fácil |
| 9 | Strings referenciadas | Entender mensagens, nomes, paths | ✅ Médio | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 10 | Imports / APIs externas (DLLs) | Saber quais libs externas são usadas | ✅ Médio | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 11 | Frame da função (vars locais, args) | Estrutura da stack frame | ✅ Médio | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 12 | Comentários do IDA/Ghidra | Anotações automáticas do disassembler | ✅ Médio | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 13 | Data xrefs (leitura/escrita em globais) | Quem acessa cada variável global | ⚠️ Limitado | ✅ Médio | ✅ Médio | ✅ Médio |
| 14 | Tipos e assinaturas de funções | Parâmetros, retorno, calling convention | ❌ Não viável | ✅ Médio | ✅ Médio | ✅ Fácil |
| 15 | Estruturas e enums | Layout de structs usadas pelo binário | ❌ Não viável | ⚠️ Limitado | ⚠️ Limitado | ✅ Médio |
| 16 | Decompilação (pseudocódigo) | Código de alto nível reconstruído | ❌ Não existe | ✅ Fácil | ✅ Fácil | ✅ Fácil |
| 17 | Call graph / Fluxo de controle (CFG) | Visualização de blocos e branches | ⚠️ Limitado | ✅ Médio | ✅ Médio | ✅ Médio |
| 18 | Nomes de variáveis globais | Labels simbólicos de dados | ✅ Médio | ✅ Fácil | ✅ Fácil | ✅ Fácil |
---
## 1. Funções (nome, endereço, assembly)
## 1. Funções (nome, endereço, assembly) ✅ Implementado
**O que é:** Lista de todas as funções reconhecidas pelo disassembler, com nome, endereço de início e o texto do assembly.
@ -38,12 +38,13 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `NextFunction()`, `GetFunctionName()`, `GetDisasm()`, `ItemSize()` | ✅ **Já implementado** |
| IDA 6.6 | `idc.NextFunction(ea)`, `idc.GetFunctionName(ea)`, `idc.GetDisasm(ea)`, `idc.ItemSize(ea)` | ✅ **Já implementado** |
| IDA 7 | `ida_funcs.get_funcs()`, `ida_lines.generate_disasm_line()` | ✅ Trivial |
| Ghidra | `currentProgram.getFunctionManager().getFunctions()`, `listing.getInstructions()` | ✅ Trivial |
---
## 2. Code References / Labels
## 2. Code References / Labels ✅ Implementado
**O que é:** Para cada instrução de jump/call, o endereço de destino e o nome (label) associado a ele.
@ -52,12 +53,13 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `Rfirst(ea)`, `Rnext(ea, ref)`, `Name(ref)` | ✅ **Já implementado** |
| IDA 6.6 | `idautils.XrefsFrom(curr_inst)` iterando instruções da função, `idc.Name(xref.to)` | ✅ **Já implementado** |
| IDA 7 | `ida_xref.xrefblk_t()` com `iscode=True` | ✅ Trivial |
| Ghidra | `instruction.getReferencesFrom()`, `ref.getToAddress()` | ✅ Trivial |
---
## 3. Xrefs de entrada (callers)
## 3. Xrefs de entrada (callers) ✅ Implementado
**O que é:** Lista de funções que chamam/referenciam a função atual.
@ -66,76 +68,92 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `RfirstB(ea)`, `RnextB(ea, xref)` | ✅ **Já implementado** |
| IDA 6.6 | `idautils.XrefsTo(ea)` com filtro por tipo (`FL_CF`, `FL_CN`, `FL_JF`, `FL_JN`) | ✅ **Já implementado** |
| IDA 7 | `ida_xref.xrefs_to(ea)` | ✅ Trivial |
| Ghidra | `function.getCallingFunctions(TaskMonitor.DUMMY)` ou via reference manager | ✅ Trivial |
---
## 4. Entry Point
## 4. Entry Point ✅ Implementado
**O que é:** O endereço onde a execução do binário começa. Pode ser o stub da CRT (`start`) ou diretamente `main`/`WinMain`.
**Para que serve:** Ponto de partida da análise. O analista sabe por onde começar a ler o código. Em modo headless do frontend, pode ser usado como âncora inicial.
**Implementação:** `BeginEA()` + `Name()` no `extract.idc` (IDA 5) / `idc.MinEA()` + `idc.Name()` no `extract.py` (IDA 6.6) → campo `entryPoint` no `AnalysisResult` → coluna `entry_point` em `static_analysis` → exposto via `AnalysisResponse` e injetado no system prompt do chat (`[ENTRY POINT]`).
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `BeginEA()` retorna o entry point; `Name()` dá o label | ✅ Trivial (testado, funciona) |
| IDA 5 | `BeginEA()` retorna o entry point; `Name()` dá o label | ✅ **Implementado** |
| IDA 6.6 | `idc.MinEA()` retorna o menor endereço do binário (entry point); `idc.Name(ea)` dá o label | ✅ **Implementado** |
| IDA 7 | `ida_loader.get_entry_point()` ou `ida_entry.get_entry_ordinals()` | ✅ Trivial |
| Ghidra | `program.getListing().getInstructionAt(program.getImageBase().add(entryOffset))`; entry offset via `program.getExecutableFormat()` ou metadados do importador | ✅ Trivial |
---
## 5. Tipo de Xref (CALL vs JUMP vs DATA)
## 5. Tipo de Xref (CALL vs JUMP vs DATA) ✅ Implementado
**O que é:** Classifica cada code reference como `CALL` (chamada de função), `JUMP` (salto condicional/incondicional) ou referência a dados.
**Para que serve:** Permite que o frontend diferencie visualmente chamadas de função de saltos locais. Essencial para coloração de syntax e navegação contextual.
**Implementação:** `XrefType()` em `extract.idc` (IDA 5) / `idautils.XrefsTo(ea)` com constantes `FL_CF`/`FL_CN`/`FL_JF`/`FL_JN` em `extract.py` (IDA 6.6) nos xrefs (`name:CALL`) e labels (`name:0xADDR:CALL`) → `XrefEntry(name, type)` + `LabelEntry.type``StaticXref.type` + `StaticLabel.type` → exposto via `XrefResponse.type` e `LabelResponse.type``ChatContextBuilder` exibe `name [CALL]`.
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `XrefType()` retorna `fl_CF` (far call), `fl_CN` (near call), `fl_JF` (far jump), `fl_JN` (near jump) | ✅ Fácil (1 enum switch) |
| IDA 5 | `XrefType()` retorna `fl_CF` (far call), `fl_CN` (near call), `fl_JF` (far jump), `fl_JN` (near jump) | ✅ **Implementado** |
| IDA 6.6 | `idautils.XrefsTo(ea)` / `idautils.XrefsFrom(curr_inst)`, cada xref tem `.type` com constantes `FL_CF`, `FL_CN`, `FL_JF`, `FL_JN` | ✅ **Implementado** |
| IDA 7 | `ida_xref.xrefblk_t().type` retorna `fl_CF/fl_CN/fl_JF/fl_JN` | ✅ Fácil |
| Ghidra | `ref.getReferenceType()` retorna `CALL`, `JUMP`, `DATA`, etc. | ✅ Fácil |
---
## 6. Flags da Função
## 6. Flags da Função ✅ Implementado
**O que é:** Atributos da função como: é library function? é thunk? usa far calling convention? tem frame pointer?
**Para que serve:** Classificação automática de funções. Ex: marcar funções importadas de DLL como "library", diferenciar funções far/near em binários 16-bit, etc.
**Implementação:** `GetFunctionFlags(ea)` em `extract.idc` (IDA 5) / `idc.GetFunctionFlags(ea)` em `extract.py` (IDA 6.6) testando bits `FUNC_LIB`, `FUNC_THUNK`, `FUNC_FAR`, `FUNC_FRAME` → campo `flags` em `FunctionResult` → coluna `flags` em `static_function` → exposto via `FunctionDetailResponse.flags` → incluído no chunk de embedding (`Flags: ...`) e no context builder do chat.
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `GetFunctionFlags(ea)` retorna bits: `FUNC_LIB`, `FUNC_THUNK`, `FUNC_FAR`, `FUNC_FRAME`, etc. | ✅ Fácil (bitmask) |
| IDA 5 | `GetFunctionFlags(ea)` retorna bits: `FUNC_LIB`, `FUNC_THUNK`, `FUNC_FAR`, `FUNC_FRAME`, etc. | ✅ **Implementado** |
| IDA 6.6 | `idc.GetFunctionFlags(ea)` — mesma API, acessível via `idc.FUNC_LIB`, `idc.FUNC_THUNK`, `idc.FUNC_FAR`, `idc.FUNC_FRAME` | ✅ **Implementado** |
| IDA 7 | `ida_funcs.get_func(ea).flags` | ✅ Fácil |
| Ghidra | `function.isThunk()`, `function.isLibrary()`, `function.getCallingConvention()` | ✅ Fácil |
---
## 7. Segmentos (.text, .data, .rdata, etc.)
## 7. Segmentos (.text, .data, .rdata, etc.) ✅ Implementado
**O que é:** Mapa de memória do binário — cada segmento com nome, endereço inicial, endereço final e classe (CODE, DATA, BSS, etc.).
**Para que serve:** Contexto para o frontend mostrar em qual região de memória cada função/string está. Permite filtrar funções por segmento (ex: "só .text").
**Implementação:** Loop `FirstSeg()`/`NextSeg()` no `extract.idc` (IDA 5) / `idc.FirstSeg()`/`idc.NextSeg()` no `extract.py` (IDA 6.6) → `SegmentEntry(name, startAddress, endAddress)` → tabela `static_segment` com FK para `static_analysis` → exposto via `GET /analysis/{id}/segments` → incluído no chunk `METADATA` do embedding.
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `SegByName()`, `SegStart()`, `SegEnd()`, `SegName()`, iteração com `FirstSeg()`/`NextSeg()` | ✅ Fácil (loop de segmentos) |
| IDA 5 | `SegByName()`, `SegStart()`, `SegEnd()`, `SegName()`, iteração com `FirstSeg()`/`NextSeg()` | ✅ **Implementado** |
| IDA 6.6 | `idc.FirstSeg()`, `idc.NextSeg(seg)`, `idc.SegName(seg)`, `idc.SegStart(seg)`, `idc.SegEnd(seg)` — mesma API, namespace `idc` | ✅ **Implementado** |
| IDA 7 | `ida_segment.get_segm_list()`, `ida_segment.get_segm_by_name()` | ✅ Fácil |
| Ghidra | `program.getMemory().getBlocks()` | ✅ Fácil |
---
## 8. Tamanho / Fim da Função
## 8. Tamanho / Fim da Função ✅ Implementado
**O que é:** Endereço final da função (`FindFuncEnd`), permitindo calcular tamanho em bytes e delimitar o escopo.
**Para que serve:** Já usado internamente no extract.idc. Expor no JSON permite ao frontend mostrar "tamanho: 245 bytes" ou destacar o range da função no mapa de memória.
**Implementação:** `FindFuncEnd(ea) - ea` no `extract.idc` (IDA 5) / `idc.FindFuncEnd(ea) - ea` no `extract.py` (IDA 6.6) → campo `int size` no `FunctionResult` → coluna `function_size` em `static_function` → exposto via `FunctionDetailResponse.size` → incluído nos chunks (`[FUNCTION] name at 0xADDR (67 bytes)`) e no context builder do chat.
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `FindFuncEnd(ea)` | ✅ **Já usado internamente** |
| IDA 5 | `FindFuncEnd(ea)` | ✅ **Implementado** |
| IDA 6.6 | `idc.FindFuncEnd(ea)` — mesma API, namespace `idc` | ✅ **Implementado** |
| IDA 7 | `ida_funcs.get_func(ea).end_ea` | ✅ Trivial |
| Ghidra | `function.getBody().getMaxAddress()` | ✅ Trivial |
@ -150,6 +168,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | Iterar sobre segmentos de dados com `isLoaded(ea)` e `GetString(ea, -1, ASCSTR_C)`. Também é possível buscar "string literals" no segmento `.data`/`.rdata` com `GetStringType()`. | ✅ Médio (iteração manual sobre bytes) |
| IDA 6.6 | `idautils.Strings()` retorna lista de objetos string com conteúdo, endereço e tipo. `idc.GetStringType(ea)` para classificação ASCSTR_C/UNICODE. | ✅ Fácil |
| IDA 7 | `ida_bytes.get_strlit_contents()`, `ida_strlist.string_info_t()` — API nativa de strings | ✅ Fácil |
| Ghidra | `program.getListing().getDefinedData(true)` filtrado por `StringDataInstance` | ✅ Fácil |
@ -164,6 +183,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | Iterar segmentos externos (`SegByName(".idata")`) e usar `Name(ea)` nos endereços da IAT. Alternativa: parse da tabela de imports manualmente. | ✅ Médio (requer lógica de parse) |
| IDA 6.6 | `ida_nalt.get_import_module_name(ea)` e iteração sobre a IAT com `idautils.XrefsTo(ea)` filtrado por segmento externo. `idaapi.enum_import_names()` disponível. | ✅ Fácil |
| IDA 7 | `ida_nalt.get_import_module_name()`, `idaapi.enum_import_names()` | ✅ Fácil |
| Ghidra | `program.getExternalManager().getExternalLibraryNames()`, `getExternalLibraryFunctions()` | ✅ Fácil |
@ -178,6 +198,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `GetFrame(ea)` retorna o id da estrutura, `GetStrucSize(id)`, iterar membros com `GetStrucMember()`/`GetMemberName()` | ✅ Médio (API de estruturas frágil no IDA 5) |
| IDA 6.6 | `ida_frame.get_frame(ea)` disponível via IDAPython; `ida_struct.get_struc_members(id)` para iterar vars locais e argumentos | ✅ Fácil |
| IDA 7 | `ida_frame.get_frame(ea)`, `ida_struct.get_struc_members()` | ✅ Fácil |
| Ghidra | `function.getStackFrame()`, `stackFrame.getStackVariables()` | ✅ Fácil |
@ -192,6 +213,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `GetCommentEx(ea, 0)` para comentários regulares, `GetRptCmt(ea)` para comentários repetíveis | ✅ Médio (precisa testar quais flags funcionam) |
| IDA 6.6 | `idc.GetCommentEx(ea, 0)` e `idc.GetCommentEx(ea, 1)` (repetível) — mesma API, namespace `idc` | ✅ Fácil |
| IDA 7 | `ida_bytes.get_cmt(ea, False)`, `ida_bytes.get_cmt(ea, True)` | ✅ Fácil |
| Ghidra | `listing.getComment(CodeUnit.EOL_COMMENT, address)` e `PRE_COMMENT`, `POST_COMMENT` | ✅ Fácil |
@ -206,6 +228,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `Dfirst(ea)` e `Dnext(ea, ref)` retornam data xrefs. API existe mas suporte pode ser limitado. | ⚠️ Limitado (testar viabilidade) |
| IDA 6.6 | `idautils.XrefsTo(ea)` filtrando por `xref.type` não-code (`dr_O`, `dr_W`, `dr_R`). API mais madura que IDC 5. | ✅ Médio |
| IDA 7 | `ida_xref.xrefs_to(ea)` com filtro `data`, ou `ida_xref.xrefblk_t()` | ✅ Médio |
| Ghidra | `referenceManager.getReferencesTo(address)` e filtrar por tipo `DATA` | ✅ Médio |
@ -220,6 +243,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | Suporte a tipos muito limitado. `GetType()` pode retornar string, mas raramente populado. | ❌ **Não viável** |
| IDA 6.6 | `ida_typeinf.get_tinfo(ea)` e `ida_typeinf.print_tinfo(tif, ...)` disponíveis via IDAPython. Suporte a tipos é mais maduro que IDA 5. | ✅ Médio |
| IDA 7 | `ida_typeinf.get_tinfo(ea)`, `ida_typeinf.print_tinfo()` | ✅ Médio |
| Ghidra | `function.getReturnType()`, `function.getParameters()`, `function.getSignature()` | ✅ Fácil |
@ -234,6 +258,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `GetStrucId()`, `GetStrucName()` — API existe mas tipos raramente aplicados pelo IDA 5 | ❌ **Não viável** |
| IDA 6.6 | `ida_struct.get_struc_list()` e `ida_typeinf` disponíveis. Depende da qualidade da análise de tipos do IDA. | ⚠️ Limitado (depende da análise do IDA) |
| IDA 7 | `ida_struct.get_struc_list()`, `ida_typeinf` para tipos locais | ⚠️ Limitado (depende da análise do IDA) |
| Ghidra | `program.getDataTypeManager().getAllStructures()` | ✅ Médio |
@ -243,11 +268,12 @@ Documento de referência sobre quais dados de análise estática são extraívei
**O que é:** Código de alto nível reconstruído a partir do assembly — `if/else`, `while`, chamadas de função com nomes de parâmetros.
**Para que serve:** Leitura muito mais rápida do que assembly. É o principal diferencial do Ghidra e IDA 7+ sobre o IDA 5.
**Para que serve:** Leitura muito mais rápida do que assembly. É o principal diferencial do Ghidra e IDA 6.6+ sobre o IDA 5.
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | Não tem decompiler (Hex-Rays só a partir do IDA 6.6+) | ❌ **Não existe** |
| IDA 6.6 | `ida_hexrays.decompile(ea)` retorna AST, `cfunc.print()` gera string. Plugin `hexrays.plw` incluso na engine. | ✅ Fácil (requer licença Hex-Rays) |
| IDA 7 | `ida_hexrays.decompile(ea)` retorna AST, `cfunc.print()` gera string | ✅ Fácil (requer licença Hex-Rays) |
| Ghidra | `decompInterface.decompileFunction(function, timeout, monitor)``decompResults.getDecompiledFunction().getC()` | ✅ Fácil (nativo e gratuito) |
@ -262,6 +288,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | `GetFchunkAttr(ea, FUNCATTR_START)` e iteração sobre chunks. `FlowChart` não disponível no IDC 5. | ⚠️ Limitado (possível via chunks) |
| IDA 6.6 | `ida_gdl.FlowChart(f)` disponível via IDAPython, retorna nós e arestas. `idautils.Chunks(ea)` para iteração over function chunks. | ✅ Médio |
| IDA 7 | `ida_gdl.FlowChart(f)` retorna nós e arestas; `ida_gdl.gen_flow_graph()` | ✅ Médio |
| Ghidra | `BasicBlockModel` + iteração sobre `function.getBody()` → blocos, `function.getCalledFunctions()` → call graph | ✅ Médio |
@ -276,6 +303,7 @@ Documento de referência sobre quais dados de análise estática são extraívei
| Engine | API | Viabilidade |
|--------|-----|:-----------:|
| IDA 5 | Iterar segmentos de dados e usar `Name(ea)` + `isData(GetFlags(ea))` | ✅ Médio |
| IDA 6.6 | `ida_name.get_name_list()` disponível via IDAPython; `ida_bytes.is_data(ida_bytes.get_flags(ea))` para filtrar labels de dados | ✅ Fácil |
| IDA 7 | `ida_name.get_name_list()`, `ida_bytes.is_data()` | ✅ Fácil |
| Ghidra | `program.getSymbolTable().getGlobalSymbols()`, `listing.getDataAt()` | ✅ Fácil |
@ -283,10 +311,10 @@ Documento de referência sobre quais dados de análise estática são extraívei
## Prioridades Recomendadas
1. **Entry point + Tipo de xref + Flags** baixo esforço, alto valor, fecha o básico
2. **Strings + Imports** — esforço médio, altíssimo valor para entendimento do binário
3. **Segmentos + Tamanho da função** baixo esforço, enriquece o contexto
4. **Decompilação** (Ghidra/IDA 7) — esforço médio, é o grande diferencial vs IDA 5
1. ~~Entry point + Tipo de xref + Flags~~**concluído**, baixo esforço, alto valor, fecha o básico
2. **Strings + Imports** — esforço baixo/médio (via IDAPython no IDA 6.6+), altíssimo valor para entendimento do binário
3. ~~Segmentos + Tamanho da função~~**concluído**, baixo esforço, enriquece o contexto
4. **Decompilação** (IDA 6.6/IDA 7/Ghidra) — esforço médio, é o grande diferencial. IDA 6.6 tem Hex-Rays disponível (plugin `hexrays.plw` incluso), permitindo extrair pseudocódigo via `ida_hexrays.decompile(ea)`.
5. **Frame + Variáveis globais** — enriquece a visualização de cada função
6. **Call graph / CFG** — habilita visualização gráfica no frontend
7. **Tipos + Estruturas** — depende muito da engine, menor prioridade

View File

@ -0,0 +1,28 @@
package ai.decompile.engine.controller;
import ai.decompile.engine.model.dto.EngineResponse;
import ai.decompile.engine.service.EngineDiscoveryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "Engine", description = "Static analysis engine discovery")
@RestController
@RequiredArgsConstructor
public class EngineController {
private final EngineDiscoveryService engineDiscoveryService;
@Operation(
summary = "List available analysis engines",
description =
"Retrieve all registered static analysis engines with their availability status.",
tags = {"Engine"},
operationId = "listEngines")
@GetMapping("/engines")
public List<EngineResponse> listEngines() {
return engineDiscoveryService.listEngines();
}
}

View File

@ -0,0 +1,2 @@
@org.springframework.modulith.NamedInterface("controller")
package ai.decompile.engine.controller;

View File

@ -1,7 +1,16 @@
package ai.decompile.engine.model;
import lombok.Getter;
@Getter
public enum EngineType {
IDA5,
IDA66,
GHIDRA
IDA5("IDA Pro 5.0"),
IDA66("IDA Pro 6.6"),
GHIDRA("Ghidra");
private final String label;
EngineType(String label) {
this.label = label;
}
}

View File

@ -0,0 +1,3 @@
package ai.decompile.engine.model.dto;
public record EngineResponse(String name, String label, boolean available) {}

View File

@ -0,0 +1,2 @@
@org.springframework.modulith.NamedInterface("dto")
package ai.decompile.engine.model.dto;

View File

@ -0,0 +1,22 @@
package ai.decompile.engine.service;
import ai.decompile.engine.model.dto.EngineResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class EngineDiscoveryService {
private final List<EngineService> engineServices;
public List<EngineResponse> listEngines() {
return engineServices.stream()
.map(
e -> {
var type = e.supportedEngine();
return new EngineResponse(type.name(), type.getLabel(), e.isAvailable());
})
.toList();
}
}

View File

@ -7,4 +7,8 @@ public interface EngineService {
AnalysisResult analyze(String filePath);
EngineType supportedEngine();
default boolean isAvailable() {
return true;
}
}

View File

@ -15,4 +15,9 @@ public class GhidraEngineService implements EngineService {
public EngineType supportedEngine() {
return EngineType.GHIDRA;
}
@Override
public boolean isAvailable() {
return false;
}
}