Kayaker
September 27th, 2006, 18:27
That's interesting Maximus. I didn't know the product existed, it looks pretty impressive (ouch - Oreans).
I've made a few more attempts at trying to figure out how/why the sptd driver is not 'compatible' with Softice. It's now apparent the DriverEntry routine at least is wrapped in CV. I haven't done any testing to see if CV alone detects the presence of a kernel debugger, but it's apparent that one way or another sptd "reacts" to the presence of a KD and modifies it's behaviour.
One of the things I noticed is that sptd uses PsSetLoadImageNotifyRoutine to detect when certain modules are loaded, notably ntdll and winlogon.exe. Under the 'modified' conditions I gave above of loading sptd *after* Sice you can trace this routine for debugging purposes.
(Sidenote: Actually there is a jump table used and some addresses point to 'false' routines (i.e. a RET instead of the correct LoadImageNotifyRoutine callback), but the jump table can be 'corrected' to point to the proper (virgin) addresses).
Anyway, under "goodboy" conditions, there exists a LoadImageNotifyRoutine Callback, all is rosy in the world of the app. Under "badboy" conditions, say you boot VMWare with WinDbg kernel debugger active, then this Callback is never created!
So, not surprisingly, debugger detection leads to modified behaviour. Since this modified behaviour can be subtle or dramatic (i.e. no NotifyRoutine callback), and all occurs during boot loading, it would be just about impossible to "fix" the program after the fact.
I'll explain how I determined this business with the LoadImageNotifyRoutine Callback since it's not something normally easily detected, especially without a kernel debugger.
The PsSetLoadImageNotifyRoutine routine registers a driver-supplied callback that is subsequently notified whenever an image is loaded for execution. There exists a table of callbacks (maximum of 8), which are located at an unexported variable address in ntoskrnl, _PspLoadImageNotifyRoutine. Another variable holds the number of callbacks, _PspLoadImageNotifyRoutineCount. The callbacks themselves, if present, are executed through PsCallImageNotifyRoutines during process initialization, also at other times such as if ZwMapViewOfSection is used. A callback will be called for any usermode module or for a driver module not loaded from a system process.
To determine if a _PspLoadImageNotifyRoutine callback table existed, under the conditions of not having a kernel debugger handy, I used two utilities. One is LiveKD. The other is a simple full-text kernel mode disassembler I wrote quite some time ago. This allowed me to disassemble a known exported function in order to find the address for the unexported _PspLoadImageNotifyRoutine callback table variable. Then I used LiveKD to view that address, confirming whether there was an active callback or not.
First step was to understand what to look for in IDA with symbols loaded:
Code:
PAGE:005554F7 _PsSetLoadImageNotifyRoutine@4 proc near
PAGE:005554F7 mov edi, edi
...
PAGE:00555517 mov esi, offset _PspLoadImageNotifyRoutine
The second step was to "live" disassemble this routine by name
and find the address of the callback table:
Code:
>kdasm df PsSetLoadImageNotifyRoutine
1 8062C4F7 8bff mov edi,edi
...
16 8062C517 be000d5680 mov esi,80560d00 // _PspLoadImageNotifyRoutine
The third step was to display the _PspLoadImageNotifyRoutine address with LiveKD.
The address is actually at _PspLoadImageNotifyRoutineCount, which is just before
the callback table itself (8 dwords):
Code:
kd> dd 80560ce8
80560ce8 00000001 00000000 00000000 00000000
80560cf8 00000000 00000000 e139204f 00000000
80560d08 00000000 00000000 00000000 00000000
80560d18 00000000 00000000
The "address" e139204f is not actually a direct address of the SPTD NotifyRoutine callback, but can be easily calculated from it. (In Win2K it would be a true address, but this changed slightly in XP and above).
Now if you were to do the exact same thing with the WinDbg kernel debugger active, you would find that the SPTD driver never creates the above callback routine and the table would be empty. Bye bye normal operation..
Anyway, hope that's a somewhat interesting tidbit, though it doesn't really accomplish a hell of a lot. If interested, the kernel mode disassembler I wrote is attached, I released it a couple of years ago at rootkit.com. It's based on the NASM disassembler, for years I've used that source code compiled into a usermode dll for disassembly projects, this time I compiled it into a kernel mode dll to give full-text kernel disassembly as well. It will disassemble by address or ntoskrnl function name. Full VC++ source and explanations included.
Thanks again for the heads up on the VM!
Cheers,
Kayaker