cover image for post 'Practical Reverse Engineering Solutions – Page 123 (Part I)'

Practical Reverse Engineering Solutions – Page 123 (Part I)

my go at exercise 1 on pages 123ff

This blog post presents my solution to exercise 1 on page 123 from the book Practical Reverse Engineering by Bruce Dang, Alexandre Gazet and Elias Bachaalany (ISBN: 1118787315). The book is my first contact with reverse engineering, so take my statements with a grain of salt. All code snippets are on GitHub. For an overview of my solutions consult this progress page.

Problem Statement

problem statement

On Windows 8 x64, the following kernel functions have InitalizeListHead inlined at least once: CcAllocateInitializeMbcb, CmpInitCallbacks, ExCreateCallback, ExpInitSystemPhase0, ExpInitSystemPhase1, ExpTimerInitialization, InitBootProcessor, IoCreateDevice, IoInitializeIrp, KeInitThread, KeInitializeMutex, KeInitializeProcess, KeInitializeTimerEx, KeInitializeTimerTable, KiInitializeProcessor, KiInitializeThread, MiInitializeLoadedModuleList, MiInitializePrefetchHead, PspAllocateProcess, PspAllocateThread. Identify where InitializeListHead is inlined in these routines.

Solutions

To save space I’m removing the raw instruction in hex. I’m also not showing the upper 32 bits of the addresses which are fffff800 for all kernel routines in this exercise.

► CcAllocateInitializeMbcb

InitializeListHead is inlined here:

`11d632ef  lea     rax,[rbx+10h]
`11d632f3  lea     rcx,[rbx+30h]
`11d632f7  mov     r11d,2FBh
`11d632fd  mov     word ptr [rbx],r11w
`11d63301  mov     qword ptr [rax+8],rax
`11d63305  mov     qword ptr [rax],rax

Rbx points to memory allocated with ExAllocatePoolWithTag:

`11d632d2  call    nt!ExAllocatePoolWithTag (fffff800`11ee8010)
`11d632d7  mov     rbx,rax

Because the kernel function is named CcAllocateInitializeMbcb, the memory is probably for an _MBCB structure:

nt!_MBCB
   +0x000 NodeTypeCode     : Int2B
   +0x002 NodeIsInZone     : Int2B
   +0x004 PagesToWrite     : Uint4B
   +0x008 DirtyPages       : Uint4B
   +0x00c Reserved         : Uint4B
   +0x010 BitmapRanges     : _LIST_ENTRY
   +0x020 ResumeWritePage  : Int8B
   +0x028 MostRecentlyDirtiedPage : Int8B
   +0x030 BitmapRange1     : _BITMAP_RANGE
   +0x060 BitmapRange2     : _BITMAP_RANGE
   +0x090 BitmapRange3     : _BITMAP_RANGE

Our snippet accesses the member at offset 10h, which is BitmapRanges of type _LIST_ENTRY.

► CmpInitCallbacks

InitializeListHead is inlined here:

`12165566  lea     rax,[nt!CallbackListHead (fffff800`11f5fb80)]
`1216556d  lea     rdx,[nt!`string' (fffff800`11cf31e8)]
`12165574  mov     dword ptr [nt!CmpCallBackCount (fffff800`11ef9d30)],ecx
`1216557a  mov     qword ptr [nt!CmpCallbackListLock (fffff800`11f5fb70)],rcx
`12165581  mov     qword ptr [nt!CmpContextListLock (fffff800`11f5fb78)],rcx
`12165588  mov     qword ptr [nt!CallbackListDeleteEvent (fffff800`11f5fb90)],rcx
`1216558f  lea     rcx,[nt!CmLegacyAltitude (fffff800`11ef9d50)]
`12165596  mov     qword ptr [nt!CallbackListHead+0x8 (fffff800`11f5fb88)],rax
`1216559d  mov     qword ptr [nt!CallbackListHead (fffff800`11f5fb80)],rax

The first member of the kernel variable CallbackListHead is indeed a list head:

kd> x nt!CallBackListHead
81b4a8b0 nt!CallbackListHead = <no type information>
kd> dt nt!_ERESOURCE 0x81b4a8b0
   +0x000 SystemResourcesList : _LIST_ENTRY [ 0x81b4a8b0 - 0x81b4a8b0 ]
   +0x008 OwnerTable       : (null)
   +0x00c ActiveCount      : 0n0
   +0x00e Flag             : 0
   +0x010 SharedWaiters    : (null)
   +0x014 ExclusiveWaiters : (null)
   +0x018 OwnerEntry       : _OWNER_ENTRY
   +0x020 ActiveEntries    : 0
   +0x024 ContentionCount  : 0
   +0x028 NumberOfSharedWaiters : 0
   +0x02c NumberOfExclusiveWaiters : 0
   +0x030 Address          : 0xbee0bee0 Void
   +0x030 CreatorBackTraceIndex : 0xbee0bee0
   +0x034 SpinLock         : 0x81b4e36c

► ExCreateCallback

InitializeListHead is inlined here:

`12138031  lea     rax,[rcx+10h]
`12138035  mov     byte ptr [rcx+20h],r14b
`12138039  mov     qword ptr [rax+8],rax
`1213803d  mov     qword ptr [rax],rax

► ExpInitSystemPhase0

InitializeListHead is inlined four times. The first occurrence is:

`12344161  lea     rax,[nt!ExpSystemResourcesList (fffff800`11f09b20)]
`12344168  lea     rcx,[nt!ExpEnvironmentLock+0x18 (fffff800`11f09a78)]
`1234416f  lea     edx,[rbx+1]
`12344172  xor     r8d,r8d
`12344175  mov qword ptr [nt!ExpTimeout (fffff800`11f09b18)],0FFFFFFFFFD9DA600h
`12344180  mov     qword ptr [nt!ExpSystemResourcesList+0x8 (fffff800`11f09b28)],rax
`12344187  mov     qword ptr [nt!ExpSystemResourcesList (fffff800`11f09b20)],rax

A second occurrence of InitializeListHead is here:

`123441aa  lea     rax,[nt!ExPagedLookasideListHead (fffff800`11f09ab0)]
`123441b1  lea     rdx,[nt!ExNPagedLookasideListHead (fffff800`11f09aa0)]
`123441b8  lea     rcx,[nt!ExpFirmwareTableResource (fffff800`11f09b40)]
`123441bf  mov     qword ptr [nt!ExPagedLookasideListHead+0x8 (fffff800`11f09ab8)],rax
`123441c6  mov     qword ptr [nt!ExPagedLookasideListHead (fffff800`11f09ab0)],rax

Right after ExPagedLookasideListHead is initialized, there’s a third occurrence of InitializeListHead:

`123441b1  lea     rdx,[nt!ExNPagedLookasideListHead (fffff800`11f09aa0)]
`123441b8  lea     rcx,[nt!ExpFirmwareTableResource (fffff800`11f09b40)]
`123441bf  mov     qword ptr [nt!ExPagedLookasideListHead+0x8 (fffff800`11f09ab8)],rax
`123441c6  mov     qword ptr [nt!ExPagedLookasideListHead (fffff800`11f09ab0)],rax
`123441cd  lea     rax,[nt!ExpFirmwareTableProviderListHead (fffff800`11f09bb0)]
`123441d4  mov     qword ptr [nt!ExNPagedLookasideListHead+0x8 (fffff800`11f09aa8)],rdx
`123441db  mov     qword ptr [nt!ExNPagedLookasideListHead (fffff800`11f09aa0)],rdx

The function InitializeListHead is used a fourth time to initialize ExpFirmwareTableProviderListHead:

`123441cd  lea     rax,[nt!ExpFirmwareTableProviderListHead (fffff800`11f09bb0)]
`123441d4  mov     qword ptr [nt!ExNPagedLookasideListHead+0x8 (fffff800`11f09aa8)],rdx
`123441db  mov     qword ptr [nt!ExNPagedLookasideListHead (fffff800`11f09aa0)],rdx
`123441e2  mov     qword ptr [nt!ExNPagedLookasideLock (fffff800`11f09ac0)],rbx
`123441e9  mov     qword ptr [nt!ExpFirmwareTableProviderListHead+0x8 (fffff800`11f09bb8)],rax
`123441f0  mov     qword ptr [nt!ExpFirmwareTableProviderListHead (fffff800`11f09bb0)],rax

