Vir Gnarus
BSOD Kernel Dump Expert
- Mar 2, 2012
- 474
That's alright, dude, I thank you for pursuing it. I personally have no knowledge on the subject when it comes to scripting and using the dbgeng, but I do know that the stack base and limit are reserved in the KTHREAD data structure, which is practically the header for a thread (it's part of the ETHREAD data structure, but it's the first portion.). So if you happen to take the thread address and run it through dt pointing to the _KTHREAD symbols, you'll get the information you seek. Take this example:
As you can see, the StackBase and StackLimit values correspond to the output from !thread, which is because !thread just reads those values (amongst others) from the KTHREAD data structure and outputs them in a more friendly manner. Because the KTHREAD structure starts at the very beginning of the ETHREAD structure (as in offset 0x000), the offset you see for each value is the offset from the very beginning of the thread's address. Therefore you don't even have to pump out the whole structure to get the values you seek, nor do you need to do additional math by adding in more offsets, just dump whatever's at [threadaddress]+0x30 and [threadaddress]+0x278 to get the stack limit and base values, respectively:
Now the problem would be figuring out the thread address without resorting to !thread or any other extensions. That I cannot figure off the top of my head, but I'm sure you're resourceful, and I personally plan on figuring it out eventually (never bothered to do it previously). Maybe if you can somehow break down the !thread extension to see how it does it, that would work. Remember, the thread address is really just the starting point for the ETHREAD data structure, with of course it also being the starting point for the KTHREAD structure. Knowing that could probably help a bit.
Code:
3: kd> !thread
GetPointerFromAddress: unable to read from fffff80002d09000
THREAD [COLOR=#008000]fffffa8006063040[/COLOR] Cid 0004.0034 Teb: 0000000000000000 Win32Thread: 0000000000000000 RUNNING on processor 3
Not impersonating
GetUlongFromAddress: unable to read from fffff80002c48ba4
Owning Process fffffa80053e8040 Image: System
Attached Process N/A Image: N/A
fffff78000000000: Unable to get shared data
Wait Start TickCount 2711
Context Switch Count 2536 IdealProcessor: 2
ReadMemory error: Cannot get nt!KeMaximumIncrement value.
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address nt!ExpWorkerThread (0xfffff80002ae3730)
Stack Init fffff880035afdb0 Current fffff880035aef10
Base [COLOR=#0000ff]fffff880035b0000 [/COLOR]Limit [COLOR=#0000ff]fffff880035aa000 [/COLOR]Call 0
Priority 13 BasePriority 12 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
...
3: kd> dt !_KTHREAD [COLOR=#008000]fffffa8006063040[/COLOR]
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x018 CycleTime : 0x587ad7fa
+0x020 QuantumTarget : 0x5c9df4ce
+0x028 InitialStack : 0xfffff880`035afdb0 Void
[COLOR=#0000ff] +0x030 StackLimit : 0xfffff880`035aa000 Void[/COLOR]
+0x038 KernelStack : 0xfffff880`035aef10 Void
+0x040 ThreadLock : 0
+0x048 WaitRegister : _KWAIT_STATUS_REGISTER
+0x049 Running : 0x1 ''
+0x04a Alerted : [2] ""
+0x04c KernelStackResident : 0y1
+0x04c ReadyTransition : 0y0
+0x04c ProcessReadyQueue : 0y0
+0x04c WaitNext : 0y0
+0x04c SystemAffinityActive : 0y0
+0x04c Alertable : 0y0
+0x04c GdiFlushActive : 0y0
+0x04c UserStackWalkActive : 0y0
+0x04c ApcInterruptRequest : 0y0
+0x04c ForceDeferSchedule : 0y0
+0x04c QuantumEndMigrate : 0y0
+0x04c UmsDirectedSwitchEnable : 0y0
+0x04c TimerActive : 0y0
+0x04c SystemThread : 0y1
+0x04c Reserved : 0y000000000000000000 (0)
+0x04c MiscFlags : 0n8193
+0x050 ApcState : _KAPC_STATE
+0x050 ApcStateFill : [43] "???"
+0x07b Priority : 13 ''
+0x07c NextProcessor : 3
+0x080 DeferredProcessor : 0
+0x088 ApcQueueLock : 0
+0x090 WaitStatus : 0n0
+0x098 WaitBlockList : 0xfffffa80`06063148 _KWAIT_BLOCK
+0x0a0 WaitListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0xfffff800`02c51450 ]
+0x0a0 SwapListEntry : _SINGLE_LIST_ENTRY
+0x0b0 Queue : 0xfffff800`02c772d8 _KQUEUE
+0x0b8 Teb : (null)
+0x0c0 Timer : _KTIMER
+0x100 AutoAlignment : 0y1
+0x100 DisableBoost : 0y0
+0x100 EtwStackTraceApc1Inserted : 0y0
+0x100 EtwStackTraceApc2Inserted : 0y0
+0x100 CalloutActive : 0y0
+0x100 ApcQueueable : 0y1
+0x100 EnableStackSwap : 0y1
+0x100 GuiThread : 0y0
+0x100 UmsPerformingSyscall : 0y0
+0x100 VdmSafe : 0y0
+0x100 UmsDispatched : 0y0
+0x100 ReservedFlags : 0y000000000000000000000 (0)
+0x100 ThreadFlags : 0n97
+0x104 Spare0 : 0
+0x108 WaitBlock : [4] _KWAIT_BLOCK
+0x108 WaitBlockFill4 : [44] "x???"
+0x134 ContextSwitches : 0x9e8
+0x108 WaitBlockFill5 : [92] "x???"
+0x164 State : 0x2 ''
+0x165 NpxState : 0 ''
+0x166 WaitIrql : 0 ''
+0x167 WaitMode : 0 ''
+0x108 WaitBlockFill6 : [140] "x???"
+0x194 WaitTime : 0xa97
+0x108 WaitBlockFill7 : [168] "x???"
+0x1b0 TebMappedLowVa : (null)
+0x1b8 Ucb : (null)
+0x108 WaitBlockFill8 : [188] "x???"
+0x1c4 KernelApcDisable : 0n-1
+0x1c6 SpecialApcDisable : 0n0
+0x1c4 CombinedApcDisable : 0xffff
+0x1c8 QueueListEntry : _LIST_ENTRY [ 0xfffffa80`06063d18 - 0xfffffa80`06062828 ]
+0x1d8 TrapFrame : (null)
+0x1e0 FirstArgument : (null)
+0x1e8 CallbackStack : (null)
+0x1e8 CallbackDepth : 0
+0x1f0 ApcStateIndex : 0 ''
+0x1f1 BasePriority : 12 ''
+0x1f2 PriorityDecrement : 0 ''
+0x1f2 ForegroundBoost : 0y0000
+0x1f2 UnusualBoost : 0y0000
+0x1f3 Preempted : 0 ''
+0x1f4 AdjustReason : 0 ''
+0x1f5 AdjustIncrement : 0 ''
+0x1f6 PreviousMode : 0 ''
+0x1f7 Saturation : 0 ''
+0x1f8 SystemCallNumber : 0
+0x1fc FreezeCount : 0
+0x200 UserAffinity : _GROUP_AFFINITY
+0x210 Process : 0xfffffa80`053e8040 _KPROCESS
+0x218 Affinity : _GROUP_AFFINITY
+0x228 IdealProcessor : 2
+0x22c UserIdealProcessor : 2
+0x230 ApcStatePointer : [2] 0xfffffa80`06063090 _KAPC_STATE
+0x240 SavedApcState : _KAPC_STATE
+0x240 SavedApcStateFill : [43] "???"
+0x26b WaitReason : 0x5 ''
+0x26c SuspendCount : 0 ''
+0x26d Spare1 : 0 ''
+0x26e CodePatchInProgress : 0 ''
+0x270 Win32Thread : (null)
[COLOR=#0000ff]+0x278 StackBase : 0xfffff880`035b0000 Void[/COLOR]
+0x280 SuspendApc : _KAPC
+0x280 SuspendApcFill0 : [1] "??????"
+0x281 ResourceIndex : 0x1 ''
+0x280 SuspendApcFill1 : [3] "???"
+0x283 QuantumReset : 0x6 ''
+0x280 SuspendApcFill2 : [4] "???"
+0x284 KernelTime : 0x25
+0x280 SuspendApcFill3 : [64] "???"
+0x2c0 WaitPrcb : (null)
+0x280 SuspendApcFill4 : [72] "???"
+0x2c8 LegoData : (null)
+0x280 SuspendApcFill5 : [83] "???"
+0x2d3 LargeStack : 0 ''
+0x2d4 UserTime : 0
+0x2d8 SuspendSemaphore : _KSEMAPHORE
+0x2d8 SuspendSemaphorefill : [28] "???"
+0x2f4 SListFaultCount : 0
+0x2f8 ThreadListEntry : _LIST_ENTRY [ 0xfffffa80`06063e48 - 0xfffffa80`06062958 ]
+0x308 MutantListHead : _LIST_ENTRY [ 0xfffffa80`06063348 - 0xfffffa80`06063348 ]
+0x318 SListFaultAddress : (null)
+0x320 ReadOperationCount : 0n25794
+0x328 WriteOperationCount : 0n0
+0x330 OtherOperationCount : 0n123
+0x338 ReadTransferCount : 0n538946
+0x340 WriteTransferCount : 0n0
+0x348 OtherTransferCount : 0n1653
+0x350 ThreadCounters : (null)
+0x358 StateSaveArea : 0xfffff880`035afe00 _XSAVE_FORMAT
+0x360 XStateSave : (null)
As you can see, the StackBase and StackLimit values correspond to the output from !thread, which is because !thread just reads those values (amongst others) from the KTHREAD data structure and outputs them in a more friendly manner. Because the KTHREAD structure starts at the very beginning of the ETHREAD structure (as in offset 0x000), the offset you see for each value is the offset from the very beginning of the thread's address. Therefore you don't even have to pump out the whole structure to get the values you seek, nor do you need to do additional math by adding in more offsets, just dump whatever's at [threadaddress]+0x30 and [threadaddress]+0x278 to get the stack limit and base values, respectively:
Code:
3: kd> dps fffffa8006063040+30 L1; dps fffffa8006063040+278 L1
fffffa80`06063070 fffff880`035aa000 [COLOR=#008000]< stack limit[/COLOR]
fffffa80`060632b8 fffff880`035b0000 [COLOR=#008000]< stack base[/COLOR]
Now the problem would be figuring out the thread address without resorting to !thread or any other extensions. That I cannot figure off the top of my head, but I'm sure you're resourceful, and I personally plan on figuring it out eventually (never bothered to do it previously). Maybe if you can somehow break down the !thread extension to see how it does it, that would work. Remember, the thread address is really just the starting point for the ETHREAD data structure, with of course it also being the starting point for the KTHREAD structure. Knowing that could probably help a bit.
Last edited: