来自: http://blog.csdn.net/liangjingbo/article/details/2992858
知识概要
金山的wps系列的dps wps et的二进制格式是和微软的office系列的ppt word excel相对应的,OpenOffice应该也是一样兼容微软的二进制格式的。这里的原因大家都应该知道还不是因为人家微软是老大啊,不过有反垄断法的保护,微软还是要公开它的二进制格式给其他厂商的。闲话少说,开始正题.
要进行二进制检测前,必须知道以下知识。
1.仓库(这里有个很重要的 根仓库 root storage)
2.标准流
3.短流和短流存放流
4.扇区
5.短扇区
6.主扇区配置表,扇区配置表,短扇区配置表
简单的关系整理如下:
1. 仓库中包含流(可能是标准流,也可能是短流),就像D盘中有文件一样
2. 仓库中可以包含仓库 就像D盘中可以包含文件夹一样
3. 存储的最小单位为扇区。流是一些扇区的组合,而扇区配置表指定了这些组合的关系
4. 短流是小于标准流大小的流,而短流同样是一些扇区的组合,但是这些扇区又可以划分到短扇区单元
5. 主扇区配置表,指定那些用于存储扇区配置表的扇区
6. 扇区配置表和短扇区配置表,都是用来指定一个流所对应的扇区链
如果如上关系搞不清楚,可参看 http://blog.csdn.net/liangjingbo/archive/2008/09/03/2874959.aspx,这篇文章。
加密检测
复合文档的前512个字节都是很有格式规律的,在这里我们可以找到扇区大小,根仓库的入口地址,主扇区配置表等。
进入分析之前,我们首先要找到根仓库的入口地址(即目录的入口地址)
每个目录大小为128个字节,开头用64个字节描述该目录的名字
1.word文件
首先在目录中找到 “WordDocument”目录,对应的二进制为:
- u_bits_8 word[23]={0x57,0x00,0x6F,0x00,0x72,0x00,0x64,0x00,0x44,0x00,0x6F,0x00,0x63,0x00,0x75,0x00,0x6D,0x00,0x65,0x00,0x6E,0x00,0x74}
注意:这里的大小端问题
然后查看该目录的流的入口sector,注意如果是该流的大小大于等于标准流的大小,则在 扇区配置表中(SAT)中查询扇区链,如果 小于标准流的大小,则在 短扇区配置表中(SSAT)中查询扇区链。定位到指定的扇区后,进行一定的偏移,进行判断。简易的代码示意如下:
- //judge whether .doc file is encrypted or not.
- int is_encrypted_doc(char* file_path)
- {
- ifstream ifs(file_path,ios_base::binary);
- if (ifs)
- {
- unsigned int stream_address;
- sid_32 stream_sector;
- int stream_length;
- bits_8 tmp[20];
- Header header(ifs); //read msat and sat chain
- DirectoryEntry d_entry(&header);
- if (!d_entry.get_stream_address("WordDocument",stream_address,stream_sector,stream_length))
- {
- ifs.close();
- return FILE_ERROR;
- }
- ifs.seekg(stream_address);
- ifs.read(&tmp[0],20);
- ifs.close();
- if(tmp[11]&0x01) return FILE_ENCRYPTED ;
- return FILE_COMMON;
- }
- else
- return FILE_NO_FOUND;
- }
2.excel文件
excel文件和word文件的原理基本一致,它是寻找“workbook”目录。excel的配置是采用“配置名称 长度 内容”这种格式的,所以如果要找到加密的字段,必须从前面一直向后读,只读到加密的配置字段,简易代码如下:
- //judge whether .xls file is encrypted or not.
- int is_encrypted_xls(char* file_path)
- {
- ifstream ifs(file_path,ios_base::binary);
- if (ifs)
- {
- unsigned int stream_address;
- sid_32 stream_sector;
- int stream_length;
- bits_8 tmp[64];
- Header header(ifs); //read msat and sat chain
- DirectoryEntry d_entry(&header);
- if (!d_entry.get_stream_address("WorkBook",stream_address,stream_sector,stream_length))
- {
- ifs.close();
- return FILE_ERROR;
- }
- ifs.seekg(stream_address);
- ifs.read(tmp,64);
- unsigned int count = 0;
- while (count+4< 64)
- {
- bits_16 flag = convert_chars_to_bits(tmp[count],tmp[count+1]);
- if (flag!=FILEPASS)
- {
- flag = convert_chars_to_bits(tmp[count+2],tmp[count+3]);
- count+=flag+4;
- }
- else
- return FILE_ENCRYPTED;
- }
- return FILE_COMMON;
- }
- else
- return FILE_NO_FOUND;
- }
3.ppt文件
ppt文件的设置比较让人烦,在powerpoint2003中它的加密字段值为0xF3D1C4DF表示加密,可是powerpoint2002,这个值又表示不加密。这就郁闷了,后来发现了一个变通的方法,那就是加密的文档中的字段(0x0FF50000 -->RT_UserEditAtom. )的值不同,主要是加密文档多出了一些加密的信息,我们就是通过检测这个字段来完成加密检测的,由于该字段名字占了四个字节,所以就直接搜索二进制文件的内容就可以了,搜索到后,检测后面的一个字节,如果是0x1C 则为common ,为 0x20 则为encrypted。
注:版权所有,如有转帖请注明出处。