
يلتقط رموز PIN الخاصة بـ Windows Hello عند إدخالها عبر حقن DLL في LogonUI.exe يضبط نقطة توقف عتادية لوحدة المعالجة المركزية على NgcSerializeConvenienceCredential، بالإضافة إلى مُعدِّد WHFB/NGC/TPM.
على مضيف يكون فيه Windows Hello محميًا بواسطة VBS/VSM (حاوية NgcIso معزولة في VTL1) + TPM، فإن PIN غير قابل للاسترداد دون اتصال والتخمين الآلي المباشر محظور بواسطة trustlet النواة الآمنة. المسار الموثوق الوحيد هو الالتقاط عند الإدخال.
يلتقط هذا المشروع PIN عبر وضع نقطة توقف عتادية للمعالج على الدالة التي
تحزم PIN المكتوب داخل LogonUI.exe، وقراءة الوسيط من سياق الخيط المحتجز
في Vectored Exception Handler، والسماح للتعليمة الأصلية غير المعدّلة بالتنفيذ،
بحيث ينجح تسجيل الدخول بـ PIN بشكل طبيعي.
كما يوفّر Get-WHFBKeys.ps1، وهو أداة كاملة لتعداد WHFB/NGC/TPM وجمع المواد المفتاحية.
تم التحقق منه من البداية إلى النهاية على Windows 11 26200 (Home) مع Intel fTPM 2.0 وVBS قيد التشغيل.
| الحماية الملاحظة | النتيجة |
|---|---|
VBS / VSM قيد التشغيل (حالة VBS في Win32_DeviceGuard = 2، LsaIso.exe موجود) | التسلسل الهرمي للمفاتيح يعيش في VTL1 (النواة الآمنة)، غير قابل للوصول من SYSTEM في VTL0 |
حاوية NgcIso (NgcIsoHeader_… في Container.json / كتل الحامي NgcIsoCtnr.dll المحمّلة في NgcSvc) | سر PIN يُفكّ داخل trustlet، وليس في وضع المستخدم العادي |
مواد رئيسية مختومة بـ TPM (srk في Container.json، نوع المفتاح impl) | لا يوجد مفتاح نصي صريح على القرص، وفك الختم يتطلب TPM |
مكافحة التخمين (softLockoutAttemptLimit = 5، sealedLockoutAuth في Protectors.json) | التخمين المباشر يؤدي إلى القفل، والعدّاد يُفرض بواسطة VTL1، وغير قابل لإعادة الضبط من القرص |
عند شاشة القفل / تسجيل الدخول، يُكتب PIN في موفّر بيانات اعتماد NGC المستضاف بواسطة
LogonUI.exe (يعمل كـ SYSTEM، وليس PPL، ويُشغَّل عند الطلب). يسلّم الموفّر
PIN المكتوب إلى ngckeyenum.dll!NgcSerializeConvenienceCredential، حيث يشير arg1 (RCX) إلى:
struct { // arg1
uint64_t type; // 1 (convenience-PIN credential)
void* buffer; // -> ASCII PIN, e.g. 0x32 0x30 0x30 0x32 = "2002" example PIN
uint32_t length; // digit count (e.g. 4)
};
// arg2 = full NGC key name "S-1-5-...-1001/<container-guid>//<key-guid>"
// arg3 = username, arg4 = computername, arg5 = SID, arg6 = "Negotiate"
الاعتراض الكلاسيكي من نوع inline/trampoline على NgcSerializeConvenienceCredential (أو على
NgcPackAuthBuffer) يُفسد بيانات اعتماد تسجيل الدخول المُسلسلة. العَرَض خبيث وصامت:
شاشة تسجيل الدخول تُعاد تحميلها فقط دون أي خطأ، ويُرفض رمز PIN الصحيح، والرفض المتكرر
يُقفل رمز PIN مؤقتًا (مما يفرض تسجيل الدخول بكلمة المرور). كما أن إنهاء NgcSvc بالقوة
يُعطّل الحاوية بالمثل.
نحتاج إلى أداة التقاط بدائية تقرأ الوسيط دون تغيير بايت واحد من الشيفرة أو من تدفق التحكم للدالة الهدف.
تُحقن ngccap.dll (انظر src/ngccap.c) في LogonUI.exe وتقوم بما يلي:
تسليح نقطة توقف تنفيذ عتادية في المعالج. تحلّ
ngckeyenum!NgcSerializeConvenienceCredential، ثم تضبط DR0 = الهدف و
DR7 = L0 | exec | len-1 على كل خيط في العملية (عبر
CreateToolhelp32Snapshot → OpenThread → SuspendThread → GetThreadContext /
SetThreadContext مع CONTEXT_DEBUG_REGISTERS → ResumeThread).
معالجة الفخ في معالج استثناءات موجّه (Vectored Exception Handler). عند دخول الدالة،
يرفع المعالج EXCEPTION_SINGLE_STEP قبل تنفيذ التعليمة. يتحقق الـ VEH من
ContextRecord->Rip == target، ويقرأ Rcx → {buffer, length}، وينسخ رمز PIN بصيغة ASCII،
ثم:
EFlags حتى لا تُطلق نقطة التوقف نفسها فورًا مجددًا، وEXCEPTION_CONTINUE_EXECUTION.تُنفَّذ التعليمة الأصلية دون تعديل. لأنه لم تُرقَّع أي شيفرة ولم يُضَف أي
trampoline/إطار مكدس إضافي، فإن NgcSerializeConvenienceCredential تُنفَّذ
تمامًا كما كانت ستفعل. تُبنى بيانات الاعتماد بشكل صحيح، ويقبلها LSA، و
ينجح تسجيل الدخول بـ PIN بشكل طبيعي.
تنظيف ذاتي. بعد أول عملية التقاط، تمسح مكتبة DLL قيم DR0/DR7 على جميع الخيوط وتزيل الـ VEH، تاركةً العملية في حالتها الأصلية النقية.
WHFB-PIN-Capture/
├─ README.md
├─ Get-WHFBKeys.ps1 # WHFB/NGC/TPM enumerator + key-material harvester
└─ src/
├─ ngccap.c # HW-breakpoint capture DLL
├─ build.bat # cl.exe build (MSVC 2022 Build Tools)
└─ logonui_watch.ps1 # injects ngccap.dll into LogonUI on sight
SeDebugPrivilege). يعمل LogonUI بصلاحيات
SYSTEM لكنه ليس PPL، لذا يمكن لرمز مسؤول مرتفع الصلاحيات فتحه والحقن فيه.:: 1) build the capture DLL
cd src
build.bat
:: 2) start the injector (elevated admin PowerShell)
powershell -ExecutionPolicy Bypass -File .\logonui_watch.ps1
3) Lock the workstation (Win+L) and sign back in with your PIN, it works normally.
4) Read the captured PIN:
type C:\Windows\Temp\pin_capture.log
-> >>> PIN CAPTURED = "1234"
المسارات قابلة للتهيئة: يجب أن يتطابق LOGPATH في أعلى ngccap.c و$plog في logonui_watch.ps1
(القيمة الافتراضية C:\Windows\Temp\pin_capture.log).
يُبلّغ Get-WHFBKeys.ps1 عن حالة TPM، والانضمام إلى الجهاز / تزويد NGC، وسياسة WHFB، ومخزن
حاويات NGC على القرص (الحاويات ← الحماة ← المفاتيح، مع رفع الصلاحيات ذاتيًا إلى SYSTEM)، ومفاتيح NCrypt
(Passport KSP / Platform Crypto Provider / Software KSP مع تصدير المفتاح العام)، وتسجيل
القياسات الحيوية، مع إصدار تقرير JSON. لا يستخرج أبدًا المفاتيح الخاصة (المختومة بـ TPM، غير القابلة للتصدير)؛
بل يقوم بتفريغ المفاتيح العامة والبيانات الوصفية وكائنات الحماية الثنائية الموجودة على القرص.
powershell -ExecutionPolicy Bypass -File .\Get-WHFBKeys.ps1 -DumpBlobs -OutDir .\out
المسارات غير المتصلة بالإنترنت ومسارات القوة الغاشمة ثبت أنها مغلقة، وتم التقاط رمز PIN بينما سجّل المالك الدخول بشكل طبيعي باستخدام رمز PIN الصحيح باستخدام DLL الخاص بنقطة التوقف العتادية.
للاستخدام التعليمي وأغراض أبحاث الأمن المصرّح بها فقط. دون أي ضمان.