Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
cfgrip — Дисассемблирует PE/ELF x86/x64 бинарные файлы, разрешает косвенные переходы через GOT, таблицы переходов и трассировку регистров, а также экспортирует полный граф потока управления в структурированный JSON для статического анализа и патчинга. | Kitploit
Инструменты/GitLabGitLab/binaryhardening/cfgrip
Статический анализОбратная инженерияОтладчикиАнализ Бинарных Файлов
GitLabbinaryhardening/cfgrip

cfgrip

Дисассемблирует PE/ELF x86/x64 бинарные файлы, разрешает косвенные переходы через GOT, таблицы переходов и трассировку регистров, а также экспортирует полный граф потока управления в структурированный JSON для статического анализа и патчинга.

Репозиторий
225 дней назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
Сайт

cfgrip

PE/ELF x86/x64 — извлекатель CFG. Принимает бинарный файл, дизассемблирует его, разрешает каждый переход и вызов (GOT, таблицы переходов, трассировка регистров) и экспортирует полный граф потока управления в виде структурированного JSON.

зачем

Вам нужно точно знать, куда ведёт каждая ветвь. Не для чтения — для патчинга. Передайте JSON в Zydis или AsmJit, найдите точную инструкцию, которую нужно перехватить или изменить, и запишите обратно. Команды античита используют его для картографирования игровых бинарных файлов. RE-специалисты используют его для подъёма кода в свои собственные пайплайны анализа. Аналитики ПО отслеживают пути выполнения без запуска бинарного файла.

cfgrip даёт вам карту. Что вы с ней делаете — решать вам.

что он извлекает

Для каждого обработанного бинарного файла cfgrip создаёт:

  • Список функций с адресами, опциональным конечным адресом (из .pdata), именами (точка входа, экспортируемые, обнаруженные) и пометками thunk (заглушки PLT)
  • Базовые блоки для каждой функции — последовательности инструкций, завершающиеся ветвлениями, вызовами, возвратами или ловушками
  • Рёбра графа потока управления — преемники каждого блока (прямые ветвления, fall-through, косвенные цели)
  • Таблицу импорта — разрешённые библиотечные импорты с адресами
  • Косвенные цели — вызовы, разрешённые через GOT, записи таблиц переходов, ветвления, отслеженные по регистрам, и неразрешённые (помеченные как таковые)
  • Границы функций — несколько проходов обнаружения (шаблоны пролога, цели вызовов, хвостовые вызовы, записи .pdata, указатели на функции в секции данных) для максимального покрытия

С флагом --clean дополнительно:

  • Прыжко-нитевое соединение цепочек jmp → jmp в прямые рёбра
  • Удаление мёртвых базовых блоков (без входящих рёбер)
  • Аннотирование каждой инструкции stack_offset (дельта RSP от входа в функцию)
  • Построение секции xrefs, сопоставляющей каждую цель вызова/перехода с её вызывающими

Обработка косвенных ветвлений происходит следующим образом:

  1. Проверка GOT (Global Offset Table) на наличие известных импортов
  2. Сканирование назад в поиске инструкций LEA для обнаружения таблиц переходов, затем чтение записей таблицы
  3. Трассировка регистров назад по цепочкам mov/lea для поиска конкретных адресов

использование

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

Подайте на вход бинарный файл, на выходе получите <binary>.cfg.
Используйте --subs-only, чтобы извлечь только функции, достижимые из точки входа через граф вызовов — пропускает недостижимые экспортируемые функции и кандидаты с прологами.
Используйте --clean, чтобы применить прыжко-нитевое соединение, удаление мёртвых блоков, отслеживание смещения стека и анализ перекрёстных ссылок.


Пример:

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

формат вывода

Файл .cfg представляет собой структурированный JSON. Вот как он выглядит:

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

Теперь каждая функция включает опциональные поля:

  • end_address — точный конец функции, если доступен (из таблицы исключений PE .pdata), в противном случае вычисляется как максимальный адрес инструкции среди всех блоков
  • is_thunk — true для заглушек PLT и thunk-ов импорта (функции, которые только перенаправляют на другой адрес)

Вывод с --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": [ ... ]
    },
    ...
  ]
}

Поле "mode": "subs-only" сообщает downstream-инструментам, что этот CFG содержит только функции, достижимые из точки входа. Недостижимые экспортируемые функции и кандидаты с прологами исключены — меньше функций, чище поверхность анализа.

