Skip to content

Office 格式简析

目前常见的 Microsoft Office 格式主要分为 97 ~ 2003 和 2007 ~ 两种格式。Microsoft Office 97 ~ 2003 的文件格式都是由 MS-CFB 结构来表示的 OLE 文件。Microsoft Office 2007 ~ 则是由 OOXML 格式的文件结构压缩而成的 zip 包来存储。

而 OOXML 又是以 XML 文件为基础的,所以,概括的说,Office文档主要基于 ole、xml、ooxml 这三种文件格式构建起来的。

常见的文件扩展名以及用途如下:

ExtensionsUsageRemark
doc、xls、ppt属于 97-2003 版 Office
docx、xlsx、pptx属于 2007 ~ 版 Office 文档,但没有启用宏
docm、xlsm、pptm属于启用了宏的 2007 ~ 版 Office 文档,可以存储 Visual Basic Applications(VBA)宏代码
ppsx是 2007 的 PPT 的一种格式,打开就是幻灯片播放模式

按照我们常规的认知,一个文档应当包含以下几个部分:

  1. 文档内容
    • 可能涉及对 embedded objects 或 external objects 的引用
    • 文档的展示相关:字体、页面大小、打印方式等等
  2. 文档工具
    • 为了更好、更方便的操作文档内容进行编辑、展示、提示以及其他功能,而提供的一些跟文档相关的组件,如 vba、formula、animation 等等
  3. 文档属性
    • 如,创作时间、作者、最后修改时间等等
  4. 保护措施
    • 签名
    • 读(打开)、写 保护

一、Malware

由于 ms-office 文件的广泛使用,恶意软件作者对其进行了充分的挖掘、利用,催生出了一系列针对这些文档的病毒,期中常常被用于恶意目的的组件或者方式有:宏病毒、漏洞利用、嵌入文件

1.1 漏洞

漏洞利用是指软件自身缺陷被攻击者利用来执行高危动作,如利用 ole 的特点调用第三方组件并执行;栈溢出造成的任意代码执行漏洞(CVE-2017-11882) 等等,常见的漏洞有:

1.2 宏病毒

宏(Macro)是 ms-office 提供的一种利用一系列独立的 office 命令来实现任务执行的自动化,以简化日常工作的工具。当前的 ms-office 是使用 Visual Basic for Applications(VBA)编写的,它是 Microsoft 的 Visual Basic 编程语言专门为 Office 服务的一种变体。VBA 可在大多数 Office 程序中使用,例如 Access,Excel,Outlook,PowerPoint,Project,Publisher,Visio 和 Word 等等。

宏病毒主要是利用 宏 来进行感染和传播。它利用宏语言的功能寄存在文档或模板中,一旦带有宏病毒的文档被打开,宏就可能会执行,而宏病毒就会被激活。

它的主要感染路径大致如下:单个Office文档 => Office文档模板 => 多个Office文档

常见的宏主要存在于以下两种形式(vba && xlm):

此外,还有一种攻击方式被称为「模板注入」,实际上还是上述两种 macros 的利用,不过内容可能会随时发生变化

  • office2007_template_inject

此外,宏病毒常常用以下方式保护、隐藏自己:

  1. 禁止提示信息
On Error Resume Next                     '如果发生错误,不弹出出错窗口,继续执行下面语句
Application.DisplayAlerts = wdAlertsNone '不弹出警告窗口
Application.DisplayStatusBar = False     '不显示状态栏,以免显示宏的运行状态
Options.VirusProtection = False          '关闭病毒保护功能,运行前如果包含宏,不提示
  1. 屏蔽命令菜单,不许查看宏
' Disable或者删除特定菜单项,用来使“工具—宏”菜单失效的语句:
CommandBars(“Tools”).Controls(16).Enabled = False
  1. 隐藏宏的真实代码
  • 在“自动宏”中,不包括任何感染或破坏的代码,但包含了创建、执行和删除新宏(实际进行感染和破坏的宏)的代码;将宏代码字体颜色设置成与背景一样的白色等
  • “自动宏” 是指利用 AutoExec、AutoNew、AutoOpen、AutoClose、AutoExit 自动触发执行的宏
  1. 文档密码保护
  • 打开文档时需要密码 或者 查看vba脚本时需要密码

另外,病毒作者常用密码逃逸手段以增加检测难度,事实上也很有效。这种方法的全称是:VelvetSweatshop Default Password Ploy

  • 对象:Excel 4.0 xls 97 ~ files with a compromised macro
  • 表现:XLS files appear password protected but aren’t, opening automatically to install malware from compromised macros.
  • 原因:Excel 会首先尝试使用默认密码 'VelvetSweatshop' 以 read-only 模式打开文件,如果失败时,再向用户要求输入密码。(This read-only technique has been known about for over 10 years.)
  • Reference

1.3 Embedded

