首先,楼主是什么平台?我看了从 2000 到 Vista 平台,CcGetLsnForFileObject 函数的实现大致都是相同的。都是获取 BCB 链的自旋锁,分析脏页,释放锁。出错的指令是 F2 66 AF repne scas word ptr es:[edi]。这句是较为经典的字符串长度计算优化代码,一般用法如下:xor eax, eaxrepne scas byte ptr es:[edi]作用就是在 es:[edi] 字符串里查找 AL (AL此时为0),即寻找字符串的结束符,以计算长度。这个功能和 CcGetLsnForFileObject 函数的实现基本无关 (或者就是我分析的目标和楼主不是一个平台,您Win7?)我的第一个推断就是函数被 Patch 破坏了??导致产生了错误的指令?所以请楼主 u 一下您平台的 CcGetLsnForFileObject 函数,以进一步分析、定位错误。谢谢。
kd> u CcGetLsnForFileObjectnt!CcGetLsnForFileObject:8086d7ac 8bff mov edi,edi8086d7ae 55 push ebp8086d7af 8bec mov ebp,esp8086d7b1 83ec1c sub esp,1Ch8086d7b4 8b4508 mov eax,dword ptr [ebp+8] ; 取 FileObject8086d7b7 8b4014 mov eax,dword ptr [eax+14h] ; 取 FileObject->SectionObjectPointer8086d7ba 33d2 xor edx,edx8086d7bc 56 push esi8086d7bd 8b7004 mov esi,dword ptr [eax+4] ; 取 FileObject->SectionObjectPointer->SharedCacheMap 到 esi8086d7c0 33c0 xor eax,eax8086d7c2 3bf2 cmp esi,edx ; if(SharedCacheMap == NULL)8086d7c4 8945f8 mov dword ptr [ebp-8],eax ; Oldest.LowPart = 0; (initialize lsn variables)8086d7c7 8955fc mov dword ptr [ebp-4],edx ; Oldest.HighPart = 0; (initialize lsn variables)8086d7ca 8955f0 mov dword ptr [ebp-10h],edx ; Newest.LowPart = 0; (initialize lsn variables)8086d7cd 8955f4 mov dword ptr [ebp-0Ch],edx ; Newest.HighPart = 0; (initialize lsn variables)8086d7d0 0f84a6000000 je nt!CcGetLsnForFileObject+0xd0 (8086d87c)8086d7d6 57 push edi8086d7d7 8d8eb8000000 lea ecx,[esi+0B8h]8086d7dd 8d55e4 lea edx,[ebp-1Ch]8086d7e0 ff15d4108080 call dword ptr [nt!_imp_KeAcquireInStackQueuedSpinLock (808010d4)];; FASTCALL :;; KeAcquireInStackQueuedSpinLock(&SharedCacheMap->BcbSpinLock, &LockHandle);; | |; | +-- [ebp-1Ch]; +-- [esi+0B8h] (这指针类型是 _SHARED_CACHE_MAP);8086d7e6 8d7e10 lea edi,[esi+10h] ; _SHARED_CACHE_MAP.BcbList (+0x010)8086d7e9 8b07 mov eax,dword ptr [edi] ; BcbList.Flink8086d7eb 83e810 sub eax,10h ; 取到 _BCB 的首指针8086d7ee 8d4810 lea ecx,[eax+10h] ; while (&Bcb->BcbLinks != &SharedCacheMap->BcbList)8086d7f1 3bcf cmp ecx,edi ;8086d7f3 7465 je nt!CcGetLsnForFileObject+0xae (8086d85a)8086d7f5 53 push ebx8086d7f6 668138fd02 cmp word ptr [eax],2FDh8086d7fb 7550 jne nt!CcGetLsnForFileObject+0xa1 (8086d84d);; 显然 repne scas word ptr es:[edi] 是错误的指令,这句代码(F2 66 AF)根本不符合上下文语境。;8086d7fd 80780200 cmp byte ptr [eax+2],08086d801 744a je nt!CcGetLsnForFileObject+0xa1 (8086d84d)8086d803 8b7020 mov esi,dword ptr [eax+20h]........
CcGetLsnForFileObject 函数内部相关数据结构:
kd> dt nt!_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 +0x02c Flags : Uint4B +0x030 FileName : _UNICODE_STRING +0x038 CurrentByteOffset : _LARGE_INTEGER +0x040 Waiters : Uint4B +0x044 Busy : Uint4B +0x048 LastLock : Ptr32 Void +0x04c Lock : _KEVENT +0x05c Event : _KEVENT +0x06c CompletionContext : Ptr32 _IO_COMPLETION_CONTEXT
kd> dt nt!_SECTION_OBJECT_POINTERS +0x000 DataSectionObject : Ptr32 Void>>>+0x004 SharedCacheMap : Ptr32 Void +0x008 ImageSectionObject : Ptr32 Void
kd> dt nt!_SHARED_CACHE_MAP +0x000 NodeTypeCode : Int2B +0x002 NodeByteSize : Int2B +0x004 OpenCount : Uint4B +0x008 FileSize : _LARGE_INTEGER>>>+0x010 BcbList : _LIST_ENTRY +0x018 SectionSize : _LARGE_INTEGER +0x020 ValidDataLength : _LARGE_INTEGER +0x028 ValidDataGoal : _LARGE_INTEGER +0x030 InitialVacbs : [4] Ptr32 _VACB +0x040 Vacbs : Ptr32 Ptr32 _VACB +0x044 FileObject : Ptr32 _FILE_OBJECT +0x048 ActiveVacb : Ptr32 _VACB +0x04c NeedToZero : Ptr32 Void +0x050 ActivePage : Uint4B +0x054 NeedToZeroPage : Uint4B +0x058 ActiveVacbSpinLock : Uint4B +0x05c VacbActiveCount : Uint4B +0x060 DirtyPages : Uint4B +0x064 SharedCacheMapLinks : _LIST_ENTRY +0x06c Flags : Uint4B +0x070 Status : Int4B +0x074 Mbcb : Ptr32 _MBCB +0x078 Section : Ptr32 Void +0x07c CreateEvent : Ptr32 _KEVENT +0x080 WaitOnActiveCount : Ptr32 _KEVENT +0x084 PagesToWrite : Uint4B +0x088 BeyondLastFlush : Int8B +0x090 Callbacks : Ptr32 _CACHE_MANAGER_CALLBACKS +0x094 LazyWriteContext : Ptr32 Void +0x098 PrivateList : _LIST_ENTRY +0x0a0 LogHandle : Ptr32 Void +0x0a4 FlushToLsnRoutine : Ptr32 void +0x0a8 DirtyPageThreshold : Uint4B +0x0ac LazyWritePassCount : Uint4B +0x0b0 UninitializeEvent : Ptr32 _CACHE_UNINITIALIZE_EVENT +0x0b4 NeedToZeroVacb : Ptr32 _VACB +0x0b8 BcbSpinLock : Uint4B +0x0bc Reserved : Ptr32 Void +0x0c0 Event : _KEVENT +0x0d0 VacbPushLock : _EX_PUSH_LOCK +0x0d8 PrivateCacheMap : _PRIVATE_CACHE_MAP +0x130 WriteBehindWorkQueueEntry : Ptr32 Void
//// This is the Buffer Control Block structure for representing data which// is "pinned" in memory by one or more active requests and/or dirty. This// structure is created the first time that a call to CcPinFileData specifies// a particular integral range of pages. It is deallocated whenever the Pin// Count reaches 0 and the Bcb is not Dirty.//// NOTE: The first four fields must be the same as the PUBLIC_BCB.//
typedef struct _BCB {
union {
// // To ensure QuadAlign (sizeof (BCB)) >= QuadAlign (sizeof (MBCB)) // so that they can share the same pool blocks. //
MBCB Dummy;
struct {
// // Type and size of this record //
CSHORT NodeTypeCode;
// // Flags //
BOOLEAN Dirty; BOOLEAN Reserved;
// // Byte FileOffset and and length of entire buffer //
ULONG ByteLength; LARGE_INTEGER FileOffset;
// // Links for BcbList in SharedCacheMap //
LIST_ENTRY BcbLinks;
// // Byte FileOffset of last byte in buffer (used for searching) //
LARGE_INTEGER BeyondLastByte;
// // Oldest Lsn (if specified) when this buffer was set dirty. //
LARGE_INTEGER OldestLsn;
// // Most recent Lsn specified when this buffer was set dirty. // The FlushToLsnRoutine is called with this Lsn. //
LARGE_INTEGER NewestLsn;
// // Pointer to Vacb via which this Bcb is mapped. //
PVACB Vacb;
// // Count of threads actively using this Bcb to process a request. // This must be manipulated under protection of the BcbListSpinLock // in the SharedCacheMap. //
ULONG PinCount;
// // Resource to synchronize buffer access. Pinning Readers and all Writers // of the described buffer take out shared access (synchronization of // buffer modifications is strictly up to the caller). Note that pinning // readers do not declare if they are going to modify the buffer or not. // Anyone writing to disk takes out exclusive access, to prevent the buffer // from changing while it is being written out. //
ERESOURCE Resource;
// // Pointer to SharedCacheMap for this Bcb. //
PSHARED_CACHE_MAP SharedCacheMap;
// // This is the Base Address at which the buffer can be seen in // system space. All access to buffer data should go through this // address. //
PVOID BaseAddress; }; };
} BCB;还是那句话,楼主 U 一下你的 CcGetLsnForFileObject 函数以便分析。
0. 楼主你早贴 minidump 就好了。当然,是 kernel dump 就更好了...
1. 楼主第一个帖子里的 dump 显然和实际的情况不符,Windbg 错误的栈定位到了:
STACK_TEXT: ada3dd30 8053e648 00000a0c 00000000 00000000 nt!CcGetLsnForFileObject+0x4f ada3dd64 7c92e4f4 badb0d00 0352fc08 aedfad98 nt!PopRunDownSourceTargetList+0x10e WARNING: Frame IP not in any known module. Following frames may be wrong.
而 nt!CcGetLsnForFileObject 函数内部根本没有字符串 (repne scas word ptr es:[edi]) 相关操作,枉费我一番功夫呀。进一步分析楼主贴出的 minidump 可以发现这次 Windbg 仍然有个小错误。2. minidump 里的 nt!CcGetLsnForFileObject 如下:
kd> u CcGetLsnForFileObjectnt!CcGetLsnForFileObject:804e5200 8bff mov edi,edi804e5202 55 push ebp804e5203 8bec mov ebp,esp804e5205 83ec1c sub esp,1Ch804e5208 8b4508 mov eax,dword ptr [ebp+8]804e520b 8b4014 mov eax,dword ptr [eax+14h]804e520e 33d2 xor edx,edx804e5210 56 push esi804e5211 8b7004 mov esi,dword ptr [eax+4]804e5214 33c0 xor eax,eax804e5216 3bf2 cmp esi,edx804e5218 8945f8 mov dword ptr [ebp-8],eax804e521b 8955fc mov dword ptr [ebp-4],edx804e521e 8955f0 mov dword ptr [ebp-10h],edx804e5221 8955f4 mov dword ptr [ebp-0Ch],edx804e5224 0f84a6000000 je nt!CcGetLsnForFileObject+0xd0 (804e52d0)804e522a 57 push edi804e522b 8d8eb8000000 lea ecx,[esi+0B8h]804e5231 8d55e4 lea edx,[ebp-1Ch]804e5234 ff1504874d80 call dword ptr [nt!_imp_KeAcquireInStackQueuedSpinLock (804d8704)]804e523a 8d7e10 lea edi,[esi+10h]804e523d 8b07 mov eax,dword ptr [edi]804e523f 83e810 sub eax,10h804e5242 8d4810 lea ecx,[eax+10h]804e5245 3bcf cmp ecx,edi804e5247 7465 je nt!CcGetLsnForFileObject+0xae (804e52ae)804e5249 53 push ebx804e524a 668138fd02 cmp word ptr [eax],2FDh804e524f 7550 jne nt!CcGetLsnForFileObject+0xa1 (804e52a1)804e5251 80780200 cmp byte ptr [eax+2],0804e5255 744a je nt!CcGetLsnForFileObject+0xa1 (804e52a1)804e5257 8b7020 mov esi,dword ptr [eax+20h]
这个和我上面分析的帖子完全一致。而楼主您列出来的是? -_-!
3. minidump 里显示,真正的问题比较复杂,我现在手头有点事,下个帖子给你分析一下。
我能从 Minidump 中看出什么:
1. 楼主在玩魔兽 (或者你在写外挂搞魔兽)
2. Windbg 又出错了!
Windbg 告诉我们出错的 call stack 是:
STACK_TEXT: b694cbf4 b694cd18 1743cf2e b694cd64 0019e824 nt!RtlInitUnicodeString+0x1bWARNING: Frame IP not in any known module. Following frames may be wrong.b694cd30 8053e648 000026d8 00000000 00000000 0xb694cd18b694cd30 7c92e4f4 000026d8 00000000 00000000 nt!KiFastCallEntry+0xf80019e86c 00000000 00000000 00000000 00000000 0x7c92e4f4
nt!KiFastCallEntry+0xd7:8053e627 33c9 xor ecx,ecx8053e629 8a0c18 mov cl,byte ptr [eax+ebx]8053e62c 8b3f mov edi,dword ptr [edi]8053e62e 8b1c87 mov ebx,dword ptr [edi+eax*4]8053e631 2be1 sub esp,ecx8053e633 c1e902 shr ecx,28053e636 8bfc mov edi,esp8053e638 3b35549a5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80559a54)]8053e633 c1e902 shr ecx,28053e636 8bfc mov edi,esp8053e638 3b35549a5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80559a54)]8053e63e 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053e7ec)8053e644 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]8053e646 ffd3 call ebx8053e648 8be5 mov esp,ebp8053e64a 8b0d24f1dfff mov ecx,dword ptr ds:[0FFDFF124h]
nt!KiFastCallEntry 告诉我们,一切正常,某些“好但是阴险”的钩子点没有工作,程序在 8053e646 准备进入 SSDT。但是 SSDT 里的某个项被 Hook 了。
WARNING: Frame IP not in any known module. Following frames may be wrong.b694cd30 8053e648 000026d8 00000000 00000000 0xb694cd18 << Hook!b694cd30 7c92e4f4 000026d8 00000000 00000000 nt!KiFastCallEntry+0xf8
那么,0xb694cd18 是什么?没有答案:
kd> dd 0xb694cd18b694cd18 00000000 1743cf2e 00320031 e2aee6e0b694cd28 00040003 8588f008 b694cd64 8053e648b694cd38 000026d8 00000000 00000000 1743ce10b694cd48 00000000 1743bf98 00001000 00000003b694cd58 8588f008 00000000 01000000 0019e86cb694cd68 7c92e4f4 badb0d00 0019e7f8 ffffffffb694cd78 b6ebfda0 00000000 00000000 00000000b694cd88 00000000 00000000 00000000 00000000
结合栈桢分析,我发现这里是 Windbg 自己解析出错了!因为 nt!RtlInitUnicodeString 只开辟了一个局部变量,而这个分析显然有问题:
kd> dd espb694cbf0 b694cd64 f7bbd806 b694cd18 1743cf2eb694cc00 b694cd64 0019e824 f7bbd6ed 2e576f57b694cc10 00657865 00000000 00000003 00000001b694cc20 00004021 00000000 00000000 00000000b694cc30 00000000 00000000 b694ccc4 f718a0c5b694cc40 0019e5dc 00100001 0019e580 0019e5b0b694cc50 00000003 00004021 855b1b00 ebfb2640b694cc60 8060d590 ebf9f247 0019e5dc 00100001
kd> kbChildEBP RetAddr Args to Child b694cbf4 b694cd18 1743cf2e b694cd64 0019e824 nt!RtlInitUnicodeString+0x1bWARNING: Frame IP not in any known module. Following frames may be wrong.b694cd30 8053e648 000026d8 00000000 00000000 0xb694cd18b694cd30 7c92e4f4 000026d8 00000000 00000000 nt!KiFastCallEntry+0xf80019e86c 00000000 00000000 00000000 00000000 0x7c92e4f4
Windbg 认为:b694cd64 f7bbd806 是局部变量b694cd18 是返回地址1743cf2e 是参数一b694cd64 是参数二
但是显然应该是:
b694cd64 是局部变量 —— push edif7bbd806 是返回地址 —— 回到钩子函数里b694cd18 是参数一 —— RtlInitUnicodeString 的 DestinationString1743cf2e 是参数二 —— RtlInitUnicodeString 的 SourceString
这个猜想太大胆了 OK!验证一下:
kd> u f7bbd806*** WARNING: Unable to verify timestamp for hfile.sys*** ERROR: Module load completed but symbols could not be loaded for hfile.syshfile+0x806:f7bbd806 ?? ??? ^ Memory access error in 'u f7bbd806'
原来是 hfile.sys 挂钩了 SSDT。google 一下,这可不是什么好东西!
kd> lmstart end module name........f7bba000 f7bbad00 dxgthk (deferred)f7bbd000 f7bbdf80 hfile T (no symbols)f7c03000 f7c03b80 Null (deferred)........
---------------------------------------------------------------------------
RtlInitUnicodeString 参数一:b694cd18
kd> dt nt!_unicode_string b694cd18 "Logs???" +0x000 Length : 0 +0x002 MaximumLength : 0 +0x004 Buffer : 0x1743cf2e "Logs???"
RtlInitUnicodeString 参数二:1743cf2e
kd> db 1743cf2e1743cf2e 4c 00 6f 00 67 00 73 00-f8 e8 8a 6b 46 42 7e 72 L.o.g.s....kFB~r1743cf3e 60 00 0c 7c e8 5a 09 03-22 28 0c 7c e5 39 58 78 `..|.Z.."(.|.9Xx1743cf4e 78 78 8b 73 e5 41 8d 2d-3d 3d 2d 74 05 3a fd fd xx.s.A.-==-t.:..1743cf5e fd 01 8e 84 ec 6b 62 7a-7a f8 cb 6b 66 42 1c 18 .....kbzz..kfB..1743cf6e d8 50 ab 6b 06 3a a0 78-9f 17 52 9d 87 42 e1 f2 .P.k.:.x..R..B..1743cf7e f0 e0 eb 7c 26 3a 72 72-72 72 8b 6b 46 42 55 f5 ...|&:rrrr.kFBU.1743cf8e ad 0b eb 73 a8 4a f5 ff-2a 2a 0d 00 01 02 6f 10 ...s.J..**....o.1743cf9e 70 05 e0 01 1c 00 80 85-28 00 f0 94 29 63 d5 9d p.......(...)c..
非常好!和我预期的一模一样~ B-)
我说到这里,楼主自己也能分析出蓝屏的原因了吧。
看样子 hfile.sys 驱动想初始化一个 UNICODE_STRING ——“LOGS”,但是它这里没有指定字符串的结束符:1743cf2e 4c 00 6f 00 67 00 73 00-f8 e8 8a 6b 46 42 7e 721743cf2e 4c 00 6f 00 67 00 73 00-00 00 8a 6b 46 42 7e 72 << 这才是正确的!
结果,可怜的 repne scas word ptr es:[edi] 指令,一直从地址 1743cf2e 计算字符串长度到 1743d000:
eax=00000000 ebx=1743ced0 ecx=ffffff96 edx=b694cd18 esi=805d96b6 edi=1743d000eip=8052bd97 esp=b694cbf0 ebp=b694cd30 iopl=0 nv up ei pl nz ac pe cycs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010217
看看这一段吧:
kd> db 1743cf2e 1743d0001743cf2e 4c 00 6f 00 67 00 73 00-f8 e8 8a 6b 46 42 7e 72 L.o.g.s....kFB~r1743cf3e 60 00 0c 7c e8 5a 09 03-22 28 0c 7c e5 39 58 78 `..|.Z.."(.|.9Xx1743cf4e 78 78 8b 73 e5 41 8d 2d-3d 3d 2d 74 05 3a fd fd xx.s.A.-==-t.:..1743cf5e fd 01 8e 84 ec 6b 62 7a-7a f8 cb 6b 66 42 1c 18 .....kbzz..kfB..1743cf6e d8 50 ab 6b 06 3a a0 78-9f 17 52 9d 87 42 e1 f2 .P.k.:.x..R..B..1743cf7e f0 e0 eb 7c 26 3a 72 72-72 72 8b 6b 46 42 55 f5 ...|&:rrrr.kFBU.1743cf8e ad 0b eb 73 a8 4a f5 ff-2a 2a 0d 00 01 02 6f 10 ...s.J..**....o.1743cf9e 70 05 e0 01 1c 00 80 85-28 00 f0 94 29 63 d5 9d p.......(...)c..1743cfae 9d 15 19 d7 92 ad f2 fa-72 5a 13 be 71 ad 3f 7b ........rZ..q.?{1743cfbe eb 82 f2 b5 2f a5 00 fd-af ae ae 94 46 42 d6 d4 ..../.......FB..1743cfce d4 d4 cf a4 c8 5a 45 85-27 07 ad 8c c9 52 25 2d .....ZE.'....R%-1743cfde 2d 29 2f 9d 0b 74 7f 7f-6e ca e8 5a 66 4a a4 b6 -)/..t..n..ZfJ..1743cfee b6 b4 b2 a5 08 5b 15 d5-d5 95 b2 ad ef 9c f8 f8 .....[..........1743cffe f1 e8 ?? ..?
为了找 00 00 结束符,指令一直访问到地址错误、蓝屏,精神可嘉。
最后对楼主的建议:
1. 玩 WOW 前赶紧卸载那什么 hfile.sys 小心它 LOGS 你的密码啥的。
2. 开启360。我发现你的机器上有360,但是自我保护没开启。/**** WARNING: Unable to verify timestamp for safeboxkrnl.sys*** ERROR: Module load completed but symbols could not be loaded for safeboxkrnl.sys*/
3. 您若是无聊就把 hfile.sys 发给我看看 (wangyu_at_qihoo_dot_net),我若是无聊就把它给逆了。
4. 写的累死我了,楼主给点掌声吧... : P
王宇分析的很生动!不过还有值得挖掘的地方,使用dds命令看一下栈,很可能还执行过其它模块的函数:kd> dds espb694cbf0 b694cd64b694cbf4 f7bbd806 hfile+0x806b694cbf8 b694cd18b694cbfc 1743cf2eb694cc00 b694cd64b694cc04 0019e824b694cc08 f7bbd6ed hfile+0x6edb694cc0c 2e576f57b694cc10 00657865b694cc14 00000000b694cc18 00000003b694cc1c 00000001b694cc20 00004021b694cc24 00000000b694cc28 00000000b694cc2c 00000000b694cc30 00000000b694cc34 00000000b694cc38 b694ccc4b694cc3c f718a0c5 kl1+0x20c5b694cc40 0019e5dcb694cc44 00100001b694cc48 0019e580b694cc4c 0019e5b0b694cc50 00000003b694cc54 00004021b694cc58 855b1b00b694cc5c ebfb2640 cmdguard+0x16640b694cc60 8060d590 nt!ProbeForReadb694cc64 ebf9f247 cmdguard+0x3247b694cc68 0019e5dcb694cc6c 00100001
楼主是否有可能产生一个kernel dump或者full dump(最好),然后压缩一下传上来?