Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
cfgrip — Désassemble les binaires PE/ELF x86/x64, résout les branches indirectes via GOT, les tables de saut et le traçage de registres, et exporte le graphe de flot de contrôle complet sous forme de JSON structuré pour l'analyse statique et le patching. | Kitploit
Outils/GitLabGitLab/binaryhardening/cfgrip
Analyse StatiqueRétro-ingénierieDébogueursAnalyse de Binaires
GitLabbinaryhardening/cfgrip

cfgrip

Désassemble les binaires PE/ELF x86/x64, résout les branches indirectes via GOT, les tables de saut et le traçage de registres, et exporte le graphe de flot de contrôle complet sous forme de JSON structuré pour l'analyse statique et le patching.

Voir le dépôt
2il y a 25 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager
Site web

cfgrip

Extracteur de CFG (graphe de flot de contrôle) pour PE/ELF x86/x64. Prend un binaire en entrée, le désassemble, résout chaque saut et appel (GOT, tables de saut, traçage de registres) et exporte le graphe de flot de contrôle complet au format JSON structuré.

pourquoi

Vous avez besoin de savoir exactement où va chaque branche. Pas pour lire — pour patcher. Alimentez le JSON dans Zydis ou AsmJit, localisez l'instruction exacte que vous devez hooker ou modifier, et réécrivez. Les équipes anti-triche l'utilisent pour cartographier les binaires de jeux. Les gens en rétro-ingénierie l'utilisent pour extraire du code dans leurs propres pipelines d'analyse. Les analystes logiciels tracent les chemins d'exécution sans exécuter le binaire.

cfgrip vous donne la carte. Ce que vous en faites vous appartient.

ce qu'il extrait

Pour chaque binaire traité, cfgrip produit :

  • Liste des fonctions avec adresses, adresse de fin optionnelle (depuis .pdata), noms (point d'entrée, exports, découvertes) et marquage des thunks (stubs PLT)
  • Blocs de base par fonction — séquences d'instructions terminées par des branchements, appels, retours ou traps
  • Arêtes du graphe de flot — successeurs de chaque bloc (branchements directs, fall-through, cibles indirectes)
  • Table d'imports — imports de bibliothèques résolus avec adresses
  • Cibles indirectes — appels résolus via GOT, entrées de table de saut, branchements tracés par registres, et non résolus (marqués comme tels)
  • Limites des fonctions — plusieurs passes de détection (motifs de prologue, cibles d'appels, appels terminaux, entrées .pdata, pointeurs de fonction en section data) pour une couverture maximale

Avec --clean, il effectue en outre :

  • Enchaînement de sauts (jmp → jmp) en arêtes directes
  • Élagage des blocs de base morts (sans arêtes entrantes)
  • Annotation de chaque instruction avec stack_offset (delta RSP depuis l'entrée de la fonction)
  • Construction d'une section xrefs qui relie chaque cible d'appel/saut à ses appelants

Il gère les branchements indirects en :

  1. Vérifiant la GOT (Global Offset Table) pour les imports connus
  2. Scannant en arrière les instructions LEA pour localiser les tables de saut, puis en lisant les entrées de la table
  3. Traçant les registres en arrière à travers les chaînes mov/lea pour trouver des adresses concrètes

utilisation

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

Donnez-lui un binaire, récupérez <binary>.cfg en sortie.
Utilisez --subs-only pour n'extraire que les fonctions atteignables depuis le point d'entrée via le graphe d'appels — ignore les exports inatteignables et les candidats prologue.
Utilisez --clean pour appliquer l'enchaînement de sauts, l'élagage des blocs morts, le suivi des décalages de pile et l'analyse des références croisées.


Exemple :

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

le format de sortie

Le fichier .cfg est du JSON structuré. Voici à quoi il ressemble :

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"
          ]
        },
        ...
        ...
        ...

Chaque fonction inclut désormais des champs optionnels :

  • end_address — fin précise de la fonction lorsqu'elle est disponible (depuis la table d'exceptions .pdata du PE), sinon calculée comme l'adresse d'instruction maximale parmi tous les blocs
  • is_thunk — true pour les stubs PLT et les thunks d'import (fonctions qui ne font que rediriger vers une autre adresse)

Sortie de --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": [ ... ]
    },
    ...
  ]
}

Le champ "mode": "subs-only" indique aux outils en aval que ce CFG ne contient que les fonctions atteignables depuis le point d'entrée. Les exports inatteignables et les candidats prologue sont exclus — moins de fonctions, surface d'analyse plus propre.

