Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
BYOVD-DriverKiller — Driver Reverse & Exploitation | Kitploit
أدوات/GitHubGitHub/alex3o/byovd-driverkiller
ExploitationReverse EngineeringPost-ExploitationBinary AnalysisLearning & EducationRed Teaming
GitHubalex3o/byovd-driverkiller

BYOVD-DriverKiller

Driver Reverse & Exploitation

عرض المستودع
8314منذ 11 أشهرتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

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

BYOVD-DriverKiller

⚠️ تحذير: هذا المشروع تعليمي واستعراضي بشكل صارم. ليس موجّهًا للاستخدام في سياق خبيث. الهدف هو تعلّم منهجية الهندسة العكسية وخطوات استغلال درايفر في نظام ويندوز.


أشرح هنا المنهجية التي اتبعتها لحل التمرين المقترح من طرف d1rk(SaadAhla) https://github.com/SaadAhla، والذي يتمثل في إجراء هندسة عكسية واستغلال على درايفر شرعي وموقّع وغير موجود في قوائم الحظر (HVCI، LOLBIN...). يتوفّر برنامج بلغة C يسمح بإنهاء أي عملية نشطة على النظام عبر هذا الدرايفر الخاص بوضع النواة، وسأفصّل طريقة عمله بعد قليل.

POC-BYOD

📃 الاستخدام: DriverKiller.exe <nom_processus.exe> [-d]

الخيار -d: يسمح بحذف الخدمة والدرايفر من النظام بعد الاستغلال.

يجب تفعيل وضع توقيع الاختبار (testsigning mode) على الجهاز الهدف لأن شهادة الدرايفر منتهية الصلاحية.


الجزء 1 - الهندسة العكسية:

يوفّر التمرين ملفًا بامتداد .sys، مُسمّى بهاش SHA-256 الخاص به. تتمثل الخطوة الأولى في فتح هذا الملف باستخدام IDA.
IDA متاح مجانًا. يكفي الذهاب إلى موقع Hex-Rays لإنشاء ترخيص وتنزيل البرنامج.

نبدأ بسرد جدول عناوين الاستيراد (IAT) الخاص بالدرايفر والبحث عن استدعاء API الذي يهمّنا: ZwTerminateProcess.

screen1-git

عند النقر المزدوج على ZwTerminateProcess، يقوم IDA بإعادة توجيهنا إلى الكود المترجم لهذه الدالة. وباختيار المدخل ثم عرض المراجع المتقاطعة (cross-references)، نحصل على قائمة بدوال الدرايفر التي تستدعيها.

screen2-git

نلاحظ أن الدالة sub_12EF4، عند الإزاحة 1CE، هي التي تستخدم ZwTerminateProcess. بعد النقر المزدوج، يعرض IDA كودها المترجم.

screen11-git

يكشف الكود المُفكَّك عن استدعاءات ZwOpenProcess (الذي يفتح مقبضًا للعملية الهدف) وZwTerminateProcess (الذي ينهي العملية عبر هذا المقبض).

من خلال الاطلاع على توثيق ZwOpenProcess (https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwopenprocess)، نلاحظ أن المعامل ClientID يشير إلى مؤشر يحدد PID العملية المستهدفة.

في السطر أعلاه، تتم تهيئة ClientId.UniqueProcess بالمتغير v22. هذا الأخير يُعرَّف مباشرةً بالأعلى:

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);

لفهم هذا الإسناد، يجب تحديد المتغير i والحقل +10.

screen3-git

أعلى هذه الدالة، نلاحظ استدعاءً لـ ZwQuerySystemInformation مع المعامل SYSTEM_PROCESS_INFORMATION. نفهم أيضًا أن i هو عداد التكرار على مداخل هذه البنية مع المتغير v6.

وفقًا لتوثيق ZwQuerySystemInformation: (https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation)، تُرجع هذه الدالة مصفوفة تحتوي على مدخل لكل عملية نشطة على النظام.

البنية SYSTEM_PROCESS_INFORMATION موصوفة هنا: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation

root@kitploit:~
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    PVOID Reserved2;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID Reserved3;
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;
    ULONG Reserved4;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    PVOID Reserved5;
    SIZE_T QuotaPagedPoolUsage;
    PVOID Reserved6;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

