## Sunday, 30 July 2017

### Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 7

Exercise 7 on page 35:

Sample H. The function sub_10BB6 has a loop searching for something.
First recover the function prototype and then infer the types based on the
context. Hint: You should probably have a copy of the PE specifi cation
nearby.

Due to alignment issues, our routine is located at 10BB2 and has the following disassembly:

sub_10BB2:

mov     eax, [esp+4]
push    ebx
push    esi
mov     esi, [eax+3Ch]
movzx   eax, word ptr [esi+14h]
xor     ebx, ebx
cmp     [esi+6], bx
push    edi
lea     edi, [eax+esi+18h]
jbe     short loc_10BEB

loc_10BCE:
push    [esp+0Ch+arg_4]
push    edi
call    ds:dword_169A4
test    eax, eax
pop     ecx
pop     ecx
jz      short loc_10BF3
movzx   eax, word ptr [esi+6]
inc     ebx
cmp     ebx, eax
jb      short loc_10BCE

loc_10BEB:
xor     eax, eax

loc_10BED:
pop     edi
pop     esi
pop     ebx
retn    8

loc_10BF3:
mov     eax, edi
jmp     short loc_10BED

The PE file format and offsets have been described in detail here: http://www.sunshine2k.de/reversing/tuts/tut_pe.htm

Other useful sites are:

http://www.csn.ul.ie/~caolan/pub/winresdump/winresdump/doc/pefile2.html
https://github.com/corkami/pics/blob/master/binary/pe101/pe101.pdf
https://sourceforge.net/p/mingw/mingw-org-wsl/ci/master/tree/include/winnt.h

Firstly, we notice that the program contains the statement retn 8, which means it takes two arguments that are passed on the stack. Thus, its abstract prototype looks as follows:

sub_10BB2(param1, param2);

The first parameter seems to be a pointer that fetches a value from the offset 0x3C. Looking at the PE file format specification, we see the offset at 0x3C of the DOS header structure contains a pointer to the PE header structure. Therefore, we assume that param1 points to a DOS header file structure.

We refine the function prototype to:

Below, the disassembly including the provisional decompilation is provided:

mov     eax, [esp+4]   // function has first argument at esp+4, which means it is located on the stack
push    ebx
push    esi
mov     esi, [eax+3Ch] // long offsetpeheader = PIMAGE_DOS_HEADER->lfanew;
xor     ebx, ebx // int countSections = 0;
cmp     [esi+6], bx   // word numSections = pNtHeaders->FileHeader.NumberOfSections
push    edi      // save edi for later
lea     edi, [eax+esi+18h]  // int* sectionTable = pNtHeaders->OptionalHeader + sizeOptHeader; AND! the end address is immediately the beginning of the new
data structure, i.e. the first section! SectionTable is located at offset(OptionalHeader) + SizeOfOptionalHeader
jbe     short loc_10BEB   // when we have no sections (countSections == numSections) , go to exit routine

loc_10BCE:
push    dword ptr [esp+14h]
push    edi
call    ds:dword_169A4 // dword_169A4(sectionTable, param2)
test    eax, eax // check if returned 0
pop     ecx // pop value from stack to ecx
pop     ecx // pop value from stack to ecx
jz      short loc_10BF3 // if eax == 0 , jump
movzx   eax, word ptr [esi+6] // reload number of Header
add     edi, 28h // sectionTable += 0x28; // one section table has a size of 0x28 bytes (40 bytes)
inc     ebx // countSections += 1;
cmp     ebx, eax // if countSections < numSections goto loc_10BCE:
jb      short loc_10BCE

loc_10BEB:
xor     eax, eax // int* retVal = 0;

loc_10BED:
// clean up stack (stdcall convention)
pop     edi
pop     esi
pop     ebx
retn    8    // function has two parameters, 2 x 4 bytes

loc_10BF3:
mov     eax, edi // int* retVal = sectionTable;
jmp     short loc_10BED

Finally, we arrive at the following decompiled function:

int countSections = 0;

while (countSections < numSections) {
int retVal = dword_169A4(sectionTablePtr, param2); // call unknown function
if (retVal == 0) {
return sectionTablePtr;
}

sectionTablePtr += 0x28; // get the next sectionTable
countSections += 1; // set the number of processed sections
}

return 0; // we have not found the target section

}

## Saturday, 22 July 2017

### Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 6

Exercise 6 on page 35 of the book Practical Reverse Engineering presents us with a malware samples.
These can be downloaded at the following page:

In this exercise, we are expected to have a look at the following routine sub_13842:

.text:00013842 sub_13842
.text:00013842                 mov     eax, [ecx+60h]
.text:00013845                 push    esi
.text:00013846                 mov     esi, [edx+8]
.text:00013849                 dec     byte ptr [ecx+23h]
.text:0001384C                 sub     eax, 24h
.text:0001384F                 mov     [ecx+60h], eax
.text:00013852                 mov     [eax+14h], edx
.text:00013855                 movzx   eax, byte ptr [eax]
.text:00013858                 push    ecx
.text:00013859                 push    edx
.text:0001385A                 call    dword ptr [esi+eax*4+38h]
.text:0001385E                 pop     esi
.text:0001385F                 retn

Firstly, we see that the function prototype takes two parameters, which are not saved on the stack but in the two registers ecx and edx. This can be deducted from the fact that these two registers are immediately referenced without prior initialization.
On a very high abstraction level, the function prototype looks as follows:

sub_13842(struct1* a, struct2* b);

Moreover, we see that edx+8 points to some kind of base address, as it is used to compute the address of the function called on the following line:

.text:0001385A                 call    dword ptr [esi+eax*4+38h]

Both parameters edx and ecx obviously point to some kind of data structure, whose contents we are about to reveal:

struct1:
offset+60: struct3*: s3
offset+23: char: unknown0x23

struct2:
offset+08: void*: here we have some kind of trampoline / array of function pointers

struct3:
offset+00: char: index
offset+14: struct2*: s2

struct4:
offset+38: int*: unknown

sub_13842(struct1* a, struct2* b)

.text:00013842 sub_13842
.text:00013842                 mov     eax, dword ptr[ecx+60h] // struct3* v1 = a->s3;
.text:00013845                 push    esi // just save esi register value
.text:00013846                 mov     esi, [edx+8] // void* v2 = b->unknown0x8
.text:00013849                 dec     byte ptr [ecx+23h] // a->unknown0x23 = a->unknown0x23 - 1;
.text:0001384C                 sub     eax, 24h // v1 = v1 - 0x24;
.text:0001384F                 mov     [ecx+60h], eax // a->s3 = v1;
.text:00013852                 mov     [eax+14h], edx // v1->s2 = b;
.text:00013855                 movzx   eax, byte ptr [eax] // char index = v1->index;
.text:00013858                 push    ecx
.text:00013859                 push    edx // call fct(
.text:0001385A                 call    dword ptr [esi+eax*4+38h] // call b->unknown0x8+0x38h[index](b, a)
.text:0001385E                 pop     esi
.text:0001385F                 retn

Overall, the decompiled code looks as follows:

sub_13842(struct1* a, struct2* b) {

struct3* v1 = a->s3;
void* v2 = b->unknown0x8;
a->unknown0x23 = a->unknown0x23 -1;
v1 = v1 - 0x24;
a->s3 = v1;
v1->s2 = b;
char index = v1->index;
b->unknown0x8+0x38h[index](b, a);

}

## Sunday, 16 July 2017

### Practical Reverse Engineering Exercise Solutions: RtlValidateUnicodeString

This blog post contains my solution for the decompilation exercise of the RtlValidateUnicodeString function in the Windows Kernel. The following contains the disassembly without annotations:

kd> uf rtlvalidateunicodestring
ntdll!RtlValidateUnicodeString:
77686f6c 8bff            mov     edi,edi
77686f6e 55              push    ebp
77686f6f 8bec            mov     ebp,esp
77686f71 837d0800        cmp     dword ptr [ebp+8],0
77686f75 0f85fc380300    jne     ntdll!RtlValidateUnicodeString+0xb (776ba877)

ntdll!RtlValidateUnicodeString+0x12:
77686f7b 6800010000      push    100h
77686f80 ff750c          push    dword ptr [ebp+0Ch]
77686f83 e809000000      call    ntdll!RtlUnicodeStringValidateEx (77686f91)

ntdll!RtlValidateUnicodeString+0x1f:
77686f88 5d              pop     ebp
77686f89 c20800          ret     8

ntdll!RtlValidateUnicodeString+0xb:
776ba877 b80d0000c0      mov     eax,0C000000Dh
776ba87c e907c7fcff      jmp     ntdll!RtlValidateUnicodeString+0x1f (77686f88)

