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 منظم للتحليل الثابت والتصحيح.

عرض المستودع
2منذ 25 أياملم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
الموقع الإلكتروني

cfgrip

أداة استخراج CFG (رسم تدفق التحكم) لملفات PE/ELF ذات بنية x86/x64. تأخذ ملفًا ثنائيًا، تفك تجميعه، وتحل كل قفزة واستدعاء (GOT، جداول القفز، تتبع السجلات)، ثم تصدر رسم تدفق التحكم الكامل بصيغة JSON منظمة.

لماذا

تحتاج إلى معرفة أين يذهب كل فرع بدقة — ليس للقراءة، بل للتعديل. قم بتغذية الـ JSON إلى Zydis أو AsmJit، حدد التعليمة الدقيقة التي تحتاج إلى ربط أو تعديل، ثم اكتب التعديل. تستخدمه فرق مكافحة الغش لرسم خرائط ملفات الألعاب الثنائية. يستخدمه محللو الهندسة العكسية لرفع الكود إلى خطوط التحليل الخاصة بهم. يتتبع محللو البرمجيات مسارات التنفيذ دون تشغيل الملف الثنائي.

يمنحك cfgrip الخريطة. ما تفعله بها متروك لك.

ما يستخرجه

لكل ملف ثنائي يعالجه cfgrip، ينتج:

  • قائمة الدوال مع العناوين، وعنوان نهاية اختياري (من .pdata)، وأسماء (نقطة الدخول، الصادرات، المكتشفة)، ووسم التوابع (stubs 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 — نهاية دقيقة للدالة عند توفرها (من جدول الاستثناءات .pdata في PE)، وإلا تُحسب كأقصى عنوان تعليمة عبر جميع الكتل
  • is_thunk — true لـ stubs PLT وتوابع الاستيراد (دوال تعيد التوجيه فقط إلى عنوان آخر)

مخرجات --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" للإشارة إلى تطبيق كلا المرشحين. يتم تقليل عدد الدوال إلى الدوال التي يمكن الوصول إليها من نقطة الدخول فقط، وتحتوي الدوال المتبقية على إزاحات مكدس ومراجع متقاطعة.

اكتشاف حدود الدوال

يكتشف cfgrip الدوال من خلال عدة مراحل كشف:

الدوال التي تحتوي على is_thunk: true هي stubs 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>

نص بديل نص بديل

ما يدعمه

البحث

يعتمد اكتشاف حدود الدوال في هذه الأداة على النهج الموصوف في "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)إدخالات الدوال وقت التشغيل من جدول معالجة الاستثناءاتبداية/نهاية دقيقة لكل دالة PE x64
مؤشرات البياناتقيم 8 بايت في .rdata/.data تشير إلى كود قابل للتنفيذمؤشرات الدوال، جداول الدوال الافتراضية، دوال الاستدعاءات الخلفية
الصيغPE (32/64-bit)نعم
ELF (64-bit)نعم
المعمارياتx86نعم
x86-64نعم
الاستدعاءات غير المباشرةحل GOTنعم
اكتشاف جداول القفزنعم
تتبع السجلات للخلفنعم
اكتشاف الدوالنقطة الدخولنعم
الصادراتنعم
أهداف callنعم
مسح المقدمة (MSVC x64, GCC, CET endbr64)نعم
اكتشاف استدعاءات الذيل (jmp → دالة)نعم
PE .pdata (جدول معالجة الاستثناءات)نعم
فحص مؤشر دالة في قسم البياناتنعم
اكتشاف التوابعstubs PLT / توابع الاستيراد (is_thunk)نعم
حدود الدوالend_address من .pdata أو أقصى تعليمةنعم
وضع الاستدعاءات الفرعية فقطعلم --subs-onlyنعم
تنظيف CFG--clean (ربط القفزات، تقليم الكتل الميتة، فروق المكدس، المراجع المتقاطعة)نعم
الاستدلالوصف الورقةتنفيذنا
H1–H4تواقيع المقدمة (push rbp, سجلات محفوظة للاستدعاء، جمع المكدس، enter)isProlog() في disasm/engine.cpp — يكشف push rbp, push r15..rbx, sub rsp >= 0x20, enter
H5بذر أهداف الاستدعاءكل هدف call مباشر هو بداية دالة
H6اكتشاف القفزة إلى دالة (استدعاء الذيل)jmp إلى مرشحي المقدمة يضيف الهدف إلى قائمة الدوال
H7تحليل جدول الاستثناءاتإدخالات RUNTIME_FUNCTION في .pdata لـ PE تعطي بداية/نهاية دقيقة
H8تحليل المرجع البيانيscanDataPointers() يجول أقسام البيانات بحثًا عن مؤشرات كود