
إزالة خطافات قسم .text في ntdll بشكل صحيح عبر Native API. على عكس أدوات إزالة الخطافات الأخرى، لا يترك نسختين من ntdll محمّلتين. يدعم x86/x64/wow64.
إزالة خطاف صحيحة لقسم .text في ntdll عبر Native API. تدعم x86/x64/wow64.
يتنقل البرنامج في PEB لتحديد العنوان الأساسي لـ ntdll.dll ويحلل يدويًا جدول تصدير PE لحل دوال NT API دون لمس جدول عناوين الاستيراد (IAT). ثم يستخدم NtOpenFile لفتح نسخة ntdll.dll النظيفة من القرص، وينشئ كائن قسم عبر NtCreateSection، ويقوم بتعيينه في العملية عبر NtMapViewOfSection للحصول على مصدر إزالة خطاف دون تحميل dll ثانية فعليًا عبر LoadLibrary. يُغيَّر قسم .text المُخطَّف إلى PAGE_EXECUTE_READWRITE عبر NtProtectVirtualMemory، وتُنسخ نسخة .text النظيفة فوق المُخطَّفة باستخدام memcpy مخصص، ثم تُستعاد الحماية إلى العلامات الأصلية. بعد التحقق بايتًا ببايت من نجاح إزالة الخطاف، يُلغى تعيين النسخة النظيفة بشكل صحيح عبر NtUnmapViewOfSection بحيث لا تبقى نسخة ntdll ثانية محمّلة في الذاكرة.
معظم أكواد إزالة الخطاف العامة هي حرفيًا نسخ ولصق من نفس المصدر الرديء (مثل مثال ired.team وتقريبًا كل أداة إزالة خطاف مفتوحة المصدر على GitHub) وتعاني من مشاكل ضخمة تجعلها عديمة الفائدة ضد أي EDR حقيقي. تستخدم VirtualProtect بدلًا من الواجهات الأصلية (Native APIs) وهو ما يُفشل الغرض بالكامل لأنك تستدعي دوالًا مُخطَّفة لإزالة خطاف دوال أخرى، وتضبط صلاحيات RWX على قسم .text وهو مؤشر اختراق (IOC) ضخم ترصده EDRs فورًا، كما أنها لا تلغي تعيين النسخة النظيفة فعليًا لأن CloseHandle على تعيين قسم لا يحرر الذاكرة. أنت بحاجة إلى UnmapViewOfFile أو NtUnmapViewOfSection لكن الجميع ينسى هذا الجزء، لذا يتركون نسختين من ntdll محمّلتين في العملية، وهو في الأساس لافتة نيون ضخمة تقول «أنا برنامج خبيث». كما يحاولون استخدام FreeLibrary على ntdll الرئيسية وهو أمر لا يعمل أصلًا ويسبب تسريب المقابض (handles)، علاوة على أنهم يغيّرون الحماية إلى RWX مرتين دون داعٍ بينما تكفي مرة واحدة إذا أعدت الحماية بشكل صحيح.
يصلح هذا التنفيذ الأخطاء الشائعة في أكواد إزالة الخطاف العامة باستخدام الواجهات الأصلية في كل خطوة (NtOpenFile، NtCreateSection، NtMapViewOfSection، NtProtectVirtualMemory)، وإلغاء تعيين النسخة النظيفة بشكل صحيح عبر NtUnmapViewOfSection لتجنب ترك نسختين من ntdll محمّلتين، وعدم استخدام FreeLibrary على ntdll الرئيسية، والتحقق من النجاح عبر مقارنة الذاكرة. لكنه لا يتجنب مؤشرات الاختراق (IOCs) الأساسية التي تكتشفها EDRs الحديثة. استخدام NtOpenFile على C:\Windows\System32\ntdll.dll هو IOC يُسجَّل في السجلات، وNtCreateSection مع SEC_IMAGE بالإشارة إلى ntdll.dll يُتتبَّع عبر ETW، وتعديل حماية الذاكرة على قسم .text في ntdll علامة خطر كبرى حتى مع الواجهات الأصلية، والكتابة إلى .text قابلة للاكتشاف عبر استدعاءات رد الكتابة في الذاكرة. هذه التقنية معروفة جيدًا، وتمتلك EDRs الحديثة مثل CrowdStrike وSentinelOne توقيعات للنمط بأكمله. أما EDRs المتقدمة مثل Microsoft Defender for Endpoint وElastic فلم تعد تستخدم خطافات وضع المستخدم (usermode hooks) أصلًا لأنها تعتمد على استدعاءات النواة (kernel callbacks) وقياس عن بُعد ETW، لذا فإن إزالة الخطاف لا تفعل شيئًا حرفيًا ضدها. تعمل هذه الطريقة ضد EDRs الأساسية التي تستخدم الخطافات المضمنة (inline hooks) فقط وعكس المنتجات الأمنية القديمة، لكنها تفشل ضد أي شيء يحتوي مكونات بوضع النواة أو تحليلًا سلوكيًا. تشمل البدائل الأفضل استدعاءات syscall المباشرة حيث لا تستدعي دوالًا مُخطَّفة من الأساس، وHeaven's Gate لعبور حدود wow64، والاستخراج اليدوي للـ syscalls من ntdll .text وقت التشغيل، أو ببساطة تجنب الواجهات المشبوهة تمامًا لأن إزالة الخطاف في 2024/2025 أصبحت عمومًا تقنية ميتة ضد EDR الحقيقية للمؤسسات.
تعمل على عمليات x64 الأصلية، وعمليات x86 الأصلية، وعمليات wow64 (x86 على ويندوز x64). تكتشف تلقائيًا wow64 وتستخدم دليل النظام الصحيح (System32 مقابل SysWOW64) بحيث لا تحتاج إلى التفكير في ذلك.
فقط قسم .text في ntdll.dll تتم معالجته لأنه المكان الذي تعيش فيه جميع أكواد الدوال الفعلية وحيث تُوضع خطافات EDR كخطافات دوال مضمنة (تعليمات jmp في مقدمات الدوال). أما الأقسام الأخرى مثل .data و.rdata فتُترك دون مساس لأنه لا يوجد سبب للتعامل معها، وإنما يخلق ذلك مزيدًا من مؤشرات الاختراق (IOCs) دون أي فائدة.
cl /EHsc /std:c++17 main.cpp /Fe:unhook.exe
أو أي شيء آخر، أي مترجم c++ حديث يعمل. يتطلب windows.h وwinternl.h.
الوصول غير المصرح به إلى أنظمة الحاسوب غير قانوني. استخدمه على أنظمة تمتلكها أو لديك إذن باختبارها. سجن «pound-me-in-the-ass» الفيدرالي حقيقي.
يستخدم الكود ماكرو CONTAINING_RECORD للتنقل في قوائم LDR بشكل صحيح، ويصل إلى PEB عبر سجلات المقاطع (gs على x64، fs على x86)، ويقوم ببحث مبرمج مسبقًا عن قسم .text عبر مقارنة الاسم وهو ما كان يمكن أن يكون أكثر أناقة لكن المهم أنه يعمل، ويعالج الأخطاء عبر أكواد NTSTATUS وماكرو NT_SUCCESS، ويلف عمليات الذاكرة في try/except الخاص بـ SEH من أجل الأمان. إذا كنت لا تستطيع قراءة c++ وفهم تفاصيل تنسيق PE الداخلية فربما لا ينبغي لك استخدام هذا على أي حال.