The function prototype is given here:

NTSTATUS NTAPI RtlValidateUnicodeString(IN ULONG Flags, IN PCUNICODE_STRING UnicodeString);

Note that the function returns a NTSTATUS value, which is publicly documented by Microsoft at https://msdn.microsoft.com/en-us/library/cc704588.aspx.

Other relevant data structures are _unicode_string:

kd> dt nt!_unicode_string
+0x000 Length           : Uint2B
+0x002 MaximumLength    : Uint2B
+0x004 Buffer           : Ptr32 Uint2B

The following listing gives the disassembly with my annotations / comments:

kd> uf rtlvalidateunicodestring
ntdll!RtlValidateUnicodeString:
; hot-patch point
77686f6c 8bff            mov     edi,edi

; function prologue
77686f6e 55              push    ebp
77686f6f 8bec            mov     ebp,esp

; check if Flags are set to zero
77686f71 837d0800        cmp     dword ptr [ebp+8],0
77686f75 0f85fc380300    jne     ntdll!RtlValidateUnicodeString+0xb (776ba877)

; Flags are set to  zero
ntdll!RtlValidateUnicodeString+0x12:

77686f7b 6800010000      push    100h
77686f80 ff750c          push    dword ptr [ebp+0Ch]
; call RtlUnicodeStringValidateEx(UnicodeString, 0x100)
77686f83 e809000000      call    ntdll!RtlUnicodeStringValidateEx (77686f91)

ntdll!RtlValidateUnicodeString+0x1f:
; function epilogue
77686f88 5d              pop     ebp
77686f89 c20800          ret     8

ntdll!RtlValidateUnicodeString+0xb:
; flags are not set to zero
776ba877 b80d0000c0      mov     eax,0C000000Dh
Function return value is set to 0x0C000000D
776ba87c e907c7fcff      jmp     ntdll!RtlValidateUnicodeString+0x1f (77686f88)

Finally, the decompiled function is provided:

NTSTATUS NTAPI RtlValidateUnicodeString(IN ULONG Flags, IN PCUNICODE_STRING UnicodeString){
if (Flags != 0) {
return 0x0C000000D // corresponding NTSTATUS: STATUS_INVALID_PARAMETER
}
RtlUnicodeStringValidateEx(UnicodeString, 0x100);
return
}

### Practical Reverse Engineering Exercise Solutions: LiveKd / WinDbg Cheat Sheet

Here are a couple of commands I regularly use for reverse engineering:

uf <function>: Unassemble function
dt nt!_ktss: Show the definition of the data structure _ktss
?? sizeof(_ktss): Show the size the data structure _ktss occupies in memory
.hh uf: Show help for the function uf
x nt!*createfile*: Search all functions having the string "createfile" in its name
!vtop <PDPT-pointer> <virtualAddress>: Compute physical address of given virtual address and the pointer to the page directory pointer table

### Practical Reverse Engineering Exercise Solutions: KiInitializeTSS

Another exercise for us is the decompilation of the KiInitializeTSS function:

nt!KiInitializeTSS:
82847359 8bff            mov     edi,edi
8284735b 55              push    ebp
8284735c 8bec            mov     ebp,esp
8284735e 8b4508          mov     eax,dword ptr [ebp+8]
82847361 b9ac200000      mov     ecx,20ACh
82847366 66894866        mov     word ptr [eax+66h],cx
8284736a 33c9            xor     ecx,ecx
8284736c 6a10            push    10h
8284736e 66894864        mov     word ptr [eax+64h],cx
82847372 66894860        mov     word ptr [eax+60h],cx
82847376 59              pop     ecx
82847377 66894808        mov     word ptr [eax+8],cx
8284737b 5d              pop     ebp
8284737c c20400          ret     4

We obtain the function prototype: (source)

VOID
NTAPI
KiInitializeTSS(IN PKTSS Tss)
{
}

Structure of _KTSS:

