Since my breakpoints were at User32's WaitMessageWhatever return, this would happen if my mouse went over the window, giving the cool effect that the frozen target was still alive, detecting my efforts in real time. So what to do now?
- checked windbg on another machine, then olly - all tests exhibit same behavior
- compared PEB and TIB before and after the protection looking for some magical flag setting crap that the target may be doing.... no big differences
- the target loads drivers, so fearing some rootkit behavior, compared nt!KiTrap03 before and after the protection, no changes
- continuing this way, compared nt!CommonDispatchException and then nt!KiDispatchException, still no differences
- using the leaked Windows 2000 source (from torrent), omeg's fine comments on KiDispatchException (http://omeg.pl/code/XP_32_KiDispatchException.txt) and ReactOS (http://doxygen.reactos.org/blah/blah) it was easy to create an annotated IDA listing of my particular ontkrnlpa.exe
- traced the difference to a call to nt!DbgkForwardException which would return 0 during the protection - tracing is a little complicated by the way: KiDispatchException is part of the logic path that eventually communicates with KD itself - it splits into two paths several times depending on whether the exception came from user or kernel mode - obviously you can only use KD (insert BP, single-step) on the user mode paths otherwise the CPU will loop, interrupting on the same BP continuously
- tracing into this, found this crap:
nt!DbgkForwardException+0x2b: 80639e31 64a124010000 mov eax,dword ptr fs:[00000124h] 80639e37 f6804802000004 test byte ptr [eax+248h],4 80639e3e 7404 je nt!DbgkForwardException+0x3e (80639e44) ; success 80639e40 33c0 xor eax,eax ; zero return value, indicating failure
this value was 4 during the protection, so the je/jz was skipped and the failure path taken - patching this in memory allowed breakpoints and stepping to happen!
- so wtf is this check? ReactOS again is indispensible, with its code for DbgkForwardException - didn't take much to match this up:
00338 /* Check if this is to be sent on the debug port */ 00339 if (DebugPort) 00340 { 00341 /* Use the debug port, unless the thread is being hidden */ 00342 Port = PsGetCurrentThread()->HideFromDebugger ? 00343 NULL : Process->DebugPort; 00344 }
- finally, googled for this HideFromDebugger and found ivanlef0u's page (http://www.ivanlef0u.tuxfamily.org/?p=48) where he explains this protection completely over 3 years ago! man am I behind!
Oct 22, 2010 EDIT: upb sent me this rootkit.com link dating back to 2005 so this may not be news to anybody
very interesting post! talk about it later. greetings!
ReplyDelete