All four kernel variables ExpSystemResourcesList, ExNPagedLookasideListHead, ExpFirmwareTableProviderListHead and ExpSystemResourcesList are indeed of type _LIST_ENTRY which can be easily verified with the kernel debugger:

0: kd> x nt!ExpSystemResourcesList
fffff800`11f09b20 nt!ExpSystemResourcesList = <no type information>
0: kd> dt nt!_ERESOURCE fffff800`11f09b20
   +0x000 SystemResourcesList : _LIST_ENTRY [ 0xfffff800`11f09b40 - 0xfffffa80`317eaca8 ]
   ...

► ExpInitSystemPhase1

There’s one instance of InitializeListHead to initialize the list ExpHostList:

`123695f9  lea     rax,[nt!ExpHostList (fffff800`11f09930)]
`12369600  xor     ebp,ebp
`12369602  mov     qword ptr [nt!ExpHostList+0x8 (fffff800`11f09938)],rax
`12369609  mov     qword ptr [nt!ExpHostList (fffff800`11f09930)],rax

► ExpTimerInitialization

InitializeListHead is used once to initialize the list ExpWakeTimerList:

`12338643  lea     rax,[nt!ExpWakeTimerList (fffff800`11f09270)]
`1233864a  lea     rdx,[nt! ?? ::PBOPGDP::`string' (fffff800`12377770)]
`12338651  lea     rcx,[rbp-39h]
`12338655  xor     ebx,ebx
`12338657  mov     qword ptr [nt!ExpWakeTimerList+0x8 (fffff800`11f09278)],rax
`1233865e  mov     qword ptr [nt!ExpWakeTimerList (fffff800`11f09270)],rax

► InitBootProcessor

InitializeListHead is used to initialize the lists WheapPfaList

`1236bcb4  lea     rax,[nt!WheapPfaList (fffff800`11ef9a90)]
`1236bcbb  mov     qword ptr [nt!WheapPfaLock (fffff800`11ef9aa0)],r13
`1236bcc2  mov     qword ptr [nt!WheapPfaList+0x8 (fffff800`11ef9a98)],rax
`1236bcc9  mov     qword ptr [nt!WheapPfaList (fffff800`11ef9a90)],rax

… and HandleTableListHead:

`1236c212  lea     rax,[nt!HandleTableListHead (fffff800`11f09c30)]
`1236c219  mov     qword ptr [nt!HandleTableListLock (fffff800`11f09c40)],r13
`1236c220  mov     qword ptr [nt!HandleTableListHead+0x8 (fffff800`11f09c38)],rax
`1236c227  mov     qword ptr [nt!HandleTableListHead (fffff800`11f09c30)],rax

► IoCreateDevice

The following two consecutive blocks of three lines both look like InitializeListHead:

`1205d019  lea     rax,[rcx+50h]
`1205d01d  mov     qword ptr [rax+8],rax
`1205d021  mov     qword ptr [rax],rax

and

`1205d024  lea     rax,[rcx+60h]
`1205d028  mov     qword ptr [rax+8],rax
`1205d02c  mov     qword ptr [rax],rax

There’s a third occurrence here:

`1205d200  mov     rax,qword ptr [rsp+50h]
`1205d205  add     rax,50h
`1205d209  mov     qword ptr [rax+8],rax
`1205d20d  mov     qword ptr [rax],rax

► IoInitializeIrp

There’s one instance of InitializeListHead here:

`11ca0740  lea     rax,[rbx+20h]
`11ca0744  mov     byte ptr [rbx+46h],cl
`11ca0747  mov     qword ptr [rax+8],rax
`11ca074b  mov     qword ptr [rax],rax

The register rbx probably points to an IRP which has the following structure:

0: kd> dt _IRP
ntdll!_IRP
   +0x000 Type             : Int2B
   +0x002 Size             : Uint2B
   +0x004 AllocationProcessorNumber : Uint2B
   +0x006 Reserved         : Uint2B
   +0x008 MdlAddress       : Ptr64 _MDL
   +0x010 Flags            : Uint4B
   +0x018 AssociatedIrp    : <unnamed-tag>
   +0x020 ThreadListEntry  : _LIST_ENTRY
   +0x030 IoStatus         : _IO_STATUS_BLOCK
   +0x040 RequestorMode    : Char
   +0x041 PendingReturned  : UChar
   +0x042 StackCount       : Char
   +0x043 CurrentLocation  : Char
   +0x044 Cancel           : UChar
   +0x045 CancelIrql       : UChar
   +0x046 ApcEnvironment   : Char
   +0x047 AllocationFlags  : UChar
   +0x048 UserIosb         : Ptr64 _IO_STATUS_BLOCK
   +0x050 UserEvent        : Ptr64 _KEVENT
   +0x058 Overlay          : <unnamed-tag>
   +0x068 CancelRoutine    : Ptr64     void 
   +0x070 UserBuffer       : Ptr64 Void
   +0x078 Tail             : <unnamed-tag>

So the lines are initialize ThreadListEntry at offset 20h which is in fact a _LIST_ENTRY.

► KeInitThread

InitializeListHead is used in four places, which all set members of the thread structure with type _KTHREAD:

kd> dt _KTHREAD -b
ntdll!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
      ...
      +0x008 WaitListHead     : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64
...
   +0x098 ApcState         : _KAPC_STATE
      +0x000 ApcListHead      : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64
      ...
...
   +0x308 MutantListHead   : _LIST_ENTRY
...

The first instance of InitializeListHead is:

`11fd735b  lea     rax,[rcx+8]
`11fd735f  mov     qword ptr [rax+8],rax
`11fd7363  mov     qword ptr [rax],rax

The register rcx points to a _KTHREAD structure. At offset 8 we find the WaitListHead inside the Header structure. The second instance follows right after that and initializes MutantListHead at offset 308h of _KTHREAD:

`11fd7366  lea     rax,[rcx+308h]
`11fd736d  mov     qword ptr [rax+8],rax
`11fd7371  mov     qword ptr [rax],rax

The third occurences of InitializeListHead is:

`11fd73bd  lea     rcx,[rdi+98h]
`11fd73c4  mov     qword ptr [rdi+248h],rcx
`11fd73cb  lea     rax,[rdi+258h]
`11fd73d2  mov     qword ptr [rdi+250h],rax
`11fd73d9  mov     qword ptr [rcx+8],rcx
`11fd73dd  mov     qword ptr [rcx],rcx

Rdi holds the same address as rcx and therefore also points to the _KTHREAD structure. At offset 98h of the thread structure is member ApcState, and at offset and 8 into ApcState we have indeed a Flink and Blink pointers. The fourth and last InitializeListHead usage follows right after the previous one:

`11fd73e0  lea     rax,[rdi+0A8h]
`11fd73e7  mov     qword ptr [rax+8],rax
`11fd73eb  mov     qword ptr [rax],rax

This time the member at offset 0A8h is initialized, which is 98h + 10h or the second _LIST_ENTRY of ApcState.

► KeInitializeMutex

This very short routine has the following unassembly. The InitializeListHead lines are highlighted:

`11cb6cec  lea     rax,[rcx+8]
`11cb6cf0  mov     byte ptr [rcx],2
`11cb6cf3  mov     word ptr [rcx+2],0Eh
`11cb6cf9  mov     dword ptr [rcx+4],1
`11cb6d00  xor     edx,edx
`11cb6d02  mov     qword ptr [rcx+28h],rdx
`11cb6d06  mov     qword ptr [rax+8],rax
`11cb6d0a  mov     qword ptr [rax],rax
`11cb6d0d  mov     word ptr [rcx+30h],100h
`11cb6d13  ret

The register rcx points to a mutex of type _KMUTANT. At offset 8 into this structure there’s indeed a _LIST_ENTRY:

0: > nt!_KMUTANT
   +0x000 Header           : _DISPATCHER_HEADER
      ...
      +0x008 WaitListHead     : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64

► KeInitializeProcess

InitializeListHead is first used here:

`11d605b6  lea     rax,[rcx+20h]
`11d605ba  mov     word ptr [rcx+18h],1
`11d605c0  mov     byte ptr [rcx+1Ah],6
`11d605c4  mov     qword ptr [rax+8],rax
`11d605c8  mov     qword ptr [rax],rax

rcx points to a _FAST_MUTEX:

ntdll!_FAST_MUTEX
   +0x000 Count            : Int4B
   +0x008 Owner            : Ptr64 Void
   +0x010 Contention       : Uint4B
   +0x018 Event            : _KEVENT
   +0x030 OldIrql          : Uint4B

