
برنامج تشغيل حماية العمليات في وضع النواة مع واجهة مستخدم رسومية
مشغل حماية عمليات في وضع النواة باستخدام ObRegisterCallbacks لإزالة صلاحيات الوصول للذاكرة من المقابض. تنفيذ أساسي يربط إنشاء المقابض ويزيل PROCESS_VM_READ/WRITE/OPERATION من محاولات الوصول غير المصرح بها.


ملاحظة: إذا لم تتحرك الصورة، شاهدها مباشرة على Imgur
يسجل المشغل استدعاءات كائن (OB callbacks) على ارتفاع 321123 ويعترض عمليات OB_OPERATION_HANDLE_CREATE و OB_OPERATION_HANDLE_DUPLICATE. عندما تحاول عملية فتح مقبض لهدف محمي، نتحقق من اسم العملية المصدر مقابل قائمة بيضاء (explorer.exe, csrss.exe, svchost.exe, MsMpEng.exe, RuntimeBroker.exe) ونقوم بإزالة حقوق الوصول إذا لم تكن مسموحة.
التنفيذ الحالي يستند إلى مطابقة الأسماء باستخدام PsGetProcessImageFileName (API غير موثق). تتم إدارة قائمة الحماية عبر قائمة مرتبطة مع مزامنة باستخدام قفل الدوران (spinlock). يوجد خيط عامل (worker thread) ولكن منطق التحديث لم يتم تنفيذه بعد.
يوفر مكون وضع المستخدم واجهة رسومية ImGui لإضافة العمليات إلى قائمة الحماية. يتم الاتصال عبر رموز IOCTL عبر الرابط الرمزي \\Device\\Aegis باستخدام نقل METHOD_BUFFERED. يقوم المشغل بإنشاء رابط رمزي من \\DosDevices\\Aegis إلى \\Device\\Aegis ليتمكن وضع المستخدم من الوصول إليه عبر \\\\.\\Aegis.
النواة (km/):
driver.c - DriverEntry, تسجيل OB, موزع IOCTL, إنشاء الجهاز/الرابط الرمزيprotect_manager/ - إدارة قائمة العمليات، الخيط العامل (منطق التحديث معلق)وضع المستخدم (um/):
client.cpp - الحلقة الرئيسية، عرض ImGui، إدارة النوافذgui/ - إعداد DirectX 11 + ImGui، خطوط مخصصة (Gilroy)service_manager/ - تكامل SCM لتحميل/إلغاء تحميل المشغلioctl_manager/ - غلاف DeviceIoControl للاتصال بالمشغل321123 (المعيار لجهات خارجية هو 321000+، تم تعيينه أعلى لتجنب التصادم)PsGetProcessImageFileName - API غير موثق يعيد اسم ملف .exe فقط (بحد أقصى 15 حرف)KSPIN_LOCK على مستوى DISPATCH_LEVEL (IRQL 2) لمنع حالات السباقNonPagedPool لـ protect_manager (دائمًا في RAM، وصول أسرع، مساحة محدودة)PagedPool لهياكل العمليات الفردية (يمكن إخراجها من الصفحات)KEVENT للمعالجة غير المتزامنة (حاليًا دمية)METHOD_BUFFERED للتعامل الآمن مع المخازن، نوع الجهاز 0x8000 (نطاق جهات خارجية)SERVICE_DEMAND_STARTDeviceIoControl مع رموز IOCTL معرفة في ioctl.h المشتركتسجيل استدعاء OB:
// تسجيل استدعاءات OB لإنشاء/تكرار المقابض
OB_CALLBACK_REGISTRATION ob_registration = { 0 };
OB_OPERATION_REGISTRATION op_registration = { 0 };
RtlSecureZeroMemory(&ob_registration, sizeof(ob_registration));
RtlSecureZeroMemory(&op_registration, sizeof(op_registration));
op_registration.ObjectType = PsProcessType;
op_registration.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
// نهتم بالتكرار لأن المخترقين الأذكياء أو البرامج الضارة غالبًا لا ينشئون مقابض
// بل يكررون المقابض الحالية لتجنب إثارة الشكوك
op_registration.PreOperation = pre_open_process;
RtlInitUnicodeString(&ob_registration.Altitude, L"321123");
// 321000 هو المعيار لمشغلات الطرف الثالث، قمنا بتعيينه أعلى قليلاً لتجنب التصادم
status = ObRegisterCallbacks(&ob_registration, ®_handle);
إزالة صلاحيات الوصول للمقبض:
OB_PREOP_CALLBACK_STATUS pre_open_process(PVOID reg_context, POB_PRE_OPERATION_INFORMATION info)
{
if (info->ObjectType == *PsProcessType) {
PEPROCESS proc = (PEPROCESS)info->Object;
char* process_name = (char*)PsGetProcessImageFileName(proc);
// قفل القائمة على مستوى DISPATCH_LEVEL لمنع شاشة الموت الزرقاء
KIRQL irql;
KeAcquireSpinLock(&g_protect_manager->list_lock, &irql);
// التحقق مما إذا كانت العملية موجودة في قائمة الحماية
for (entry = g_protect_manager->process_list.Flink;
entry != &g_protect_manager->process_list;
entry = entry->Flink) {
pprocess proces = CONTAINING_RECORD(entry, process, entry);
if (strcmp(proces->path, process_name) == 0) {
// التحقق من العملية المصدر - السماح بعمليات النظام
PEPROCESS source_process = IoGetCurrentProcess();
char* source_name = (char*)PsGetProcessImageFileName(source_process);
if (strcmp(source_name, "explorer.exe") == 0 ||
strcmp(source_name, "csrss.exe") == 0 || ...) {
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
return OB_PREOP_SUCCESS;
}
// إزالة VM_READ, VM_WRITE, VM_OPERATION (0x1, 0x10, 0x20)
// لا نضبطها على 0 لأن ذلك قد يسبب أخطاء
info->Parameters->CreateHandleInformation.DesiredAccess &= ~(0x1 | 0x10 | 0x20);
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
return OB_PREOP_SUCCESS;
}
}
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
}
return OB_PREOP_SUCCESS;
}
إدارة قائمة العمليات:
NTSTATUS protect_manager_protect_process(pprotect_manager self, pprocess process)
{
// KIRQL (مستوى طلب المقاطعة) 0-31 يخبر وحدة المعالجة المركزية بعدم الإزعاج
// 0 = PASSIVE_LEVEL, 2 = DISPATCH_LEVEL, 31 = HIGH_LEVEL
KIRQL irql;
// الحصول على قفل الدوران، يرفع IRQL إلى DISPATCH_LEVEL (2)
// يقفل القائمة حتى لا تتغير أثناء التحرير
KeAcquireSpinLock(&self->list_lock, &irql);
InsertTailList(&self->process_list, &process->entry);
KeReleaseSpinLock(&self->list_lock, irql);
// إشارة للخيط العامل للتحديث
self->refresh_needed = TRUE;
KeSetEvent(&self->worker_event, 0, FALSE); // FALSE = إعادة IRQL تلقائية
return STATUS_SUCCESS;
}
اتصال IOCTL من وضع المستخدم:
bool ioctl_manager::check(std::string name)
{
// فتح جهاز المشغل عبر الرابط الرمزي \\\\.\\Aegis -> \\Device\\Aegis
this->driver_object = CreateFile(this->path, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
// إرسال اسم العملية إلى المشغل عبر IOCTL
result = DeviceIoControl(this->driver_object, IOCTL_PROTECT_PID,
(LPVOID)data.c_str(), data.size() + 1,
NULL, 0, &bytes_returned, NULL);
CloseHandle(this->driver_object); // لا تنس إغلاق المقابض
return result;
}
جميع الأكواد موثقة بشكل شامل مع شروحات لمفاهيم النواة، مستويات IRQL، إدارة الذاكرة، والمشاكل المحتملة. لا تتردد في مراجعة المصدر - إنه تعليمي وموثق جيدًا.
bcdedit /set testsigning on)مخرجات البناء: km.sys (المشغل) و um.exe (تطبيق وضع المستخدم).
OB_OPERATION_HANDLE_CREATE، هجمات التكرار ممكنةprotect_manager.c فارغExAllocatePool بدلاً من ExAllocatePool2PsActiveProcessHead، إخفاء المشغل من PsLoadedModuleListلأغراض تعليمية فقط. يستخدم APIs غير موثقة قد تتعطل مع تحديثات Windows. يتطلب التوقيع الاختباري أو التوقيع المناسب للبرمجة للتشغيل.