Вывод с --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" },
        ...
      ]
    },
    ...
  ]
}

Каждая инструкция в режиме --clean включает stack_offset — дельту RSP от входа в функцию на момент этой инструкции. Секция xrefs сопоставляет каждую цель вызова/перехода со всеми инструкциями, которые на неё ссылаются.

Комбинированный вывод --subs-only --clean

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

Та же структура, что и у --clean, но с "mode": "subs-only+clean" для указания, что были применены оба фильтра. Количество функций сокращено до только достижимых из точки входа, а для оставшихся функций указаны смещения стека и перекрёстные ссылки.

обнаружение границ функций

cfgrip обнаруживает функции с помощью нескольких проходов обнаружения:

Функции с is_thunk: true — это заглушки PLT или thunk-и импорта — одноблочные функции, которые перенаправляют на другой адрес.

сборка

Требуется CMake и компилятор C++17. Capstone загружается автоматически.

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

Или на Windows с Visual Studio:

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

alt text alt text

что он поддерживает

исследование

Обнаружение границ функций в этом инструменте основано на подходе, описанном в статье "Function Boundary Detection in Stripped Binaries" (Alves-Foss & Song, 2019), где представлен мульти-эвристический алгоритм для определения начал и концов функций в stripped x86/x64-бинарных файлах.

Статья доступна по адресу papers/Function_Boundary_Detection_in_Stripped_Binaries.pdf.

Как наша реализация соотносится с эвристиками из статьи:

Ключевая идея статьи в том, что алгоритмические эвристики — без машинного обучения — могут достигать высокой точности на stripped бинарных файлах. Наша реализация следует этой философии, используя многопроходный подход, где каждый проход ловит функции, которые могли быть пропущены другими.

Скачать инструмент
ПроходЧто обнаруживаетПокрытие
Сканирование прологовpush rbp, push r15/r14/r13/r12/rbx/rdi/rsi, sub rsp, >=0x20, enterMSVC x64, GCC, листовые функции, CET (endbr64)
Цели вызововКаждая цель инструкции call является началом функцииПрямые и разрешённые через GOT косвенные вызовы
Хвостовые вызовыИнструкции jmp, указывающие на кандидатов с прологамиОптимизированные цепочки хвостовых вызовов
.pdata (PE)Записи функций времени выполнения из таблицы обработчиков исключенийТочные начало/конец для каждой x64 PE-функции
Указатели на данные8-байтовые значения в .rdata/.data, указывающие на исполняемый кодУказатели на функции, vtable, обратные вызовы
ФорматыPE (32/64-бит)ДА
ELF (64-бит)ДА
Архитектурыx86ДА
x86-64ДА
Косвенные вызовыРазрешение GOTДА
Обнаружение таблиц переходовДА
Обратная трассировка регистровДА
Обнаружение функцийТочка входаДА
Экспортируемые функцииДА
Цели callДА
Сканирование прологов (MSVC x64, GCC, CET endbr64)ДА
Обнаружение хвостовых вызовов (jmp → функция)ДА
PE .pdata (таблица обработчиков исключений)ДА
Сканирование указателей на функции в секции данныхДА
Обнаружение thunkЗаглушки PLT / thunk-и импорта (is_thunk)ДА
Границы функцийend_address из .pdata или максимальная инструкцияДА
Режим subs-onlyФлаг --subs-onlyДА
Очистка CFG--clean (прыжко-нитевое соединение, удаление мёртвых блоков, дельты стека, перекрёстные ссылки)ДА
ЭвристикаОписание из статьиНаша реализация
H1–H4Сигнатуры прологов (push rbp, сохраняемые callee регистры, sub rsp, enter)isProlog() в disasm/engine.cpp — обнаруживает push rbp, push r15..rbx, sub rsp >= 0x20, enter
H5Посев целей вызововКаждая прямая цель call является началом функции
H6Обнаружение перехода-к-функции (хвостовой вызов)jmp к кандидату с прологом добавляет цель в очередь функций
H7Разбор таблицы исключенийЗаписи PE .pdata RUNTIME_FUNCTION дают точные начало/конец
H8Анализ ссылок на данныеscanDataPointers() обходит секции данных в поиске указателей на код