Offset 20h lies inside Event of type _KEVENT. At offset 8 (=20h-18h) there’s sure enough a _LIST_ENTRY:

0: kd> dt _KEVENT -b
nt!_KEVENT
   +0x000 Header           : _DISPATCHER_HEADER
      ...
      +0x008 WaitListHead     : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64

The second usage of InitializeListHead is:

`12111030  lea     rax,[rcx+8]
`12111034  mov     qword ptr [rax+8],rax
`12111038  mov     qword ptr [rax],rax

This time rcx is of type _KPROCESS with a _LIST_ENTRY at offset 8:

0: kd> dt _KPROCESS -b
nt!_KPROCESS
   +0x000 Header           : _DISPATCHER_HEADER
      ...
      +0x008 WaitListHead     : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64

Finally, there are three consecutive uses of InitializeListHead:

`121110ea  lea     rax,[rbx+18h]
`121110ee  mov     rdx,rbp
`121110f1  mov     rcx,rbx
`121110f4  mov     qword ptr [rax+8],rax
`121110f8  mov     qword ptr [rax],rax
`121110fb  lea     rax,[rbx+0F0h]
`12111102  mov     qword ptr [rax+8],rax
`12111106  mov     qword ptr [rax],rax
`12111109  lea     rax,[rbx+30h]
`1211110d  mov     qword ptr [rax+8],rax
`12111111  mov     qword ptr [rax],rax

Rbx points to a _KPROCESS and the code above initializes the three lists ProfileListHead, ThreadListHead and ReadyListHead.

0: kd> dt _KPROCESS
ntdll!_KPROCESS
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 ProfileListHead  : _LIST_ENTRY
   ...
   +0x030 ThreadListHead   : _LIST_ENTRY
   ...
   +0x0f0 ReadyListHead    : _LIST_ENTRY
   ...

► KeInitializeTimerEx

Another short routine with obvious InitializeListHead:

`11d2e5b0  xor     r8d,r8d
`11d2e5b3  lea     rax,[rcx+8]
`11d2e5b7  add     dl,8
`11d2e5ba  mov     qword ptr [rcx],r8
`11d2e5bd  mov     byte ptr [rcx],dl
`11d2e5bf  mov     qword ptr [rax+8],rax
`11d2e5c3  mov     qword ptr [rax],rax
`11d2e5c6  mov     qword ptr [rcx+18h],r8
`11d2e5ca  mov     qword ptr [rcx+38h],r8
`11d2e5ce  ret

The register rcx points to a _KTIMER structure, which has a _LIST_ENTRY at offset 8:

nt!_KTIMER
   +0x000 Header           : _DISPATCHER_HEADER
      ...
      +0x008 WaitListHead     : _LIST_ENTRY
         +0x000 Flink            : Ptr64
         +0x008 Blink            : Ptr64

► KeInitializeTimerTable

There’s one potential InitializeListHead:

`12160caa  lea     rax,[rbx+3008h]

nt!KeInitializeTimerTable+0x91: 
`12160cb1  mov     qword ptr [rax-8],rbp
`12160cb5  mov     qword ptr [rax+8],rax
`12160cb9  mov     qword ptr [rax],rax

► KiInitializeProcessor

There’s one potential InitializeListHead:

