NULL Data Pointer Pattern: case study
CARE: Crash Analysis Report Environment
DATA (Dump Analysis + Trace Analysis) Facebook group
Please join the community of memory (dump) and trace analysis engineers. This group promotes scientific methods and memory dump-based worldview.
Twitter @ DumpAnalysis You can now follow portal and blog news at DumpAnalysis on Twitter
LinkedIn Group Dr. Watson Enthusiasts All about Dr. Watson errors and more. Get news, excerpts and progress reports about the forthcoming book The Science of Dr. Watson: An Illustrated History of Debugging (ISBN 978-1906717070)
2010 (0x7DA) - The Year of Dump Analysis 2011 (0x7DB) - 2020 (0x7E4) The Debugging Decade
Here is the promised case study for the previous post about data NULL pointers. The complete dump has this bugcheck:
0: kd> !analyze -v
[...]
KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e)
This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Some common problems are exception code 0x80000003. This means a hard coded breakpoint or assertion was hit, but this system was booted /NODEBUG. This is not supposed to happen as developers should never have hardcoded breakpoints in retail code, but ... If this happens, make sure a debugger gets connected, and the system is booted /DEBUG. This will let us see why this breakpoint is happening.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 8081c7c4, The address that the exception occurred at
Arg3: f1b5d730, Trap Frame
Arg4: 00000000
[...]
FAULTING_IP:
nt!IoIsOperationSynchronous+e
8081c7c4 f6412c02 test byte ptr [ecx+2Ch],2
TRAP_FRAME: f1b5d730 -- (.trap 0xfffffffff1b5d730)
[...]
0: kd> .trap 0xfffffffff1b5d730
ErrCode = 00000000
eax=8923b008 ebx=00000000 ecx=00000000 edx=8923b008 esi=891312d0 edi=89f0b300
eip=8081c7c4 esp=f1b5d7a4 ebp=f1b5d7a4 iopl=0 nv up ei ng nz ac pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010296
nt!IoIsOperationSynchronous+0xe:
8081c7c4 f6412c02 test byte ptr [ecx+2Ch],2 ds:0023:0000002c=??
0: kd> kv 100
ChildEBP RetAddr Args to Child
f1b5d7a4 f42cdea9 8923b008 89f0b300 8923b008 nt!IoIsOperationSynchronous+0xe
f1b5d7bc 8081df85 89f0b300 8923b008 00000200 driveB!FsdDeviceIoControlFile+0×19
f1b5d7d0 808ed7a9 00000000 f1b5da84 f1b5db6c nt!IofCallDriver+0×45
f1b5da20 f3c3a521 89f0b300 f1b5da84 f1b5da84 nt!IoVolumeDeviceToDosName+0×89
WARNING: Stack unwind information not available. Following frames may be wrong.
f1b5da3c f3c3b58e 00000618 e4e00420 f1b5dad4 driverA+0×18531
[…]
f1b5dc3c 8081df85 89f48b48 87fa3008 89140d30 driverA+0×1df4
f1b5dc50 808f5437 87fa3078 89140d30 87fa3008 nt!IofCallDriver+0×45
f1b5dc64 808f61bf 89f48b48 87fa3008 89140d30 nt!IopSynchronousServiceTail+0×10b
f1b5dd00 808eed08 000000f0 00000000 00000000 nt!IopXxxControlFile+0×5e5
f1b5dd34 808897bc 000000f0 00000000 00000000 nt!NtDeviceIoControlFile+0×2a
f1b5dd34 7c8285ec 000000f0 00000000 00000000 nt!KiFastCallEntry+0xfc (TrapFrame @ f1b5dd64)
0856e154 7c826fcb 77e416f5 000000f0 00000000 ntdll!KiFastSystemCallRet
0856e158 77e416f5 000000f0 00000000 00000000 ntdll!NtDeviceIoControlFile+0xc
0856e1bc 6f050c6c 000000f0 5665824c 0856e234 kernel32!DeviceIoControl+0×137
[…]
From WDK help we know that the first parameter to IoIsOperationSynchronous is a pointer to an IRP structure:
0: kd> !irp 8923b008
Irp is active with 3 stacks 3 is current (= 0x8923b0c0)
No Mdl: System buffer=878b7288: Thread 8758a020: Irp stack trace.
cmd flg cl Device File Completion-Context
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
>[ e, 0] 0 0 89f0b300 00000000 00000000-00000000
\FileSystem\DriverB
Args: 00000200 00000000 004d0008 00000000
Disassembling the function shows some pointer dereferencing and we can reconstruct it starting from EBP+8, a pointer to an IRP.
0: kd> .asm no_code_bytes
Assembly options: no_code_bytes
0: kd> u nt!IoIsOperationSynchronous nt!IoIsOperationSynchronous+0xe
nt!IoIsOperationSynchronous:
8081c7b6 mov edi,edi
8081c7b8 push ebp
8081c7b9 mov ebp,esp
8081c7bb mov eax,dword ptr [ebp+8]
8081c7be mov ecx,dword ptr [eax+60h]
8081c7c1 mov ecx,dword ptr [ecx+18h]
EAX+60 seems to be a current stack location member of IRP and it is a pointer itself to _IO_STACK_LOCATION structure:
0: kd> dt -r _IRP 8923b008
ntdll!_IRP
+0x000 Type : 6
+0x002 Size : 0x268
+0x004 MdlAddress : (null)
+0x008 Flags : 0x70
[...]
+0x038 CancelRoutine : (null)
+0x03c UserBuffer : 0xf1b5d814
+0×040 Tail : __unnamed
+0×000 Overlay : __unnamed
+0×000 DeviceQueueEntry : _KDEVICE_QUEUE_ENTRY
+0×000 DriverContext : [4] (null)
+0×010 Thread : 0×8758a020 _ETHREAD
+0×014 AuxiliaryBuffer : (null)
+0×018 ListEntry : _LIST_ENTRY [ 0×0 - 0×0 ]
+0×020 CurrentStackLocation : 0×8923b0c0 _IO_STACK_LOCATION
[…]
ECX+18 is a pointer to a file object in _IO_STACK_LOCATION structure:
0: kd> dt _IO_STACK_LOCATION 8923b008+60
ntdll!_IO_STACK_LOCATION
+0x000 MajorFunction : 0xc0 ''
+0x001 MinorFunction : 0xb0 ''
+0x002 Flags : 0x23 '#'
+0x003 Control : 0x89 ''
+0x004 Parameters : __unnamed
+0x014 DeviceObject : (null)
+0×018 FileObject : (null)
+0×01c CompletionRoutine : (null)
+0×020 Context : (null)
2C offset at the crash point test byte ptr [ecx+2Ch],2 is _FILE_OBJECT Flags member:
0: kd> dt _FILE_OBJECT
ntdll!_FILE_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Vpb : Ptr32 _VPB
+0x00c FsContext : Ptr32 Void
+0x010 FsContext2 : Ptr32 Void
+0x014 SectionObjectPointer : Ptr32 _SECTION_OBJECT_POINTERS
+0x018 PrivateCacheMap : Ptr32 Void
+0x01c FinalStatus : Int4B
+0x020 RelatedFileObject : Ptr32 _FILE_OBJECT
+0x024 LockOperation : UChar
+0x025 DeletePending : UChar
+0x026 ReadAccess : UChar
+0x027 WriteAccess : UChar
+0x028 DeleteAccess : UChar
+0x029 SharedRead : UChar
+0x02a SharedWrite : UChar
+0x02b SharedDelete : UChar
+0×02c Flags : Uint4B
+0×030 FileName : _UNICODE_STRING
+0×038 CurrentByteOffset : _LARGE_INTEGER
+0×040 Waiters : Uint4B
+0×044 Busy : Uint4B
+0×048 LastLock : Ptr32 Void
+0×04c Lock : _KEVENT
+0×05c Event : _KEVENT
+0×06c CompletionContext : Ptr32 _IO_COMPLETION_CONTEXT
So it looks like driverA passed an IRP with NULL File object address to driverB and this is also shown in the output of !irp command above.
- Dmitry Vostokov @ DumpAnalysis.org -
_1125.png)
Coming Soon:
Debugging Notebook: Essential Concepts, WinDbg Commands and Tools
Crash Dump Analysis for System Administrators and Support Engineers
New Magazines:
Debugged! MZ/PE: MagaZine for/from Practicing Engineers
New Books:
Memory Dump Analysis Anthology, Volume 3
First Fault Software Problem Solving: A Guide for Engineers, Managers and Users
x64 Windows Debugging: Practical Foundations
Also available:
Windows Debugging: Practical Foundations
DLL List Landscape: The Art from Computer Memory Space
Dumps, Bugs and Debugging Forensics: The Adventures of Dr. Debugalov
WinDbg: A Reference Poster and Learning Cards
Memory Dump Analysis Anthology, Volume 2
Memory Dump Analysis Anthology, Volume 1
New Children's Book: