I'm debugging a process which is like frozen:
I suspect the root cause is the thread below THREAD 877f4030 Cid 0568.0fb8 that is stuck on the user-mode call to GetOverlappedResult.
I have opened the dump with kd.exe.
Namely, I'm interested into knowing more about the NotificationEvent which obviously is never releasing our thread.
In the thread info we have:
879f6fdc NotificationEvent
In what type should I cast address 879f6fdc ? or in which structure field should I search for it, so as to understand, or have a clue to what is blocking the situation ?
As far as the Thread Infos goes, this thread currently does not list any IRP that would be in undesired or unfinished state.
Below entire Thread Information for the corresponding thread:
THREAD 877f4030 Cid 0568.0fb8 Teb: 7ff3d000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
879f6fdc NotificationEvent
Not impersonating
DeviceMap 89809fc8
Owning Process 87950030 Image: OurProduct.exe
Attached Process N/A Image: N/A
Wait Start TickCount 1472232 Ticks: 5394 (0:00:01:24.146)
Context Switch Count 2791788 IdealProcessor: 0
UserTime 00:00:06.848
KernelTime 00:00:09.890
Win32 Start Address MSVCR120!_threadstartex (0x721fbfb4)
Stack Init 8c761fd0 Current 8c761bc8 Base 8c762000 Limit 8c75f000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Kernel stack not resident.
ChildEBP RetAddr Args to Child
8c761be0 824cfced 877f4030 00000000 8ab36120 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
8c761c18 824ceb4b 877f40f0 877f4030 879f6fdc nt!KiSwapThread+0x266
8c761c40 824c856f 877f4030 877f40f0 00000000 nt!KiCommitThreadWait+0x1df
8c761cb8 8267ae07 879f6fdc 00000006 826bca01 nt!KeWaitForSingleObject+0x393
8c761d20 8248f8a6 00001018 00000000 00000000 nt!NtWaitForSingleObject+0xc6
8c761d20 774f7094 00001018 00000000 00000000 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame # 8c761d34)
09f9f61c 774f6a24 758b179c 00001018 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
09f9f620 758b179c 00001018 00000000 00000000 ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
09f9f68c 758b7841 00001018 ffffffff 00000000 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [Non-Fpo])
09f9f6a0 758cb9e1 00001018 ffffffff 064f3d10 KERNELBASE!WaitForSingleObject+0x12 (FPO: [Non-Fpo])
09f9f6b8 745be159 00001018 0639ee0c 09f9f6ec KERNELBASE!GetOverlappedResult+0x57 (FPO: [Non-Fpo])
What is the correct way to proceed and know which event or synchronisation mechanism is faulting ?
some commands on the NotificationEvent address:
0: kd> !object 879f6fdc
879f6fdc: Not a valid object (ObjectType invalid)
0: kd> dt nt!_KEVENT 879f6fdc
+0x000 Header : _DISPATCHER_HEADER
and then:
0: kd> dt nt!_DISPATCHER_HEADER 879f6fdc
+0x000 Type : 0 ''
+0x001 TimerControlFlags : 0 ''
+0x001 Absolute : 0y0
+0x001 Coalescable : 0y0
+0x001 KeepShifting : 0y0
+0x001 EncodedTolerableDelay : 0y00000 (0)
+0x001 Abandoned : 0 ''
+0x001 Signalling : 0 ''
+0x002 ThreadControlFlags : 0x4 ''
+0x002 CpuThrottled : 0y0
+0x002 CycleProfiling : 0y0
+0x002 CounterProfiling : 0y1
+0x002 Reserved : 0y00000 (0)
+0x002 Hand : 0x4 ''
+0x002 Size : 0x4 ''
+0x003 TimerMiscFlags : 0 ''
+0x003 Index : 0y0
+0x003 Processor : 0y00000 (0)
+0x003 Inserted : 0y0
+0x003 Expired : 0y0
+0x003 DebugActive : 0 ''
+0x003 ActiveDR7 : 0y0
+0x003 Instrumented : 0y0
+0x003 Reserved2 : 0y0000
+0x003 UmsScheduled : 0y0
+0x003 UmsPrimary : 0y0
+0x003 DpcActive : 0 ''
+0x000 Lock : 0n262144
+0x004 SignalState : 0n0
+0x008 WaitListHead : _LIST_ENTRY [ 0x877f40f0 - 0x877f40f0 ]
from a former investigation I remember that if +0x003 DpcActive was 1, it would mean we'd be waiting for some hardware operation to put it to 0. But in this case it is 0.
So right now, I just don't know what this NotificationEvent is waiting for.
Any idea ?
Events do not wait, Threads do. NotificationEvents are signaled by whoever would perform the operation and then notify the the waiters about the completion of the operation. In other words your stack is an example of a Async IO where we pass an overlapped structure with an hEvent set. reference https://msdn.microsoft.com/en-us/library/windows/desktop/ms684342(v=vs.85).aspx
You should be inspecting the source which has scheduled this IO or the type of IO we are waiting for instead of dumping out the event. The event will be signaled when the operation is completed.
Related
While debugging windows kernel with WinDbg,
I found following line:
inc dword ptr gs : [2EB8h]
Can someone please explain what this means?
(Intel Syntax, x86, Windows-10)
The GS segment in kernel mode (windows x64) points to the Kernel Processor Control Region (KPCR).
You can dump it with the !pcr command:
kd> !pcr
KPCR for Processor 0 at fffff802fbd73000:
Major 1 Minor 1
NtTib.ExceptionList: fffff802fd6d8000
NtTib.StackBase: fffff802fd6d9070
NtTib.StackLimit: 0000000000b0e968
NtTib.SubSystemTib: fffff802fbd73000
NtTib.Version: 00000000fbd73180
NtTib.UserPointer: fffff802fbd737f0
NtTib.SelfTib: 000000007f005000
SelfPcr: 0000000000000000
Prcb: fffff802fbd73180
Irql: 0000000000000000
IRR: 0000000000000000
IDR: 0000000000000000
InterruptMode: 0000000000000000
IDT: 0000000000000000
GDT: 0000000000000000
TSS: 0000000000000000
CurrentThread: ffffe001e41a3080
NextThread: 0000000000000000
IdleThread: fffff802fbde9740
DpcQueue: Unable to read nt!_KDPC_DATA.DpcListHead.Flink # fffff802fbd75f00
You can confirm that the KPCR really is pointed to by the GS segment register by reading the MSR (Model Specific Register) named IA32_GS_BASE (which value is 0xc0000101):
kd> rdmsr 0xc0000101
msr[c0000101] = fffff802`fbd73000
As you can see they both point, in my example, to 0xfffff802fbd73000.
The PCR is described by the KPCR structure:
kd> dt nt!_kpcr
+0x000 NtTib : _NT_TIB
+0x000 GdtBase : Ptr64 _KGDTENTRY64
+0x008 TssBase : Ptr64 _KTSS64
+0x010 UserRsp : Uint8B
+0x018 Self : Ptr64 _KPCR
+0x020 CurrentPrcb : Ptr64 _KPRCB //points to the _KPRCB member at 0x180
+0x028 LockArray : Ptr64 _KSPIN_LOCK_QUEUE
+0x030 Used_Self : Ptr64 Void
+0x038 IdtBase : Ptr64 _KIDTENTRY64
+0x040 Unused : [2] Uint8B
+0x050 Irql : UChar
+0x051 SecondLevelCacheAssociativity : UChar
+0x052 ObsoleteNumber : UChar
+0x053 Fill0 : UChar
+0x054 Unused0 : [3] Uint4B
+0x060 MajorVersion : Uint2B
+0x062 MinorVersion : Uint2B
+0x064 StallScaleFactor : Uint4B
+0x068 Unused1 : [3] Ptr64 Void
+0x080 KernelReserved : [15] Uint4B
+0x0bc SecondLevelCacheSize : Uint4B
+0x0c0 HalReserved : [16] Uint4B
+0x100 Unused2 : Uint4B
+0x108 KdVersionBlock : Ptr64 Void
+0x110 Unused3 : Ptr64 Void
+0x118 PcrAlign1 : [24] Uint4B
+0x180 Prcb : _KPRCB
As you can see the last field of the KPCR structure is another structure (not a pointer, but the structure itself) named KPRCB (which stands for Kernel Processor Control Block) at offset 0x180.
Here's the start of this structure:
kd> dt nt!_kprcb
+0x000 MxCsr : Uint4B
+0x004 LegacyNumber : UChar
+0x005 ReservedMustBeZero : UChar
+0x006 InterruptRequest : UChar
+0x007 IdleHalt : UChar
+0x008 CurrentThread : Ptr64 _KTHREAD
+0x010 NextThread : Ptr64 _KTHREAD
+0x018 IdleThread : Ptr64 _KTHREAD
+0x020 NestingLevel : UChar
+0x021 ClockOwner : UChar
+0x022 PendingTickFlags : UChar
+0x022 PendingTick : Pos 0, 1 Bit
+0x022 PendingBackupTick : Pos 1, 1 Bit
+0x023 IdleState : UChar
+0x024 Number : Uint4B
...
Above output truncated for brevity as this structure (and thus the PCR) is extremely large: the size of the PCR in windows 10 x64 is 0x8040 bytes (0x7EC0 for the KPRCB).
Given your 0x2eb8 offset in GS (which points to the PCR), we can just subtract the KPRCB offset from the PCR (0x180):
kd> ? 0x2eb8 - 0x180
Evaluate expression: 11576 = 00000000`00002d38
And then check which field is at offset 0x2d38 in the KPRCB:
0: kd> .shell -ci "dt nt!_kprcb" findstr /i 0x2d38
+0x2d38 KeSystemCalls : Uint4B
(note: you can just dt nt!_kprcb and look at offset 0x2d38).
So, the incremented field in your example is named KeSystemCalls and is a 32-bit field (Uint4B) as shown in your code.
Field Usage
Searching in the IDA disassembler (ntoskrnel.exe windows 10 - x64) we have 2 hits on the 0x2eb8 value:
KiSystemCall64
VslpDispatchIumSyscall
The first one is the "normal" syscall dispatcher while the second one is the syscall dispatcher for IUM processes (aka Trustlets).
In both of these functions the use of the field is exactly the same (example in KiSystemCall64):
.text:0000000140187360 call r10 ; perform syscall
.text:0000000140187363
.text:0000000140187363 loc_140187363:
.text:0000000140187363 inc dword ptr gs:2EB8h ; increment syscall counter
So this field is simply a monotonic counter for the number of system calls that happened since the system boot.
This Answer is Just an Extension to Nietsa's answer
Apart From Being used to Create Process->cookie
KeSystemCalls member in poi(nt!KiProcessorBlock) Structure
kd> ?? ##masm(poi(nt!KiProcessorBlock)) == #$prcb
bool true
kd> ? #$pcr
Evaluate expression: -2104316928 = 8292ac00
kd> ? #$pcr+120
Evaluate expression: -2104316640 = 8292ad20
kd> ? #$prcb
Evaluate expression: -2104316640 = 8292ad20
kd> ? poi(nt!KiProcessorBlock)
Evaluate expression: -2104316640 = 8292ad20
is also used to provide the performance counter values for
"\system\System Calls/sec" data
C:\>powershell -c "&{get-counter -counter \"\System\System Calls/sec\"}"
Timestamp CounterSamples
144196.186791101
if one follows the pdh api
s = PdhCollectQueryData(hQuery);
one can observe the calls to NtQueryInformationSystem with SYSTEM_INFO_CLASS 2 == SystemPerformanceInformation which Leads to nt!ExpQuerySystemInformation on the kernel side filling the information from KPRCB
kd> # \+590h nt!ExpQuerySystemInformation l 600
nt!ExpQuerySystemInformation+0x57f:
82a01d73 038290050000 add eax,dword ptr [edx+590h]
kd> ?? #FIELD_OFFSET(nt!_KPRCB , KeSystemCalls)
long 0n1424
kd> ? 0n1424
Evaluate expression: 1424 = 00000590 <<<< (windows 7 sp2 32 bit )
I have a problem with the remote desktop connection on Windows 7 professional 64 bits (6.1 version 7601).
When I type the password of the server and click on connect button, it crashs.
I know that if the printers checkbox is checked, it causes this type of problems but I disable all local resources.
Here is the dump files :
https://www.dropbox.com/s/xvthjbldyr1ncl2/LocalDumps.zip?dl=0
Thanks.
The debug symbols are now online and I see in Windbg that the BLEtokenCredentialProvider.dll from CSR Harmony Wireless Software Stack causes your crash:
APPLICATION_VERIFIER_HEAPS_CORRUPTED_HEAP_BLOCK_EXCEPTION_RAISED_FOR_PROBING (c)
Exception raised while verifying the heap block.
This situation happens if we really cannot determine any particular
type of corruption for the block. For instance you will get this if
during a heap free operation you pass an address that points to a
non-accessible memory area.
This can also happen for double free situations if we do not find the
block among full page heap blocks and we probe it as a light page heap block.
Arguments:
Arg1: 0000000025701000, Heap handle used in the call.
Arg2: f0f0f0f0f0f0f0f0, Heap block involved in the operation.
Arg3: 0000000000000000, Size of the heap block.
Arg4: 00000000c0000005, Reserved.
DUMP_QUALIFIER: 400
CONTEXT: (.ecxr)
rax=000000000d65cee0 rbx=0000000000000001 rcx=000007fffff94000
rdx=000000000000fffd rsi=0000000000000000 rdi=000000000000000c
rip=000007fee9f9a668 rsp=000000001a20d9a0 rbp=0000000000000000
r8=000000001a203000 r9=0000000040010006 r10=0000000000000000
r11=000000001a20c528 r12=0000000000000000 r13=000000000000005d
r14=f0f0f0f0f0f0f0f0 r15=0000000000000000
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
verifier!VerifierStopMessage+0x1f0:
000007fe`e9f9a668 cc int 3
Resetting default scope
FAULTING_IP:
verifier!VerifierStopMessage+1f0
000007fe`e9f9a668 cc int 3
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 000007fee9f9a668 (verifier!VerifierStopMessage+0x00000000000001f0)
ExceptionCode: 80000003 (Break instruction exception)
ExceptionFlags: 00000000
NumberParameters: 1
Parameter[0]: 0000000000000000
DEFAULT_BUCKET_ID: BREAKPOINT_AVRF
PROCESS_NAME: mstsc.exe
ERROR_CODE: (NTSTATUS) 0x80000003 - {AUSNAHME} Haltepunkt Im Quellprogramm wurde ein Haltepunkt erreicht.
EXCEPTION_CODE: (HRESULT) 0x80000003 (2147483651) - Mindestens ein Argument ist ung ltig.
EXCEPTION_CODE_STR: 80000003
EXCEPTION_PARAMETER1: 0000000000000000
WATSON_BKT_PROCSTAMP: 524b5b3d
WATSON_BKT_PROCVER: 6.3.9600.16415
BUILD_VERSION_STRING: 6.1.7601.24000 (win7sp1_ldr.171231-1547)
THREAD_ATTRIBUTES:
OS_LOCALE: FRA
PROBLEM_CLASSES:
ID: [0n300]
Type: [#APPLICATION_FAULT_STRING]
Class: Primary
Scope: DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
BUCKET_ID
Name: Omit
Data: Add
String: [BREAKPOINT]
PID: [Unspecified]
TID: [Unspecified]
Frame: [0]
ID: [0n92]
Type: [AVRF]
Class: Addendum
Scope: DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
BUCKET_ID
Name: Add
Data: Omit
PID: [0x2fe0]
TID: [0x1c98]
Frame: [0] : verifier!VerifierStopMessage
BUGCHECK_STR: BREAKPOINT_AVRF
PRIMARY_PROBLEM_CLASS: BREAKPOINT
LAST_CONTROL_TRANSFER: from 000007fee9f994f2 to 000007fee9f9a668
STACK_TEXT:
00000000`1a20d9a0 000007fe`e9f994f2 : 00000000`1a20ea28 000007fe`e9f91988 000007fe`fd649270 000007fe`e9f91610 : verifier!VerifierStopMessage+0x1f0
00000000`1a20da50 000007fe`e9fb5863 : 000007fe`e9fb6604 00000000`1a20e9f0 000007fe`fd470000 00000000`1a20e9f0 : verifier!AVrfpDphReportCorruptedBlock+0x32a
00000000`1a20db10 00000000`76d67398 : 00000000`1a20dc70 00000000`1a20dc40 00000000`00000000 00000000`76d58468 : verifier!_chkstk+0xf3
00000000`1a20db40 00000000`76d7bf9d : 00000000`1a210000 00000000`1a20e9f0 00000000`1a20e9f0 000007fe`e9fde0fc : ntdll!_C_specific_handler+0x8c
00000000`1a20dbb0 00000000`76d504ca : 00000000`1a210000 00000000`01001002 000007fe`00001950 00000000`02991710 : ntdll!RtlpExecuteHandlerForException+0xd
00000000`1a20dbe0 00000000`76d7b63e : 00000000`1a20e7b0 00000000`1a20e2c0 00000000`00000000 00000000`00000000 : ntdll!RtlDispatchException+0x45a
00000000`1a20e2c0 000007fe`e9f96be1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!KiUserExceptionDispatch+0x2e
00000000`1a20e9f0 000007fe`e9f98b87 : 00000000`25701000 f0f0f0f0`f0f0f0f0 00000000`00000000 00000000`00000000 : verifier!AVrfpDphFindBusyMemoryNoCheck+0x91
00000000`1a20ea50 00000000`76dd4a14 : 00000000`25700000 00000000`1a20f2e0 00000000`01001002 00000000`00000000 : verifier!AVrfDebugPageHeapSize+0x5b
00000000`1a20ea90 00000000`76d9427f : 00000000`25700000 00000000`00000000 00000000`25700000 f0f0f0f0`f0f0f0f0 : ntdll!RtlDebugSizeHeap+0x34
00000000`1a20eae0 000007fe`e9fb093f : 00000000`00000000 f0f0f0f0`f0f0f0f0 00000000`02a80000 000007fe`d87e9a63 : ntdll! ?? ::FNODOBFM::`string'+0xd26f
00000000`1a20eb30 000007fe`d87eed84 : 00000000`25700000 00000000`00000000 f0f0f0f0`f0f0f0f0 00000000`76c11a00 : verifier!AVrfpHeapFree+0x57
00000000`1a20ebc0 00000000`25700000 : 00000000`00000000 f0f0f0f0`f0f0f0f0 00000000`76c11a00 00000000`00000000 : BLEtokenCredentialProvider+0xed84
00000000`1a20ebc8 00000000`00000000 : f0f0f0f0`f0f0f0f0 00000000`76c11a00 00000000`00000000 000007fe`d87e6b46 : 0x25700000
SYMBOL_NAME: bletokencredentialprovider+ed84
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: BLEtokenCredentialProvider
IMAGE_NAME: BLEtokenCredentialProvider.dll
DEBUG_FLR_IMAGE_TIMESTAMP: 4f686c3b
STACK_COMMAND: .ecxr ; kb
BUCKET_ID: X64_BREAKPOINT_AVRF_bletokencredentialprovider+ed84
FAILURE_EXCEPTION_CODE: 80000003
FAILURE_IMAGE_NAME: BLEtokenCredentialProvider.dll
BUCKET_ID_IMAGE_STR: BLEtokenCredentialProvider.dll
FAILURE_ID_HASH_STRING: um:breakpoint_avrf_80000003_bletokencredentialprovider.dll!unknown
FAILURE_ID_HASH: {2a6d23c0-cb20-73ec-3d92-f208d9f741cc}
Followup: MachineOwner
---------
0:020> lmvm BLEtokenCredentialProvider
Browse full module list
start end module name
000007fe`d87e0000 000007fe`d885d000 BLEtokenCredentialProvider T (no symbols)
Loaded symbol image file: BLEtokenCredentialProvider.dll
Image path: C:\Program Files\CSR\CSR Harmony Wireless Software Stack\BLEtokenCredentialProvider.dll
Image name: BLEtokenCredentialProvider.dll
Browse all global symbols functions data
Timestamp: Tue Mar 20 12:38:35 2012 (4F686C3B)
CheckSum: 000826D1
ImageSize: 0007D000
File version: 2.1.63.0
Product version: 2.1.63.0
Look for an update and if there is no one, remove this tool.
The section object from a 3thParty vendor is named rpsPdf10.mutex and it's intended use is to mimic a semaphore by writing a Boolean flag to it.
Using LiveKd and with a lot of help from SO, I've issued following command's trying to get detailed info of this Section object.
0: kd>!process 0 0 3thParty.exe
...
PROCESS fffffa800ea80060
SessionId: 0 Cid: 0a00 Peb: fffdf000 ParentCid: 014c
DirBase: 99349000 ObjectTable: fffff8a004448bf0 HandleCount: 338.
Image: 3thParty.exe
...
0: kd> !handle 0 7 fffffa800ea80060
...
08 fffff8a012e26710 Section rpsPdf10.mutex
...
0: kd> !object fffff8a012e26710
Object: fffff8a012e26710 Type: (fffffa800cd7cea0) Section
ObjectHeader: fffff8a012e266e0 (new version)
HandleCount: 38 PointerCount: 39
Directory Object: fffff8a00a980080 Name: rpsPdf10.mutex
0: kd> dt -r1 nt!_SECTION_OBJECT 0xfffff8a012e26710
+0x000 StartingVa : 0x00000022`00000100 Void
+0x008 EndingVa : 0x00000000`0008dfb0 Void
+0x010 Parent : 0xfffffa80`c0000001 Void
+0x018 LeftChild : (null)
+0x020 RightChild : 0xfffffa80`00000034 Void
+0x028 Segment : 0xfffff8a0`102d7820 _SEGMENT_OBJECT
+0x000 BaseAddress : 0xfffffa80`0fbed900 Void
+0x008 TotalNumberOfPtes : 1
+0x010 SizeOfSegment : _LARGE_INTEGER 0x1
+0x018 NonExtendedPtes : 0x1000
+0x01c ImageCommitment : 0
+0x020 ControlArea : (null)
+0x028 Subsection : (null)
+0x030 MmSectionFlags : 0xfffffa80`10987b10 _MMSECTION_FLAGS
+0x038 MmSubSectionFlags : 0x00000000`03400000 _MMSUBSECTION_FLAGS
All this looks correct to me but how can I find the content the section?
points to note as in earlier answer machine is 32 bit and os is win7 and windbg version is insider preview 16278 commands are arch agnostic and pointer arithmetic if any are arch dependent
and the walk through is on live binary not in a dump as there is a very fair chance that the page might have been paged out in the dump and demo might be inconclusive i might add to this answer later
getting contents form section is kinda convoluted
(there are several types of Section like
1) ALPC section(com objects )
2) File backed Section
3) PageFileBacked Section etc
the walkthrough below is for a pagefile backed section (most common type)
Assuming you compiled and executed the code below
the exe will create a SectionObject in global namespace
and the contents will be backed by PagingFile and will be waiting for a
keypress
#include <windows.h>
#include <stdio.h>
#define bsize 256
int main(){
char szMsg[]={"Message from blabb to lieven from Stack Overflow."};
int ret = NULL;
HANDLE hMap = CreateFileMapping((HANDLE)-1,NULL,4,0,bsize,"Global\\MyMap");
if(hMap){
PCHAR buff = (PCHAR) MapViewOfFile(hMap,0xf001f,0,0,bsize);
if(buff){
CopyMemory(buff, szMsg, sizeof(szMsg));
ret = getchar();
UnmapViewOfFile(buff);
}
CloseHandle(hMap);
}
return ret;
}
assuming the process is waiting for a keypress launch livekd or setup a live kernel debugging connection if it is running in a remote machine / vm
C:>livekd -k "c:\Program Files\Windows Kits\10\Debuggers\x86\cdb.exe"
LiveKd v5.62 - Execute kd/windbg on a live system
Launching c:\Program Files\Windows Kits\10\Debuggers\x86\cdb.exe:
Microsoft (R) Windows Debugger Version 10.0.16278.1000 X86
get the the _EPROCESS and set context
kd> !process 0 0 secobj.exe
PROCESS 8605ab28 SessionId: 1 Cid: 0fbc Peb: 7ffd9000 ParentCid: 0af4
DirBase: 7e2712e0 ObjectTable: c288ba00 HandleCount: 9.
Image: secobj.exe
kd> .process /p /r 8605ab28
Implicit process is now 8605ab28
kd> ? #$proc
Evaluate expression: -2046448856 = 8605ab28
kd> ?? (char *)#$proc->ImageFileName
char * 0x8605ac94
"secobj.exe"
look for a handle of type Section in the current process notice since our
section is named in global namespace windbg deciphers that for us
kd> !handle 0 3 #$proc Section
Searching for handles of type Section
PROCESS 8605ab28 SessionId: 1 Cid: 0fbc Peb: 7ffd9000 ParentCid: 0af4
DirBase: 7e2712e0 ObjectTable: c288ba00 HandleCount: 9.
Image: secobj.exe
Handle table at c288ba00 with 9 entries in use
0024: Object: c238e9c8 GrantedAccess: 000f0007 Entry: c37b7048
Object: c238e9c8 Type: (84ec6040) Section
ObjectHeader: c238e9b0 (new version)
HandleCount: 1 PointerCount: 2
Directory Object: 98a0f170 Name: MyMap
dumping the SectionObject
kd> dt nt!_SECTION_OBJECT c238e9c8
+0x000 StartingVa : 0xc227e2c8 Void
+0x004 EndingVa : 0x00d3db6c Void
+0x008 Parent : 0xb0d3db20 Void
+0x00c LeftChild : (null)
+0x010 RightChild : 0x00000003 Void
+0x014 Segment : 0xc36aba20 _SEGMENT_OBJECT
kd> $$ Notice the Last Segment member it is not SEGMENT_OBJECT but
nt!_segment or actually a pointer to ControlArea for this Section
kd> dt nt!_SEGMENT 0xc36aba20
+0x000 ControlArea : 0x85182d08 _CONTROL_AREA
+0x004 TotalNumberOfPtes : 1
+0x008 SegmentFlags : _SEGMENT_FLAGS
+0x00c NumberOfCommittedPages : 1
+0x010 SizeOfSegment : 0x1000
+0x018 ExtendInfo : (null)
+0x018 BasedAddress : (null)
+0x01c SegmentLock : _EX_PUSH_LOCK
+0x020 u1 : <unnamed-tag>
+0x024 u2 : <unnamed-tag>
+0x028 PrototypePte : 0xc36aba50 _MMPTE
+0x030 ThePtes : [1] _MMPTE
kd> $$ you can expand the union u2 and dump the FirstMappedVa of the union to look at the contents of this Section
kd> dt nt!_SEGMENT u2.FirstMappedVa 0xc36aba20
+0x024 u2 :
+0x000 FirstMappedVa : 0x000e0000 Void
dumping the contents
kd> da 0xe0000
000e0000 "Message from blabb to lieven fro"
000e0020 "m Stack Overflow."
kd>
or do !ca to get the FirstMappedVa which points to the first page
if the contents are greater than one page boundary fetching them is
kinda tedious as they may have been paged out and would need an execution
operation and thus a page fault handled to get them into view
kd> !ca poi(0xc36aba20)
ControlArea # 85182d08
Segment c36aba20 Flink 00000000 Blink 00000000
Section Ref 1 Pfn Ref 0 Mapped Views 1
User Ref 2 WaitForDel 0 Flush Count 0
File Object 00000000 ModWriteCount 0 System Views 0
WritableRefs 0
Flags (2000) Commit
Pagefile-backed section
Segment # c36aba20
ControlArea 85182d08 ExtendInfo 00000000
Total Ptes 1
Segment Size 1000 Committed 1
CreatingProcess 8605ab28 FirstMappedVa e0000 <-------------
ProtoPtes c36aba50
Flags (80000) ProtectionMask
Subsection 1 # 85182d58
ControlArea 85182d08 Starting Sector 0 Number Of Sectors 0
Base Pte c36aba50 Ptes In Subsect 1 Unused Ptes 0
Flags 8 Sector Offset 0 Protection 4
kd>
Adding another answer to show another pagefile backed section contents
where you may need to go to the Creating Process and look at its virtual address instead of the process that is current
you may know shell keeps some global counters in a shared section
0104: Object: c2255450 GrantedAccess: 00000006 Entry: c5d9b208
Object: c2255450 Type: (84ec6040) Section
ObjectHeader: c2255438 (new version)
HandleCount: 6 PointerCount: 7
Directory Object: 9d662520 Name: windows_shell_global_counters
code to retrieve them
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <shlwapi.h>
#pragma comment(lib,"shlwapi.lib")
//add all items in the ... place holder in arrays below
PCHAR enuname[] = { "GLOBALCOUNTER_SEARCHMANAGER",...};
int foo [] = { GLOBALCOUNTER_SEARCHMANAGER,...};
void main (void) {
long cval = NULL;
for(int i =0; i < _countof(foo) ;i++) {
cval = SHGlobalCounterGetValue((SHGLOBALCOUNTER)foo[i]);
printf ("%65s = %0x\n" ,enuname[i], cval);
}
}
compiling and executing this you may get a result like this (keep in mind the counters are volatile so you may need to be quick enough for comparing)
C:\secobj\shglob>shglob.exe | head -n 13
GLOBALCOUNTER_SEARCHMANAGER = 0
GLOBALCOUNTER_SEARCHOPTIONS = 0
GLOBALCOUNTER_FOLDERSETTINGSCHANGE = 0
GLOBALCOUNTER_RATINGS = 0
GLOBALCOUNTER_APPROVEDSITES = 0
GLOBALCOUNTER_RESTRICTIONS = 5
GLOBALCOUNTER_SHELLSETTINGSCHANGED = 2
GLOBALCOUNTER_SYSTEMPIDLCHANGE = 0
GLOBALCOUNTER_OVERLAYMANAGER = 0
GLOBALCOUNTER_QUERYASSOCIATIONS = 0
GLOBALCOUNTER_IESESSIONS = 0
GLOBALCOUNTER_IEONLY_SESSIONS = 0
GLOBALCOUNTER_APPLICATION_DESTINATIONS = 83
looking at current process
kd> ? #$proc
Evaluate expression: -2033240552 = 86cf3618
kd> ?? (char *)#$proc->ImageFileName
char * 0x86cf3784
"cdb.exe"
kd> !handle 0 3 #$proc Section
0164: Object: c2255450 GrantedAccess: 00000006 Entry: c3df32c8
Object: c2255450 Type: (84ec6040) Section
ObjectHeader: c2255438 (new version)
HandleCount: 11 PointerCount: 12
Directory Object: 9d662520 Name: windows_shell_global_counters
kd> dc ##c++(((nt!_segment *)((nt!_section_object *) 0xc2255450)->Segment)->u2.FirstMappedVa)
00290000 ???????? ???????? ???????? ???????? ????????????????
00290010 ???????? ???????? ???????? ???????? ????????????????
00290020 ???????? ???????? ???????? ???????? ????????????????
00290030 ???????? ???????? ???????? ???????? ????????????????
00290040 ???????? ???????? ???????? ???????? ????????????????
00290050 ???????? ???????? ???????? ???????? ????????????????
00290060 ???????? ???????? ???????? ???????? ????????????????
00290070 ???????? ???????? ???????? ???????? ????????????????
it may be that this current process obtained a handle with OpenFileMapping but didn't map it yet or the page is paged out (livekd can't use pagein ) whatever we cant seem to view this section content
lets look who created this shared section
kd> ? ##c++(((nt!_segment *)((nt!_section_object *) 0xc2255450)->Segment)->u1.CreatingProcess)
Evaluate expression: -2050635184 = 85c5ca50
kd> !process 85c5ca50 0
PROCESS 85c5ca50 SessionId: 1 Cid: 0af4 Peb: 7ffd9000 ParentCid: 0704
DirBase: 7e271420 ObjectTable: c5d873c8 HandleCount: 888.
Image: explorer.exe
it looks logical explorer.exe seemed to have created this shared section
lets check by dumping 0n13 dwords from the creating process virtual address
kd> .process /p /r 85c5ca50
kd> dc ##c++(((nt!_segment *)((nt!_section_object *) 0xc2255450)->Segment)->u2.FirstMappedVa) l0n13
00290000 00000000 00000000 00000000 00000000 ................
00290010 00000000 00000005 00000002 00000000 ................
00290020 00000000 00000000 00000000 00000000 ................
00290030 00000083 ....
I've been learning x64 assembly language and, as in other languages, I can throw a breakpoint in when debugging and step through the program. The breakpoint is said to pause program execution and the debugging utility even displays which values are in the CPU registers at the given point in time. However, how is it possible that the values are the real values given there are many other programs running on the computer which must be using the same CPU registers to execute when I'm debugging? Are these values actually not in the CPU when the program is paused during debugging? Thanks.
Update: Windows 10 user mode code.
The operating system is scheduling threads based on various information like priority, processor affinity etc. When the OS decides to give another thread the chance to run, that's called a Context switch (Wikipedia). During the context switch, the operating system will save the current thread's registers and then restore the new thread's registers.
Internally, the operating system needs to maintain all that information. You can easily have 1000 threads, so the OS must have 1000 times all the registers somewhere in memory.
You can safely use a user mode debugger and have a look at the kernel structures. Since you're on Windows, I'll use windbg, which is part of the Debugging Tools for Windows.
In order to follow, start any program (notepad is always a good candidate) and attach WinDbg (F6).
First, let's get the correct information from Microsoft:
0:000> .symfix
0:000> .reload /f
Those commands will make sure that we have the correct symbols (PDBs).
Next, let's look at a kernel thread (not at the user mode part of the thread, since the kernel schedules it):
0:000> dt nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 CycleTime : Uint8B
+0x018 HighCycleTime : Uint4B
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr32 Void
[...]
+0x1b8 WaitPrcb : Ptr32 _KPRCB
[...]
+0x1f4 ThreadCounters : Ptr32 _KTHREAD_COUNTERS
+0x1f8 XStateSave : Ptr32 _XSTATE_SAVE
As we can see, the information to maintain a thread is quite large (0x1f8+4 or 508 bytes).
If you read the Wikipedia article, you found out:
This is usually stored in a data structure called a process control block (PCB) or switchframe.
That's the _KPRCB structure at offset 1b8. Let's look at that one:
0:000> dt nt!_KPRCB
ntdll!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD
+0x008 NextThread : Ptr32 _KTHREAD
[...]
+0x3658 Context : Ptr32 _CONTEXT
+0x365c ContextFlags : Uint4B
+0x3660 ExtendedState : Ptr32 _XSAVE_AREA
Given we switch the context, let's assume that _CONTEXT is the right thing to look at.
0:000> dt nt!_CONTEXT
+0x000 ContextFlags : Uint4B
+0x004 Dr0 : Uint4B
+0x008 Dr1 : Uint4B
+0x00c Dr2 : Uint4B
+0x010 Dr3 : Uint4B
+0x014 Dr6 : Uint4B
+0x018 Dr7 : Uint4B
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : Uint4B
+0x090 SegFs : Uint4B
+0x094 SegEs : Uint4B
+0x098 SegDs : Uint4B
+0x09c Edi : Uint4B
+0x0a0 Esi : Uint4B
+0x0a4 Ebx : Uint4B
+0x0a8 Edx : Uint4B
+0x0ac Ecx : Uint4B
+0x0b0 Eax : Uint4B
+0x0b4 Ebp : Uint4B
+0x0b8 Eip : Uint4B
+0x0bc SegCs : Uint4B
+0x0c0 EFlags : Uint4B
+0x0c4 Esp : Uint4B
+0x0c8 SegSs : Uint4B
+0x0cc ExtendedRegisters : [512] UChar
So yes, there they are: the registers.
And, know what? Seems I attached to a 32 bit process, so you probably got different results. Anyway, try again and you'll get:
0:000> dt nt!_CONTEXT
+0x000 P1Home : Uint8B
+0x008 P2Home : Uint8B
+0x010 P3Home : Uint8B
+0x018 P4Home : Uint8B
+0x020 P5Home : Uint8B
+0x028 P6Home : Uint8B
+0x030 ContextFlags : Uint4B
[...]
+0x078 Rax : Uint8B
+0x080 Rcx : Uint8B
+0x088 Rdx : Uint8B
+0x090 Rbx : Uint8B
+0x098 Rsp : Uint8B
+0x0a0 Rbp : Uint8B
+0x0a8 Rsi : Uint8B
+0x0b0 Rdi : Uint8B
+0x0b8 R8 : Uint8B
+0x0c0 R9 : Uint8B
[...]
+0x280 Xmm14 : _M128A
+0x290 Xmm15 : _M128A
+0x300 VectorRegister : [26] _M128A
+0x4a0 VectorControl : Uint8B
+0x4a8 DebugControl : Uint8B
+0x4b0 LastBranchToRip : Uint8B
+0x4b8 LastBranchFromRip : Uint8B
+0x4c0 LastExceptionToRip : Uint8B
+0x4c8 LastExceptionFromRip : Uint8B
Summary: the kernel creates as many "objects" of type _CONTEXT as needed where it maintains the registers. Whenever a context switch shall happen, the kernel saves the current registers and restores other ones.
When debugging, your thread is suspended, so it will not run on the CPU. The CPU can also not be halted, because you need to be able to interact with the debugger. The CPU is executing instructions of the debugger. However, the debugger will give the information from _KTHREAD to you.
That's all quite simplified, but maybe enough for the moment. There are things like software and hardware context switches (read at OSWiki) and other things. It's certainly also interesting how the kernel gets its registers before it restores other user mode registers etc., but that's too much for a SO post.
I forced a complete kernel dump for an application that appears to be waiting on a deadlocked thread in a kernel driver. I believe I have identified the offending thread as it has 1920031 ticks (0:08:19:12.675) which is roughly how long the application has been waiting. The thread has also only spent .015 milliseconds in user and kernel time:
THREAD 85e18cf8 Cid 0988.1160 Teb: 7ffa8000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Non-Alertable
85dac938 NotificationEvent
85da5350 SynchronizationEvent
IRP List:
b7d67818: (0006,0094) Flags: 00060000 Mdl: 00000000
85d95c70: (0006,0094) Flags: 00060000 Mdl: 00000000
Not impersonating
DeviceMap 8c808980
Owning Process ba224730 Image: MyApplication.exe
Attached Process N/A Image: N/A
Wait Start TickCount 2447201 Ticks: 1920031 (0:08:19:12.675)
Context Switch Count 326 IdealProcessor: 1
UserTime 00:00:00.015
KernelTime 00:00:00.015
Win32 Start Address 0x6b19f28e
Stack Init c5463fd0 Current c5463748 Base c5464000 Limit c5461000 Call 0
Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Kernel stack not resident.
ChildEBP RetAddr
c5463760 830ce8d5 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
c5463798 830cd733 nt!KiSwapThread+0x266
c54637c0 830c94e4 nt!KiCommitThreadWait+0x1df
c546393c 8327d1db nt!KeWaitForMultipleObjects+0x535
c5463bc8 8327cf48 nt!ObpWaitForMultipleObjects+0x262
c5463d18 8308da16 nt!NtWaitForMultipleObjects+0xcd
c5463d18 777870d4 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame # c5463d34)
WARNING: Frame IP not in any known module. Following frames may be wrong.
012af6f8 00000000 0x777870d4
It has two pending IRPs to the same device and same file.
2: kd> !irp 85d95c70
Irp is active with 1 stacks 1 is current (= 0x85d95ce0)
No Mdl: No System Buffer: Thread 85e18cf8: Irp stack trace.
cmd flg cl Device File Completion-Context
>[IRP_MJ_DEVICE_CONTROL(e), N/A(0)]
0 1 8886d6b8 a1b90a48 00000000-00000000 pending
\Driver\nsiproxy
Args: 00000014 00000014 0012003f 012af5b0
2: kd> !object a1b90a48
Object: a1b90a48 Type: (85b36518) File
ObjectHeader: a1b90a30 (new version)
HandleCount: 1 PointerCount: 10
!findhandle on that file confirms MyApplication.exe has access to it.
600: Entry ba707c00 Granted Access 100080
The file is not locked:
2: kd> dt -r nt!_OBJECT_HEADER a1b90a30
+0x000 PointerCount : 0n10
+0x004 HandleCount : 0n1
+0x004 NextToFree : 0x00000001 Void
+0x008 Lock : _EX_PUSH_LOCK
+0x000 Locked : 0y0
+0x000 Waiting : 0y0
+0x000 Waking : 0y0
+0x000 MultipleShared : 0y0
+0x000 Shared : 0y0000000000000000000000000000 (0)
+0x000 Value : 0
+0x000 Ptr : (null)
How can one thread have two nearly-identical pending IRPs to the same device and file?
How can the file object be open in two IRPs but only have one open handle?
Thanks!