Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
cfgrip — PE/ELF x86/x64 바이너리를 디스어셈블하고, GOT, 점프 테이블, 레지스터 추적을 통해 간접 분기를 해결하며, 정적 분석 및 패치를 위해 전체 제어 흐름 그래프를 구조화된 JSON으로 내보냅니다. | Kitploit
도구/GitLabGitLab/binaryhardening/cfgrip
Static AnalysisReverse EngineeringDebuggersBinary Analysis
GitLabbinaryhardening/cfgrip

cfgrip

PE/ELF x86/x64 바이너리를 디스어셈블하고, GOT, 점프 테이블, 레지스터 추적을 통해 간접 분기를 해결하며, 정적 분석 및 패치를 위해 전체 제어 흐름 그래프를 구조화된 JSON으로 내보냅니다.

저장소 보기
225일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
웹사이트

cfgrip

PE/ELF x86/x64 CFG 추출기. 바이너리를 입력받아 디스어셈블하고, 모든 점프와 호출(GOT, 점프 테이블, 레지스터 추적)을 분석한 후, 전체 제어 흐름 그래프를 구조화된 JSON으로 내보냅니다.

필요한 이유

모든 분기가 어디로 가는지 정확히 알아야 합니다. 읽기 위한 것이 아닙니다 — 패치를 위한 것입니다. JSON을 Zydis나 AsmJit에 넣고, 후킹하거나 수정해야 할 정확한 명령어를 찾은 후 다시 쓰면 됩니다. 안티치트 팀은 게임 바이너리를 매핑하는 데 사용합니다. 리버스 엔지니어는 코드를 자신의 분석 파이프라인으로 가져오는 데 사용합니다. 소프트웨어 분석가는 바이너리를 실행하지 않고 실행 경로를 추적합니다.

cfgrip은 지도를 제공합니다. 그것으로 무엇을 할지는 여러분의 몫입니다.

추출하는 내용

cfgrip이 처리하는 모든 바이너리에 대해 다음을 생성합니다:

  • 함수 목록 — 주소, 선택적 종료 주소(.pdata에서), 이름(진입점, 익스포트, 발견된 것), 썽크 태깅(PLT 스텁)
  • 함수별 기본 블록 — 분기, 호출, 리턴 또는 트랩으로 종료되는 명령어 시퀀스
  • 제어 흐름 엣지 — 각 블록의 후속 블록(직접 분기, 폴스루, 간접 대상)
  • 임포트 테이블 — 주소가 확인된 라이브러리 임포트
  • 간접 대상 — GOT 확인 호출, 점프 테이블 항목, 레지스터 추적 분기, 확인되지 않은 항목(표시됨)
  • 함수 경계 — 최대 커버리지를 위한 여러 탐지 패스(프롤로그 패턴, 호출 대상, 테일 콜, .pdata 항목, 데이터 섹션 함수 포인터)

--clean 옵션을 사용하면 추가로:

  • jmp → jmp 체인을 직접 엣지로 점프-스레딩
  • 죽은 기본 블록 제거(들어오는 엣지 없음)
  • 각 명령어에 stack_offset(함수 진입점으로부터의 RSP 델타) 주석
  • 모든 호출/점프 대상을 호출자로 다시 매핑하는 xrefs 섹션 구축

간접 분기를 처리하는 방법:

  1. GOT(전역 오프셋 테이블) 확인하여 알려진 임포트 확인
  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 — PLT 스텁 및 임포트 썽크(다른 주소로만 리디렉션하는 함수)인 경우 true

--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" 필드는 다운스트림 도구에 이 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"으로 두 필터가 모두 적용되었음을 나타냅니다. 함수 개수는 진입점에서 도달 가능한 함수로 줄어들고, 남은 함수에는 스택 오프셋과 xrefs가 있습니다.

함수 경계 탐지

cfgrip은 여러 탐지 패스를 통해 함수를 발견합니다:

is_thunk: true 함수는 PLT 스텁 또는 임포트 썽크입니다 — 다른 주소로 리디렉션하는 단일 블록 함수입니다.

빌드

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)에서 설명된 접근 방식을 기반으로 합니다. 이 논문은 스트립된 x86/x64 바이너리에서 함수 시작과 끝을 찾기 위한 다중 휴리스틱 알고리즘을 소개합니다.

논문은 papers/Function_Boundary_Detection_in_Stripped_Binaries.pdf에서 확인할 수 있습니다.

논문의 휴리스틱에 대한 구현 매핑:

논문의 핵심 통찰은 머신 러닝 없이 알고리즘적 휴리스틱으로 스트립된 바이너리에서 높은 정확도를 달성할 수 있다는 것입니다. 우리의 구현은 이 철학을 따르며, 각 패스가 다른 패스가 놓칠 수 있는 함수를 잡아내는 다중 패스 접근 방식을 사용합니다.

도구 다운로드
패스탐지 대상적용 범위
프롤로그 스캔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 함수의 정확한 시작/끝
데이터 포인터.rdata/.data에서 실행 코드를 가리키는 8바이트 값함수 포인터, vtable, 콜백
형식PE (32/64비트)YES
ELF (64비트)YES
아키텍처x86YES
x86-64YES
간접 호출GOT 확인YES
점프 테이블 탐지YES
역방향 레지스터 추적YES
함수 발견진입점YES
익스포트YES
call 대상YES
프롤로그 스캔 (MSVC x64, GCC, CET endbr64)YES
테일-콜 탐지 (jmp → 함수)YES
PE .pdata (예외 처리기 테이블)YES
데이터 섹션 함수 포인터 스캔YES
썽크 탐지PLT 스텁 / 임포트 썽크 (is_thunk)YES
함수 경계.pdata 또는 최대 명령어로부터의 end_addressYES
서브스 온리 모드--subs-only 플래그YES
CFG 정리--clean (점프-스레드, 죽은 블록 제거, 스택 델타, xrefs)YES
휴리스틱논문 설명구현
H1–H4프롤로그 시그니처 (push rbp, callee-saved regs, stack sub, enter)disasm/engine.cpp의 isProlog() — push rbp, push r15..rbx, sub rsp >= 0x20, enter 탐지
H5호출 대상 시딩모든 직접 call 대상은 함수 시작점
H6점프-투-함수 (테일 콜) 탐지프롤로그 후보로의 jmp는 대상을 함수 큐에 추가
H7예외 테이블 파싱PE .pdata RUNTIME_FUNCTION 항목은 정확한 시작/끝 제공
H8데이터 참조 분석scanDataPointers()가 데이터 섹션을 코드 포인터로 스캔