利用复合文档可以内嵌其它文档的特性,可以嵌套如:

  • images、video、audio
  • other streams, eg. rtf、pdf、docx ... (rtf、docx等复合文档又可以继续嵌套... MY GOD ~)

二、MS-CFB

经常被称为 OLE(Object Linking and Embedded),实际上 OLE (是一种面向对象的技术)包含的内容更多,是 COM 技术的基础,而 CFB 只是 OLE 中关于文件格式的一种描述。

复合文档的物理结构比较简单:

  • cfb_sectors

注意:Compound File Header (512 bytes)也会独占一个 sector, 没有用到的地方填充 0.

这里是逻辑结构:

  • cfb_summary

文档中的内容都以 stream 来保持具体内容,storage 来组织 stream 的结构。而这些内容在文件中的位置、查找方式、解读方式,就由 Directory Entry Array 来表达。

复合文档的结构非常类似 FAT 文件系统,storage 相当于 directory,stream 相当于 file。为了文件的快速定位,我们需要相应的分区索引表(DiFat 和 Fat)。在 复合文档中,为了节省空间,会将 sector 划分成等长的 short-sector 用于小对象(short-stream)的存储,而它的索引需要 Mini-Fat

由于 CFB 文件由 sectors 组成,这里统一称呼为:

  • msat (master sector allocation table),又名 DiFat
  • sat (sector allocation table),又名 Fat
  • ssat (short-sector allocation table)
  • stream
  • short_stream

他们的功能如下:

  • msat 表包含了用于构造 sat 表的 sectors 的 sid
  • sat 表包含了很多 sid 链(有特定的 sid 标识链条结束)
    • 每个 sid 链上的 sectors 联合构成了一个完整的 object (如,stream、storage、directory entry array、ssat ...)的物理存储。
  • ssat 表包含了很多 ssid 链(有特定的 ssid 标识链条结束)
    • 每个 ssid 链上的 short-sectors 联合构成了一个完整的 short-stream

到这里,我们大概可以想到为了解析 CFB 结构,需要知道以下几个内容:

  1. Directory Entry 的结构 和 存放位置
  2. msat 表在文件中的位置
  3. stream 和 short-stream 的切割点:什么情况下用 stream 什么时候用 short-stream
  4. short-sector 存储于哪些 sector 中
  5. ssid 存储于哪些 sector 中

这些内容就存放在 Compound File Header 和 Directory Entry Root 中。

OLE

OLE, Object Linking and Embedded。

微软在 1991 年制定的 OLE1.0 规范,主要解决多个应用程序之间的通信和消息传递问题,微软希望第三方开发商能够遵守这个规范,以使在当时的Windows平台上的应用程序能够相互协调工作,更大的提高工作效率。然而事与愿违,只有很少的软件开发商支持它。为此,微软于1993 年发布了新的规范 OLE2.0,它在原有的基础上完善并增强了以下各方面的性能:

  1. OLE自动化:一个程序有计划地控制另一个程序的能力。
  2. OLE控件:小型的组件程序,可嵌入到另外的程序,提供自己的专有功能。
  3. OLE文档:完善了早期的混合文档功能,不仅支持简单链接和嵌入,还支持在位激活、拖放等功能。

强大的功能使得很多的开发商开始支持新的 OLE 技术,因为微软在 OLE2.0 中建立了 COM(Component Object Model即组件对象模式)规范。

OLE 相关的基础概念有:

  • 容器:
    • 容器是一个客户程序,它具有申请并使用其它COM组件通过接口为其它程序实现的功能;
  • 服务器:
    • 服务器通过特定的接口将自己完成的一些功能,提供给使用自己的应用程序(例如画笔程序是一个文档服务器,它提供创建并编辑BMP 图像的功能)。当打开Word,选择【插入】菜单下的【对象...】项,您可以看到在您的系统中存在哪些文档服务器,此时的Word以文档容器的身份出现。
  • 在位激活:
    • 当您双击插入的对象后发现Word的菜单有些改变成文档服务器程序的菜单,可以在当前的环境下编辑对象,这称为在位激活。

简单的说,OLE 是一种可以用来创建复杂文档的技术,这些复杂文档可以包含来自不同渠道(数据源)的信息,并保留其原始属性。例如,一个支持 OLE 的文档(例如word)能够支持嵌入的表格对象,并且嵌入的文档会保留所有原来的属性。如果用户打算编辑嵌入的数据,windows 操作系统会激活原来的应用程序(如excel)并载入这个嵌入的文档。

OLE 格式

OLE 文件的 Property Sets 通过以下两个 stream 存储:

  • "\005SummaryInformation"
  • "\005DocumentSummaryInformation"

这两个 stream 都以 PropertySetStream 结构(见 [MS-OSHARED] 的 section3.2.1 )开头。

OLE文件中包含的常见内容主要有:

1. linked or embedded object

