office系列文件的加密检测

                                                         知识概要  

    金山的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”目录,对应的二进制为:

  1.   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)中查询扇区链。定位到指定的扇区后,进行一定的偏移,进行判断。简易的代码示意如下:

  1. //judge whether .doc file is encrypted or not.
  2. int is_encrypted_doc(char* file_path)
  3. {
  4.   ifstream ifs(file_path,ios_base::binary);     
  5.   
  6.   if (ifs)
  7.   {
  8.       unsigned int stream_address;
  9.       sid_32 stream_sector;
  10.       int stream_length;
  11.       bits_8 tmp[20];
  12.       Header header(ifs); //read msat and sat chain
  13.       DirectoryEntry d_entry(&header);
  14.       if (!d_entry.get_stream_address("WordDocument",stream_address,stream_sector,stream_length))
  15.       {
  16.           ifs.close();
  17.           return FILE_ERROR;
  18.       }
  19.       ifs.seekg(stream_address);
  20.       ifs.read(&tmp[0],20);   
  21.       ifs.close();
  22.       if(tmp[11]&0x01) return FILE_ENCRYPTED ;
  23.       return FILE_COMMON;
  24.   }
  25.   else
  26.       return FILE_NO_FOUND;
  27. }

       2.excel文件

         excel文件和word文件的原理基本一致,它是寻找“workbook”目录。excel的配置是采用“配置名称 长度 内容”这种格式的,所以如果要找到加密的字段,必须从前面一直向后读,只读到加密的配置字段,简易代码如下:

 

  1. //judge whether .xls file is encrypted or not.
  2. int is_encrypted_xls(char* file_path)
  3. {
  4.   ifstream ifs(file_path,ios_base::binary);     
  5.   if (ifs)
  6.   {
  7.       unsigned int stream_address;
  8.       sid_32 stream_sector;
  9.       int stream_length;
  10.       bits_8 tmp[64];
  11.       Header header(ifs); //read msat and sat chain
  12.       DirectoryEntry d_entry(&header);
  13.       if (!d_entry.get_stream_address("WorkBook",stream_address,stream_sector,stream_length))
  14.       {
  15.           ifs.close();
  16.           return FILE_ERROR;
  17.       }
  18.       ifs.seekg(stream_address);
  19.       ifs.read(tmp,64);
  20.       unsigned int count = 0;
  21.       while (count+4< 64)
  22.       {
  23.            bits_16 flag = convert_chars_to_bits(tmp[count],tmp[count+1]);
  24.            if (flag!=FILEPASS)
  25.            {
  26.                flag =  convert_chars_to_bits(tmp[count+2],tmp[count+3]);
  27.                count+=flag+4;
  28.            }
  29.            else
  30.                return FILE_ENCRYPTED;
  31.       }
  32.       return FILE_COMMON;
  33.   }
  34.   else
  35.       return FILE_NO_FOUND;
  36. }

       3.ppt文件

        ppt文件的设置比较让人烦,在powerpoint2003中它的加密字段值为0xF3D1C4DF表示加密,可是powerpoint2002,这个值又表示不加密。这就郁闷了,后来发现了一个变通的方法,那就是加密的文档中的字段(0x0FF50000 -->RT_UserEditAtom. )的值不同,主要是加密文档多出了一些加密的信息,我们就是通过检测这个字段来完成加密检测的,由于该字段名字占了四个字节,所以就直接搜索二进制文件的内容就可以了,搜索到后,检测后面的一个字节,如果是0x1C 则为common ,为 0x20 则为encrypted。

注:版权所有,如有转帖请注明出处。

你可能感兴趣的:(hide)