Sortie de --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" },
        ...
      ]
    },
    ...
  ]
}

Chaque instruction en mode --clean inclut stack_offset — le delta RSP depuis l'entrée de la fonction à ce point d'instruction. La section xrefs relie chaque cible d'appel/saut à toutes les instructions qui y font référence.

Sortie combinée --subs-only --clean

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

Même structure que --clean, mais avec "mode": "subs-only+clean" pour indiquer que les deux filtres ont été appliqués. Le nombre de fonctions est réduit aux seules fonctions atteignables depuis le point d'entrée, et les fonctions restantes possèdent des décalages de pile et des références croisées.

détection des limites de fonctions

cfgrip découvre les fonctions grâce à plusieurs passes de détection :

Les fonctions avec is_thunk: true sont des stubs PLT ou des thunks d'import — des fonctions mono-bloc qui redirigent vers une autre adresse.

compilation

Nécessite CMake et un compilateur C++17. Capstone est téléchargé automatiquement.

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

Ou sur Windows avec Visual Studio :

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

alt text alt text

ce qu'il supporte

recherche

La détection des limites de fonctions dans cet outil est basée sur l'approche décrite dans "Function Boundary Detection in Stripped Binaries" (Alves-Foss & Song, 2019), qui introduit un algorithme multi-heuristique pour localiser les débuts et fins de fonctions dans des binaires x86/x64 ébarbés.

L'article est disponible dans papers/Function_Boundary_Detection_in_Stripped_Binaries.pdf.

Comment notre implémentation correspond aux heuristiques de l'article :

L'idée clé de l'article est que des heuristiques algorithmiques — sans apprentissage automatique — peuvent atteindre une haute précision sur des binaires ébarbés. Notre implémentation suit cette philosophie, en utilisant une approche multi-passes où chaque passe capture des fonctions que les autres pourraient manquer.

Télécharger l’outil
PasseCe qu'elle détecteCouvre
Analyse de prologuepush rbp, push r15/r14/r13/r12/rbx/rdi/rsi, sub rsp, >=0x20, enterMSVC x64, GCC, fonctions feuilles, CET (endbr64)
Cibles d'appelsChaque cible d'instruction call est un début de fonctionAppels directs et indirects résolus via GOT
Appels terminauxInstructions jmp ciblant des candidats prologueChaînes d'appels terminaux optimisées
.pdata (PE)Entrées de fonction runtime depuis la table de gestionnaires d'exceptionsDébut/fin précis pour chaque fonction PE x64
Pointeurs de donnéesValeurs 8 octets dans .rdata/.data pointant vers du code exécutablePointeurs de fonction, vtables, callbacks
FormatsPE (32/64-bit)Oui
ELF (64-bit)Oui
Architecturesx86Oui
x86-64Oui
Appels indirectsRésolution GOTOui
Détection de tables de sautOui
Traçage arrière de registresOui
Découverte de fonctionsPoint d'entréeOui
ExportsOui
Cibles callOui
Analyse de prologue (MSVC x64, GCC, CET endbr64)Oui
Détection d'appels terminaux (jmp → fonction)Oui
PE .pdata (table de gestionnaires d'exceptions)Oui
Scan des pointeurs de fonction en section dataOui
Détection de thunksStubs PLT / thunks d'import (is_thunk)Oui
Limites de fonctionend_address depuis .pdata ou instruction maximaleOui
Mode subs-onlyDrapeau --subs-onlyOui
Nettoyage du CFG--clean (enchaînement de sauts, élagage des blocs morts, deltas de pile, références croisées)Oui
HeuristiqueDescription dans l'articleNotre implémentation
H1–H4Signatures de prologue (push rbp, registres sauvegardés, sub de pile, enter)isProlog() dans disasm/engine.cpp — détecte push rbp, push r15..rbx, sub rsp >= 0x20, enter
H5Ensemencement par cibles d'appelsChaque cible directe de call est un début de fonction
H6Détection de saut-vers-fonction (appel terminal)jmp vers des candidats prologue ajoute la cible à la file d'attente des fonctions
H7Analyse de table d'exceptionsLes entrées RUNTIME_FUNCTION du .pdata PE donnent un début/fin précis
H8Analyse de références de donnéesscanDataPointers() parcourt les sections de données à la recherche de pointeurs vers du code