一、简介
最近在做文档类的恶代检测,写个总结。
本篇文章负责介绍pdf文档的格式以及恶代分析中需要注意的问题以及相应工具推荐。希望能给各位做恶代分析时提供一些帮助。
后序会更新一些其他文档格式解析与恶代分析内容等,欢迎各位关注。
二、PDF文件格式介绍
PDF(便携式文件格式,Portable Document Format)是由Adobe Systems于1993年基于文件交换所发展出的一种文件格式。Adobe公司素有“漏洞之王”的美誉,所以学习PDF文件格式对研究分析漏洞具有极大帮助。PDF格式较为复杂,本文以研究漏洞的目的分析PDF格式,探寻如何找出并分析PDF中存在的恶意代码,而并非做一个详细的PDF parser解析器,因此会省略对不相关关键字的介绍,请各位留意。
PDF的结构可以从文件结构和逻辑结构两个方面来理解。PDF的文件结构指的是其文件物理组织方式,逻辑结构则指的是其内容的逻辑组织方式。
1. PDF的文件结构
PDF文件格式包含以下4个部分:
2. PDF文件格式图示:
3. PDF文件的逻辑结构
本段主要介绍PDF文件体的读取方式。
作为一种结构化的文件格式,一个PDF文档是由一些称为“对象”的模块组成的。每个对象都有数字标号,这样的话可以这些对象就可以被其他的对象所引用。这些对象不需要按照顺序出现在PDF文档里面,出现的顺序可以是任意的,比如一个PDF文件有3页,第3页可以出现在第1页以前,对象按照顺序出现唯一的好处就是能够增加文件的可读性,对象的信息以偏移+索引的形式保存在交叉引用表内。
文件尾说明了根对象的对象号,并且说明交叉引用表的位置,通过对交叉引用表的查询可以找到目录对象(Catalog)。这个目录对象是该PDF文档的根对象,包含PDF文档的大纲(outline)和页面组对象(pages)引用。大纲对象是指PDF文件的书签树;页面组对象(pages)包含该文件的页面数,各个页面对象(page)的对象号。
4. PDF的层级结构图示:
页面(page)对象为PDF中最重要的对象,包含如何显示该页面的信息,例如使用的字体,包含的内容(文字,图片等),页面的大小。里面的信息可以直接给出,当然里面的子项更多的是对其他对象的引用,真正的信息存放在其他对象里面。页面中包含的信息是包含在一个称为流(stream)的对象里,这个流的长度(字节数)必须直接给出或指向另外一个对象(包含一个整数值,表明这个流的长度)。
可见stream流对象我们恶代分析需要获取的重点。
5. 页面信息图示:
理解了上面的内容之后,我们可以得出针对恶代分析的PDF文件的大致解析思路:
当然,也可以采取针对PDF层级结构的文档解析方式,见仁见智,因人而异。
三、以二进制文本解析Pdf文档结构
PDF文件是一种文本和二进制混排的格式,但是Adobe更愿意让人把它当成二进制的文件,所以,PDF文件可以直接拖入16进制编辑器中打开。前面我们介绍了PDF的文件结构以及逻辑结构,现在我们在16进制编辑器中打开PDF文件,更直白的展示PDF的关键字段以及文件结构。
对于对象的额外解释:如果一个样本文件的交叉引用表格式如下
即交叉引用表中第五行顺序数为4的对象,其偏移为4976
四、Pdf文件混淆
如图,下面的样本进行了混淆
解释:<<>>代表obj对象之间的字典内容,保存了流的关键字和特征信息,因此去除混淆是必要的第一步操作,pdf文件的混淆只出现在这里#54代表0x54,上面的内容去除混淆之后即为
五、关键字
下面介绍了PDF文件解析时所需要的关键字
六、流的提取
/Filter关键字之后保存了stream流的编码信息一共包括以下几种:
一共包括上面几种编码方式,按常见顺序进行了排序,可以级联编码。例如:
表示流先经过了ASCIIHexDecode再经过了FlateDecode编码解密是即先对流进行FlateDecode解码再对流进行ASCIIHexDecode解码目前遇到2种级联编码样本(如上),可能会有更多级联编码方式(3级或以上)解码后能够触发攻击的流对象为javascript脚本或者图片对象,常见的恶意攻击代码储存在javascript脚本中。
下面的图片是提取自样本中的PDF steam流文件中的js脚本,已经很明显是攻击代码了:
七、一些坑
PDF的恶意攻击样本毫无疑问会使用一些特殊手段对抗杀软的扫描检查,下面统计了一下恶意样本常见的规避行为:
1. 交叉引用表
(1) 坑1 引用表偏移不正确
上面有提到过交叉引用表的偏移地址为固定数值,推测adobe的parser是从文件尾开始解析,获得交叉引用表的偏移地址(Xref中X在文档中所在的位置即为偏移地址),找到交叉引用表再定位到各个对象,实际测试发现偏移地址可以不正确8980偏移地址实际可能为任意地址。
(2) 坑2 引用表可以有多个
样本如上,正常来讲,一个文档只存在一个%EOF结束符,但是这个样本里出现了两个
2. 字符串长度
(1) 坑1 流对象长度可以直接跟对象
正常一个字典语句中/Length之后的数值代表stream~endstream两个关键字之间流的长度,如下
但测试发现流的长度可以是obj对象
所以stream流对象压缩前的实际长度为4880虽然是PDF格式的正规使用方法,但同时也是规避杀软的一种手法。
(2) 坑2 流对象长度可以为任意值
同理,正常流对象长度为上图,实际测试发现样本
WTF is ANIWAY_LEN??? 长度可以为填ascii字符???所以,/Length后面可以不跟数值stream流的实际长度实际==关键字endstream偏移-关键字stream偏移-包含的0x0D或0x0A
3. 解码问题
(1) 坑1 javascript可以支持文本和八进制
有JS编程基础的肯定注意到了,因此在这里需要判断javascript内容在对象中还是在()内亦或是否需要转码
(2) 坑2 编码方式缩写形式
正常文件默认/Filter关键字之后会出现xxdecode关键字表示stream流编码方式,但测试发现样本可以没有xxdecode关键字,但同样进行了编码处理,如上/Fl字段即为/FlateDecode的简写,对应表如下:
(3) 坑3 编码形式可以级联
如上表示流先经过了ASCIIHex加密再进行了FlateDecode加密解码时需要先进行FlateDecode解密之后再进行ASCIIHexDecode解密
八、常用分析工具推荐
介绍完恶代格式后,推荐一些恶代分析的基本工具
1. PdfStreamDumper
2. PDFParser
3. ParanoiDF
4. References