0

    【2016-4-8】Outlook邮件删除恢复的原理及实现

    2023.04.15 | admin | 240次围观

    背景介绍

    Outlook客户端将所有的邮件、附件和日历等内容全都以二进制的方式存放在个人文件夹(PST,Personal Storage Table)中。Outlook为每个邮箱账户建立一个PST文件,邮箱用户的收件箱、发件箱和删除的邮件都以目录的方式组织在PST文件中,普通删除的邮件只是从收件箱中移动到垃圾箱,使用Outlook客户端依然能够查看这些邮件,对于已彻底删除的邮件,其索引在PST中被移除,用Outlook打开相应的PST文件后,不会显示该封邮件任何信息。同样,对于被破坏或者直接删除的PST文件,其中的邮件也无法直接用Outlook打开,这就需要运用恢复技术来恢复该封邮件。

    在取证过程中,删除的邮件往往是关注的重点,对刑事案件的侦查来说是至关重要的信息,恢复的正确性、完整性直接影响到所涉及案件的结果。

    PST文件的结构

    PST文件在逻辑上主要分为3层,如图1所示:

    图1(PST文件的逻辑结构)

    NDB Layer (数据块层)是基础设施层,定义PST文件物理结构和Node、Block、B-tree、Page等基本数据结构,为上层的各种消息对象和属性表提供基本的存取结构和组织方式。

    LTP Layer(属性列表层)在NDB层基础上定义了两个结构PC(Property Context)、TC(Table Context),为上层提供支持,并规定了PC 和TC中数据存放格式。

    Messaging Layer(邮件对象层)主要定义邮件、目录、联系人、附件、会议、日历等概念,并且这些邮件、联系人等都用中间层的PC(Property Context)和TC(Table Context)存放数据。

    PST中邮件相关的结构

    Block结构

    Block为存放数据的基本单位,一个Block的大小规定为64B的倍数,最大是8KB,如果一个Block需存放大小超过8KB的数据,就需要把这些数据划分为多个块,并用一个树状结构组织起来。在PST中,Messaging层和LTP层的数据,都用NBD层的Block来存储,这些Block组织在一个B树结构BBTree(Block B-Tree)中,其中记录了每个Block的索引号BID(Block ID)和在PST文件中的绝对偏移IB(Byte index)。

    PST文件中,每个Block块除块尾BLOCKTRAILER结构24字节外,其他数据部分是加密的,加密方式是比较简单的逐位变换的方式。

    Node结构

    在NDB 层里,Node是一个基本的抽象结构,在整个PST文件中用来索引每个逻辑上独立的数据块,不同的Node有不同索引号NID(Node ID),Node结构里包含了存放实际数据的数据块(Block结构)的索引号BID、子节点索引号SID(SubNode ID)、父节点索引号PID(Parent Node ID)。在PST文件里,类似Messaging层的邮件、联系人、附件,LTP层的PC、TC这样逻辑上的独立数据都用一个Node来表示。

    Node的结构(Unicode版本)如下:

    表1 node结构表

    成员名称

    位置(字节号)

    大小(字节)

    说明

    nid

    0-7

    8

    node的索引号

    bidData

    8-15

    8

    对应数据块的索引号(BlockID)

    bidSub

    16-23

    8

    子节点索引号

    nidParent

    24-27

    4

    父节点索引号

    dwPadding

    28-31

    4

    填充,为以后扩展预留

    如果一个Node中的某种属性需要额外的节点来存放,就用 bidSub来索引这个子节点(sub Node),如同Block一样,如果需要使用多个子节点来存放数据块,就要用一个子树来组织这些节点。如果这个Node表示的是一个目录对象(Folder Object)或者一封邮件对象(Message Object),如收件箱中的一份邮件,就用nidParent来记录这份邮件的父节点,即收件箱目录,以便保持邮件之间的层次关系。

    NBT 和BBT结构

    NBT(Node B-Tree),B树结构,存放了所有Node结构的索引; BBT(Block B-Tree),B树结构,存放了所有Block结构的索引,通过NBT和BBT可以在PST中可以高效快速地定位每个具体的节点,这也是B树这种数据结构的特点。NBT和BBT是 PST中非常重要数据结构,整个邮件的解析和恢复都依靠这两种树状结构。

    当需要读取一封邮件时,首先在NBT中得到该封邮件的Node,然后找到Node的bidData所指的Block后,就去BBT中查找,找到对应的Block结构后就可得到实际的数据。

    其查找过程如下:

    图2 邮件节点查找过程

    如上图所示,拿到一个NID后,需要经过三次查找就得到所对应的数据块。

    BTH结构

    HN(Heap on Node),是在NDB层的Node之上构造的一个堆结构,也就是若干个Node组合在一起形成一个堆结构,然后在这个HN中又有一个B树用来组织各种属性值,即BTH(B-Tree on Heap Node)。在HN的尾部有个Heap Item分配表(HNPAGEMAP),记录了各个Heap Item的起始偏移,在BTH的各条记录中记录了这些存放个属性值的Heap Item的索引号HID(Heap Item ID)。

    PC结构

    在一个PC结构中,包含了一个BTH,BTH的叶子节点(Leaf Records)记录了各种属性值,一个Leaf Record结构如下:

    图3 PC属性记录的位结构

    图中wPropId和wPropType共4字节,合起来成为Property Tag,这就是上面(Key,Data)键值对中的Key, wPropId表示属性的ID,如0x3007表示的是邮件创建时间的属性,wPropType则表示属性的类型,如字符串类型用0x1F表示[这些属性ID和属性值类型在参考资料2中有定义。]。dwValueHnid则是键值对中的Data,即对应的属性值,其大小为4字节,如果属性值超过4字节,就需要另外一个Heap Item或者另外的一个Node来存放,注意HID和NID的低5位都表示这个ID的类型,如果低5位的值为NID_TYPE_HID(值是0),这时dwValueHnid就是这个Heap Item的序号,否则就是另外一个Node 索引号,这个Node 类型是一个内部类型(NID_TYPE_INTERNAL,值是1),在邮件subNode的树中可以找到。

    一个PC的结构大致可以用下图表示:

    图4 PC结构的内部构造

    上图中Node的bidData所指的Block中是一个PC结构,一个PC结构有3部分组成:

    1. HNHDR,Heap 结构的头信息;

    2. BTH,Heap 中的B-Tree结构,用来存放每条属性记录;

    3. HNPAGEMAP,记录Heap中每个分配块开始位置,便于查找每个Heap Item。

    TC结构

    如同PC结构一样,TC结构也是建立在一个堆结构(Heap on Node)上的,在逻辑上TC表示一张二维表,用来记录邮件的收件人、附件等信息。一个TC包含三部分:

    1. TCINFO结构,描述整张表格的属性,如表表头信息,实际数据存放位置等;

    2. RowIndex结构,TC内嵌的BTH结构,记录了表的行号和NID的对应关系;

    3. Row Matrix结构,实际存放数据的块,通常存放在subNode B-Tree中。

    一个典型的TC结构如下:

    上图中一个Node表示的TC结构,Node的bidData指向的是一个TC所在的数据块(在NBT树中查找),和PC一样,其中有个hnidRowData =0x1400所表示的一个Node,指向实际的数据,在subnode B Tree中就是NID=0x1400的节点。

    PST中邮件的表示

    邮件对象(Message object)

    一封正常邮件的收件人、发送人、主题、发送接收时间和内容等属性都存放在LTP层提供的PC结构中,而附件列表和抄送、暗送地址列表则放在邮件Node中bidSub所属的节点中,这些节点使用LTP层的TC结构来存放pst文件删除邮件后容量没有变小,如下图:

    图5 PST中邮件内部结构

    一封邮件用一个Node来表示,在Node里,bidData所指向的PC结构存放了邮件的属性,包括邮件标题、邮件内容、接收时间、发件人等。Node里的bidSub所指向的sub-Node BTree里存放了邮件的附件列表和接收人列表等索引节点号NID,这些节点分别用PC结构和TC结构来表示。

    图中Unicode String Data 是存放邮件内容的数据块。邮件内容较小时,可以放在PC结构中一个Heap Item中,如果超过一个PC的容量时(8KB),就放在sub-Node B-Tree中,在Data Tree中存放的是附件的二进制数据,就是图中PC中PT_BINARY属性所指的内容,这也是为什么内容过长的邮件不易恢复的原因。

    附件对象(Attachment object)

    邮件的附件存放在邮件Node的SubNode B-Tree中,用一个LTP层的TC结构来表示邮件的附件列表,这个列表中只记录附件的名称和大小信息,表的每一条记录关联一个PC结构,这个PC结构包含了一个附件的所有信息,包括实际数据的位置。其结构如下:

    图6 PST中附件的结构

    附件的实际数据存放在若干个Block块中,视附件大小而定,当大小超过一个Block的最大容量(8KB)时,就用一个二级索引树来表示。

    Outlook邮件删除操作分析

    Outlook中已删除邮件 目录中存放的是用户删除的邮件,注意这只是对邮件的一个标记。Outlook客户端的邮件删除操作其实并没有擦除数据,只是修改了邮件目录关系和对应的标志位,邮件数据事实上还存在PST文件中。

    如果用户继续在该邮件标题上右击鼠标选择【删除】,会弹出一个对话框询问用户是否永久删除邮件,如下图所示:

    或者用户在 已删除邮件 文件夹右击鼠标,选择【清空文件夹】,然后Outlook客户端会询问是否删除已删除文件夹里所有邮件,选择【是】,也会彻底删除邮件,如下图:

    如上操作就会彻底删除邮件,用户不能通过Outlook操作恢复这些邮件了。

    Outlook邮件删除机制

    PST文件删除数据块的方式是浅删除:仅在NBT和BBT中删除邮件相关的Node和Block索引,然后回收相应的数据块以供下次再利用。Outlook为了效率考虑,回收相应的数据块时并不直接擦除这些数据块,而是仅仅在一个MAP表标记这些数据块可用,下次使用时直接覆盖即可,使用完以后标记为该数据块不可用。

    当在Outlook中彻底删除一封邮件时,outlook首先在NBT中删掉该邮件对应的Node记录,然后在BBT中删掉Node的bidData和bidSub所对应的记录,这时,两棵B树的子节点数目发生改变pst文件删除邮件后容量没有变小,根据B树删除操作,会重新组织两棵B树的节点以保持树的平衡(B树是一种平衡树,任何增加删除操作之后都要通过移动节点来保持树的再次平衡),这时节点的索引(NID和BID)在PST中就不存在了。为了删除效率考虑,这时并不将该邮件所对应的数据块(PC结构,subNode BTree和邮件数据块)清零处理,而是仅记录了这些数据块是可用的,在下次直使用时直接写上新的内容。当邮件删除后并未填上新内容时,就可以恢复出该封删掉的邮件了,这就是Outlook邮件恢复所依赖的原理。

    Outlook邮件删除恢复的原理

    由于outlook所有的邮件都组织在一个PST文件中,其恢复与磁盘文件的恢复技术不同,其恢复方法依赖于PST文件的结构、邮件在PST中的存储方式及Outlook删除机制(这里所说的删除不是将邮件放入垃圾箱,而是从垃圾箱中彻底删除,在Outlook客户端中无法还原)。邮件恢复包括以下2种情况:

    1.完整的PST内彻底删除的邮件

    2.损坏的PST文件或未分配簇中的PST碎片内所有的邮件

    对于第一种情况,需要考虑PST结构和Outlook邮件删除机制,第二种情况考虑的是不完整的PST文件,这是恢复需要考虑邮件数据块的存储特征。

    邮件数据块的特征

    在本文所提出的扫描恢复中,所依据的就是数据的特征,特征的完整性也就决定了恢复内容的完整性和恢复的准确性,在一个邮件Node的各个部分中,重要并且特征完整的部分就是其PC块,PC中记录了邮件的发送人、接收人、发送/接收时间以及邮件内容等重要的信息。而且在PC结构中,其头部有固定的两字节标识符0xECBC,在PC数据块偏移0x14字节的地方有字符串为“IMP.Note”描述信息,这两个特征可以用于确定一个PC结构的开始部分,如下图所示:

    注意,每个PC结构前两字节是Heap Item的分配表(HNPAGEMAP)相对偏移(上图中的0x07D8,表示向后偏移0x78D的地方是HNPAGEMAP结构),可以通过检查HNPAGEMAP结构的完整性来确定这个PC结构的结尾部分,从而确定PC结构的结束部分。这样确定了一个PC结构的起始和结束位置,也就保证了恢复的数据块的完整性。

    恢复技术的实现

    恢复的实现可分为2个步骤:扫描、解析。

    扫描:先判断PST文件是否完整,对于完整的PST,先通过PST文件结构找到标记数据块可用的MAP表,然后定位到已删除的邮件数据块。对于不完整的PST文件,根据邮件数据块的特征,从PST文件的开始到结尾顺序扫描,过滤出所有特征完整的邮件数据块。

    解析:根据本文前面描述的邮件存储结构,解析出邮件的PC结构,提取其中的各种属性,如收件人、发件人、收发时间、附件列表以及主题和正文。

    流程如下:

    图7 邮件删除恢复流程图

    恢复的不足之处

    一封邮件的PC结构和其subNode 以及附件的数据块在PST中并不是依次连续存放的,它们是通过一个Node联系在一起的。当Node删除之后,这种关系就丢失了,即使找到一封邮件的PC块,联系人列表,附件列表及附件二进制数据块,限于PST中Node组织的机制,很难将失去索引而分散在PST文件中的数据块全部组织起来并还原为同删除前一样完整的邮件。

    参考资料:

    1.MicroSoft [MS-PST].pdf (v=office.12).aspx

    2.MicroSoft [MS-OXCROPS].pdf (v=exchg.80).aspx

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论