包含嵌入、链接对象的容器文档的逻辑布局如下图:

  • OLEStream
    • OLE2.0 中,由复合文档的以 "\1Ole" 为名的 stream object 包含。OLEStream structure 表述了存储对象是用于 linked object 还是 embedded object。当此结构是为 linked object 指定 storage object 时,它还指定了对此链接对象的引用。
  • CompObjStream
    • OLE2.0 中,名为 "\1CompObj" 的流,主要用于描述 Clipboard Format、用于显示的linked object 或 embedded object 的名字。
  • Embedded Object Native Data
    • OLE1.0 中,其由 EmbeddedObject structure 的 NativeData field 指定。
    • OLE2.0 中,Native Data 的指定方式有以下两种,可以互换使用:
      • 由复合文档的以 "\1Ole10Native" 为名的 stream object 包含。如 OLENativeStream structure 的 NativeData field 所指定。
      • 由 creating application 创建的 stream objects 可以包含 native data。此类流对象是 creating application 的私有对象,未在文档中说明。
        • creating application: An application whose data is stored in or referenced by documents from other applications.
  • Embedded Object Presentation Data
    • 用于指定如何在 container application 中显示 linked or embedded object 对象
    • OLE1.0 中,其由 EmbeddedObject structure 的 Presentation field 指定
    • OLE2.0 中,由复合文档的以 "\2OlePres" 为前缀(后跟着3个十进制数字,并且最多只能有999个Presentations)的 stream objects 指定。每一个 stream 都包含一个 OLEPresentationStream structure。

2. 宏

常见的 宏 有两种:vba 和 ms-excel4.0, 它们出现的主要位置有:

  • vba project
    • office97 ~ 2003: vba project storage
    • office2007 ~ : vbaProject.bin
  • microsoft office excel 4.0
    • office97 ~ 2003: book\workbook stream
      • 注:主要通过 BIFF 格式保存了 formula、drawing group 等内容
    • office2007 ~ : macrosheets
  • macro template
    • office2007 ~ : /[xx]/_rels/settings.xml.rels 中引用外部(远程)模板文件
  • VbaProjectStg
    • binary powerpoint document 中用于指定一个用于 VBA project 的结构化存储

3. officeart

  • office97 ~ 2003:
    • worddocument、book\workbook、'powerpoint document' stream
      • Office Drawing Binary File Format (MS-ODRAW),This file format is also known as OfficeArt.
  • office2007 ~ :
    • TODO

4. encryption and obfuscation

详见 Office 格式简析 - Crypto

这里需要注意的是 vba project 的保护(待确认):

  • vba project
    • 可以对其中的 stream 设置独立的密码 (未确认)
      • VBA uses a reversible encryption algorithm for selected data.
    • PROJECT Stream: ProjectProtectionState
      • ProjectProtectionState: "CMG="0705D8E3D8EDDBF1DBF1DBF1DBF1"" specifies no sources are restricted access to the VBA project. The value is obfuscated by Data Encryption (section 2.4.3).
      • ProjectPassword (section 2.3.1.16): "DPB="0E0CD1ECDFF4E7F5E7F5E7"" specifies the VBA project has no password. The value is obfuscated by Data Encryption (section 2.4.3).
      • ProjectVisibilityState (section 2.3.1.17): "GC="1517CAF1D6F9D7F9D706"" specifies the VBA project is visible. The value is obfuscated by Data Encryption (section 2.4.3).
      • LibName: "VBE" specifies a built in name for the VBA Automation type library.

VBA Project 格式

VBA project 是由一系列 records 组成的结构。其中每个 record 都定义了 project 的三要素之一的部分内容。每个 record 都是以结构开头:ID(2 bytes) + Size(4 bytes) + ...

project 的三要素有:project information, project references, and project items.

1. project information

ole 中 VBA 存储(storage)结构如下:

VBA

