阅读:2908回复:6
在内存中找到文件的内容
这一篇可能会有所帮助,鉴于格式散乱,建议想细看的下载DOC版本看,要在这调整。。。我比较懒
Finding File Contents in Memory The NT Insider, Vol 11, Issue 1, Jan-Feb 2004 | Published: 12-Mar-04| Modified: 19-Mar-04 声明:原文来自www.osr.com,所有权利归原作者所有,翻译并贴在这里的目的只为学习和交流,除了商用你可以随意地使用这篇译文。但请不要删除声明。 ——by jununfly 版本:20090120 在调试课上,我总是邀请学生带来crash dumps让我们分析。这有助于我们掌握分析崩溃的技能。近来,一学生带来了当访问文件时他的过滤驱动崩溃的一个dump。他问”我怎么知道正被访问的是哪个文件?” 一旦我们向下跟踪,学生问"我如何看见文件的内容 – 你确定它在内存里?" 如果你需要向下跟踪一个内存中的文件,你可以像本文介绍的一样做。 在深入这个机制钱,理解用于跟踪的数据结构的基本关系很有用。关键的数据结构是: FILE_OBJECT – 这是Windows用于跟踪一个文件的一个单一的打开实例的对象。因此,如果你有一个文件的多个打开实例,你就有多个文件对象。 SECTION_OBJECT_POINTERS – 这是把指定的FILE_OBJECT连接到虚拟内存控制结构(当文件内容在内存中时它保持对文件内容的跟踪 – 并允许Windows在那些内容不在内存中时取得它们.)上的数据结构。 CONTROL_AREA – 内存管理器用这个数据结构来跟踪一个给定部分的状态信息。 SHARED_CACHE_MAP – 缓存管理器用这个数据结构来跟踪文件中单独的被缓存的区域(region)的状态。一个单一文件中可能有许多这样的被缓存的区域。 VACB – 缓存管理器用这个数据结构来描述在缓存中正被使用的虚拟地址,来访问一个被缓存的区域中的数据。 在当前版本的Windows提供的公有类型信息中所有这些数据结构都可用 – 因此要找到缓存所用的虚拟地址我们已经万事俱备。有了这些虚拟地址,找到真实的文件数据就小菜一碟。 一般,我们使用IRP中的值或使用一个句柄并查找对象句柄表中的值来找到FILE_OBJECT。因此,我们可以使用!irp命令(显示一个IRP和它的栈位置)或者用!handle命令.不论哪个,我们要用作为结果的信息。这里,我选择用句柄,且以"Microsoft Word"进程为例。为了达到这个目的我用了命令"!handle 0 3 86304020".第一个参数指示我想要看到进程的所有的句柄(我不确定我要的是哪个句柄).第二个参数是标记域,它指示我想要每个句柄的信息(默认值是1,表示仅提供根本信息.额外的标记意味着我展示各种对象的名).第三个参数是进程的地址(以便句柄命令使用正确的句柄表).通过这我能浏览对象句柄表来找出这个文件的句柄: 0cf0: Object: 85df1028 GrantedAccess: 0012019fObject: 85df1028 Type: (86fdbe70) File ObjectHeader: 85df1010 HandleCount: 1 PointerCount: 1 Directory Object: 00000000 Name: \Documents and Settings\mason\My Documents\Files in Memory.doc {HarddiskVolume1} 这给了我文件对象的地址(85df1028),然后我用它来显示指定文件对象的相关信息: lkd> dt nt!_FILE_OBJECT 85df1028 +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86f22cc0 +0x008 Vpb : 0x86f22c38 +0x00c FsContext : 0xe3d92d90 +0x010 FsContext2 : 0xe16f35b0 +0x014 SectionObjectPointer : 0x85f50c6c +0x018 PrivateCacheMap : (null) +0x01c FinalStatus : 0 +0x020 RelatedFileObject : (null) +0x024 LockOperation : 0x1 '' +0x025 DeletePending : 0 '' +0x026 ReadAccess : 0x1 '' +0x027 WriteAccess : 0x1 '' +0x028 DeleteAccess : 0 '' +0x029 SharedRead : 0x1 '' +0x02a SharedWrite : 0x1 '' +0x02b SharedDelete : 0 '' +0x02c Flags : 0x40042 +0x030 FileName : _UNICODE_STRING "\Documents and Settings\mason\My Documents\Files in Memory.doc" +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0 +0x040 Waiters : 0 +0x044 Busy : 0 +0x048 LastLock : 0x860c35a0 +0x04c Lock : _KEVENT +0x05c Event : _KEVENT +0x06c CompletionContext : (null) 由此能找出SECTION_OBJECT_POINTERS结构(85f50c6c),用调试器显示如下: lkd> dt nt!_SECTION_OBJECT_POINTERS 0x85f50c6c +0x000 DataSectionObject : 0x869ed9d8 +0x004 SharedCacheMap : (null) +0x008 ImageSectionObject : (null) 这告诉我文件有一个data section object 但没有相应的shared cache map (意味着这个文件实例没有被缓存)也没有image section object (意味着它不是一个可执行的镜像).现在是狡猾的部分。事实上部分对象指向一个CONTROL_AREA.我可以用DataSectionObject的地址来在调试器中看到它: kd> dt nt!_CONTROL_AREA 0x869ed9d8 +0x000 Segment : 0xe34fd698 +0x004 DereferenceList : _LIST_ENTRY [ 0x0 - 0x0 ] +0x00c NumberOfSectionReferences : 1 +0x010 NumberOfPfnReferences : 7 +0x014 NumberOfMappedViews : 1 +0x018 NumberOfSubsections : 1 +0x01a FlushInProgressCount : 0 +0x01c NumberOfUserReferences : 2 +0x020 u : __unnamed +0x024 FilePointer : 0x85f84478 +0x028 WaitingForDeletion : (null) +0x02c ModifiedWriteCount : 0 +0x02e NumberOfSystemCacheViews : 0 注意FilePointer没有指回到同一文件对象。要知道一个FILE_OBJECT仅仅是一个打开实例,而不是真实的文件。然而,内存管理器必须使用一个指定的FILE_OBJECT来执行分页I/O – 且这也是它将会使用的文件对象。如果我显示这个对象的信息你会注意到一些有趣的事情: lkd> !object 0x85f84478 Object: 85f84478 Type: (86fdbe70) File ObjectHeader: 85f84460 HandleCount: 0 PointerCount: 1 Directory Object: 00000000 Name: \Documents and Settings\mason\My Documents\~WRL2542.tmpory.doc {HarddiskVolume1} 注意这个文件的名和原始文件的名不一样。如果我用dt 命令来显示它,就能看到整个文件结构: lkd> dt nt!_FILE_OBJECT 0x85f84478 +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86f22cc0 +0x008 Vpb : 0x86f22c38 +0x00c FsContext : 0xe3d92d90 +0x010 FsContext2 : 0xe1a706e8 +0x014 SectionObjectPointer : 0x85f50c6c +0x018 PrivateCacheMap : (null) +0x01c FinalStatus : 0 +0x020 RelatedFileObject : (null) +0x024 LockOperation : 0 '' +0x025 DeletePending : 0 '' +0x026 ReadAccess : 0x1 '' +0x027 WriteAccess : 0 '' +0x028 DeleteAccess : 0 '' +0x029 SharedRead : 0x1 '' +0x02a SharedWrite : 0x1 '' +0x02b SharedDelete : 0x1 '' +0x02c Flags : 0x144042 +0x030 FileName : _UNICODE_STRING "\Documents and Settings\mason\My Documents\~WRL2542.tmpory.doc" +0x038 CurrentByteOffset : _LARGE_INTEGER 0x200 +0x040 Waiters : 0 +0x044 Busy : 0 +0x048 LastLock : (null) +0x04c Lock : _KEVENT +0x05c Event : _KEVENT +0x06c CompletionContext : (null) 注意SectionObjectPointers域和其他的文件对象有相同的地址 – 这实际上是同一文件的两个实例,虽然是用不同的名打开的!既然我们没有一个缓存映射,文件根本没有被存到缓存管理器中(这表示文件是内存映射的)。因此,我们不能遍历缓存结构来找出这个文件的上下文,因为它没有在文件系统的数据缓存中。 让我们再做个尝试,这一次用一个来自网络浏览器的文件。我打开www.osronline.com并浏览Internet Explorer进程.从那里我选择了FILE_OBJECT 8606bea8: lkd> dt nt!_FILE_OBJECT 8606bea8 +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86f22cc0 +0x008 Vpb : 0x86f22c38 +0x00c FsContext : 0xe1d32710 +0x010 FsContext2 : 0xe18a25b8 +0x014 SectionObjectPointer : 0x86cae074 +0x018 PrivateCacheMap : (null) +0x01c FinalStatus : 0 +0x020 RelatedFileObject : (null) +0x024 LockOperation : 0 '' +0x025 DeletePending : 0 '' +0x026 ReadAccess : 0x1 '' +0x027 WriteAccess : 0x1 '' +0x028 DeleteAccess : 0 '' +0x029 SharedRead : 0x1 '' +0x02a SharedWrite : 0x1 '' +0x02b SharedDelete : 0 '' +0x02c Flags : 0x140042 +0x030 FileName : _UNICODE_STRING "\Documents and Settings\mason\Cookies\index.dat" +0x038 CurrentByteOffset : _LARGE_INTEGER 0x0 +0x040 Waiters : 0 +0x044 Busy : 0 +0x048 LastLock : (null) +0x04c Lock : _KEVENT +0x05c Event : _KEVENT +0x06c CompletionContext : (null) 由此看看SectionObjectPointer域: lkd> d nt!_SECTION_OBJECT_POINTERS 0x86cae074 +0x000 DataSectionObject : 0x86e3e1a8 +0x004 SharedCacheMap : 0x86413008 +0x008 ImageSectionObject : (null) 注意此时有一个共享的缓存映射。让我们再来看看data section object: lkd> dt nt!_CONTROL_AREA 0x86e3e1a8 +0x000 Segment : 0xe1bae688 +0x004 DereferenceList : _LIST_ENTRY [ 0x0 - 0x0 ] +0x00c NumberOfSectionReferences : 2 +0x010 NumberOfPfnReferences : 0x2a +0x014 NumberOfMappedViews : 0xe +0x018 NumberOfSubsections : 2 +0x01a FlushInProgressCount : 0 +0x01c NumberOfUserReferences : 0xd +0x020 u : __unnamed +0x024 FilePointer : 0x86cce290 +0x028 WaitingForDeletion : (null) +0x02c ModifiedWriteCount : 0 +0x02e NumberOfSystemCacheViews : 2 同样,这也没有指回到同一文件对象: lkd> dt nt!_FILE_OBJECT 0x86cce290 +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86f22cc0 +0x008 Vpb : 0x86f22c38 +0x00c FsContext : 0xe1d32710 +0x010 FsContext2 : 0xe2ae4938 +0x014 SectionObjectPointer : 0x86cae074 +0x018 PrivateCacheMap : (null) +0x01c FinalStatus : 0 +0x020 RelatedFileObject : (null) +0x024 LockOperation : 0 '' +0x025 DeletePending : 0 '' +0x026 ReadAccess : 0x1 '' +0x027 WriteAccess : 0 '' +0x028 DeleteAccess : 0 '' +0x029 SharedRead : 0x1 '' +0x02a SharedWrite : 0x1 '' +0x02b SharedDelete : 0x1 '' +0x02c Flags : 0x144042 +0x030 FileName : _UNICODE_STRING "\Documents and Settings\mason\Cookies\index.dat" +0x038 CurrentByteOffset : _LARGE_INTEGER 0x1000 +0x040 Waiters : 0 +0x044 Busy : 0 +0x048 LastLock : (null) +0x04c Lock : _KEVENT +0x05c Event : _KEVENT +0x06c CompletionContext : (null) 这是用于分页的文件对象 – 注意此时两个文件对象的文件名相同。与上个例子类似但不一样。这次,我们也有共享的缓存映射,显示信息如下: lkd> dt nt!_SHARED_CACHE_MAP 0x86413008 +0x000 NodeTypeCode : 767 +0x002 NodeByteSize : 304 +0x004 OpenCount : 1 +0x008 FileSize : _LARGE_INTEGER 0x48000 +0x010 BcbList : _LIST_ENTRY [ 0x86413018 - 0x86413018 ] +0x018 SectionSize : _LARGE_INTEGER 0x100000 +0x020 ValidDataLength : _LARGE_INTEGER 0x48000 +0x028 ValidDataGoal : _LARGE_INTEGER 0x48000 +0x030 InitialVacbs : [4] 0x86face00 +0x040 Vacbs : 0x86413038 -> 0x86face00 +0x044 FileObject : 0x866068d8 +0x048 ActiveVacb : 0x86face00 +0x04c NeedToZero : (null) +0x050 ActivePage : 0 +0x054 NeedToZeroPage : 0 +0x058 ActiveVacbSpinLock : 0 +0x05c VacbActiveCount : 1 +0x060 DirtyPages : 0 +0x064 SharedCacheMapLinks : _LIST_ENTRY [ 0x8640b06c - 0x862f706c ] +0x06c Flags : 0x1000 +0x070 Status : 0 +0x074 Mbcb : (null) +0x078 Section : 0xe2d329f0 +0x07c CreateEvent : (null) +0x080 WaitOnActiveCount : (null) +0x084 PagesToWrite : 0 +0x088 BeyondLastFlush : 0 +0x090 Callbacks : 0xf7479c2c +0x094 LazyWriteContext : 0xe1d32710 +0x098 PrivateList : _LIST_ENTRY [ 0x8641312c - 0x8641312c ] +0x0a0 LogHandle : (null) +0x0a4 FlushToLsnRoutine : (null) +0x0a8 DirtyPageThreshold : 0 +0x0ac LazyWritePassCount : 0 +0x0b0 UninitializeEvent : (null) +0x0b4 NeedToZeroVacb : (null) +0x0b8 BcbSpinLock : 0 +0x0bc Reserved : (null) +0x0c0 Event : _KEVENT +0x0d0 VacbPushLock : _EX_PUSH_LOCK +0x0d8 PrivateCacheMap : _PRIVATE_CACHE_MAP 注意这个文件有一个单一的VACB: 0x86face00. 我们能用它来显示在缓存中用来映射这个文件的内存区域: lkd> dt nt!_VACB 0x86face00 +0x000 BaseAddress : 0xd4680000 +0x004 SharedCacheMap : 0x86413008 +0x008 Overlay : __unnamed +0x010 LruList : _LIST_ENTRY [ 0x86facfa8 - 0x86facfc0 ] 这提供了我们能用来看文件真实的数据内容的内存位置: lkd> db d4680000d4680000 43 6c 69 65 6e 74 20 55-72 6c 43 61 63 68 65 20 Client UrlCache d4680010 4d 4d 46 20 56 65 72 20-35 2e 32 00 00 80 04 00 MMF Ver 5.2.....d4680020 00 40 00 00 80 08 00 00-22 03 00 00 00 00 00 00 .@......".......d4680030 00 00 80 00 00 00 00 00-00 b0 14 00 00 00 00 00 ................d4680040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................d4680050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................d4680060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................d4680070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 一旦你用过几次这个技术,在内存中找到真实的数据非常简单。当然,有些告诫你应该知道: 文件不需要被存储到缓存管理器中。这通常是对内存映射的文件来说的(据个例子,被Microsoft Word或Notepad访问的文件).当然,混合访问会轻易地引起文件被存储到缓存中。 文件不需要被整个映射到缓存中。当前版本的Windows中缓存管理器拿256KB用于映射文件。因此,如果一个文件大于256KB,只有一部分会被映射到缓存中。 虚拟地址不需要出现在物理内存中。仅仅是因为缓存区域被定义为这个区域不需要包含数据。如果有数据存在,那就是文件数据(受文件大小的限制). 在内存中找文件内容.rar |
|
沙发#
发布于:2009-02-03 13:49
收藏 学习!!!
在调试课上,我总是邀请学生带来crash dumps让我们分析。这有助于我们掌握分析崩溃的技能 国外教育和国内教育的差距啊!!! |
|
板凳#
发布于:2009-02-03 16:01
引用第1楼x-star于2009-02-03 13:49发表的 : 作者是在调试培训课,不是学校的课堂。 |
|
地板#
发布于:2009-02-05 09:27
反正在看了"星际争霸即使对战游戏成大学选修课"之后,你还得来个一楼的感慨
|
|
地下室#
发布于:2010-03-12 16:50
学习
|
|
5楼#
发布于:2010-04-17 10:12
顶一个。。。。。。。
|
|
6楼#
发布于:2010-04-26 22:21
够乱的...
|
|
|