jununfly
驱动牛犊
驱动牛犊
  • 注册日期2008-10-17
  • 最后登录2010-06-01
  • 粉丝0
  • 关注0
  • 积分86分
  • 威望560点
  • 贡献值2点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2860回复:6

在内存中找到文件的内容

楼主#
更多 发布于:2009-02-03 11:14
这一篇可能会有所帮助,鉴于格式散乱,建议想细看的下载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
x-star
驱动小牛
驱动小牛
  • 注册日期2007-04-26
  • 最后登录2018-11-17
  • 粉丝0
  • 关注0
  • 积分65分
  • 威望664点
  • 贡献值1点
  • 好评度39点
  • 原创分1分
  • 专家分1分
  • 社区居民
沙发#
发布于:2009-02-03 13:49
收藏  学习!!!

在调试课上,我总是邀请学生带来crash dumps让我们分析。这有助于我们掌握分析崩溃的技能
国外教育和国内教育的差距啊!!!
AlexSho
驱动牛犊
驱动牛犊
  • 注册日期2008-01-10
  • 最后登录2017-12-01
  • 粉丝0
  • 关注0
  • 积分20分
  • 威望164点
  • 贡献值0点
  • 好评度45点
  • 原创分0分
  • 专家分0分
  • 社区居民
板凳#
发布于:2009-02-03 16:01
引用第1楼x-star于2009-02-03 13:49发表的  :
收藏  学习!!!

在调试课上,我总是邀请学生带来crash dumps让我们分析。这有助于我们掌握分析崩溃的技能
国外教育和国内教育的差距啊!!!


作者是在调试培训课,不是学校的课堂。
jununfly
驱动牛犊
驱动牛犊
  • 注册日期2008-10-17
  • 最后登录2010-06-01
  • 粉丝0
  • 关注0
  • 积分86分
  • 威望560点
  • 贡献值2点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2009-02-05 09:27
反正在看了"星际争霸即使对战游戏成大学选修课"之后,你还得来个一楼的感慨
lcjoo
驱动牛犊
驱动牛犊
  • 注册日期2007-02-08
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分39分
  • 威望351点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2010-03-12 16:50
学习
rhpeng
驱动牛犊
驱动牛犊
  • 注册日期2009-10-15
  • 最后登录2011-10-02
  • 粉丝0
  • 关注0
  • 积分26分
  • 威望241点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2010-04-17 10:12
顶一个。。。。。。。
Pegram
论坛版主
论坛版主
  • 注册日期2005-12-03
  • 最后登录2013-08-23
  • 粉丝13
  • 关注5
  • 积分1333分
  • 威望4717点
  • 贡献值1点
  • 好评度78点
  • 原创分0分
  • 专家分2分
6楼#
发布于:2010-04-26 22:21
够乱的...
《寒江独钓》与《竹林蹊径》的合作作者。精通USB开发,设计了CY001 USB驱动套件(http://bbs.driverdevelop.com/read.php?tid-119314.html)。
游客

返回顶部