其中 Project Root Storage 是一个独立的 storage。例如,OLE 文件中的 Macros storage。

  • VBA Storage
    • sub-structure
      • _VBA_PROJECT Stream
        • MUST
        • 包含了 VBA project 的基础信息,如,版本号(用于加载此结构的剩余内容) 等
      • dir Stream
        • MUST
        • 指明 VBA project properties, project references, 和 module properties
        • The entire stream MUST be compressed as specified in Compression
      • "Module Stream"
        • VBA project 中的每个 module 必须拥有一个 Module Stream
        • VBA project 中 modules 的源码。此 stream 的名字由 MODULESTREAMNAME 指定。
      • SRP Streams
        • Optional
        • 指定 特定实现和版本相关 的性能缓存的流。必须是读取时忽略。写入时不得出现。
  • PROJECT Stream
    • MUST
    • VBA Project Properties, 如 工程的目录结构、脚本类型、module的可编辑窗口的信息等等, 以及一些 VBA project 的附加信息,如:ProjectPassword、ProjectVisibilityState 等 sample_vba_project 注:[[MS-OVBA] - v20200219 的 2.3.1.3 ProjectModule] 有脚本类型的相关说明
  • PROJECTwm Stream
    • Optional
    • 包含了用于 module name 在 multibyte character set (MBCS) 和 UTF-16 之间互相映射的信息
  • PROJECTlk Stream
    • Optional
    • 包含了 VBA project 中的 ActiveX controls 的 license 信息
  • Designer Storages
    • Optional
    • 每个 vba project 中的 designer module 都必定有一个与之对应的 designer storage ,此 storage 的名字由 dir stream 中相关 module 中的 MODULESTREAMNAME record 指定。
    • 每个 designer storage 必定有一个 VBFrame Stream
      • VBFrame Stream,用于描述 designer module 的属性信息,此 stream 的名字必须是以 UTF-16 character 0x0003 开头紧接着是 UTF-16 的 "VBFrame"。
    • 如果此 designer 是一个 Office Form ActiveX control, 那么此 storage 必定包含 [MS-OFORMS] section 2中描述的必须 storages 和 streams。

2. project references

dir Stream 中的 records 包含了 VBA project 对外部资源引用的信息。主要有三类:REFERENCECONTROL、REFERENCEREGISTERED、REFERENCEPROJECT。

3. project items

VBA project 包含一系列用于嵌入 macros 的 project items。而 project item 是由多个 records 组合定义。主要有以下 5 种 project item(详见 MS-OVBA 文档): project package, document modules, procedural modules, class modulesdesigner modules

4. pcode

它并不广为人知,一般来说 VBA 编写的宏以三种不同的可执行形式存在,每种形式都可以是在运行时实际执行的内容,具体取决于具体情况. 它们是:

  • source code
    • 这是最为我们熟知的形式。但大多数情况下,office 会完全忽略源代码。
    • 事实上,删除源代码是可能的,但宏仍然可以毫无问题地执行(从 pcode)
      • 这种威胁利用技术被称为 VBA Stomping
  • p-code
    • 当每行 vba 脚本被输入到 vba 编辑器中时,它会立即被编译成 pcode 并存储到模块流中。 pcode 正是大部分时间被执行的代码。
    • 事实上,即使在 vba 编辑器中打开宏模块的源码,显示的也不是解压后的源码,而是反编译成源码的 pcode。
    • 只有在使用与创建文档时使用的 vba 版本不同的 office 版本下打开文档时,才会将存储的压缩源代码重新编译为 pcode,然后执行该 pcode
    • 这使得可以在支持 vba 的任何版本的 office 上打开包含 vba 的文档,并使内部的宏保持可执行,尽管不同版本的 vba 使用不同(不兼容)的 pcode 指令。
  • dxecodes
    • 当 pcode 至少被执行过一次后,它会以进一步标记化形式存储在文档的其他地方(在流中,其名称以 _SRP 开头,后跟一个数字)。从那里它可以执行得更快。
    • 但是 execode 的格式极其复杂,并且特定于创建它们的特定 Office 版本(不是 VBA 版本)。这使得它们的通用性很差。
    • 此外,它们的存在不是必需的 --- 它们可以被删除并且宏将运行得很好(从 pcode)

综上,我们可以知道:

  • source 的通用性最好,但只有在 pcode 不能使用时,才会被使用
  • execodes 的通用性最差,但执行得最快
  • p-code 则是执行速度和通用性的折中,也是用的比较广泛的形式

因此,我们有必要解析 pcode,具体可以参考:github.com/bontchev/pcodedmp

Microsoft Office Excel 4.0

Microsoft Office Excel 4.0, 主要存在于 MS-XLS 的 book\workbook stream 中。此 stream 以 BIFF8(Binary Interchange File Format) 格式组织各个细节。

Stream 由以下几部分组成:

  • Globals Substream
    • 描述 workbook 中的全局属性和数据
      • 注意 Lbl、ShrFmla 数据
  • Chart Sheet Substream
  • Dialog Sheet Substream
  • Macro Sheet Substream
  • Worksheet Substream

使用 Excel 4 Macros 的一些细节:

  • 使用 relative named range 时,函数主体和结果之间的单元格距离必须都相同,否则可能会计算出错误的结果。
  • Office 2007 ~ 中,任何带有 Excel 4 Macro 的文件都必须另存为启用宏的工作簿 (.xlsm),尝试另存为标准 Excel 文件将触发以下错误消息: must_save_excel4_as_xlsm
  • 任何包含数组的函数,例如 GET.WORKSPACE(37) 或 NAMES() 都应该包含在 INDEX 函数中: 如,=INDEX(GET.WORKSPACE(37),!A1),在这个例子中,A1 包含应该检索的数组中的数字,例如如果 A1 包含值 2,它将返回 GET.WORKSPACE(37) 数组中的第二项。
  • 使用 Macro Worksheet 时,工作表设置为显示公式,而不是公式的结果。可以使用 Ctrl + | 在公式视图和结果视图之间切换。

