هل سبق لك أن أردت النظر تحت غطاء نظام التشغيل ، والنظر في الهيكل الداخلي لآلياته ، وتحريف البراغي وإلقاء نظرة على الفرص التي فتحت؟ ربما أرادوا العمل مباشرة مع الأجهزة ، لكنهم اعتقدوا أن السائقين هم علم الصواريخ؟
أقترح أن أسير على طول الجسر حتى القلب ونرى مدى عمق حفرة الأرنب.
لذا ، أقدم إطار عمل محرك القرصنة لقرص kernel ، المكتوب بلغة C ++ 17 ، ومصممًا ، إذا أمكن ، لإزالة الحواجز بين وضع kernel ووضع المستخدم أو لتخفيف وجودهما قدر الإمكان. وأيضًا ، مجموعة من واجهات برمجة تطبيقات وضع المستخدم و kernel والأغلفة من أجل التطوير السريع والمريح في Ring0 للمبتدئين والمبرمجين المتقدمين.
الملامح الرئيسية:
- الوصول إلى منافذ الإدخال / الإخراج ، بالإضافة إلى إعادة توجيه الدخول والخروج وتعليمات cli و sti إلى وضع المستخدم عبر IOPL
- يلتف فوق نظام تويتر
- الوصول إلى MSR (السجلات الخاصة بالنموذج)
- مجموعة من الوظائف للوصول إلى ذاكرة وضع المستخدم للعمليات الأخرى وذاكرة kernel
- العمل مع الذاكرة الفعلية ، DMI / SMBIOS
- إنشاء نمط المستخدم والتدفقات النووية ، تسليم APC
- استدعاءات وضع المستخدم *** و Ps *** وفلاتر نظام الملفات
- قم بتنزيل برامج تشغيل غير موقعة ومكتبات kernel
... وأكثر من ذلك بكثير.
وسنبدأ بتحميل وتوصيل الإطار بمشروع C ++ الخاص بنا.
جيثبللتجميع ، من المستحسن للغاية استخدام أحدث إصدار من Visual Studio وأحدث WDK (Windows Driver Kit) المتاح ، والذي يمكن تنزيله من
موقع Microsoft الرسمي على الويب .
للاختبار ، يعد برنامج VMware Player المجاني مع Windows المثبت ، الذي لا يقل عن Windows 7 ، بأي سعة ، مثاليًا.
التجميع تافه ولن يسبب أسئلة:
- افتح Kernel-Bridge.sln
- اختر عمق البت المطلوب
- Ctrl + Shift + B
ونتيجة لذلك ، نحصل على برنامج تشغيل ومكتبة في وضع المستخدم بالإضافة إلى ملفات الأداة المساعدة ذات الصلة (
* .inf للتثبيت اليدوي ،
* .cab لتوقيع برنامج التشغيل على Microsoft Hardware Certification Publisher ، إلخ).
لتثبيت برنامج التشغيل (إذا لم يكن هناك توقيع رقمي ضروري لـ x64 - شهادة EV المقابلة) ، فأنت بحاجة إلى وضع النظام في وضع الاختبار ، وتجاهل التوقيع الرقمي لبرامج التشغيل. للقيام بذلك ، قم بتشغيل سطر الأوامر كمسؤول:
bcdedit.exe /set loadoptions DISABLE_INTEGRITY_CHECKS
bcdedit.exe /set TESTSIGNING ON
... وإعادة تشغيل الجهاز. إذا تم كل شيء بشكل صحيح ، سيظهر نقش في الزاوية اليمنى السفلية التي يكون فيها Windows في وضع الاختبار.
اكتمل إعداد بيئة الاختبار ، فلنبدأ في استخدام واجهة برمجة التطبيقات في مشروعنا.
يحتوي الإطار على التسلسل الهرمي التالي:
/ Kernel-Bridge / API - مجموعة من الوظائف للاستخدام في برامج التشغيل ووحدات
kernel ، وليس لها تبعيات خارجية ويمكن استخدامها بحرية في مشاريع الطرف الثالث
/ User-Bridge / API - مجموعة من أغلفة وضع المستخدم فوق برنامج التشغيل ووظائف الأداة المساعدة للعمل مع ملفات PE ، أحرف PDB ، إلخ.
/ SharedTypes / - كل من وضع المستخدم والعناوين النووية التي تحتوي على الأنواع الشائعة الضرورية
يمكن تحميل برنامج التشغيل بطريقتين: كسائق عادي وكمرشح صغير. يفضل الطريقة الثانية ، لأنه يمنح الوصول إلى الوظائف المتقدمة للمرشحات واسترجاعات وضع المستخدم لأحداث النظام.
لذا ، قم بإنشاء مشروع وحدة تحكم في C ++ ، وقم بتوصيل ملفات الرأس الضرورية وتحميل برنامج التشغيل:
#include <Windows.h> #include "WdkTypes.h" // x32/x64 WDK #include "CtlTypes.h" // IOCTL- #include "User-Bridge.h" // API, int main() { using namespace KbLoader; BOOL Status = KbLoadAsFilter( L"X:\\Folder\\Path\\To\\Kernel-Bridge.sys", L"260000" // ); if (!Status) return 0; // ! // API ... // : KbUnload(); return 0; }
عظيم! الآن يمكننا استخدام واجهة برمجة التطبيقات والتفاعل مع النواة.
لنبدأ بالوظيفة الأكثر شيوعًا في بيئة مطوري الغش - قراءة وكتابة ذاكرة عملية أخرى:
using namespace Processes::MemoryManagement; constexpr int Size = 64; BYTE Buffer[Size] = {}; BOOL Status = KbReadProcessMemory(
لا شيء معقد! دعونا ننزل إلى مستوى واحد - قراءة وكتابة الذاكرة النووية:
using namespace VirtualMemory; constexpr int Size = 64; BYTE Buffer[Size];
ماذا عن وظائف التفاعل مع الحديد؟ على سبيل المثال ، منافذ الإدخال / الإخراج.
سنقوم بإعادة توجيههم إلى وضع المستخدم من خلال تجميع 2 بت IOPL في سجل EFlags ، وهي مسؤولة عن مستوى الامتياز الذي تتوفر فيه تعليمات
الدخول /
الخروج /
cli /
sti .
وبالتالي ، سنتمكن من تنفيذها في وضع المستخدم بدون خطأ التعليمات المميزة:
#include <intrin.h> using namespace IO::Iopl; // , ! KbRaiseIopl(); // in/out/cli/sti ! ULONG Frequency = 1000; // 1 kHz ULONG Divider = 1193182 / Frequency; __outbyte(0x43, 0xB6); // // : __outbyte(0x42, static_cast<unsigned char>(Divider)); __outbyte(0x42, static_cast<unsigned char>(Divider >> 8)); __outbyte(0x61, __inbyte(0x61) | 3); // ( ) for (int i = 0; i < 5000; i++); // Sleep(), IOPL ! __outbyte(0x61, __inbyte(0x61) & 252); // KbResetIopl();
لكن ماذا عن الحرية الحقيقية؟ بعد كل شيء ، غالبًا ما يرغب المرء في تنفيذ التعليمات البرمجية التعسفية بامتيازات kernel. نكتب كل كود النواة في وضع المستخدم وننقل التحكم إليه من النواة (يتم إيقاف تشغيل SMEP تلقائيًا ، قبل استدعاء برنامج التشغيل يحفظ سياق FPU ويتم إجراء المكالمة نفسها داخل كتلة try..except باستثناء):
using namespace KernelShells;
ولكن إلى جانب التدليل على الأصداف ، هناك أيضًا وظيفة جادة تسمح لك بإنشاء DLP بسيط استنادًا إلى النظام الفرعي لمرشحات الملف والكائن والمعالجة.
يسمح لك الإطار بتصفية
CreateFile /
ReadFile /
WriteFile /
DeviceIoControl ، بالإضافة إلى أحداث فتح / تكرار المقابض (
ObRegisterCallbacks ) وأحداث بدء العمليات / الخيوط وتحميل الوحدات (
PsSet *** NotifyRoutine ). سيسمح هذا ، على سبيل المثال ، بحظر الوصول إلى الملفات العشوائية أو استبدال معلومات حول الأرقام التسلسلية للقرص الثابت.
مبدأ العمل:
- يقوم برنامج التشغيل بتسجيل مرشحات الملفات وتثبيت عمليات الاسترجاع Ob *** / Ps ***
- يفتح برنامج التشغيل منفذ اتصال يتصل به العملاء الراغبون في الاشتراك في حدث
- يتم إرفاق تطبيقات وضع المستخدم بالمنفذ وتتلقى بيانات من برنامج التشغيل حول الحدث الذي حدث ، وإجراء التصفية (معالجات اقتطاع الحقوق ، ومنع الوصول إلى الملف ، وما إلى ذلك) وإعادة الحدث إلى kernel
- يقوم السائق بتطبيق التغييرات المستلمة.
مثال على الاشتراك في
ObRegisterCallbacks وقطع الوصول إلى العملية الحالية:
#include <Windows.h> #include <fltUser.h> #include "CommPort.h" #include "WdkTypes.h" #include "FltTypes.h" #include "Flt-Bridge.h" ... // ObRegisterCallbacks: CommPortListener<KB_FLT_OB_CALLBACK_INFO, KbObCallbacks> ObCallbacks; // PROCESS_VM_READ: Status = ObCallbacks.Subscribe([]( CommPort& Port, MessagePacket<KB_FLT_OB_CALLBACK_INFO>& Message ) -> VOID { auto Data = static_cast<PKB_FLT_OB_CALLBACK_INFO>(Message.GetData()); if (Data->Target.ProcessId == GetCurrentProcessId()) { Data->CreateResultAccess &= ~PROCESS_VM_READ; Data->DuplicateResultAccess &= ~PROCESS_VM_READ; } ReplyPacket<KB_FLT_OB_CALLBACK_INFO> Reply(Message, ERROR_SUCCESS, *Data); Port.Reply(Reply); // });
لذلك ، استعرضنا لفترة وجيزة النقاط الرئيسية للجزء الخاص بوضع المستخدم للإطار ، لكن واجهة برمجة التطبيقات الأساسية ظلت خلف الكواليس.
توجد جميع واجهات برمجة التطبيقات والأغلفة في المجلد المقابل:
/ Kernel-Bridge / API /وهي تشمل العمل مع الذاكرة ، والعمليات ، مع الأوتار والأقفال ، وأكثر من ذلك بكثير ، تبسيط تطوير برامج التشغيل الخاصة بهم إلى حد كبير. تعتمد واجهات برمجة التطبيقات والأغلفة على نفسها فقط ولا تعتمد على البيئة الخارجية: يمكنك استخدامها بحرية في برنامج التشغيل الخاص بك.
مثال على العمل مع الأوتار في النواة هو حجر عثرة لجميع المبتدئين:
#include <wdm.h> #include <ntstrsafe.h> #include <stdarg.h> #include "StringsAPI.h" WideString wString = L"Some string"; AnsiString aString = wString.GetAnsi().GetLowerCase() + " and another string!"; if (aString.Matches("*another*")) DbgPrint("%s\r\n", aString.GetData());
إذا كنت تريد تنفيذ معالجك الخاص لرمز IOCTL الخاص بك ، فيمكنك القيام بذلك بسهولة وفقًا للمخطط التالي:
- اكتب معالجًا في /Kernel-Bridge/Kernel-Bridge/IOCTLHandlers.cpp
- في نفس الملف ، أضف معالجًا إلى نهاية صفيف معالجات في دالة DispatchIOCTL
- قم بإضافة فهرس الاستعلام إلى تعداد Ctls :: KbCtlIndices في CtlTypes.h في الموقع نفسه كما في صفيف معالجات في العنصر 2
- اتصل بمعالجك من وضع المستخدم من خلال كتابة غلاف في User-Bridge.cpp ، وإجراء مكالمة باستخدام وظيفة KbSendRequest
يتم دعم جميع أنواع I / O الثلاثة (METHOD_BUFFERED و METHOD_NEITHER و METHOD_IN_DIRECT / METHOD_OUT_DIRECT) ، بشكل افتراضي ، يتم استخدام METHOD_NEITHER.
هذا كل شيء! تغطي المقالة جزءًا صغيرًا فقط من جميع الاحتمالات. آمل أن يكون الإطار مفيدًا للمطورين المبتدئين لمكونات kernel والمهندسين العكسيين ومطوري الغش ومكافحة الغش والحماية.
وأيضاً ، الجميع مدعو للمشاركة في التطوير. في الخطط المستقبلية:
- أغلفة للمعالجة المباشرة لسجلات PTE وإعادة توجيه الذاكرة النووية إلى وضع المستخدم
- الحاقنات بناءً على ميزات إنشاء تدفق APC الحالية وتسليمها
- منصة GUI للهندسة العكسية الحية وأبحاث Windows kernel
- محرك برمجة لتنفيذ قطع من كود النواة
- دعم SEH في الوحدات المحملة ديناميكيًا
- اجتياز اختبارات HLK
شكرا لكم على اهتمامكم!