Nt! KeWaitForSingleObject without Args

I'm currently trying to debug a system deadlock, and it's hard for me to figure it out.

Child-SP RetAddr : Args to Child : Call Site fffff880`035cb760 fffff800`02ecef72 : 00000000`00000002 fffffa80`066e8b50 00000000`00000000 fffffa80`066a16e0 : nt!KiSwapContext+0x7a fffff880`035cb8a0 fffff800`02ee039f : fffffa80`0b9256b0 00000000`000007ff 00000000`00000000 00000000`00000000 : nt!KiCommitThreadWait+0x1d2 fffff880`035cb930 fffff880`0312a5e4 : 00000000`00000000 fffff800`00000000 fffffa80`079a3c00 00000000`00000000 : nt!KeWaitForSingleObject+0x19 

Why should the first argument to KeWaitForSingleObject be null?

If I don’t understand, is this not the first argument to wait for an object? Is it just a dead end that this thread is not waiting for anything, or is this normal behavior?

In addition, I see another process (services.exe) showing a similar stack trace:

 1: kd> .thread fffffa800d406b50 Implicit thread is now fffffa80`0d406b50 1: kd> kv *** Stack trace for last set context - .thread/.cxr resets it Child-SP RetAddr : Args to Child : Call Site fffff880`09ed4800 fffff800`02ecef72 : fffffa80`0d406b50 fffffa80`0d406b50 00000000`00000000 fffff8a0`00000000 : nt!KiSwapContext+0x7a fffff880`09ed4940 fffff800`02ee039f : 00000000`000000b4 fffffa80`0b1df7f0 00000000`0000005e fffff800`031ae5e7 : nt!KiCommitThreadWait+0x1d2 fffff880`09ed49d0 fffff800`031d1e3e : fffffa80`0d406b00 00000000`00000006 00000000`00000001 00000000`093bf000 : nt!KeWaitForSingleObject+0x19f fffff880`09ed4a70 fffff800`02ed87d3 : fffffa80`0d406b50 00000000`77502410 fffff880`09ed4ab8 fffffa80`0b171a50 : nt!NtWaitForSingleObject+0xde 

Is this thread expected by itself?

+4
source share
2 answers

You are debugging a 64-bit process.

Remember the x64 calling convention described here . The first 4 arguments are passed to the registers. After that, the arguments are pushed onto the stack.

Unfortunately, kv blindly displays stack arguments. In fact, it would be rather difficult (and sometimes impossible) to determine which first 4 arguments were actually during the call, since they probably were not saved anywhere that can be restored.

So, you are looking at the 5th argument of nt!NtWaitForSingleObject , where nullptr is a fairly typical argument for Timeout .

Fortunately for us, debugging types, all is not lost! There is a windbg extension that does its best to restore arguments when calling a function. The extension is called CMKD . You can place the DLL extension in your winext folder and call it like this:

 0:000> !cmkd.stack -p Call Stack : 7 frames ## Stack-Pointer Return-Address Call-Site 00 000000a408c7fb28 00007ffda95b1148 ntdll!NtWaitForSingleObject+a Parameter[0] = 0000000000000034 Parameter[1] = 0000000000000000 Parameter[2] = 0000000000000000 Parameter[3] = (unknown) 01 000000a408c7fb30 00007ff7e44c13f1 KERNELBASE!WaitForSingleObjectEx+98 Parameter[0] = 0000000000000034 Parameter[1] = 00000000ffffffff Parameter[2] = 0000000000000000 Parameter[3] = 00007ff7e44cba28 02 000000a408c7fbd0 00007ff7e44c3fed ConsoleApplication2!main+41 Parameter[0] = (unknown) Parameter[1] = (unknown) Parameter[2] = (unknown) Parameter[3] = (unknown) 

Note that it is not always possible to find an argument, since some of them are (unknown) . But this is a good job and can be an invaluable tool when debugging 64-bit code.

+10
source

This is similar to a 64-bit OS, so the calling convention should not pass all the parameters on the stack. Rather, the first four parameters are passed to RCX, RDX, R8, and R9 with the rest of the parameters on the stack. Therefore, if you catch the KeWaitForSingleObject call, it will be easy for you to see what's in RCX and from there. After you select several frames of the stack, it is difficult to say, because something will be loaded into this register. The original value is probably stored somewhere, but it will be difficult to find.

+3
source

Source: https://habr.com/ru/post/1210176/


All Articles