PtgExp、ShrFmla、Array

PtgExp 一般会出现在 formula 的第一个 rgce 元素。此时,它表示当前单元格是 array formula 或 shared formula 的一部分。

PtgExp.row 和 PtgExp.col 指定了一个在当前 sheet 中的 cell

  • 这个 cell 也是 array formula 或 shared formula 的一部分
    • 也就是说必定有一个 formula record 的 row == PtgExp.row && col == PtgExp.col
      • 紧跟着这个 formula record 的必定是一个 ShrFmla record 或者 Array record
      • 也就是说这个 PtgExp 指向了使用此 array formula 或 shared formula 的区域中的 the first cell
        • 隐含:拥有 PtgExp 的 formula record 满足:record.row == PtgExp.row && record.col == PtgExp.col 时,它后边一定跟着 ShrFmla record 或 Array record
    • 这个 formula record 定义了区域中使用 array formula 或 shared formula 的 the first cell

ShrFmla(shared formula record)

  • 此 record 前必定有一个 formula record,这个 formula record 指定了使用此 shared formula 的区域中的 the first cell
  • 其它使用了此 shared formula 的 formula records 后续会出现,但不一定是连续的
  • 使用了此 shared formula 的 formula records 会有 Formula.fShrFmla bit 被置位,同时 Formula.cell 必定位于 ShrFmla.ref 指定的区域内

Array(array formula record)

  • 此 record 前必定有一个 Formula record,这个 formula record 指定了使用此 array formula 的区域中的 the first cell
  • 其它使用了此 array formula 的 formula records 后续会出现,但不一定是连续的
  • 使用了此 array formula 的 formula records 必定有 Formula.cell 位于 Array.ref 指定的区域内,同时这些使用 array formula 的 formula 的 rgce 必定以 PtgExp 开头。

解析过程中遇到的问题

  • RgceLoc 可以按照 RgceLocRel 来解析,以简化解析流程。
  • 解析 formula 的过程中,会遇到 "is part of a revision or not" 的分支流程,这里涉及以下三个概念:
    • UserBView Record:
      • fPersonalView : MUST be 0 if this is not a shared workbook.
    • Revision Stream
      • An instance of the Revision Stream specifies the revision logs (section 2.2.11.2) and revision records (section 2.2.11.3) for a shared workbook (section 2.2.11).
      • The name of this stream MUST be "Revision Log". A file MUST contain at most one Revision Stream. The Revision Stream MUST exist if the workbook is a shared workbook.
    • Revision Records
      • a series of records. 详情可以参考 [MS-XLS] 文档。
  • external references:
    • Supporting Link 包含了 Self-Referencing、Same-Sheet Referencing、External Workbook Referencing 等等类型。
  • name manager:
    • LblRecord : (关联 name 和 sheet)
      • 内置名字的索引,可能由 1 或 2 字节表示
      • NameParsedFormula 可能出现 ptgRef3d 的 ixti == 0xFFFF,此时,此时的结构未被文档记录:
        • we can reproduce it: make a macro sheet in ooxml and export it to xls.
          		uint8_t ptg = uint8_t(data[cce_offset] & 0x7f);
          		if (ptg == ptgRef3d || ptg == ptgRef3dA || ptg == ptgRef3dV) {
          			uint16_t ixti = *(uint16_t*)(data + cce_offset + 1);
          			if (ixti > 0xFF00 && record->cce >= 15 + 3) {
          				assert(record->itab == 0 || record->itab == 1);
              uint16_t iscope_1base = (record->itab == 1) ? record->reserved1 : record->itab;
          				uint16_t isheet_0base_a = *(uint16_t*)(data + cce_offset + 11);
          				uint16_t isheet_0base_b = *(uint16_t*)(data + cce_offset + 13);
          				assert(isheet_0base_a == isheet_0base_b);
          				auto row = *(uint16_t*)(data + cce_offset + 15);
          				auto col = (uint16_t)*(uint8_t*)(data + cce_offset + 17);
          			}
          		}
          	}
  • Rgce 的 ACTUAL_PTG_SIZE 跟实际情况不符合

DOC

