Hunting for a Driver
Consider this redirector file system exception while servicing a page fault:
1: kd> k 100
ChildEBP RetAddr
afa8b2d4 f53442c4 nt!KeBugCheckEx+0x1b
afa8b2fc f533df48 rdbss!RxExceptionFilter+0xf0
afa8b308 8083a93d rdbss!RxFsdCommonDispatch+0×3ca
afa8b330 8083a498 nt!_except_handler3+0×61
afa8b354 8083a46a nt!ExecuteHandler2+0×26
afa8b404 80816479 nt!ExecuteHandler+0×24
afa8b7bc 808346c4 nt!KiDispatchException+0×131
afa8b824 80834678 nt!CommonDispatchException+0×4a
afa8b848 808401e9 nt!KiExceptionExit+0×186
afa8b8ac f5345d44 nt!IopAllocateIrpPrivate+0xa3
afa8b8f8 f534619c rdbss!RxShadowIoHandler+0xac
afa8b924 f534adb3 rdbss!RxShadowLowIo+0×1a1
afa8b94c f5350fa7 rdbss!RxLowIoSubmit+0×182
afa8b970 f5350dbd rdbss!RxLowIoReadShell+0×7d
afa8ba1c f533d8d9 rdbss!RxCommonRead+0×416
afa8baac f534b9a2 rdbss!RxFsdCommonDispatch+0×320
afa8bacc f52c9a63 rdbss!RxFsdDispatch+0xd3
afa8baec 80840153 mrxsmb!MRxSmbFsdDispatch+0×134
afa8bb00 f71dcc45 nt!IofCallDriver+0×45
afa8bb28 80840153 fltmgr!FltpDispatch+0×6f
afa8bb3c f421576a nt!IofCallDriver+0×45
afa8bb4c f4212621 DriverA!Dispatch+0xa4
afa8bb58 80840153 DriverA!Interface_dispatch+0×53
afa8bb6c f5251aef nt!IofCallDriver+0×45
afa8bb9c f5251bd2 DriverB!PassThrough+0×115
afa8bba8 80840153 DriverB!Dispatch+0×78
afa8bbbc f281ac29 nt!IofCallDriver+0×45
WARNING: Stack unwind information not available. Following frames may be wrong.
afa8bbdc 8082784f DriverC+0×5c29
afa8bc14 80840153 nt!MiResolveMappedFileFault+0×640
afa8bc28 f780f42a nt!IofCallDriver+0×45
afa8bc40 80840153 DriverD+0×42a
afa8bc54 80824b6f nt!IofCallDriver+0×45
afa8bc6c 8082645c nt!IoPageRead+0×109
afa8bcf0 80847650 nt!MiDispatchFault+0xd74
afa8bd4c 80836c2a nt!MmAccessFault+0×9c2
afa8bd4c 77df4749 nt!KiTrap0E+0xdc
0012f568 00000000 0×77df4749
We see that DriverA and DriverB are possibly pass-through and have little influence. For DriverC and DriverD we don’t even have symbol files but they are even further down the stack. Default analysis points to the code that tries to call another driver:
1: kd> !analyze -v
[...]
RDR_FILE_SYSTEM (27)
If you see RxExceptionFilter on the stack then the 2nd and 3rd parameters are the exception record and context record. Do a .cxr on the 3rd parameter and then kb to obtain a more informative stack trace. The high 16 bits of the first parameter is the RDBSS bugcheck code, which is defined as follows:
RDBSS_BUG_CHECK_CACHESUP = 0xca550000,
RDBSS_BUG_CHECK_CLEANUP = 0xc1ee0000,
RDBSS_BUG_CHECK_CLOSE = 0xc10e0000,
RDBSS_BUG_CHECK_NTEXCEPT = 0xbaad0000,
Arguments:
Arg1: baad0080
Arg2: afa8b7d8
Arg3: afa8b4d4
Arg4: 8084014f
EXCEPTION_RECORD: afa8b7d8 -- (.exr 0xffffffffafa8b7d8)
ExceptionAddress: 8084014f (nt!IofCallDriver+0×00000041)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000044
Attempt to read from address 00000044
CONTEXT: afa8b4d4 -- (.cxr 0xffffffffafa8b4d4)
eax=00000003 ebx=00000000 ecx=86a62ed8 edx=861e0468 esi=00000000 edi=87083970
eip=8084014f esp=afa8b8a0 ebp=afa8b8ac iopl=0 nv up ei ng nz na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010286
nt!IofCallDriver+0×41:
8084014f ff548638 call dword ptr [esi+eax*4+38h] ds:0023:00000044=????????
STACK_TEXT:
afa8b8ac f5345d44 86997a50 87083970 86863604 nt!IofCallDriver+0×41
afa8b8f8 f534619c 87083970 868634e0 e36c7ad8 rdbss!RxShadowIoHandler+0xac
afa8b924 f534adb3 87083970 868634e0 e36c7ad8 rdbss!RxShadowLowIo+0×1a1
afa8b94c f5350fa7 01083970 868634e0 e36c7ad8 rdbss!RxLowIoSubmit+0×182
afa8b970 f5350dbd 87083970 868634e0 e36c7ad8 rdbss!RxLowIoReadShell+0×7d
afa8ba1c f533d8d9 87083970 868634e0 88b56910 rdbss!RxCommonRead+0×416
afa8baac f534b9a2 f5348028 868634e0 88b56910 rdbss!RxFsdCommonDispatch+0×320
afa8bacc f52c9a63 88964768 868634e0 88d6c020 rdbss!RxFsdDispatch+0xd3
afa8baec 80840153 00000000 018634e0 88f372b8 mrxsmb!MRxSmbFsdDispatch+0×134
afa8bb00 f71dcc45 88f372b8 86863628 8843d418 nt!IofCallDriver+0×45
afa8bb28 80840153 88d6c020 868634e0 868634e0 fltmgr!FltpDispatch+0×6f
afa8bb3c f421576a 00000000 88ad73f0 afa8bb6c nt!IofCallDriver+0×45
afa8bb4c f4212621 88d1ea98 868634e0 80840153 DriverA!Dispatch+0xa4
afa8bb58 80840153 88d1ea98 868634e0 88ada7f8 DriverA!Interface_dispatch+0×53
afa8bb6c f5251aef 86863604 88438a78 00000000 nt!IofCallDriver+0×45
afa8bb9c f5251bd2 88ada7f8 868634e0 80840153 DriverB!PassThrough+0×115
afa8bba8 80840153 88ada7f8 868634e0 88b3a0d8 DriverB!Dispatch+0×78
afa8bbbc f281ac29 00000000 87780ca0 afa8bc14 nt!IofCallDriver+0×45
WARNING: Stack unwind information not available. Following frames may be wrong.
afa8bbdc 8082784f 88b3a0d8 81f2afa4 88ab83d8 DriverC+0×5c29
afa8bc14 80840153 88b3a020 868634e0 88433760 nt!MiResolveMappedFileFault+0×640
afa8bc28 f780f42a 8762cf38 f7811f2f 884336a8 nt!IofCallDriver+0×45
afa8bc40 80840153 884336a8 868634e0 868634e0 DriverD+0×42a
afa8bc54 80824b6f 88ab83e8 86e0e438 88ab83d8 nt!IofCallDriver+0×45
afa8bc6c 8082645c 88b56906 88ab8410 88ab83f0 nt!IoPageRead+0×109
afa8bcf0 80847650 00000000 01fc897c c0007f20 nt!MiDispatchFault+0xd74
afa8bd4c 80836c2a 00000000 01fc897c 00000001 nt!MmAccessFault+0×9c2
afa8bd4c 77df4749 00000000 01fc897c 00000001 nt!KiTrap0E+0xdc
0012f568 00000000 00000000 00000000 00000000 0×77df4749
We assume that IofCallDriver has the same parameters as IoCallDriver but they were not passed on the stack. They are passed via ECX and EDX registers:
1: kd> !devobj 86997a50
86997a50: is not a device object
1: kd> !irp 87083970
IRP signature does not match, probably not an IRP
3: kd> .asm no_code_bytes
Assembly options: no_code_bytes
1: kd> ub f5345d44
rdbss!RxShadowIoHandler+0×8d:
f5345d25 mov dword ptr [ebp-4],ebx
f5345d28 call dword ptr [rdbss!_imp__IoGetTopLevelIrp (f534711c)]
f5345d2e mov dword ptr [ebp-20h],eax
f5345d31 push ebx
f5345d32 call dword ptr [rdbss!_imp__IoSetTopLevelIrp (f5347120)]
f5345d38 mov edx,dword ptr [ebp-24h]
f5345d3b mov ecx,dword ptr [ebp-28h]
f5345d3e call dword ptr [rdbss!_imp_IofCallDriver (f5347204)]
We have the value of EBP at the time of the crash at IofCallDriver+0×41 so we need to see how it had changed:
1: kd> uf nt!IofCallDriver
Flow analysis was incomplete, some code may be missing
nt!IofCallDriver:
8084011b mov edi,edi
8084011d push ebp
8084011e mov ebp,esp
80840120 mov eax,dword ptr [nt!pIofCallDriver (808a5000)]
80840125 test eax,eax
80840127 jne nt!IofCallDriver+0xe (80859d6b)
nt!IofCallDriver+0x15:
8084012d dec byte ptr [edx+23h]
80840130 cmp byte ptr [edx+23h],0
80840134 jle nt!IofCallDriver+0x1e (80859d72)
nt!IofCallDriver+0x2c:
8084013a mov eax,dword ptr [edx+60h]
8084013d sub eax,24h
80840140 push esi
80840141 mov dword ptr [edx+60h],eax
80840144 mov dword ptr [eax+14h],ecx
80840147 movzx eax,byte ptr [eax]
8084014a mov esi,dword ptr [ecx+8]
8084014d push edx
8084014e push ecx
8084014f call dword ptr [esi+eax*4+38h]
80840153 pop esi
80840154 pop ebp
80840155 ret
nt!IofCallDriver+0xe:
80859d6b push dword ptr [ebp+4]
80859d6e call eax
80859d70 pop ebp
80859d71 ret
nt!IofCallDriver+0x1e:
80859d72 push 0
80859d74 push 0
80859d76 push 0
80859d78 push edx
80859d79 push 35h
80859d7b call nt!KeBugCheckEx (8087c485)
80859d80 int 3
80859d81 pop ebp
80859d82 jmp eax
We see the standard prolog and therefore EBP points to the old EBP from RxShadowIoHandler:
1: kd> dp ebp l1
afa8b8ac afa8b8f8
We have the value of the pointer to a device object, which is invalid:
1: kd> dp afa8b8f8-28 l1
afa8b8d0 86a62ed8
1: kd> !devobj 86a62ed8
86a62ed8: is not a device object
and the value of the pointer to an IRP which is valid:
1: kd> dp afa8b8f8-24 l1
afa8b8d4 861e0468
1: kd> !irp 861e0468
Irp is active with 4 stacks 4 is current (= 0x861e0544)
Mdl=88ab8410: No System Buffer: Thread 8846e020: 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
[ 0, 0] 0 0 00000000 00000000 00000000-00000000
Args: 00000000 00000000 00000000 00000000
>[ 3, 0] 0 e0 86a62ed8 86ff7028 f5345bdc-87083970 Success Error Cancel
86a62ed8: is not a device object
rdbss!RxShadowIrpCompletion
Args: 00008000 00000000 00008000 00000000
From the full disassembly code of IofCallDriver we see that ECX and EDX values had not been changed so we could get our parameters from them too.
Device object is invalid in IRP too and it points to a NULL driver object:
1: kd> dt _DEVICE_OBJECT 86a62ed8
nt!_DEVICE_OBJECT
+0×000 Type : 0
+0×002 Size : 0
+0×004 ReferenceCount : 0
+0×008 DriverObject : (null)
+0×00c NextDevice : (null)
+0×010 AttachedDevice : (null)
+0×014 CurrentIrp : (null)
+0×018 Timer : (null)
+0×01c Flags : 0
+0×020 Characteristics : 0
+0×024 Vpb : 0×00040000 _VPB
+0×028 DeviceExtension : (null)
+0×02c DeviceType : 0×86a62f04
+0×030 StackSize : 4 ”
+0×034 Queue : __unnamed
+0×05c AlignmentRequirement : 0
+0×060 DeviceQueue : _KDEVICE_QUEUE
+0×074 Dpc : _KDPC
+0×094 ActiveThreadCount : 0
+0×098 SecurityDescriptor : (null)
+0×09c DeviceLock : _KEVENT
+0×0ac SectorSize : 0
+0×0ae Spare1 : 0
+0×0b0 DeviceObjectExtension : 0×86a62f88 _DEVOBJ_EXTENSION
+0×0b4 Reserved : 0×86a62f88
IofCallDriver tried to call a function pointer No.3 from the driver major dispatch table:
1: kd> dt _DRIVER_OBJECT
nt!_DRIVER_OBJECT
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x008 Flags : Uint4B
+0x00c DriverStart : Ptr32 Void
+0x010 DriverSize : Uint4B
+0x014 DriverSection : Ptr32 Void
+0x018 DriverExtension : Ptr32 _DRIVER_EXTENSION
+0x01c DriverName : _UNICODE_STRING
+0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
+0x028 FastIoDispatch : Ptr32 _FAST_IO_DISPATCH
+0x02c DriverInit : Ptr32 long
+0x030 DriverStartIo : Ptr32 void
+0x034 DriverUnload : Ptr32 void
+0×038 MajorFunction : [28] Ptr32 long
The resulted effective address is a NULL code pointer (EAX=3, major code and ESI is NULL):
call dword ptr [esi+eax*4+38h] ds:0023:00000044=????????
Now we come back to our IRP to examine a file object:
cmd flg cl Device File Completion-Context
>[ 3, 0] 0 e0 86a62ed8 86ff7028 f5345bdc-87083970 Success Error Cancel
1: kd> !fileobj 86ff7028
\Userdata\[…]\Application Suite\ApplicationSuite.RUS
Device Object: 0×87300aa8 \Driver\DriverE
Vpb: 0×8843b280
Event signalled
Access: Read SharedRead SharedDelete
Flags: 0x18c0040
Cache Supported
Handle Created
Fast IO Read
Remote Origin
FsContext: 0xe453fda0 FsContext2: 0xe26904b8
CurrentByteOffset: 0
Cache Data:
Section Object Pointers: 86b80a9c
Shared Cache Map: 00000000
Here we see another DriverE and associated drivers from its device stack:
1: kd> !devstack 0×87300aa8
!DevObj !DrvObj !DevExt ObjectName
865f9cc8 \Driver\DriverF 865f9d80
8737aaf0 \Driver\DriverG 8737aba8
87155280 \Driver\DriverH 87155338
> 87300aa8 \Driver\DriverE 87300b60 BlockVolume1
!DevNode 88b6eac0 :
DeviceInst is “STORAGE\Volume\{[…]}”
ServiceName is “volsnap”
- Dmitry Vostokov @ DumpAnalysis.org -
December 1st, 2009 at 4:10 pm
Good stuff Dmitry! Very useful.