kd> dt nt!_ktss
+0x000 Backlink         : Uint2B
+0x002 Reserved0        : Uint2B
+0x004 Esp0             : Uint4B
+0x008 Ss0              : Uint2B
+0x00a Reserved1        : Uint2B
+0x00c NotUsed1         : [4] Uint4B
+0x01c CR3              : Uint4B
+0x020 Eip              : Uint4B
+0x024 EFlags           : Uint4B
+0x028 Eax              : Uint4B
+0x02c Ecx              : Uint4B
+0x030 Edx              : Uint4B
+0x034 Ebx              : Uint4B
+0x038 Esp              : Uint4B
+0x03c Ebp              : Uint4B
+0x040 Esi              : Uint4B
+0x044 Edi              : Uint4B
+0x048 Es               : Uint2B
+0x04a Reserved2        : Uint2B
+0x04c Cs               : Uint2B
+0x04e Reserved3        : Uint2B
+0x050 Ss               : Uint2B
+0x052 Reserved4        : Uint2B
+0x054 Ds               : Uint2B
+0x056 Reserved5        : Uint2B
+0x058 Fs               : Uint2B
+0x05a Reserved6        : Uint2B
+0x05c Gs               : Uint2B
+0x05e Reserved7        : Uint2B
+0x060 LDT              : Uint2B
+0x062 Reserved8        : Uint2B
+0x064 Flags            : Uint2B
+0x066 IoMapBase        : Uint2B
+0x068 IoMaps           : [1] _KiIoAccessMap
+0x208c IntDirectionMap  : [32] UChar

Translaction to C:

VOID NTAPI iInitializeTSS(IN PKTSS Tss)
{
Tss->IoMapBase = 0x20AC;
Tss->Flags = 0;
Tss->LDT = 0;
Tss->Ss0 = 0x10;
}

Although we are technically done with the decompilation, it is worthwhile to note the meaning of the hexadecimal values.
While hexadecimal 0x10 is 16 in decimal notation, 0x20AC is 8364.

We can obtain the size of the data structure _KTSS in WinDbg with the following command. The size coincides with the value assigned to IoMapBase:

kd> ?? sizeof(_KTSS)
unsigned int 0x20ac

### Practical Reverse Engineering Exercise Solutions: KeReadyThread

Unfortunately I had no time in the past days to continue with the exercises. We continue with the decompilation of the KeReadyThread function in Windows 7.

The following listing shows the disassembly:

828a8125 8bff            mov     edi,edi
828a8127 56              push    esi
828a8128 8bf0            mov     esi,eax
828a812a 8b4650          mov     eax,dword ptr [esi+50h]
828a812d 8b4874          mov     ecx,dword ptr [eax+74h]
828a8130 f6c107          test    cl,7

828a8135 e8b74af8ff      call    nt!KiInSwapSingleProcess (8282cbf1)
828a813a 84c0            test    al,al

828a8143 5e              pop     esi
828a8144 c3              ret

According to this source, it has the following prototype:

VOID
)

So, the function KeReadyThread takes one parameter, but does not reference it with the ebp register and the last instruction is a simple RET. The PKTHREAD structure is given below:

0: kd> dt nt!_kthread
+0x010 CycleTime        : Uint8B
+0x018 HighCycleTime    : Uint4B
+0x020 QuantumTarget    : Uint8B
+0x028 InitialStack     : Ptr32 Void
+0x02c StackLimit       : Ptr32 Void
+0x030 KernelStack      : Ptr32 Void
+0x034 ThreadLock       : Uint4B
+0x038 WaitRegister     : _KWAIT_STATUS_REGISTER
+0x039 Running          : UChar
+0x03a Alerted          : [2] UChar
+0x03c KernelStackResident : Pos 0, 1 Bit
+0x03c ReadyTransition  : Pos 1, 1 Bit
+0x03c ProcessReadyQueue : Pos 2, 1 Bit
+0x03c WaitNext         : Pos 3, 1 Bit
+0x03c SystemAffinityActive : Pos 4, 1 Bit
+0x03c Alertable        : Pos 5, 1 Bit
+0x03c GdiFlushActive   : Pos 6, 1 Bit
+0x03c UserStackWalkActive : Pos 7, 1 Bit
+0x03c ApcInterruptRequest : Pos 8, 1 Bit
+0x03c ForceDeferSchedule : Pos 9, 1 Bit
+0x03c QuantumEndMigrate : Pos 10, 1 Bit
+0x03c UmsDirectedSwitchEnable : Pos 11, 1 Bit
+0x03c TimerActive      : Pos 12, 1 Bit
+0x03c SystemThread     : Pos 13, 1 Bit
+0x03c Reserved         : Pos 14, 18 Bits
+0x03c MiscFlags        : Int4B
+0x040 ApcState         : _KAPC_STATE
+0x040 ApcStateFill     : [23] UChar
+0x057 Priority         : Char
+0x058 NextProcessor    : Uint4B
+0x05c DeferredProcessor : Uint4B
+0x060 ApcQueueLock     : Uint4B
+0x064 ContextSwitches  : Uint4B
+0x068 State            : UChar
+0x069 NpxState         : Char
+0x06a WaitIrql         : UChar
+0x06b WaitMode         : Char
+0x06c WaitStatus       : Int4B
+0x070 WaitBlockList    : Ptr32 _KWAIT_BLOCK
+0x074 WaitListEntry    : _LIST_ENTRY
+0x074 SwapListEntry    : _SINGLE_LIST_ENTRY
+0x07c Queue            : Ptr32 _KQUEUE
+0x080 WaitTime         : Uint4B
+0x084 KernelApcDisable : Int2B
+0x086 SpecialApcDisable : Int2B
+0x084 CombinedApcDisable : Uint4B
+0x088 Teb              : Ptr32 Void
+0x090 Timer            : _KTIMER
+0x0b8 AutoAlignment    : Pos 0, 1 Bit
+0x0b8 DisableBoost     : Pos 1, 1 Bit
+0x0b8 EtwStackTraceApc1Inserted : Pos 2, 1 Bit
+0x0b8 EtwStackTraceApc2Inserted : Pos 3, 1 Bit
+0x0b8 CalloutActive    : Pos 4, 1 Bit
+0x0b8 ApcQueueable     : Pos 5, 1 Bit
+0x0b8 EnableStackSwap  : Pos 6, 1 Bit
+0x0b8 GuiThread        : Pos 7, 1 Bit
+0x0b8 UmsPerformingSyscall : Pos 8, 1 Bit
+0x0b8 VdmSafe          : Pos 9, 1 Bit
+0x0b8 UmsDispatched    : Pos 10, 1 Bit
+0x0b8 ReservedFlags    : Pos 11, 21 Bits
+0x0b8 ThreadFlags      : Int4B
+0x0bc ServiceTable     : Ptr32 Void
+0x0c0 WaitBlock        : [4] _KWAIT_BLOCK
+0x120 QueueListEntry   : _LIST_ENTRY
+0x128 TrapFrame        : Ptr32 _KTRAP_FRAME
+0x12c FirstArgument    : Ptr32 Void
+0x130 CallbackStack    : Ptr32 Void
+0x130 CallbackDepth    : Uint4B
+0x134 ApcStateIndex    : UChar
+0x135 BasePriority     : Char
+0x136 PriorityDecrement : Char
+0x136 ForegroundBoost  : Pos 0, 4 Bits
+0x136 UnusualBoost     : Pos 4, 4 Bits
+0x137 Preempted        : UChar
+0x138 AdjustReason     : UChar
+0x139 AdjustIncrement  : Char
+0x13a PreviousMode     : Char
+0x13b Saturation       : Char
+0x13c SystemCallNumber : Uint4B
+0x140 FreezeCount      : Uint4B
+0x144 UserAffinity     : _GROUP_AFFINITY
+0x150 Process          : Ptr32 _KPROCESS
+0x154 Affinity         : _GROUP_AFFINITY
+0x160 IdealProcessor   : Uint4B
+0x164 UserIdealProcessor : Uint4B
+0x168 ApcStatePointer  : [2] Ptr32 _KAPC_STATE
+0x170 SavedApcState    : _KAPC_STATE
+0x170 SavedApcStateFill : [23] UChar
+0x187 WaitReason       : UChar
+0x188 SuspendCount     : Char
+0x189 Spare1           : Char
+0x18a OtherPlatformFill : UChar
+0x18c Win32Thread      : Ptr32 Void
+0x190 StackBase        : Ptr32 Void
+0x194 SuspendApc       : _KAPC
+0x194 SuspendApcFill0  : [1] UChar
+0x195 ResourceIndex    : UChar
+0x194 SuspendApcFill1  : [3] UChar
+0x197 QuantumReset     : UChar
+0x194 SuspendApcFill2  : [4] UChar
+0x198 KernelTime       : Uint4B
+0x194 SuspendApcFill3  : [36] UChar
+0x1b8 WaitPrcb         : Ptr32 _KPRCB
+0x194 SuspendApcFill4  : [40] UChar
+0x1bc LegoData         : Ptr32 Void
+0x194 SuspendApcFill5  : [47] UChar
+0x1c3 LargeStack       : UChar
+0x1c4 UserTime         : Uint4B
+0x1c8 SuspendSemaphore : _KSEMAPHORE
+0x1c8 SuspendSemaphorefill : [20] UChar
+0x1dc SListFaultCount  : Uint4B
+0x1e0 ThreadListEntry  : _LIST_ENTRY
+0x1e8 MutantListHead   : _LIST_ENTRY
+0x1f0 SListFaultAddress : Ptr32 Void
+0x1f8 XStateSave       : Ptr32 _XSTATE_SAVE

The following data structures _KAPC_STATE and _KPROCESS are referenced in the disassembly:

_KAPC_STATE:

kd> dt nt!_KAPC_STATE
+0x000 ApcListHead      : [2] _LIST_ENTRY
+0x010 Process          : Ptr32 _KPROCESS
+0x014 KernelApcInProgress : UChar
+0x015 KernelApcPending : UChar
+0x016 UserApcPending   : UChar

_KPROCESS

kd> dt nt!_kprocess
+0x010 ProfileListHead  : _LIST_ENTRY
+0x018 DirectoryTableBase : Uint4B
+0x01c LdtDescriptor    : _KGDTENTRY
+0x024 Int21Descriptor  : _KIDTENTRY
+0x034 ProcessLock      : Uint4B
+0x038 Affinity         : _KAFFINITY_EX
+0x04c SwapListEntry    : _SINGLE_LIST_ENTRY
+0x050 ActiveProcessors : _KAFFINITY_EX
+0x05c AutoAlignment    : Pos 0, 1 Bit
+0x05c DisableBoost     : Pos 1, 1 Bit
+0x05c DisableQuantum   : Pos 2, 1 Bit
+0x05c ActiveGroupsMask : Pos 3, 1 Bit
+0x05c ReservedFlags    : Pos 4, 28 Bits
+0x05c ProcessFlags     : Int4B
+0x060 BasePriority     : Char
+0x061 QuantumReset     : Char
+0x062 Visited          : UChar
+0x063 Unused3          : UChar
+0x064 ThreadSeed       : [1] Uint4B
+0x068 IdealNode        : [1] Uint2B
+0x06a IdealGlobalNode  : Uint2B
+0x06c Flags            : _KEXECUTE_OPTIONS
+0x06d Unused1          : UChar
+0x06e IopmOffset       : Uint2B
+0x070 Unused4          : Uint4B
+0x074 StackCount       : _KSTACK_COUNT
+0x078 ProcessListEntry : _LIST_ENTRY
+0x080 CycleTime        : Uint8B
+0x088 KernelTime       : Uint4B
+0x08c UserTime         : Uint4B
+0x090 VdmTrapcHandler  : Ptr32 Void

Translation of the function to C:

{
if (Thread->ApcState.Process->StackCount != 7) {
}
else {
if (KiInSwapSingleProcess(Thread) == 0) {
}
}
}

The if-structure can be changed as follows:

{
if (Thread->ApcState.Process->StackCount == 7) {
if (KiInSwapSingleProcess(Thread) != 0) {
return;
}
}

}

## Saturday, 1 July 2017

### Practical Reverse Engineering Exercise Solutions: KeInitializeQueue

We are tasked with decompiling the Windows Kernel routine KeInitializeQueue.

Firstly, we obtain its disassembly:

Secondly, we consult MSDN for its signature:

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:

typedef struct _KQUEUE {
ULONG CurrentCount;
ULONG MaximumCount;
} KQUEUE, *PKQUEUE, *RESTRICTED_POINTER PRKQUEUE;

In order to obtain the offsets for the struct parts, we query the data structure in WinDbg:

0: kd> dt nt!_KQUEUE
+0x010 EntryListHead    : _LIST_ENTRY
+0x018 CurrentCount     : Uint4B
+0x01c MaximumCount     : Uint4B

Analogously, we investigate the data structure DISPATCHER_HEADER:

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:

The _LIST_ENTRY structure, in contrast, has only a few members:

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:

VOID KeInitializeQueue(
_Out_ PRKQUEUE Queue,
_In_  ULONG    Count
)
{