Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
cfgrip — Disassembla binari PE/ELF x86/x64, risolve rami indiretti tramite GOT, tabelle di salto e tracciamento dei registri, ed esporta il grafico completo del flusso di controllo come JSON strutturato per analisi statica e patching. | Kitploit
Strumenti/GitLabGitLab/binaryhardening/cfgrip
Analisi StaticaReverse EngineeringDebuggerAnalisi di Binari
GitLabbinaryhardening/cfgrip

cfgrip

Disassembla binari PE/ELF x86/x64, risolve rami indiretti tramite GOT, tabelle di salto e tracciamento dei registri, ed esporta il grafico completo del flusso di controllo come JSON strutturato per analisi statica e patching.

Vedi Repository
224 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Sito web

cfgrip

Estrattore CFG PE/ELF x86/x64. Prende un binario in input, lo disassembla, risolve ogni salto e chiamata (GOT, tabelle di salto, tracciamento dei registri) ed esporta il grafo di controllo completo come JSON strutturato.

perché

Hai bisogno di sapere esattamente dove va ogni ramo. Non per leggere — per patchare. Inserisci il JSON in Zydis o AsmJit, individua l'istruzione esatta che devi hookare o modificare e riscrivila. I team anti-cheat lo usano per mappare i binari dei giochi. I RE lo usano per sollevare il codice nei propri pipeline di analisi. Gli analisti software tracciano i percorsi di esecuzione senza eseguire il binario. cfgrip ti fornisce la mappa. Quello che ne fai dipende da te.

cosa estrae

Per ogni binario elaborato da cfgrip, produce:

  • Elenco delle funzioni con indirizzi, indirizzo finale opzionale (da .pdata), nomi (punto di ingresso, esportazioni, scoperte) e tagging thunk (stub PLT)
  • Blocchi di base per funzione — sequenze di istruzioni terminate da rami, chiamate, ritorni o trap
  • Archi del flusso di controllo — successori di ogni blocco (rami diretti, caduta, destinazioni indirette)
  • Tabella delle importazioni — importazioni di librerie risolte con indirizzi
  • Destinazioni indirette — chiamate risolte tramite GOT, voci della tabella dei salti, rami tracciati tramite registro e quelli non risolti (contrassegnati come tali)
  • Confini delle funzioni — passaggi di rilevamento multipli (pattern di prologo, destinazioni di chiamata, chiamate di coda, voci .pdata, puntatori a funzione nella sezione dati) per la massima copertura