`11fdca27  lea     rdx,[rsi+2DA0h]
`11fdca2e  mov     qword ptr [rdx+8],rdx
`11fdca32  mov     qword ptr [rdx],rdx

► KiInitializeThread

There’s one InitializeListHead to initialize the _LIST_ENTRY at offset 478h into KiInitialProcess:

`11fdccbb  lea     rdx,[nt!KiInitialProcess+0x470 (fffff800`11fca670)]
...

`11fdcd6f  mov     qword ptr [nt!KiInitialProcess+0x478 (fffff800`11fca678)],rdx
`11fdcd76  mov     qword ptr [nt!KiInitialProcess+0x470 (fffff800`11fca670)],rdx
0: kd> x nt!ExpSystemResourcesList
fffff800`11f09b20 nt!ExpSystemResourcesList = <no type information>
0: kd> dt nt!_ERESOURCE fffff800`11f09b20
   +0x000 SystemResourcesList : _LIST_ENTRY [ 0xfffff800`11f09b40 - 0xfffffa80`317eaca8 ]
   ...

► MiInitializeLoadedModuleList

This routine uses InitializeListHead once to initialize the PsLoadedModuleList:

`1236dc44  lea     r13,[nt!PsLoadedModuleList (fffff800`11f44aa0)]
`1236dc4b  mov     r8b,1
`1236dc4e  lea     ecx,[rdx+7Eh]
`1236dc51  mov     qword ptr [nt!ExpCovPushLock (fffff800`11f092f0)],r15
`1236dc58  mov     qword ptr [nt!ExpCovUnloadedModuleList+0x8 (fffff800`11f092e8)],rax
`1236dc5f  mov     qword ptr [nt!PsLoadedModuleList+0x8 (fffff800`11f44aa8)],r13
`1236dc66  mov     qword ptr [nt!PsLoadedModuleList (fffff800`11f44aa0)],r13

At offsets and 8 into PsLoadedModuleList we find the two pointers Flink and Blink:

0: kd> x nt!PsLoadedModuleList
fffff800`03452890 nt!PsLoadedModuleList = <no type information>
0: kd> dt nt!_ERESOURCE -b fffff800`03452890
   +0x000 SystemResourcesList : _LIST_ENTRY [ 0xfffffa80`18dd4e70 - 0xfffffa80`1dbec240 ]
      +0x000 Flink            : 0xfffffa80`18dd4e70
      +0x008 Blink            : 0xfffffa80`1dbec240

► MiInitializePrefetchHead

The routine uses three consecutive InitializeListHead functions to set the lists at offset 8, 18h and 28h into the structure that rcx points to:

`11db2bc4  lea     rax,[rcx+8]
`11db2bc8  mov     qword ptr [rax+8],rax
`11db2bcc  mov     qword ptr [rax],rax
`11db2bcf  lea     rax,[rcx+18h]
`11db2bd3  mov     qword ptr [rax+8],rax
`11db2bd7  mov     qword ptr [rax],rax
`11db2bda  lea     rax,[rcx+28h]
`11db2bde  mov     qword ptr [rax+8],rax
`11db2be2  mov     qword ptr [rax],rax

► PspAllocateProcess

Two locations look like InitializeListHead:

`120f3a0a  lea     rax,[r13+5D8h]
`120f3a11  mov     qword ptr [rax+8],rax
`120f3a15  mov     qword ptr [rax],rax

and

`120f3a26  lea     rax,[r13+470h]
`120f3a2d  mov     qword ptr [rax+8],rax
`120f3a31  mov     qword ptr [rax],rax

► PspAllocateThread

There are five consecutive InitializeListHeads:

`120e95c2  lea     r11,[rsi+350h]
`120e95c9  mov     qword ptr [r11+8],r11
`120e95cd  mov     qword ptr [r11],r11
`120e95d0  lea     rax,[rsi+470h]
`120e95d7  mov     qword ptr [rax+8],rax
`120e95db  mov     qword ptr [rax],rax
`120e95de  lea     rax,[rsi+480h]
`120e95e5  mov     qword ptr [rax+8],rax
`120e95e9  mov     qword ptr [rax],rax
`120e95ec  mov     qword ptr [rsi+490h],rdi
`120e95f3  lea     rax,[rsi+3D0h]
`120e95fa  mov     qword ptr [rax+8],rax
`120e95fe  mov     qword ptr [rax],rax
`120e9601  mov     qword ptr [rsi+498h],rdi
`120e9608  mov     qword ptr [rsi+380h],rdi
`120e960f  lea     rax,[rsi+388h]
`120e9616  mov     qword ptr [rax+8],rax
`120e961a  mov     qword ptr [rax],rax

Archived Comments

Note: I removed the Disqus integration in an effort to cut down on bloat. The following comments were retrieved with the export functionality of Disqus. If you have comments, please reach out to me by Twitter or email.

radagascar1 Sep 22, 2015 01:29:26 UTC

Hello! I'm going through this book as well and your blog posts have been very helpful. I have a problem though. For the problems on these pages (123-126), how were you able to view the disassembly of these routines? I've tried a few commands using KD and nothing seems to work. It would help a lot! Thanks.

Johannes Bader Sep 22, 2015 08:06:56 UTC

I used the "uf" command. For example,

kd> uf KeReadyThread