一个 doc 文档应当由以下几个部分组成:

  1. WordDocument stream
    • 有一个 FIB structure 在流的起始位置
  2. Table stream
    • 1Table 或者 0Table 流必定存在。当二者同时存在时,base.fWhichTblStm 指定的为有效流,忽略其他即可。
    • 如果文档被加密的话,会有一个 EncryptionHeader 结构在流的起始位置。反之,如果文档没有加密,则此流没有预定义的结构。
    • 存储了文档的文本信息
  3. Data stream
    • 没有预定义的结构,也不是必定存在。它包含的是 FIB 或 文件的其它部分的引用数据,也就是说如果没有引用数据的话,这个流没有存在的必要
  4. ObjectPool storage
    • Object Pool storage 包含一些用于持久化 embedded OLE objects 的 storages。如果文档没有 embedded OLE objects 时,是不会出现此 storage 的。
    • 每一个位于 ObjectPool storage 中的 storage 都有一个 ObjInfo Stream (名为 "\003ObjInfo"),这个流里存放着用于描述 embedded OLE object 信息的 ODT structure。
      • embedded OLE object 相关的其他流的描述可以参考 [Embedded Object Native Data] 相关内容
    • 每个 sub-storage 都存储了一个用户嵌入(embedded)的文件。并且,每个 sub-storage 都是以: 下划线"_" + 10个digits 组成,如 _1557814583
      • 关联引用的关键词:sprmCFOle2、sprmCPicLocation
  5. Summary Information
    • Summary Information stream
    • Document Summary Information stream
    • Encrypt stream
      • 名为 encryption 的流,只有当以下两个条件同时满足才会出现:文档被 RC4 CryptoAPI 加密, 并且,EncryptionHeader.Flags 的 fDocProps 标记被置位
  6. Macros stream
    • vba project
  7. Signature
  8. Protected Content
  • 由 IRMDS 描述的方式进行保护的内容, 在 MS-OFFCRYPTO 有描述。

PPT

按照 [MS-PPT] - v20210817 :pageno 28 中 Part 1 ~ 11 的描述,即可解出完整的 ppt 文档内容。

注意:the UserEditAtom record closest to the end of the PointPower Document stream

其中,所有用于 presentation 的文本都存储在 "PowerPoint Document" stream 中;所有用于 presentation 的 images 都存储在Pictures stream 中;不过,Embedded files 没有存储在独立的 storages,而是被融合到 "PowerPoint Document" stream 中,此外,这些 embedded files 在存储时,有些会被压缩有些却不会。

External Objects

Slides 可以包含连接到外部的 objects。播放 ppt 的人可以在幻灯片放映期间激活链接对象以访问外部资源。External Objects 的例子有 embedded and linked audio, linked video, embedded and linked OLE objects, 以及 hyperlinks。

也就是说 Embedded or Linked Object 在 ppt 中的存在形式就是 External Objects。

有关有 External Objects 的记录,请参阅 [MS-PPT] External Object Types (section 2.10) 相关内容。简单的说,为了解析出 External Objects,我们需要关注:

  • ExternalOleObjectStg 0x1011 , 用于对象存储(如果有n个则会有n个此类型的 record)
  • DocumentContainer 0x03E8 , 用于描述文档对象
    • DocInfoListContainer 0x07D0
      • VBAInfoContainer 0x03FF
        • VBAInfoAtom 0x0400
    • ExObjListContainer 0x0409
      • storage for compressed/uncompressed OLE/VBA/ActiveX control data, 如 VbaProjectStg
    • SoundCollectionContainer
    • DrawingGroupContainer

也就是说要首先找到 DocumentContainer:

1. 构造 PersistDirectory
  Current User Stream
    CurrentUserAtom Record
      offsetToCurrentEdit field
  |-->PowerPoint Document Stream
  |		UserEditAtom
  |			offsetPersistDirectory field
  |		PersistDirectoryAtom
  UserEditAtom.offsetLastEdit (Repeat until offsetLastEdit is 0x000000)

2. 定位 DocumentContainer
  UserEditAtom.docPersistIdRef
    DocumentContainer Record

关于鉴别 embedded OLE object 对象的具体步骤可以参考 [MS-PPT] 2.1.2 PowerPoint Document Stream part 9 相关内容

关于鉴别 linked OLE object 对象的具体步骤可以参考 [MS-PPT] 2.1.2 PowerPoint Document Stream part 10 相关内容

XLS

一个 xls 文件最多只能一个 Component Object Stream。 一个 xls 文件最多只能一个 OLE Stream。 一个 xls 文件最多只能一个 Control Stream。

WorkBook stream 中存储了 excel 中所有的 text 和 formulas。

Embedded or Linked Object

在 Excel 的 workbook 中嵌入一个文件的话,这些文件会被存储在名为 "MBD + 随机的8个十六进制数字" 的 Embedding Storages 中。

每个 Embedding Storage 都表示了一个基于 storage-based 持久化的 embedded OLE object 或 ActiveX control 对象。同时,持久化在 Embedding Storage 的对象必定有一个相关联的 Obj record 在 worksheet substream、macro sheet substream 或 dialog sheet substream 中,并且 cmo.ot == 8,pictFlags.fPrstm == pictFlags.fDde == 0。

