We are tasked with decompiling the Windows Kernel routine
KeInitializeQueue.
Firstly, we obtain its disassembly:
Secondly, we consult MSDN for its signature:
1
2
3
4
| VOID KeInitializeQueue(
_Out_ PRKQUEUE Queue,
_In_ ULONG Count
);
|
The routine itself does not return anything.
We learn it takes two parameters and as the assembly contains the ret 8
instruction, the KeInitializeQueue
function cleans up the stack and thus, it uses the stdcall convention.
The KQUEUE
data structure is defined as follows:
1
2
3
4
5
6
7
8
| typedef struct _KQUEUE {
DISPATCHER_HEADER Header;
LIST_ENTRY EntryListHead;
ULONG CurrentCount;
ULONG MaximumCount;
LIST_ENTRY ThreadListHead;
} KQUEUE, *PKQUEUE, *RESTRICTED_POINTER PRKQUEUE;
|
In order to obtain the offsets for the struct parts, we query the data structure in WinDbg:
1
2
3
4
5
6
| 0: kd> dt nt!_KQUEUE
+0x000 Header : _DISPATCHER_HEADER
+0x010 EntryListHead : _LIST_ENTRY
+0x018 CurrentCount : Uint4B
+0x01c MaximumCount : Uint4B
+0x020 ThreadListHead : _LIST_ENTRY
|
Analogously, we investigate the data structure DISPATCHER_HEADER
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| 0: kd> dt nt!_DISPATCHER_HEADER
+0x000 Type : UChar
+0x001 TimerControlFlags : UChar
+0x001 Absolute : Pos 0, 1 Bit
+0x001 Coalescable : Pos 1, 1 Bit
+0x001 KeepShifting : Pos 2, 1 Bit
+0x001 EncodedTolerableDelay : Pos 3, 5 Bits
+0x001 Abandoned : UChar
+0x001 Signalling : UChar
+0x002 ThreadControlFlags : UChar
+0x002 CpuThrottled : Pos 0, 1 Bit
+0x002 CycleProfiling : Pos 1, 1 Bit
+0x002 CounterProfiling : Pos 2, 1 Bit
+0x002 Reserved : Pos 3, 5 Bits
+0x002 Hand : UChar
+0x002 Size : UChar
+0x003 TimerMiscFlags : UChar
+0x003 Index : Pos 0, 1 Bit
+0x003 Processor : Pos 1, 5 Bits
+0x003 Inserted : Pos 6, 1 Bit
+0x003 Expired : Pos 7, 1 Bit
+0x003 DebugActive : UChar
+0x003 ActiveDR7 : Pos 0, 1 Bit
+0x003 Instrumented : Pos 1, 1 Bit
+0x003 Reserved2 : Pos 2, 4 Bits
+0x003 UmsScheduled : Pos 6, 1 Bit
+0x003 UmsPrimary : Pos 7, 1 Bit
+0x003 DpcActive : UChar
+0x000 Lock : Int4B
+0x004 SignalState : Int4B
+0x008 WaitListHead : _LIST_ENTRY
|
The following page provides a clearer overview of the structure, which facilitates the comprehension: http://msdn.moonsols.com/win7rtm_x86/DISPATCHER_HEADER.html
The _LIST_ENTRY
structure, in contrast, has only a few members:
1
2
3
| 0: kd> dt nt!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
|
We try to translate it by introducing some additional variables:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| VOID KeInitializeQueue(
_Out_ PRKQUEUE Queue,
_In_ ULONG Count
)
{
Queue->Header.Type = 4;
Queue->Header.Size = 0x0A;
Queue->Header.Abandoned = 0;
Queue->Header.SignalState = 0;
Queue->Header.WaitListHead->Blink = &(Queue->WaitListHead);
Queue->Header.WaitListHead->Flink = &(Queue->WaitListHead);
Queue->EntryListHead->Blink = &(Queue->EntryListHead)
Queue->EntryListHead->Flink = &(Queue->EntryListHead)
Queue->ThreadListHead->Blink = &(Queue->ThreadListHead)
Queue->ThreadListHead->Flink = &(Queue->ThreadListHead)
if (Queue->CurrentCount != Count) {
Queue->MaximumCount = KeNumberProcessors();
}
else {
Queue->MaximumCount = Count;
}
}
|