تذكير: أحجام بعض الأنواع في ويندوز x64

  • ULONG = 4 بايت
  • USHORT = 2 بايت
  • HANDLE = 8 بايت
  • PWSTR = 8 بايت
  • KPRIORITY (typedef من LONG) = 4 بايت
  • UNICODE_STRING = 16 بايت لأن بنيتها كالتالي:
root@kitploit:~
  typedef struct _UNICODE_STRING {
    USHORT Length;        -> 2      
    USHORT MaximumLength; -> + 2 = 4
    PWSTR  Buffer;        -> + 8 = 12 (12 n'est pas un multiple de 8 donc padding de 4 ajouté en amont de Buffer) = 16
} UNICODE_STRING;

حساب إزاحة UniqueProcessId:

root@kitploit:~
    ULONG NextEntryOffset;        -> 4
    ULONG NumberOfThreads;        -> + 4 = 8
    BYTE Reserved1[48];           -> + 48 = 56
    UNICODE_STRING ImageName;     -> + 16 = 72
    KPRIORITY BasePriority;       -> + 4 = 76 (76 n'est pas un multiple de 8 donc padding de 4 ajouté) = 80
    HANDLE UniqueProcessId;       -> + 8 = 88

إذن العضو UniqueProcessId يقع عند الإزاحة 0x50 (80 بالنظام العشري).

بالنظر إلى إسناد متغيرنا v22، نجد أن i يُحوَّل إلى مؤشر من نوع QWORD (8 بايت)

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);
إذن v22 يقابل عنوان i + 10 * 8 = 80 بايت. هذا المتغير يحتوي بالفعل على PID المسترجَع من بنية SYSTEM_PROCESS_INFORMATION.

لمعرفة أي PID سيتم تمريره إلى ZwTerminateProcess، يجب تحليل الشرط المحيط بهذا الإسناد.

screen4-git

نلاحظ أنه يتم أولاً استرجاع اسم صورة العملية:

root@kitploit:~
v9 = (wchar_t )((_QWORD *)i + 8);
لأن v9 = عنوان i + 8 × 8 = 64 بايت. وهذا يقابل الحقل Buffer للعضو ImageName، حيث يقع هذا العضو عند الإزاحة 56 + 2 (USHORT) + 2 (USHORT) + 4 (padding) = 64

بناءً على المعالجات والحلقات البرمجية أدناه، يمكننا افتراض أنه تتم مقارنة بين اسم العملية المُمرَّر كوسيط (a2) والعمليات النشطة على النظام v9/String.

root@kitploit:~
sub_1C078(String, v9, (int)v13);
v17 = strupr(a2);
v18 = strupr(String);

إذن، من المفترض أن يحتوي الوسيط a2 على اسم العملية التي سيتم إنهاؤها عبر ZwTerminateProcess. نلاحظ أن a2 هو معامل للدالة sub_12EF4. للمضي قدمًا، يجب فحص مراجع هذه الدالة (أعدت تسميتها إلى ZwTerminateProcessCaller من أجل قراءة أوضح).

screen5-git

نلاحظ أن الدالة ZwTerminateProcessCaller تُستدعى بواسطة الدالة sub_13624 عند الإزاحة 61A.

screen6-git

قبل تحليل هذا الكود المُفكَّك، سأبحث عن مراجع الدالة sub_13624 (أعدت تسميتها إلى ZwTerminateProcessCallerCaller) للتأكد من أن هذا الكود يُستخدم فعلًا بعد استدعاء API لـ DeviceIoControl من وضع المستخدم (UserMode).

screen§-git

نلاحظ أن ZwTerminateProcessCallerCaller تُستدعى بواسطة الدالة sub_14130 (أعدت تسميتها إلى ZwTerminateProcessCallerCallerCaller ...ولحسن حظنا، إنها الأخيرة قبل نقطة الدخول 😅).

screen7-git

نلاحظ أن ZwTerminateProcessCallerCallerCaller تُستدعى بواسطة الدالة sub_1A4A8 عند الإزاحة 306.

screen8-git

نجد تعيين الدالة ZwTerminateProcessCallerCallerCaller:

root@kitploit:~
memset64(DriverObject->MajorFunction, (unsigned __int64)ZwTerminateProcessCallerCallerCaller, 0x1Cu);
وهذا يعني أن هذه الدالة تُعيَّن لجميع مداخل جدول MajorFunction (0x1B = 27، ويوجد 28 طلب IRP رئيسيًا).

screen9-git

قبل العودة إلى الدالة sub_13624 (الاسم المستعار ZwTerminateProcessCallerCaller)، نستعيد الاسم الرمزي (Symbolic Name) واسم الجهاز (Device Name) (متطابقان هنا): Viragtlt.

screen12-git

بالعودة إلى ZwTerminateProcessCallerCaller، نلاحظ أن معاملها الثاني (أي a2) يقابل MasterIrp->AssociatedIrp.SystemBuffer.

screen13-git

مباشرةً فوق استدعاء ZwTerminateProcessCaller نجد كود IOCTL: -2106392528 (بالنظام الست عشري: 0x82730030).

بفضل هذه المعلومات، يمكننا استنتاج أنه لاستغلال هذا الدرايفر، يجب إرسال استدعاء API DeviceIoControl إلى الدرايفر مع اسم العملية المراد إنهاؤها في SystemBuffer.


🔷 المعلومات المستخلصة من الهندسة العكسية:

  • IOCTLCode: 0x82730030
  • Device Name: Viragtlt
  • Symbolic Name: Viragtlt
  • SystemBuffer يجب أن يحتوي اسم العملية الهدف

الجزء 2 - الاستغلال

لاستغلال هذا الدرايفر (إذا كان مثبتًا ونشطًا على الجهاز الهدف)، من الضروري فتح مقبض (handle) إليه، ثم إجراء استدعاء API لـ DeviceIoControl مع Buffer يحتوي اسم العملية التي نرغب في إنهائها.
لهذا التمرين، قمت بتطوير مشروع بلغة C يقوم بـ:

  • التحقق مما إذا كان الدرايفر موجودًا ونشطًا على النظام (باسم خدمة محدد):
    • إذا كان كذلك، يستغل البرنامج الدرايفر عبر استدعاء API لـ DeviceIoControl.
    • إذا لم يكن كذلك، يستخرج البرنامج الدرايفر من موارده، وينشره على سطح مكتب المستخدم، وينشئ خدمة نشطة ثم يستغل الدرايفر عبر استدعاء API لـ DeviceIoControl. (يتطلب صلاحيات المسؤول لأنه يتم إنشاء خدمة.)
  • إذا كان الدرايفر موجودًا على النظام لكن الخدمة غير مشغّلة، يحاول البرنامج تشغيل الخدمة ثم يستغل الدرايفر عبر استدعاء API لـ DeviceIoControl.

لقد أضفت أيضًا خيارًا -d يسمح بحذف الخدمة والدرايفر من النظام بعد الاستغلال.

إليك سلوك البرنامج بلغة C في دورة تنفيذه الكاملة:

git

التهرب من AV/EDR

في هذه الحالة، لا يتم اكتشاف DriverKiller.exe بواسطة Microsoft Defender، لا في الوضع الثابت ولا في الوضع الديناميكي. التهرب ليس له معنى حقيقي هنا لأن الدرايفر المستغل يملك شهادة منتهية الصلاحية، لذا فإن استخدامه في ظروف حقيقية يصعب تصوّره. ولكن من أجل تمويه أفضل، كان يمكن تنفيذ:

  • إخفاء بعض استدعاءات API في جدول IAT عبر تطبيقات مخصصة لـ GetProcAddress وGetModuleHandle
  • الاقتراب من النواة لتنفيذ استدعاءات API (استدعاءات نظام مباشرة/غير مباشرة Direct/Indirect Syscalls)
  • تقنيات Anti-VM / Anti-Debug

نتيجة الكشف على الدرايفر بتاريخ 29/08/2025 (نتيجة موجودة مسبقًا، لم أقم بإرسال أي شيء على VirusTotal لأسباب واضحة):

image

⚠️ هذا المشروع أُنجز في إطار تعليمي. قد يحتوي على بعض عدم الدقة أو الأخطاء. أي اقتراح أو تصحيح أو نقاش مرحب به! 😃 شكرًا لـ d1rk(SaadAhla): https://github.com/SaadAhla!

تنزيل الأداة