不过不同类型的文件在 Embedding Storage 中的形式有些不一样,如:

  1. 如果 embedded file 是另外一个 binary Office document, 那么这个 embedded file 中的 storages 和 streams 会被当成对应的节点原样存储在 MDB storage 中
  2. 如果 embedded file 是一个 Open XML document, 那么这个 embedded file 会被完整存储在名为 "Package" 的 stream 中

一个 Link Storage 指定一个 linked OLE object 和任意其他的默认数据或表示为其建立的缓存。它的名字必定是由:"LNK" + 8个十六进制数字 标识。持久化在 Link Storage 的对象必定有一个相关联的 Obj record (Obj.pictFmla.lPosInCtlStm)在 worksheet substream、macro sheet substream 或 dialog sheet substream 中,并且 cmo.ot == 8,pictFlags.fPrstm == pictFlags.fDde == 0。

OOXML

OOXML(Office Open XML File Formats), 简单来说,OOXML 是一个基于 XML 的文档格式标准,最早是微软 Office2007 的产品开发技术规范,先是成为 Ecma(ECMA-376) 的标准,最后改进推广成为了 ISO 和 IEC (as ISO/IEC 29500) 的国际文档格式标准。也就是说,通过 OOXML 标准,我们能够在不依赖 Office 产品的情况下,在任何平台读写Office Word,PPT 和 Excel 文件。

OOXML 的主要目录结构如下所示:

OOXML
├── [Content_Types].xml // 描述文档各个部分的ContentType,协助解析文档

├─ docProps        // ms-office 需要此内容以打开文件,而 wps 不需要
│   ├── app.xml    //程序级别的文档属性,如:页数、文本行数、程序版本等
│   └── core.xml   //用户填写的文档属性,如:标题、主题、作者等

├─ _rels
│   └── .rels      //描述各个部分之间的关系

└─ word / xl / ppt
    ├── document.xml     //word
    ├── fontTable.xml    //word,页脚

    ├── workbook.xml     // xl
    ├── worksheets       // xl
    │    └── sheet1.xml
    ├── macrosheets      // xl, microsoft excel 4.0 macros
    │      ├── _rels
    │      │   └── sheet1.xml.rels
    │      └── sheet1.xml
    |
    |── presentation.xml // ppt
    |
    |── embeddings       //all, optional, 存放 embedded files
    |     ├── a
    |     └── b

    |── vbaData.xml      //all, vba属性,是否auoopen,是否加密
    |── vbaProject.bin   //all, 记录 vba project 信息, ole 格式
    |
    ├─ theme             //all, 记录样式,颜色编号,字体大小等等
    │    └── theme1.xml

    ├─ _rels             //all, relationships
    |    ├── settings.xml.rels   // 指定 模板 引用
    │    ├── document.xml.rels   // 使用 ID 和 URL 来定义文档各零件
    |    ├── workbook.xml.rels   // 使用 ID 和 URL 来定义文档各零件
    │    └── vbaProject.bin.rels // vba

    ├── printerSettings //all, Reference to Printer Settings Data
    │....└── printerSettings1.bin

    └─ styles.xml       //all

1. Name Representation

无论是 definedNames 中定义的,还是表格显示的名字,这些需要展示的名字都应当在 docProps\app.xml 中作为 Application-Defined File Properties 部分被定义,如下:

<TitlesOfParts>
 <vt:vector size="[0-9]+" baseType="lpstr">
  <vt:lpstr>Sheet1</vt:lpstr>
  <vt:lpstr>Sheet2</vt:lpstr>
  <vt:lpstr>Sheet3</vt:lpstr>
  <vt:lpstr>value1</vt:lpstr>
  <vt:lpstr>value2</vt:lpstr>
 </vt:vector>
</TitlesOfParts>

2. Cell References & Name

excel中可以给 函数、cell、sheet、甚至任意一段文本或图形等定义名字(也被称为 bookmark),并通过名字来引用对应的内容,引用方式参考

  • [ECMA-376-Fifth-Edition-Part-1] --- 18.17.2.3 Cell References
  • [ECMA-376-Fifth-Edition-Part-1] --- 18.17.2.5 Names

name 的组成形式:

name = [ workbook-name, "!" ], [letter | "_" | "\"], [ letter | decimal-digit | "_" | "." ] ;

其中 name 不能包含以下几种格形式:

  • TRUE or FALSE
  • user-defined-function-name
  • cell-reference

function-name 的组成形式:

function-name= prefixed-function-name | predefined-function-name | user-defined-function-name ;

predefined-function-name= "ABS" | "ACOS" | "ACOSH" | ( any of the other functions defined in §18.17.7) ;
prefixed-function-name= "ISO.", predefined-function-name | "ECMA.", predefined-function-name ; 
user-defined-function-name= letter, [ letter | decimal-digit | "." ] ;

其中 function-name 不能包含以下几种格形式:

  • TRUE or FALSE
  • name
  • cell-reference

Cell Reference 的形式有两种:R1C1-Style 和 A1-Style

operator 有以下几种格式:

":" | comma | space | "^" | "*" | "/" | "+" | "-" | "&" | "=" | "<>" | "<" | "<=" | ">" | ">=" | "%" ;

3. Formulas and expressions

  • [ECMA-376-Fifth-Edition-Part-1] --- 17.16.3 Formulas and expressions

A field instruction can involve a calculation via a formula, which is simply an expression that is an arbitrary complex arithmetic expression,如:

<sheetData>
		<row r="2" spans="4:4" x14ac:dyDescent="0.25">
			<c r="D2" s="1" t="b">
				<f>FORMULA()=FORMULA()=FORMULA('Buk1'!E11,'Buk2'!B12)=FORMULA('Buk2'!H5,'Buk3'!H3)=FORMULA('Buk3'!C9,'Buk4'!C2)=FORMULA('Buk4'!I8,'Buk5'!F2)=FORMULA('Buk5'!B12,'Buk6'!B10)=FORMULA('Buk6'!G3,'Buk7'!I2)=FORMULA('Buk7'!D13,'Buk1'!A3)=FORMULA('Buk3'!H3&amp;'Ss1'!O6&amp;'Ss1'!D16&amp;'Ss1'!K13&amp;'Ss1'!R12&amp;'Ss1'!R14,D3)=FORMULA('Buk3'!H3&amp;'Buk7'!I2&amp;'Buk4'!C2&amp;'Buk5'!F2&amp;'Buk5'!F2&amp;Ss1br2!B3&amp;'Buk1'!A3&amp;Ss1br2!D5&amp;'Buk6'!B10&amp;Ss1br2!G3&amp;'Buk7'!I2&amp;'Buk7'!I2&amp;Ss1br2!B9,D17)</f>
				<v>1</v>
			</c>
		</row>
	</sheetData>

MS-Office 的其他形式

使用 MS-Office 软件可以将 office 文件通过"另存为"保存为 xml、mhtml、html 等格式的文本文件,并且,可以再次通过 MS-Office 软件打开、编辑。

另外,这些转换而成的文本类型的文档,被加密后,是一个 ole 文件。

被转换而成的 xml 文件,在结构上保持了跟 binary 形式的 office 文件一致,并且一一对应。如,contentType 为 "application/vnd.ms-office.vbaProject" 的 binaryData 数据, 就是二进制形式的 vbaProject 内容 base64 后的结果。

这里要注意的是,在解析 binData 类型的数据时,可能会遇到 mso(ActiveMine) 文件。这是一种文件名为 *.mso 同时 MIME Types 为 application/x-mso 的结构未公开的文件格式(参考 activemime-format )。

MSO文件是将Microsoft Office文档保存为网页时创建的宏引用文件。它包含有关原始文件中包含的宏和OLE(对象链接和嵌入)对象的信息,并且可以被创建的网页作为样式表引用。MSO文件可以用文本编辑器查看,但由于内容是编码的,因此无法读取。大多数用户只会将MSO文件作为电子邮件的附件。

RTF

富文本格式(Rtf,rich text tormat)是微软的文本和图像信息交换指定的格式。Rtf文件可以划分为文件头和文档区两个部分组成。文件头和文档区由文本、控制字和控制符组成,同时利用{…}来表明层级关系。

检出

  • hash (忽略大小写、空字符)
    • function
    • stream
  • 模糊匹配
    • 简单的模式匹配
    • eg.
      • 搜索到 :VirtualProtectEx、WriteProcessMemory、CreateRemoteThread、VirtualAllocEx
      • Shell Environ$("comspec") & " /c attrib -S -h """ & Application.StartupPath & "\K4.XLS""", vbMinimizedFocus
      • Shell ("\jdq\cc$\b.exe")
      • If .Lines(1, 1) = "APMP" & .Lines(1, 2) <> "KILL" Then ........ End If
      • 混淆的文件:熵 ?

清理

  • 抹除
    • function
      • 替换函数内容为空格
    • stream :
      • 将 stream 的 size 置 0,同时抹除第一个扇区内容,断开内容扇区链
      • 一般来说,只修改 size 就可以让 office 软件无法读取相关内容。但其他杀软可能会继续报毒,毕竟 stream 的其他信息依然有效,可以在容错情况下还原出来 malicious 内容。
      • 注意:其它部分对 macro 的引用,如:
        • doc 中 fcCmds 会通过 macro names 引用对应的宏,所以
          1. 根据需要将 document 流中的 fcCmds 和 lcbCmds 所引用的数据
          2. 粗暴的将 document 流中的 fcCmds 和 lcbCmds 都置空
  • 还原
    • 还原被加密破坏的文件内容
      • 病毒感染时是有机会操作原有的正常 vba 脚本的,比如,加密(目前还没见到此类样本)。

Reference