Con --clean, inoltre:

  • Jump-thread catene di jmp → jmp in archi diretti
  • Elimina i blocchi di base morti (nessun arco entrante)
  • Annota ogni istruzione con stack_offset (delta RSP dall'ingresso della funzione)
  • Costruisce una sezione xrefs che mappa ogni destinazione di chiamata/salto ai suoi chiamanti

Gestisce i rami indiretti:

  1. Controllando la GOT (Global Offset Table) per importazioni note
  2. Scansionando all'indietro per istruzioni LEA per individuare le tabelle di salto, quindi leggendo le voci della tabella
  3. Tracciando i registri all'indietro attraverso catene di mov/lea per trovare indirizzi concreti

utilizzo

root@kitploit:~
cfgrip [--subs-only] [--clean] <binary>

Fornisci un binario e ottieni <binary>.cfg come output.
Usa --subs-only per estrarre solo le funzioni raggiungibili dal punto di ingresso attraverso il grafo delle chiamate — salta le esportazioni irraggiungibili e i candidati prologo.
Usa --clean per applicare jump-threading, eliminazione dei blocchi morti, tracciamento dello stack offset e analisi dei cross-reference.


Esempio:

root@kitploit:~
cfgrip.exe tests\example1.exe
format: PE
arch: x86-64
entry: 0x1400054bc
imports: 85
  0x140020000 EncodePointer (KERNEL32.dll)
  0x140020008 DecodePointer (KERNEL32.dll)
  0x140020010 EnterCriticalSection (KERNEL32.dll)
  0x140020018 LeaveCriticalSection (KERNEL32.dll)
  0x140020020 InitializeCriticalSectionEx (KERNEL32.dll)
  0x140020028 DeleteCriticalSection (KERNEL32.dll)
  0x140020030 MultiByteToWideChar (KERNEL32.dll)
  0x140020038 WideCharToMultiByte (KERNEL32.dll)
  0x140020040 LCMapStringEx (KERNEL32.dll)
  0x140020048 GetStringTypeW (KERNEL32.dll)
  0x140020050 GetCPInfo (KERNEL32.dll)
  0x140020058 RtlCaptureContext (KERNEL32.dll)
  0x140020060 RtlLookupFunctionEntry (KERNEL32.dll)
  0x140020068 RtlVirtualUnwind (KERNEL32.dll)
  0x140020070 UnhandledExceptionFilter (KERNEL32.dll)
  0x140020078 SetUnhandledExceptionFilter (KERNEL32.dll)
  0x140020080 GetCurrentProcess (KERNEL32.dll)
  0x140020088 TerminateProcess (KERNEL32.dll)
  0x140020090 IsProcessorFeaturePresent (KERNEL32.dll)
  0x140020098 QueryPerformanceCounter (KERNEL32.dll)
  0x1400200a0 GetCurrentProcessId (KERNEL32.dll)
  0x1400200a8 GetCurrentThreadId (KERNEL32.dll)
  0x1400200b0 GetSystemTimeAsFileTime (KERNEL32.dll)
  0x1400200b8 InitializeSListHead (KERNEL32.dll)
  0x1400200c0 IsDebuggerPresent (KERNEL32.dll)
  0x1400200c8 GetStartupInfoW (KERNEL32.dll)
  0x1400200d0 GetModuleHandleW (KERNEL32.dll)
  0x1400200d8 WriteConsoleW (KERNEL32.dll)
  0x1400200e0 RtlPcToFileHeader (KERNEL32.dll)
  0x1400200e8 RaiseException (KERNEL32.dll)
  0x1400200f0 RtlUnwindEx (KERNEL32.dll)
  0x1400200f8 GetLastError (KERNEL32.dll)
  0x140020100 SetLastError (KERNEL32.dll)
  0x140020108 InitializeCriticalSectionAndSpinCount (KERNEL32.dll)
  0x140020110 TlsAlloc (KERNEL32.dll)
  0x140020118 TlsGetValue (KERNEL32.dll)
  0x140020120 TlsSetValue (KERNEL32.dll)
  0x140020128 TlsFree (KERNEL32.dll)
  0x140020130 FreeLibrary (KERNEL32.dll)
  0x140020138 GetProcAddress (KERNEL32.dll)
  0x140020140 LoadLibraryExW (KERNEL32.dll)
  0x140020148 GetStdHandle (KERNEL32.dll)
  0x140020150 WriteFile (KERNEL32.dll)
  0x140020158 GetModuleFileNameW (KERNEL32.dll)
  0x140020160 ExitProcess (KERNEL32.dll)
  0x140020168 GetModuleHandleExW (KERNEL32.dll)
  0x140020170 GetCommandLineA (KERNEL32.dll)
  0x140020178 GetCommandLineW (KERNEL32.dll)
  0x140020180 HeapAlloc (KERNEL32.dll)
  0x140020188 HeapFree (KERNEL32.dll)
  0x140020190 FlsAlloc (KERNEL32.dll)
  0x140020198 FlsGetValue (KERNEL32.dll)
  0x1400201a0 FlsSetValue (KERNEL32.dll)
  0x1400201a8 FlsFree (KERNEL32.dll)
  0x1400201b0 VirtualProtect (KERNEL32.dll)
  0x1400201b8 CompareStringW (KERNEL32.dll)
  0x1400201c0 LCMapStringW (KERNEL32.dll)
  0x1400201c8 GetLocaleInfoW (KERNEL32.dll)
  0x1400201d0 IsValidLocale (KERNEL32.dll)
  0x1400201d8 GetUserDefaultLCID (KERNEL32.dll)
  0x1400201e0 EnumSystemLocalesW (KERNEL32.dll)
  0x1400201e8 GetFileType (KERNEL32.dll)
  0x1400201f0 CloseHandle (KERNEL32.dll)
  0x1400201f8 FlushFileBuffers (KERNEL32.dll)
  0x140020200 GetConsoleOutputCP (KERNEL32.dll)
  0x140020208 GetConsoleMode (KERNEL32.dll)
  0x140020210 ReadFile (KERNEL32.dll)
  0x140020218 GetFileSizeEx (KERNEL32.dll)
  0x140020220 SetFilePointerEx (KERNEL32.dll)
  0x140020228 ReadConsoleW (KERNEL32.dll)
  0x140020230 HeapReAlloc (KERNEL32.dll)
  0x140020238 FindClose (KERNEL32.dll)
  0x140020240 FindFirstFileExW (KERNEL32.dll)
  0x140020248 FindNextFileW (KERNEL32.dll)
  0x140020250 IsValidCodePage (KERNEL32.dll)
  0x140020258 GetACP (KERNEL32.dll)
  0x140020260 GetOEMCP (KERNEL32.dll)
  0x140020268 GetEnvironmentStringsW (KERNEL32.dll)
  0x140020270 FreeEnvironmentStringsW (KERNEL32.dll)
  0x140020278 SetEnvironmentVariableW (KERNEL32.dll)
  0x140020280 SetStdHandle (KERNEL32.dll)
  0x140020288 GetProcessHeap (KERNEL32.dll)
  0x140020290 HeapSize (KERNEL32.dll)
  0x140020298 CreateFileW (KERNEL32.dll)
  0x1400202a0 RtlUnwind (KERNEL32.dll)
functions: 1975
indirect targets: 3453
cfg written to: tests\example1.exe.cfg

il formato di output

Il file .cfg è JSON strutturato. Ecco come appare:

root@kitploit:~
{
  "binary": "tests\\example1.exe",
  "mode": "full",
  "arch": "x86-64",
  "format": "PE",
  "entry_point": "0x1400054bc",
  "imports": [
    {
      "address": "0x140020000",
      "name": "EncodePointer",
      "library": "KERNEL32.dll"
    },
    {
      "address": "0x140020008",
      "name": "DecodePointer",
      "library": "KERNEL32.dll"
    },
    {
      "address": "0x140020010",
      "name": "EnterCriticalSection",
      "library": "KERNEL32.dll"
    },
    {
      "address": "0x140020018",
      "name": "LeaveCriticalSection",
      "library": "KERNEL32.dll"
    },
    {
      "address": "0x140020020",
      "name": "InitializeCriticalSectionEx",
      "library": "KERNEL32.dll"
    },
    ...
    ...
    ...
  "functions": [
    {
      "address": "0x1400054bc",
      "name": "entry",
      "blocks": [
        {
          "address": "0x1400054bc",
          "size": 4,
          "is_prolog": false,
          "is_epilog": false,
          "instructions": [
            {
              "address": "0x1400054bc",
              "size": 4,
              "mnemonic": "sub",
              "operands": "rsp, 0x28"
            },
            {
              "address": "0x1400054c0",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x140005d30"
            },
            {
              "address": "0x1400054c5",
              "size": 4,
              "mnemonic": "add",
              "operands": "rsp, 0x28"
            },
            {
              "address": "0x1400054c9",
              "size": 5,
              "mnemonic": "jmp",
              "operands": "0x140005340"
            }
          ],
          "successors": [
            "0x140005340"
          ]
        },
        {
          "address": "0x140005340",
          "size": 8,
          "is_prolog": false,
          "is_epilog": false,
          "instructions": [
            {
              "address": "0x140005340",
              "size": 5,
              "mnemonic": "mov",
              "operands": "qword ptr [rsp + 8], rbx"
            },
            {
              "address": "0x140005345",
              "size": 5,
              "mnemonic": "mov",
              "operands": "qword ptr [rsp + 0x10], rsi"
            },
            {
              "address": "0x14000534a",
              "size": 1,
              "mnemonic": "push",
              "operands": "rdi"
            },
            {
              "address": "0x14000534b",
              "size": 4,
              "mnemonic": "sub",
              "operands": "rsp, 0x30"
            },
            {
              "address": "0x14000534f",
              "size": 5,
              "mnemonic": "mov",
              "operands": "ecx, 1"
            },
            {
              "address": "0x140005354",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x14000550c"
            },
            {
              "address": "0x140005359",
              "size": 2,
              "mnemonic": "test",
              "operands": "al, al"
            },
            {
              "address": "0x14000535b",
              "size": 6,
              "mnemonic": "je",
              "operands": "0x140005497"
            }
          ],
          "successors": [
            "0x140005497",
            "0x140005361"
          ]
        },
        {
          "address": "0x140005497",
          "size": 15,
          "is_prolog": false,
          "is_epilog": false,
          "instructions": [
            {
              "address": "0x140005497",
              "size": 5,
              "mnemonic": "mov",
              "operands": "ecx, 7"
            },
            {
              "address": "0x14000549c",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x140005e44"
            },
            {
              "address": "0x1400054a1",
              "size": 1,
              "mnemonic": "nop",
              "operands": ""
            },
            {
              "address": "0x1400054a2",
              "size": 5,
              "mnemonic": "mov",
              "operands": "ecx, 7"
            },
            {
              "address": "0x1400054a7",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x140005e44"
            },
            {
              "address": "0x1400054ac",
              "size": 2,
              "mnemonic": "mov",
              "operands": "ecx, ebx"
            },
            {
              "address": "0x1400054ae",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x14000ec14"
            },
            {
              "address": "0x1400054b3",
              "size": 1,
              "mnemonic": "nop",
              "operands": ""
            },
            {
              "address": "0x1400054b4",
              "size": 2,
              "mnemonic": "mov",
              "operands": "ecx, ebx"
            },
            {
              "address": "0x1400054b6",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x14000ebcc"
            },
            {
              "address": "0x1400054bb",
              "size": 1,
              "mnemonic": "nop",
              "operands": ""
            },
            {
              "address": "0x1400054bc",
              "size": 4,
              "mnemonic": "sub",
              "operands": "rsp, 0x28"
            },
            {
              "address": "0x1400054c0",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x140005d30"
            },
            {
              "address": "0x1400054c5",
              "size": 4,
              "mnemonic": "add",
              "operands": "rsp, 0x28"
            },
            {
              "address": "0x1400054c9",
              "size": 5,
              "mnemonic": "jmp",
              "operands": "0x140005340"
            }
          ],
          "successors": [
            "0x140005340"
          ]
        },
        ...
        ...
        ...

Ogni funzione ora include campi opzionali:

  • end_address — fine precisa della funzione quando disponibile (dalla tabella delle eccezioni PE .pdata), altrimenti calcolata come l'indirizzo massimo dell'istruzione tra tutti i blocchi
  • is_thunk — true per stub PLT e thunk di importazione (funzioni che reindirizzano solo a un altro indirizzo)

Output di --subs-only

root@kitploit:~
{
  "binary": "C:\\binaries\\target.exe",
  "mode": "subs-only",
  "arch": "x86-64",
  "format": "PE",
  "entry_point": "0x1400054bc",
  "imports": [ ... ],
  "indirect_targets": [ ... ],
  "functions": [
    {
      "address": "0x1400054bc",
      "name": "entry",
      "blocks": [ ... ]
    },
    ...
  ]
}

Il campo "mode": "subs-only" indica agli strumenti a valle che questo CFG contiene solo funzioni raggiungibili dal punto di ingresso. Le esportazioni irraggiungibili e i candidati prologo sono esclusi — meno funzioni, superficie di analisi più pulita.

Output di --clean

root@kitploit:~
{
  "binary": "C:\\binaries\\target.exe",
  "mode": "full+clean",
  "arch": "x86-64",
  "format": "PE",
  "entry_point": "0x1400054bc",
  "imports": [ ... ],
  "indirect_targets": [ ... ],
  "functions": [
    {
      "address": "0x1400054bc",
      "name": "entry",
      "blocks": [
        {
          "address": "0x1400054bc",
          "size": 4,
          "is_prolog": false,
          "is_epilog": false,
          "instructions": [
            {
              "address": "0x1400054bc",
              "size": 4,
              "mnemonic": "sub",
              "operands": "rsp, 0x28",
              "stack_offset": 0
            },
            {
              "address": "0x1400054c0",
              "size": 5,
              "mnemonic": "call",
              "operands": "0x140005d30",
              "stack_offset": -40
            },
            {
              "address": "0x1400054c5",
              "size": 4,
              "mnemonic": "add",
              "operands": "rsp, 0x28",
              "stack_offset": -40
            },
            {
              "address": "0x1400054c9",
              "size": 5,
              "mnemonic": "jmp",
              "operands": "0x140005340",
              "stack_offset": 0
            }
          ],
          "successors": [ "0x140005340" ]
        },
        ...
      ]
    },
    ...
  ],
  "xrefs": [
    {
      "target": "0x140011b00",
      "callers": [
        { "address": "0x14001a30f", "type": "call" },
        { "address": "0x140019ec1", "type": "call" },
        ...
      ]
    },
    {
      "target": "0x140007394",
      "callers": [
        { "address": "0x14001a31a", "type": "call" },
        ...
      ]
    },
    ...
  ]
}

Ogni istruzione in modalità --clean include stack_offset — il delta RSP dall'ingresso della funzione a quel punto dell'istruzione. La sezione xrefs mappa ogni destinazione di chiamata/salto a ogni istruzione che la referenzia.

Output combinato di --subs-only --clean

root@kitploit:~
{
  "binary": "C:\\binaries\\target.exe",
  "mode": "subs-only+clean",
  ...
}

Stessa struttura di --clean, ma con "mode": "subs-only+clean" per indicare che entrambi i filtri sono stati applicati. Il conteggio delle funzioni è ridotto solo alle funzioni raggiungibili dal punto di ingresso e le funzioni rimanenti hanno stack offset e xref.

rilevamento dei confini delle funzioni

cfgrip scopre le funzioni attraverso più passaggi di rilevamento:

Le funzioni con is_thunk: true sono stub PLT o thunk di importazione — funzioni a blocco singolo che reindirizzano a un altro indirizzo.

compilazione

Richiede CMake e un compilatore C++17. Capstone viene scaricato automaticamente.

root@kitploit:~
cmake -B build
cmake --build build --config Release
./build/cfgrip <binary>

Oppure su Windows con Visual Studio:

root@kitploit:~
cmake -B build -S .
cmake --build build --config Release
.\build\Release\cfgrip.exe <binary>

alt text alt text

cosa supporta

| | | |:-:| | Formati | PE (32/64-bit) | YES | | | ELF (64-bit) | YES | | Architetture | x86 | YES | | | x86-64 | YES | | Chiamate indirette | Risoluzione GOT | YES | | | Rilevamento tabelle di salto | YES | | | Tracciamento registri all'indietro | YES | | Scoperta delle funzioni | Punto di ingresso | YES | | | Esportazioni | YES | | | Destinazioni di chiamata | YES | | | Scansione prologo (MSVC x64, GCC, CET endbr64) | YES | | | Rilevamento chiamate di coda (jmp → funzione) | YES | | | PE .pdata (tabella gestori eccezioni) | YES | | | Scansione puntatori a funzione nella sezione dati | YES | | Rilevamento thunk | Stub PLT / thunk di importazione (is_thunk) | YES | | Confini delle funzioni | end_address da .pdata o istruzione massima | YES | | Modalità subs-only | Flag --subs-only | YES | | Pulizia CFG | --clean (jump-thread, eliminazione blocchi morti, delta stack, xrefs) | YES |

ricerca

Il rilevamento dei confini delle funzioni in questo strumento si basa sull'approccio descritto in "Function Boundary Detection in Stripped Binaries" (Alves-Foss & Song, 2019), che introduce un algoritmo multi-uristico per individuare l'inizio e la fine delle funzioni in binari x86/x64 stripped.

Il paper è disponibile su papers/Function_Boundary_Detection_in_Stripped_Binaries.pdf.

Come la nostra implementazione si mappa sulle euristiche del paper:

L'intuizione chiave del paper è che le euristiche algoritmiche — senza machine learning — possono raggiungere un'alta accuratezza sui binari stripped. La nostra implementazione segue questa filosofia, utilizzando un approccio multi-passaggio in cui ogni passaggio cattura funzioni che gli altri potrebbero non vedere.

Scarica lo strumento
PassaggioCosa rilevaCopre
Scansione prologopush rbp, push r15/r14/r13/r12/rbx/rdi/rsi, sub rsp, >=0x20, enterMSVC x64, GCC, funzioni foglia, CET (endbr64)
Destinazioni di chiamataOgni destinazione di istruzione call è un inizio di funzioneChiamate dirette e indirette risolte tramite GOT
Chiamate di codaIstruzioni jmp che puntano a candidati prologoCatene di chiamate di coda ottimizzate
.pdata (PE)Voci di funzione runtime dalla tabella dei gestori di eccezioniInizio/fine precisi per ogni funzione PE x64
Puntatori datiValori a 8 byte in .rdata/.data che puntano a codice eseguibilePuntatori a funzione, vtable, callback
EuristicaDescrizione nel paperNostra implementazione
H1–H4Firme del prologo (push rbp, registri salvati dal chiamato, stack sub, enter)isProlog() in disasm/engine.cpp — rileva push rbp, push r15..rbx, sub rsp >= 0x20, enter
H5Semina delle destinazioni di chiamataOgni destinazione diretta di call è un inizio di funzione
H6Rilevamento salto-a-funzione (chiamata di coda)jmp a candidati prologo aggiunge la destinazione alla coda delle funzioni
H7Analisi della tabella delle eccezioniLe voci RUNTIME_FUNCTION di PE .pdata danno inizio/fine precisi
H8Analisi dei riferimenti datiscanDataPointers() percorre le sezioni dati per puntatori a codice