Tuesday, July 2, 2013

Time slip DPC kernel debugger detection


Been quite awhile since my last entry. Spent some time in Key West, FL and spent some more time moving to the other side of town. I have a some fun things to post about over the next month or so. So stay tuned ;p

When a kernel debugger can attach to the system (KdPitchDebugger == 0) the possibility exists for software (usermode included) to implement an event object type to be set to the signaled state when a time slip occurs. In this context, a time slip occurs because an exception that is passed to the kernel debugger puts all logical processors in a wait state with interrupts masked off.

No external interrupts from timing chips (pit, hpet) can occur. Thus when the logical processor(s) are continued, the machine is living in the past so to speak. Time keeps on slippin slippin slippin...

But..

Prior to exiting the debugger, KdExitDebugger will insert the KdpTimeSlipDpc DPC object into the processor's DPC queue. This DPC will queue a passive level work item routine (KdpTimeSlipWork) which will set a provided event object to the signaled state, if one is provided. User level software can set this field with NtSetSystemInformation with an infoclass of 0x2E. The windows time service
in particular sets this field when it starts up, that is, if the service is running. However it can still be reset. I haven't really looked over the windows time service but my guess is that when and if it is notified of a time slip, that it probably attempts to synchronize the system back over NTP, but who knows.. haven't looked.

We can be sure that if this DPC is fired that a kernel debugger is attached to the system because the only way the initial DPC can be queued is via KdExitDebugger. Control flow cannot reach that point unless an exception occured which was forwarded to the debugger.

The passive level work routine will queue another timer based DPC object with KiSetTimer with a hardcoded duetime of 94B62E00. This value is relative to the system clock at 179999999900 nanoseconds, or every 180 seconds (3 minutes ;p) that it will attempt to set your provided event
object to the signaled state.

Please note this requires the SeSystemtimePrivilege privilege.

Quick example for clarity:

HANDLE a1=CreateEvent(NULL,FALSE,FALSE,NULL);

NtSetSystemInformation(0x2E,&a1,8);

if(WaitForSingleObject(a1,1)==WAIT_OBJECT_0)  //kernel debugger attached

No comments:

Post a Comment