破解OFFICE文档(word和excel)的两种方法有:
1、使用黑客字典或暴力穷举方式来猜测用户的口令字;
2、采用全查表方式直接获取加密OFFICE文档的密钥,然后通过密钥去解密文档;方法2与方法1的区别是只能获取到文档内容,而不能获取到文档的加密密码。
    这两种方法都需要知道office系统软件的加密机制,有兴趣的朋友可以去参考这篇文章:http://www.team509.com/download/MS_Word_encrypt.pdf。并且此文章对于方法1已经描述得很清楚了,在这里就不重复了。下面就重点讨论方法2:

大家可以去看另外一个牛人写的帖子:
【原创】Word Password Recovery Master 2.0.0.4 程序分析 
http://bbs.pediy.com/showthread.php?p=369640&highlight=word#post369640
对此有一个大概的了解之后,继续下面的细节方面的讨论。

    方法2简单的说就是让客户端提取OFFICE文档中的密钥流,发送给服务器,利用服务器的计算资源快速求解出解密密钥,再将密钥传回客户端,在本地解密OFFICE文件,从而得到文件内容。
    而密钥流是通过RC4算法加密过的密钥。1个40bit密钥,根据RC4算法,就可以产生出相应的密钥流(乱数),如果能做到这样,那么就可以事先建立起2^40个对应关系,记为T 表;有了这个密钥流,再根据T 表反向查表,即可快速得到40比特密钥(输入),有了密钥即可对密报进行立即解密。
    所以问题的关键就在两个:
    1、获取到这个密钥流。根据 乱数 = 密文 xor 底码 的数学公式,如果底码为0,那么乱数就=密文。所以我们只要找出OFFICE文档中一段固定的5字节或全0处就行了。
    2、建立全查表。这样就定义出了一个函数关系f,即 5字节key(输入)A  映射到  5字节ks(输出)B。这个全查表有2^40条记录。

关于全查表,目前还存在一些细节方面的问题,有请jeffcjh和各位感兴趣的朋友来帮忙解答,谢谢:

1、在没有压缩和其它任何优化处理的情况下,产生的全查表大概占多大的磁盘空间呢?
2、因为我还没有生成这个全查表,所以不清楚B5字节key(输入)A  映射到  5字节ks(输出)B的关系,按照您说的意思,5字节ks(输出)B存在大量的碰撞,也就是说,同一个5字节ks(输出)B,会有2^24个key(输入)A 值的对应?在2^16个文件中,每个文件中的只需要存放A值就够了,因为这些A值所对应的B值都是一样的?如果这样的话,不会存在根据客户端传回的B值而查询不到A值的情况吧。
3、这样说的话,前期的主要准备工作就不是对B值进行排序,而是把相同的B值划分到同一个文件中了(有什么效率比较高的方法吗)?那么查询速度的瓶颈就在于查询这个有2^24个A的文件上了?


注:由于此贴是从【求助】关于微软公布的office二进制文档格式 http://bbs.pediy.com/showthread.php?t=72128 转过来的,可能有些描述不是很清楚。有不明白的地方可以先去那个帖子看一下。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-01 19:30

1、全查表需要占用5TB的硬盘空间。5TB是这样计算出来的:
   5TB = (2^40) * 5,
   其中 2^40 表示记录总数,5 表示每个记录要占用5字节。

   如果采用差分保存技术,可以将5TB的需求降到2TB左右。

2、你的理解是对的,每个文件中的2^24个A(输入)按照映射关系都对应同一个输出B。根据5字节的B值来查表,对应文件中的2^24个A值都是“嫌疑”对象(可能的密钥),到底哪一个是“真凶”(加密该office文件的正确密钥),验证依据就是48字节随机数中后32字节的md5依赖关系。

3、将2^40个 B--A  函数对应关系摊分到2^16个文件中,每个文件保存2^24个对应关系,在每个文件内做快速排序,这样总的排序时间为
     T = (2^16) * O( (2^24) * lg(2^24) ), 
T 表达式中的前者为文件数,后者是每个文件内部快速排序的时间复杂度。

而对原始的2^40个记录进行快速排序的时间为 O( (2^40) * lg(2^40) ),
显然T大约是此值的1/2左右,所以分割后总效率上要高一点。

需要说明的是,这些讨论的技术都是基于自己来实施的假设。
如果你想利用那几个网站来进行破译,我们根本就不需考虑这些啦(网站帮我们实现了这些功能)。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-02 21:38

1、会不会存在根据客户端传回的B值而查询不到A值的情况?
2、有没有一些技巧方法能够方面快速的生成文件,并按照5字节ks(输出)B值来划分到同一个文件中呢?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-03 19:11

1、基本不存在这种情况,即可能性极小(采用彩虹链时失败概率小于千分之一),采用现在讨论的全查表方法的成功率为100%;

2、这个完全可以。根据Word加密机制,对2^40个输入A,依次计算其输出B时,根据情况分类存入到2^16个文件中去即可。但是,要注意的是,计算全部2^40个输入的输出值,这个任务在你的单机上是难以完成的,大约需要几个月的时间,所以真正实施时必须采用并行技术技术,多台机器同时做才行。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-07 11:13

"给定40比特(5字节)密钥 key 后,经由md5得到128字节的rc4密钥,再通过rc4加密算法(注:包括两个阶段)生产出5字节的伪随机数 ks (密钥流)。"

碰到个问题,rc4加密机制是将明文和密钥流进行异或就可以产生密文,我得到128的rc4密钥之后,是不是通过这个密钥再来加密“40比特(5字节)”,然后产生ks?

我的做法是这样的:
循环输入40比特key,加上固定的填充后生成一个64字节的数,再进行一轮标准的md5 hash后产生128位的结果(这个过程应该就是您说的“给定40比特(5字节)密钥 key 后,经由md5得到128字节的rc4密钥”)。后面的过程(再通过rc4加密算法(注:包括两个阶段)生产出5字节的伪随机数 ks (密钥流))我就不太明白了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-07 23:40

“给定40比特(5字节)密钥 key 后,经由md5得到128比特的rc4密钥”这句话你的理解对了。

接下来就是根据这个128比特的密钥,按照RC4算法的两个阶段(密钥调度阶段KS和密钥流产生阶段)产生密钥流ks。本来密钥流可以无限长,但具体到我们的问题,其实只需要5字节的ks就够了。以后我们就是利用5字节ks来反向查表得到40bit密钥(输入)的。

注意:“有了128比特rc4密钥之后,不是通过这个密钥再来加密“40比特(5字节)”,而是按照RC算法产生ks,用ks再来加密明文的。这正是序列密码的一个基本特点,密钥流与明文通常是独立的。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-08 00:13

我就是不太明白怎样按rc4算法来产生ks,能不能根据你提供的rc4算法来详细说明一下,比如已经生成了128位的密钥(简称为C),那么怎样使用你改写的那个rc4算法来生成ks?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-08 23:02

引用:
最初由 xiaoxinxx发布 查看帖子
我就是不太明白怎样按rc4算法来产生ks,能不能根据你提供的rc4算法来详细说明一下,比如已经生成了128位的密钥(简称为C),那么怎样使用你改写的那个rc4算法来生成ks?...
我提供的RC4代码有四个函数:
1. void RC4_KSA(UCHAR *rc4key, int KL, RC4_STATE *state);
2. void RC4_KSA_128(UCHAR *rc4key, RC4_STATE *state);
3. UCHAR RC4_PRGA(RC4_STATE *state);
4. void RC4(UCHAR *rc4key, int keylen, UCHAR *keystream, int kslen);
其中前2个函数负责密钥初始化(前者为密钥长度为KL字节的,后者专门为密钥长度为16字节的),函数3每次生成1字节密钥流ks,函数4其实是对前面三个函数的封装。

现在你经过MD5已得到了128比特(即16字节)的密钥K[],那么调用函数4:
RC4(K, 16, ks, 5);
即可得到5字节的ks。

不过这5字节是密钥流的最初5字节,在具体利用时可能不是这个位置的5字节,那些网站取的位置比较靠后,并且还不是连续的位置(有间隔),这些都是小问题,根据实际需要调用函数4生产足够长度的密钥流,再提取对应位置的数据即可。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 11:58

这几天在调试程序来生成全查表,按照您说的,B值最多就是2的16次方个,但是我的程序输入不同A,都会产生一个不同的B值,比如输入2^20个A,就会输出2^20个不同的B值,也就是说B值都没有碰撞。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 17:56

输入A总共有2^40个,得到的输出B有2^40个,但这2^40个输出B是可能存在碰撞的(即不同的A对应到相同的B)。

你所说的输入2^20个A,就会输出2^20个不同的B值,也就是说B值都没有碰撞,这在实际中是可以存在的,并不矛盾。因为以上所说的是可能存在碰撞,但不一定碰撞。实际上这是一个概率问题,可以算出碰撞的可能性有多大。如果你把2^40个输入的输出都计算出来了,我感觉几乎一定会有碰撞的,还早呢,朋友。但我不知道你是否有这么大的计算能力(把所有2^40个都算一遍),你可以通过已计算2^20个结果来估算一下总时间。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 18:29

这是生成128比特的代码,jeffcjh帮看看对不对,thanks!!!:

ArrayByteA = array [0..4] of byte;
Array16Byte = array [0..15] of byte;


function MakeKey(byteA: ArrayByteA):Array16Byte;
var
  mdContext: MD5Context;
  pwarray: array [0..63] of byte;
  byteB: Array16Byte;
  block: DWord;
begin
  block := 0;
  Fillchar(pwarray,sizeof(pwarray),0);        //pwarray数组清零
  CopyMemory(@pwarray, @byteA, 5);     //拷过去40位(5个字节) 
  //put block number in byte 6...9
  pwarray[5] := byte(block and $FF);
  pwarray[6] := byte((block shr 8) and $FF);
  pwarray[7] := byte((block shr 16) and $FF);
  pwarray[8] := byte((block shr 24) and $FF);
  pwarray[9] := $80;
  pwarray[56] := $48;

  //对pwarrey计算一轮标准的MD5 hash begin
  MD5Init(mdContext);
  MD5Update (mdContext, @pwarray, 64);
  MD5StoreDigest(mdContext);
  //对pwarrey计算一轮标准的MD5 hash end

  CopyMemory(@byteB, @mdContext.Digest, 16);
  result := byteB;
end;

生成byteB之后,就调用您的rc4函数来生成ks.

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:14

你的总体代码正确,但有一个细节我认为存在问题。

我认为你会C代码,我参考你的变量名,将这一块的正确C代码告知如下:
  unsigned char byteA[9];        // byteA[]的前5字节赋值为输入A
  unsigned char byteB[16];
  unsigned char ks[512];         // 存储生产的密钥流(乱数), 具体长度自己确定

  blockcnt = 0;             // 加密块编号,初值为0x00000000

  // byteA[]的第5至8字节赋值为块编号
  *(unsigned int *)(byteA + 5) = blockcnt;

  // 对9字节(不是64字节)作标准的MD5 !!!
  MD5Data((unsigned char*)byteA, 9, byteB);

  // 以16字节byteB[]做密钥, 根据RC4算法产生512字节乱数
  RC4(byteB, 16, ks, 0x200);

说明:
可见这一块其实是很简单的,你应能明白。
我认为存在的问题就在对数组byteA[]9字节之后的填充上。我用C语言写的代码就是对byteA的9字节作标准的MD5得到16字节散列值byteB。由于对你的上述byteA填充不是很清楚,所以提出这个疑问供参考。

另外C语言数组的下标从0开始,VB是从0还是从1开始,这个边界小问题敬请注意。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 19:16

引用:
最初由 jeffcjh发布 查看帖子
输入A总共有2^40个,得到的输出B有2^40个,但这2^40个输出B是可能存在碰撞的(即不同的A对应到相同的B)。

你所说的输入2^20个A,就会输出2^20个不同的B值,也就是说B值都没有碰撞,这在实际中是可以存在的,并不矛盾。因为以上所说的是可能存在碰撞,但不一定碰撞。实际上这是一个概率...

按照您原来的说法,B值总共就只有2^16个,而现在我输入2^20个A值,就产生了2^20个不同的B值,这显然就已经不正确了啊。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 19:24

md5的算法应该都是通用的。那估计就是我的生成128比特的代码有问题了。能否贴出这部分代码让我参考一下,到底是哪儿出错?生成对照表这个程序困扰我一个星期了。比较郁闷。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:25

引用:
最初由 xiaoxinxx发布 查看帖子
按照您原来的说法,B值总共就只有2^16个,而现在我输入2^20个A值,就产生了2^20个不同的B值,这显然就已经不正确了啊。...
你理解错了,输入A共有2^40个,相应的输出B值也有2^40个啊。我说的是这2^40个输出B是存储到2^16个文件中去。对于输出B,到底存到2^16个文件中的哪一个中去呢?这要你自己定原则了,比如可以考虑按照B的最低2字节来分类,B的最低2字节相同的就存到同一个文件中,这样自然总共会产生2^16个结果文件。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:28

那我觉得可能就是你对byteA[]9字节后的填充不对,就不用去填充,而是直接对9字节进行md5运算,具体代码我上面已经贴出来了啊。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:30

我不知道下面的填充是什么意思: 
//put block number in byte 6...9
  pwarray[5] := byte(block and $FF);
  pwarray[6] := byte((block shr 8) and $FF);
  pwarray[7] := byte((block shr 16) and $FF);
  pwarray[8] := byte((block shr 24) and $FF);
  pwarray[9] := $80;
  pwarray[56] := $48;

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:31

为什么有:
pwarray[9] := $80;
pwarray[56] := $48;
这样两个赋值?

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 19:36

我问的问题:
“因为我还没有生成这个全查表,所以不清楚B5字节key(输入)A  映射到  5字节ks(输出)B的关系,按照您说的意思,5字节ks(输出)B存在大量的碰撞,也就是说,同一个5字节ks(输出)B,会有2^24个key(输入)A 值的对应?在2^16个文件中,每个文件中的只需要存放A值就够了,因为这些A值所对应的B值都是一样的?如果这样的话,不会存在根据客户端传回的B值而查询不到A值的情况吧。”

您的回答:
"你的理解是对的,每个文件中的2^24个A(输入)按照映射关系都对应同一个输出B。根据5字节的B值来查表,对应文件中的2^24个A值都是“嫌疑”对象(可能的密钥),到底哪一个是“真凶”(加密该office文件的正确密钥),验证依据就是48字节随机数中后32字节的md5依赖关系。"

哦。我原来理解为2^24个A(输入)都会输出同一个B值。所以就以为是总共只有2^16个不同的B值,然后每个B值相同的A都放到同一个文件中,所以就有2^16个文件。看来是我理解错了。

如果存放在同一个文件中的A值所对应的B值不一样,那么文件内容应该是同时存放A和B值,而不能只存放A值啊,如果这样的话那么所占用的空间就是10T,而不是5T了啊。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 19:44

引用:
最初由 jeffcjh发布 查看帖子
为什么有:
pwarray[9] := $80;
pwarray[56] := $48;
这样两个赋值?
这些代码是我从wv-0.7.2里面转过来的。wv-0.7.2的开源代码里面就是这样写的。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 19:50

如果我的理解没错,那pwarray[9] := $80;pwarray[56] := $48;这些填充是肯定没有的。生产ks的16字节密钥纯粹是对byteA[]的9字节(前5字节是输入A,后4字节是块号)的标准MD5。

所以看来主要问题就在这里吧。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 19:51

那么我用什么方法来检查我生成的全查表是正确的呢?这个是比较关键的问题了。因为生成全查表要花费大量的时间,我只有确定按照这个公式生成的全查表是正确的,才能继续生成下去,否则如果花费几个月的时间来生成完之后,才发现生成的表是错误的,那就麻烦了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 20:06

可能还有一些细节以前没有讨论到。
关于结果存储的问题,这样理解:

由输入A计算输出B;

if          B的最低2字节为 0x0000   then  存入文件_0000.bin;
else if  B的最低2字节为 0x0001   then  存入文件_0001.bin;
......
else if  B的最低2字节为 0xfffe      then  存入文件_fffe.bin;
else                                                    存入文件_ffff.bin;

这样结果分类存入到2^16个文件中,每个文件平均大小为 5 * (2^40 / 2^16) = 80 MB, 
2^16个文件总大小:(2^16) * 80 MB  = 5 TB。

这些文件产生好了以后,如何使用呢?全查表方法大致为:
1、通过某种途径得到输出B(比如根据密报的固定底码立即得到乱数,即B);
2、根据B的最低2字节(比如说0xabcd) 找到对应文件_abcd.bin;
3、这样输入A必定存在于文件_abcd.bin中;
4、文件_abcd.bin中平均有2^24个A,到底哪一个A才是真正要求的呢?这时需要其它验证条件才能确定了。

由此可见,原来每次破译都要计算一遍2^40个函数关系,现在:
1、事先计算一遍2^40个函数关系;
2、以后破译时按照上述方法全查表,每次只要做2^24个验证即可,效率自然高得多了。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 20:12

关于结果存储的问题,这样理解:

由输入A计算输出B;

if          B的最低2字节为 0x0000   then  存入文件_0000.bin;
else if  B的最低2字节为 0x0001   then  存入文件_0001.bin;
......
else if  B的最低2字节为 0xfffe      then  存入文件_fffe.bin;
else                                                    存入文件_ffff.bin;

这样结果分类存入到2^16个文件中,每个文件平均大小为 5 * (2^40 / 2^16) = 80 MB, 
2^16个文件总大小:(2^16) * 80 MB  = 5 TB。


好方法!!!谢谢了!

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 20:14

引用:
最初由 jeffcjh发布 查看帖子
你是准备做产品卖钱啊还是怎么的?几个月时间都花得起啊。你可以生产一部分后用实际数据进行测试一下
不是做产品卖钱,而是领导给我的一个研究项目。


“不过这5字节是密钥流的最初5字节,在具体利用时可能不是这个位置的5字节,那些网站取的位置比较靠后,并且还不是连续的位置(有间隔),这些都是小问题,根据实际需要调用函数4生产足够长度的密钥流,再提取对应位置的数据即可。”

我从文档中取出全零的5个字节(未加密前的)来做测试行不行?具体方法如下:
1、创建一个doc文件,设置密码;
2、通过程序获取到128比特(即16字节)的密钥K[],然后再获取未加密前5个字节为全零的位置(为ks)。
3、再使用全查表生成程序,输入2步骤中获得的128比特(即16字节)的密钥K[](既A值),然后生成B值,如果B值等于2步骤中获取的ks,那么就说明我的全查表生成程序是正确的。

是否是这样?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 20:18

其实我并没有造这个表,需要5TB存储空间,不是小数目。但从数学进行过论证,写过一篇论文涉及到此内容,所以就给你交流了。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-10 22:28

“不过这5字节是密钥流的最初5字节,在具体利用时可能不是这个位置的5字节,那些网站取的位置比较靠后,并且还不是连续的位置(有间隔),这些都是小问题,根据实际需要调用函数4生产足够长度的密钥流,再提取对应位置的数据即可。”

意思是不是说获取word文档5字节,不是取连续的全零的地方?而是有可能从5个不同的位置取出5个字节?调用函数4生产的密钥流需要大于5字节?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-10 23:12

是的,这些位置的选取也有讲究的,不一定是密钥流最前面的几个字节,实际上如果
块号取0x000000的话,不能取前5字节。如果块号取0x00000001的话,可以取前5字节,代码类似,具体如下参考:

  unsigned char byteA[9];        // byteA[]的前5字节赋值为输入A
  unsigned char byteB[16];
  unsigned char ks[5];         // 存储生产的密钥流(乱数), 具体长度自己确定

  blockcnt = 1;             // 加密块编号

  // byteA[]的第5至8字节赋值为块编号
  *(unsigned int *)(byteA + 5) = blockcnt;

  // 对9字节(不是64字节)作标准的MD5 !!!
  MD5Data((unsigned char*)byteA, 9, byteB);

  // 以16字节byteB[]做密钥, 根据RC4算法产生5字节乱数
  RC4(byteB, 16, ks, 5);

这时因为从Word文件的0x400偏移处(对应于块号0x00000001)开始的8字节底码固定为
0x00,故可直接得到乱数,从而可以用上查表方法。

看来,你还不能急着造表,还要把相关细节考虑周到,逻辑上没有问题了才能动手。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-11 18:59

今天查了一天,还是没有匹配成功,生成的全查表还是未能与从文档中取出的B值匹配成功。现在是不知道我生成的全查表的数据不对还是从文档中取的位置不对。

jeffcjh,您能不能给出一个文档中具体的某个您已经检测成功的位置,从文档中某处取第几个字节?(类似您以前指点的“从“2F 00 36 00 01 00 01 00 01 00”之后开始第几个字节。。。”),我只有确认了从文档中取出的位置是正确的,才好检测生成的全查表是否正确。
谢谢了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-11 22:23

建议取Word文件偏移量0x400开始的5字节乱数(因为此处底码固定为0x00,所以乱数直接等于密码数据了),这时造表计算密钥时取块号为0x00000001,代码上面已提示,再说一遍也无妨:

unsigned char byteA[9];        // byteA[]的前5字节赋值为输入A
  unsigned char byteB[16];
  unsigned char ks[5];         // 存储生产的密钥流(乱数)

  blockcnt = 1;             // 加密块编号

  // byteA[]的第5至8字节赋值为块编号
  *(unsigned int *)(byteA + 5) = blockcnt;

  // 对9字节(不是64字节)作标准的MD5 !!!
  MD5Data((unsigned char*)byteA, 9, byteB);

  // 以16字节byteB[]做密钥, 根据RC4算法产生5字节乱数
  RC4(byteB, 16, ks, 5);

以后就是根据5字节ks的最后两字节来分类存入2^16个文件中。

实际破译Word密报时:
1、从word密报文件的0x400偏移处连续提取5字节作为乱数(即所讨论的输出B);
2、根据B的最后2字节对应到2^16个文件中的某个文件_xxxx.bin;
3、根据word密报中的3个16字节随机数(实际只需后两个随机数)顺序验证_xxxx.bin中的每个5字节A(最多2^24个),直至找到正确的A。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-11 22:34

1、从word密报文件的0x400偏移处连续提取5字节作为乱数(即所讨论的输出B);

0x400具体是哪个地方?因为我用的是复合文档来看的,你能否给出一个参照的位置,比如类似您以前指点的“从“2F 00 36 00 01 00 01 00 01 00”之后开始第几个字节。。。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-11 22:49

你用UltraEdit或WinHex之类的软件用二进制方法打开Word文件(HEX显示),最左边那列就是偏移,定位到0x400偏移处即可。用C函数表示,其实也就是 fseek (fp, 0x400, SEEK_SET)  的地方。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-11 22:57

哦。明白了。
00000400h: 4A 17 A1 ED A7 58 B2 90 81 F1 BB D8 59 39 E3 83
然后就取4A 17 A1 ED A7 这5个字节作为B值,对吧。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-12 10:26

对头。

如果还有什么问题,请注意VB代码与C代码之间的细微差异,比如数组第一个元素下标是从0开始还是从1开始,VB版的MD算法对传入参数的特点,等等,原理已经讨论得很多了,不会存在什么问题了,也许在编程实现上有些理解与编程代码不一致造成失败。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-12 16:25

不知道是否我的测试方法错误还是测试数据生成有误。

我的测试方法是(之前已经做好一个暴力破解的程序,并且已经测试通过):
1、先创建一个带有密码的word文档,然后使用那个暴力破解程序获取到最初的40位数(也就是我们之前说的A值);
2、获得这40位数的A值之后,使用我的生成全查表的程序生成对应的B值;
3、使用B值来匹配0x400处开始的5字节。

我的测试数据是:
A值:(49 109 90 10 4)
A值经由md5得到128比特的rc4密钥:(132, 61, 19, 190, 219, 197, 118, 199, 98, 145, 239, 167, 153, 193, 166, 55)
然后通过RC4加密得到B值:(200, 16, 14, 194, 233)

您有没有现成的程序,能不能帮我根据A值来测试128比特及B值是否正确?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-12 19:31

引用:
最初由 汪峰发布 查看帖子
我是新手刚进来两天在破解简单的软件时遇到了2个问题 1. getvbres v0.51上一个修改的按纽不能用也就是说不能修改字符串了.  2.为什么用OD的时候总是搜索不到关键的字符串呢?  那为大侠帮帮我解决一下  不胜感激啊!!!!...
关于OD中找不到关键字符串的问题,以前也遇到过,明明用UltraEdit打开看二进制数据是有那些关键词的,但OD查找失败。我认为可能有如下原因:
1、Unicode编码问题
2、对关键字符串进行了变形隐蔽,直接查找是不行的
当时我用W32dasm8.93进行反汇编查找,可以找到,所以建议你试试,有时需要几个工具配合使用才能达到目的。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-12 19:40

引用:
最初由 xiaoxinxx发布 查看帖子
不知道是否我的测试方法错误还是测试数据生成有误。

我的测试方法是(之前已经做好一个暴力破解的程序,并且已经测试通过):
1、先创建一个带有密码的word文档,然后使用那个暴力破解程序获取到最初的40位数(也就是我们之前说的A值);
2、获得这40位数的A值之后,使用我的生成全查表的程序生成...
不是测试有误,而是你没有看清我说的,代码其实早就给你提供了。

你的唯一错误就是将块号搞错了,你提供的数据对应的块号是0x00000000,
你只需将块号赋值为0x00000001,肯定就行了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-12 19:40

引用:
最初由 xiaoxinxx发布 查看帖子
不知道是否我的测试方法错误还是测试数据生成有误。

我的测试方法是(之前已经做好一个暴力破解的程序,并且已经测试通过):
1、先创建一个带有密码的word文档,然后使用那个暴力破解程序获取到最初的40位数(也就是我们之前说的A值);
2、获得这40位数的A值之后,使用我的生成全查表的程序生成...
不是测试有误,而是你没有看清我说的,代码其实早就给你提供了。

你的唯一错误就是将块号搞错了,你提供的数据对应的块号是0x00000000,
你只需将块号赋值为0x00000001,肯定就行了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-12 23:25

将块号设置为0x00000001后(原因已经讲过了),正确的数据为:

A值:(49 109 90 10 4)
A值经由md5得到128比特的rc4密钥:(102, 136, 177, 231, 82, 233, 192, 60, 211, 78, 151, 162, 168, 168, 90, 57)
然后通过RC4加密得到B值:(140, 242, 76, 34, 95)

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-13 09:09

jeffcjh;534374]将块号设置为0x00000001后(原因已经讲过了),正确的数据为:

A值:(49 109 90 10 4)
A值经由md5得到128比特的rc4密钥:(102, 136, 177, 231, 82, 233, 192, 60, 211, 78, 151, 162, 168, 168, 90
然后通过RC4加密得到B值:(140, 242, 76, 34, 95)


这个B值与0x400位置所取的连续5字节的B值不相同。
有可能是我开始获取A值的代码都有问题。检查中。。。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-13 10:46

还有一个问题

  // 对9字节(不是64字节)作标准的MD5 !!!
  MD5Data((unsigned char*)byteA, 9, byteB);

为什么是9字节而不是64字节?
在http://www.team509.com/download/MS_Word_encrypt.pdf这篇文章里的内容以及开源软件wv-0.7.2里面的代码都说是64字节啊。而且我编写的那个暴力破解word的密码也是通过了测试了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-13 11:09

引用:
最初由 xiaoxinxx发布 查看帖子
还有一个问题

  // 对9字节(不是64字节)作标准的MD5 !!!
  MD5Data((unsigned char*)byteA, 9, byteB);

为什么是9字节而不是64字节?
在http://www.team509.com/download/MS_Word_encry...
MD5算法本来是对任意长度的数据(包括长度为0的空数据)进行散列得到16字节结果。
其实将数据传给MD5算法后,在MD5内部是要按照算法本身的需要进行填充的,而你现在在MD5外面进行了填充,这个填充不知道是否正确(我认为可能错误)。到底是对是错,你拿上面我给出的测试数据进行调试验证一下即可,再贴一次也无妨:

将块号设置为0x00000001后(原因已经讲过了),正确的数据为:

A值:(49 109 90 10 4)
A值经由md5得到128比特的rc4密钥:(102, 136, 177, 231, 82, 233, 192, 60, 211, 78, 151, 162, 168, 168, 90, 57)
然后通过RC4加密得到B值:(140, 242, 76, 34, 95)

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-13 11:11

如果按你原来的填充能得到这个结果,说明填充与MD5本身的需要一致。不过即便正确,这个填充也是完全多余的。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-13 15:42

按照您说的改成这样了:

ArrayByteA = array [0..4] of byte;
Array16Byte = array [0..15] of byte;


function MakeKey(byteA: ArrayByteA):Array16Byte;
var
  mdContext: MD5Context;
  pwarray: array [0..8] of byte;
  byteB: Array16Byte;
  block: DWord;
begin
  block := 0;
  Fillchar(pwarray,sizeof(pwarray),0);        //pwarray数组清零
  CopyMemory(@pwarray, @byteA, 5);     //拷过去40位(5个字节) 
  //put block number in byte 6...9
  pwarray[5] := 1;
  pwarray[6] := 1;
  pwarray[7] := 1;
  pwarray[8] := 1;


  //对pwarrey计算一轮标准的MD5 hash begin
  MD5Init(mdContext);
  MD5Update (mdContext, @pwarray, 9);
  MD5StoreDigest(mdContext);
  //对pwarrey计算一轮标准的MD5 hash end

  CopyMemory(@byteB, @mdContext.Digest, 16);
  result := byteB;
end;


byteA值:(49 109 90 10 4)
调用 MakeKey(byteA) 得到128比特的rc4密钥却是:
(1, 35, 69, 103, 137, 171, 205, 239, 254, 220, 186, 152, 118, 84, 50, 16)

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-13 16:22

A值:(49 109 90 10 4)
A值经由md5得到128比特的rc4密钥:(102, 136, 177, 231, 82, 233, 192, 60, 211, 78, 151, 162, 168, 168, 90, 57)
然后通过RC4加密得到B值:(140, 242, 76, 34, 95)

您的这个结果是对的。查询word文档中的0x400的值就是您算出来的那个B值。估计是我的md5的算法有问题,奇怪了,我的md5的算法是通用的啊,已经在其它程序中测试通过了啊。您能不能把您的MD5的三个函数MD5Init(&ctx);MD5Update(&ctx, data, len);MD5Final(digest, &ctx);的具体代码贴出来?我看看与我的md5的算法有啥区别。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-13 20:55

你早把你的VB代码贴出来问题就早解决了。
我认为你的MD5算法没问题,而是你对块号的填充不对,应该为:
pwarray[5] := 1;
  pwarray[6] := 0;
  pwarray[7] := 0;
  pwarray[8] := 0;
我早反复说了块号要赋值为0x00000001啊,而你现在的赋值是0x01010101,能对吗?

改了这里就对了,我想。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-13 20:57

块号要赋值为0x00000001,如果一个字节一个字节赋值的话,就要颠倒过来看了,所以是:
pwarray[5] := 1;
pwarray[6] := 0;
pwarray[7] := 0;
pwarray[8] := 0;
这是32bite整数在I(NTEL指令格式)内存中的布局方法,你应该理解。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-13 20:58

引用:
最初由 jeffcjh发布 查看帖子
块号要赋值为0x00000001,如果一个字节一个字节赋值的话,就要颠倒过来看了,所以是:
pwarray[5] := 1;
pwarray[6] := 0;
pwarray[7] := 0;
pwarray[8] := 0;
这是32bite整数在I(NTEL指令格式)内存中的布局方法,...
这是32比特整数在(INTEL指令格式)内存中的布局方法,你应该理解。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-13 21:07

谢谢了。就是这个原因了。唉,这个小小的问题困扰了我几乎两个星期啊。再次感谢!

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-11-19 20:56

引用:
最初由 atjshadow发布 查看帖子
我觉得大家应该讨论一下彩虹链的方法。用全表查找的方法需要大量的空间。我想大家应该不会有那么多的空间和那么强的计算能力。你花费那么多的代价不太值。如果我用128bit的加密,那空间就更不能承受了...
如果想保证100%的成功率,只有使用完全查表的方法;当然对于128比特的密钥,目前来说是没有什么破解方法的。

彩虹链可以大大降低存储条件,但通常只能保障99%以上的成功率。

然而,不论是全查表还是彩虹链,两种方法都是要预先对整个密码函数的输入空间都计算一遍的,所以需要同样的计算能力。不过,LZ有这样大的计算能力和存储空间,所以他就没有深入考虑彩虹链的实现了。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-11-30 21:17

jeffcjh,得到密码之后,您做过使用密码来解密文档的内容的工作吗?
一个加密的WORD或者EXCEL文档,用二进制工具来查看,不是所有的字节都加密的,那么该怎样处理呢?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-02 20:14

这几天主要逛黑防去了,没留意你的问题。
通常情况下,Word是按照512字节一块(Excel按照1024字节一块)进行加密或解密的。
当你通过某种方式(比如上面讨论的查表方式)得到了40比特密钥,则按照加密机制可以生产乱数,每生产好512字节的乱数,就要将块号计数器增1,生成新的rc4密钥,再生产512字节乱数,如此重复,直至达到你的密文长度。将全部生产好的乱数与密文异或即得明文。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-02 21:37

得到40bit密钥后,对密文的解密大致如下所示:
 unsigned char byteA[9];        // byteA[]的前5字节赋值为输入A
  unsigned char byteB[16];
  unsigned char ks[512];         // 存储每次生产的512字节乱数

  blockcnt = 0;             // 加密块编号,初值为0x00000000,以后递增

  do
  {
       // byteA[]的第5至8字节赋值为块编号
     *(unsigned int *)(byteA + 5) = blockcnt;

      // 对9字节(不是64字节)作标准的MD5 !!!
      MD5Data((unsigned char*)byteA, 9, byteB);

      // 以16字节byteB[]做密钥, 根据RC4算法产生512字节乱数
    RC4(byteB, 16, ks, 0x200);
      
      //使用512字节乱数对密文解密...
      //解密公式为:底码 = 密文 xor 乱数
  } while (密文没有结束); // 注意:每次读512字节密文

你可以先用已得到的40bit密钥解密测试一下,针对blockcnt = 0和blockcnt = 1这两块密文,
它们对应的Word数据分别是Word文件的偏移0x200和0x400,每块均读512字节。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-02 21:37

这句代码
*(unsigned int *)(byteA + 5) = blockcnt;
应该为
*(unsigned int *)(byteA + 5) = blockcnt++;

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-02 23:58

问个问题:
WORD97、WORD2000、WORD2002和WORD2003的加密解密算法是不是一样的?

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 10:42

我用已得到的40bit密钥解密测试一下,针对blockcnt = 0和blockcnt = 1这两块密文,得出的结果与加密之前的值不相同。
我对比了同一个文件的加密前和加密后的文档,从0x000-0x243的数据基本上都是一样的,其中只有0x020b和0x020e不同。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-03 20:53

WORD97、WORD2000、WORD2002和WORD2003在使用默认的40比特密钥加密是过程都是一样的,除非用户选择其他加密类型。

解密后和解密前的数据不完全一致,这主要是Word在加密时对原来的明文数据进行了重新调整。判断你的40bit密钥是否正确只需看解密后的数据是否象明文(不是乱码)即可。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 21:23

解密后的数据与加密前的数据相差很远。这是我的代码,您看看有啥问题吗?

  ByteA[0] := 49;
  ByteA[1] := 109;
  ByteA[2] := 90;
  ByteA[3] := 10;
  ByteA[4] := 4;
  ByteA[5] := 0;
  ByteA[6] := 0;
  ByteA[7] := 0;
  ByteA[8] := 0;

  if not FileExists(sPath+'\'+sFileName) then Exit;
  f := TFileStream.Create(sPath+'\'+sFileName, fmOpenRead);
  nPos := 0;
  nSize := f.Size;
  try
    while nPos < nSize do
    begin
      f.Seek(nPos, soBeginning);
      f.ReadBuffer(ks, 512);
      CopyMemory(@ks1, @ks, 512);
      nPos := nPos + 512;
      MD5Init(mdContext);
      MD5Update (mdContext, @ByteA, 9);
      MD5Final(mdContext);
      CopyMemory(@byteB, @mdContext.Digest, 16);
      RC4(byteB,16,ks,512);
      for i := 0 to 511 do
        ksDrypt[i] := ks[i] xor ks1[i];
      ByteA[5] := ByteA[5] + 1;
    end;
  finally
    f.Free;
  end;

ksDrypt是最后得到的结果,与加密前的数据想对比相差很远。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-03 22:04

感觉代码细节上有点问题:
1、语句 f.Seek(nPos, soBeginning); 是定位到nPos开始读加密文件的数据吧?我认为nPos的初始值应该是512

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-03 22:08

如果解密结果看起来乱七八糟,肯定是某个地方有问题。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 22:20

nPos := 0;
...
f.Seek(nPos, soBeginning); 
f.ReadBuffer(ks, 512);


这几行代码的意思是从0开始定位,每次读取512字节。是从0开始读取还是从第512个字节开始读取?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-03 22:31

因为块号0对应Word文件的偏移0x200,块号1对应偏移0x400,所以应该是从word文件的第512个字节开始读取,逐块(512字节/块) 解密.

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 22:38

引用:
最初由 jeffcjh发布 查看帖子
因为块号0对应Word文件的偏移0x200,块号1对应偏移0x400,所以应该是从word文件的第512个字节开始读取,逐块(512字节/块) 解密.

意思是说:先把从0-512个字节的数据原封不动的先复制到新文件中,然后在从第512个字节开始逐块读取512个字节/块来解密?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-03 22:59

是的,你先这样试试

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 23:23

这样的结果也不正确:

加密前的文件的数据
0x200  EC A5 C1 00 35 40 09 04 00 00 F0 52 BF 00 00 00
0x210  00 00 00 10 00 00 00 00 00 06 00 00 07 08 00 00
0X220  0E 00 62 6A 62 6A CF 32 CF 32 00 00 00 00 00 00
0X230  00 00 00 00 00 06 00 00 00 00 00 00 04 08 16 00
0X240  32 10 00 00 AD 58 00 00 AD 58 00 00 07 00 00 00 
加密后的文件的数据
0x200  EC A5 C1 00 35 40 09 04 00 00 F0 53 BF 00 34 00
0x210  00 00 00 10 00 00 00 00 00 06 00 00 07 08 00 00
0X220  0E 00 62 6A 62 6A CF 32 CF 32 00 00 00 00 00 00
0X230  00 00 00 00 00 06 00 00 00 00 00 00 04 08 16 00
0X240  32 10 00 00 D3 C0 1A 7F 16 4B 14 CB E2 6C FC 6F

使用程序解密之后的数据
0x200  24 B5 CF C2 DC 51 28 3C 9D 2F 96 C4 D0 CA 1D 36
0X210  3F A0 D8 64 18 48 69 BE 6C 49 AA 63 CF AD D4 86
0X220  0A A3 3F 63 5D BF 89 4D BF C2 D3 5E EB 34 B6 41
0X230  51 4D BF 96 8E 7B CF BD 52 83 41 FB E4 19 34 AE
0X240  9B 37 62 D5 C7 A3 D2 66 FD 75 D3 2E 36 CF 14 97 




  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-03 23:40

哦。我使用WORD2003的密码所对应的40bit密钥来解密WORD2002的同样的密码所加密的文档了,现在密钥已经改过来了,是对的,解密之后word文档打不开,提示说:

文档的名称或路径无效。请试用如下建议:
*检查文档或驱动器的文件权限;
*使用“文件”菜单中的“打开”命令来定位文档

我使用ultraedit打开解密之后的word文档,在0xa00处看到了加密之前文档的正确的内容(WORD文档的加密之前的内容为“000000”),但是从0x1232位置到最后0x4df0位置的数据就完全不一样了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-04 08:24

你快接近成功了。但还有几点技术细节需要掌握才能使用Word软件本身打开解密后的文件。
1、解密后文件偏移第0x20b字节的最低比特位需要强制修改为0(该比特若为1,则表示Word文件是加密的);
2、Word加密文件中有两大段密文,第一段从文件偏移0x200开始,第二段从以前说过的“01 00 01 00”(后接48字节随机数)开始。针对这两大段密文需要分别解密,特别是对第二段密文解密时乱数要重新生产(块号从0开始递增);
3、第一段密文(偏移0x200)解密时,其首部0x44字节不要xor乱数,即保持原样(除了第0x20b字节最低比特位置0外)。

剩下的就只有这些东西了,good luck to you.

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-06 23:32

网上的那些OFFICE密码破解工具,好像可以破解所有的OFFICE组件,包括Word、Excel、Access、PowerPoint、Visio、Publisher、Project、 Outlook、Money、Backup、Schedule+、Mail 和 Internet Explorer等等。太强了。我现在只做到了能够破解word、excel和access,其它的都无从下手。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-07 18:10

引用:
最初由 xiaoxinxx发布 查看帖子
网上的那些OFFICE密码破解工具,好像可以破解所有的OFFICE组件,包括Word、Excel、Access、PowerPoint、Visio、Publisher、Project、 Outlook、Money、Backup、Schedule+、Mail 和 Internet Explorer等等。...
其他的office组件如果搞清楚了加密机制当然也是可以破解的,但据我所知,只有Word和Excel的默认加密文件可以做到快速破译(PowerPoint不能快速破解。至于所谓的Access加密不值一提,就无需多说了),其他的好像只能通过通常的口令穷举的方式进行破解。

如果你看到除了口令穷举方法以外的破译方法,可以将相关情况列出来,我也看看。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-08 15:48

目前的软件加密产品的密码算法除了“PDF”有用户手册加以详细描述外,基本只能通过反汇编获取到,那些提供破译服务的软件应该也是采用这种途径的吧,我猜。

当然,要全部搞清楚是一项相对巨大的工程,需要有一个研究团队。

破译方法除了暴力穷举口令外,现在比较多的是运用彩虹链的思路,也有一些公司或组织生产好了彩虹链专门来卖的。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-09 20:18

收到你的邮件了,已经给你解决。

基本如我所料,加密文件000000.doc有点特殊,
里面存在3段密报(绝大多数情况下只有两段密报),
故解密时对这3段密报均要解密(记住:块号均要从0开始计算乱数).

为方便你分析,我给出3段密报的起始偏移位置和长度如下:

  // 第1段密报
  int firstpos  = 0x200;
  int firstlen  = 0x1632 - firstpos;

  // 第2段密报(01000100)
  int secondpos  = 0x35800;
  int secondlen  = 0x36a5d - secondpos;

  // 附加段密报(绝大多数情况下不存在)
  int addedpos  = 0x1800;
  int addedlen  = 0x35694- addedpos;

对上述3段密文解密后就可以用Word正常打开了。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-11 15:53

jeffcjh,在做EXCEL解密时还有几个问题:
1、Excel是不是只有一段密文;
2、这段密文是不是从0x200开始;
3、这段密文首部多少个字节不要xor乱数呢?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-11 18:39

引用:
最初由 xiaoxinxx发布 查看帖子
jeffcjh,在做EXCEL解密时还有几个问题:
1、Excel是不是只有一段密文;
2、这段密文是不是从0x200开始;
3、这段密文首部多少个字节不要xor乱数呢?...
Excel的情况据我所知如下:
1、Excel只有一段密文,从文件偏移0x200开始;
2、Excel文件是以记录格式存储的,每个记录包括3个字段:记录类型(占2字节)、记录长度(占2字节)和记录体(其长度由“记录长度”字段来确定),故解密时必须按照记录格式来解析文件数据,对于记录类型和记录长度两个字段不xor乱数,仅对记录体解密;
3、我以某个具体实例说明如下(从密报文件偏移0x200开始的部分数据):
00000200: 09 08 10 00 00 06 05 00 EC 15 CD 07 C9 C0 00 00 
00000210: 06 03 00 00 2F 00 36 00 01 00 01 00 01 00 C1 05 
00000220: 42 C2 E4 19 72 D5 41 96 14 F7 81 53 E7 80 E4 CE 
00000230: F8 64 57 E1 EA 5A 73 12 D2 BB A0 A4 A9 94 AC EE 
00000240: B7 DE 09 DD 2B 76 CB B9 90 61 48 FE 5D E2 E1 00 
00000250: 02 00 B0 04 C1 00 02 00 38 69 E2 00 00 00 5C 00 
00000260: 70 00 4A AC 28 30 0A D9 30 25 5D 9F 11 11 5D 03 
00000270: EA C7 F1 CF A7 9D 27 DB 11 CF 47 2A C6 9F FB 0A

(具体记录的含义微软已经在其官方网站上公布了Excel文件格式,你可以搜索看看。)
你可以按照我说的3字段记录格式对上面的数据进行分析(你的Excel文件应该也差不多的)。

其中从0x214偏移开始的记录(即2F 00)是加密信息记录,36 00 01 00 01 00 01 00 后面的48字节的性质和作用与Word中第2段密数据“01000100”开始的48字节相同,就无需多说了。

由于其中某些记录的记录体是没有加密的,所以就不用解密,可见Excel解密时麻烦一些。但道理知晓后就是编程问题了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-11 18:54

引用:
最初由 ftiger发布 查看帖子
永中office 老版本 2004 加上补丁三  好像可以直接打开加密的 微软word, excel 等文件。...
如果ftiger所说是确实的,那可以说是一个很大的新闻了,但我更觉得像有些人所说的WinRar口令可以用某个软件直接去除一样,其实是假的。

如果ftiger能够实际测试一下,我们极力欢迎,或者给出相关信息,我们看看。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-11 18:56

哦。按照您说的意思,您看看我分析的对不对:
1、0x200--0x213(这20个字节原封不动的复制到新文件中);
2、0x214--0x24D(这10+48个字节就按照类似word第2段的密数据的解密方式);
3、从0x24E开始就按照3字段记录格式进行解密(block从零开始,每解密一个记录就+1):
   0x24E--0x24F(E1 00)为记录类型;
   0x250--0x251(02 00)为记录长度(正好512字节);
   然后就对记录长度的字节进行解密。

是这样吗?

另:您能否给出微软官方网站公布的Excel文件格式的链接地址?我搜索了,没找到。。。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-11 19:09

你的分析之第3点 稍微有点问题,更正如下:
1、0x214--0x24D这些数据在解密保存的文件中直接丢掉;
2、从0x24E开始就按照3字段记录格式进行解密。block块号从零开始,每解密1024字节(可能包括多个记录,最后一个记录可能会被截断到下一个1024字节中去),block就要加1(而不是每解密一个记录就+1);
3、0x24E--0x24F(E1 00)为记录类型,0x250--0x251(02 00)为记录长度(表示0x0002字节,而不是0x0200 = 512字节,这里要用intel字节顺序);

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-11 19:28

1、0x214--0x24D这些数据在解密保存的文件中直接丢掉;
    如果这58个字节的数据直接丢掉,那么解密后的文件比加密后的文件的字节数就少了58字节,而我对比过加密前和加密后的文件字节数是一样的。是不是在这段密数据解密之后添上58个0?

2、从0x24E开始就按照3字段记录格式进行解密。block块号从零开始,每解密1024字节(可能包括多个记录,最后一个记录可能会被截断到下一个1024字节中去),block就要加1(而不是每解密一个记录就+1);
  由于您之前说的“对于记录类型和记录长度两个字段不xor乱数,仅对记录体解密”,那么对于从0x24E--0x24F开始的3字段记录数据:
E1 00 02 00 B0 04 C1 00 02 00 38 69 E2 00 00 00 ......
这段数据中(第一个记录体的类型+长度)E1 00 02 00,(第二个记录体的类型+长度)C1 00 02 00 ,(第三个记录体的类型+长度)E2 00 00 00 不用解密,原封不动的复制到新文件中,而我对比了一下加密前的文件,是没有这几个数据,是不是您以前说过的,解密后的数据可能与加密前的数据有写区别的意思?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-11 19:35

1、密文中的加密记录(占58字节)是Excel软件自动添加的,在解密后不再需要,故须扔掉(否则Excel会认为你解密后的文件还是密报);
2、对,Excel对明文文件加密时会自动进行部分调整,所以解密时可以保留明文中原来没有的少量记录(如果丢掉,我猜可能也可以)

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-17 20:42

jeffcjh,还有两个问题请教您:
1、Excel的乱数(即所讨论的输出B)是从哪个位置找呢?
2、前面生成的全查表也应该适用于Excel的加密文档吧,我生成的全查表时所调用的函数4是这样的RC4(K, 16, ks, 5),其中block为1。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-18 10:47

你的这两个问题其实是一致的,看来你还并没有充分掌握全查表方法的本质精神。

要想Word和Excel使用同一个查表数据库,显然需要在Word密报中和Excel密报中的某些相同偏移位置存在固定底码(底码位置相同,但底码形式不需相同),这样一来,可以立即由密报xor底码得到乱数,从而实施全查表。

为表述准确,我用数学语言简要说明如下
定义两个偏移位置集合S1、S2:
S1 := {P | Word密报的偏移位置P的底码为某固定值};
S2 := {P | Excel密报的偏移位置P的底码为某固定值};

要想达到共享同一查表数据库的目标,只需两个集合之交集S1*S2不等于空集合即可。
一般来说,block只能为0,即均只能从文件偏移0x200的地方开始找固定底码位置。

我已将Word解密文件和Excel解密文件发给你,你自己去观察确定交集S1*S2的结果。
假设交集S1*S2中有5个位置,譬如P1, P2, P3, P4, P5(肯定存在的),5个位置不需要连续在一起,中间隔着也不影响。那么生产乱数时的函数调用必须为:
RC4(K, 16, ks, P1);
RC4(K, 16, ks, P2);
RC4(K, 16, ks, P3);
RC4(K, 16, ks, P4);
RC4(K, 16, ks, P5);
即要生产出这5位位置的乱数,作为B来保存(具体实施时自可简化)。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-18 12:18

假设交集S1*S2中有5个位置,譬如P1, P2, P3, P4, P5(肯定存在的),5个位置不需要连续在一起,中间隔着也不影响。那么生产乱数时的函数调用必须为:
RC4(K, 16, ks, P1);
RC4(K, 16, ks, P2);
RC4(K, 16, ks, P3);
RC4(K, 16, ks, P4);
RC4(K, 16, ks, P5);
即要生产出这5位位置的乱数,作为B来保存(具体实施时自可简化)。

我有点不明白,P1、P2、P3、P4、P5产生之后怎样保存为B?
假设P1=210,P2=220,P3=230,P4=240,P5=250,那么调用
RC4(K, 16, ks, P1);
RC4(K, 16, ks, P2);
RC4(K, 16, ks, P3);
RC4(K, 16, ks, P4);
RC4(K, 16, ks, P5);
后,B值是不是等于(ks[P1],Ks[P2],Ks[P3],Ks[P4],Ks[P5])?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-18 20:32

引用:
最初由 xiaoxinxx发布 查看帖子
假设交集S1*S2中有5个位置,譬如P1, P2, P3, P4, P5(肯定存在的),5个位置不需要连续在一起,中间隔着也不影响。那么生产乱数时的函数调用必须为:
RC4(K, 16, ks, P1);
RC4(K, 16, ks, P2);
RC4(K, 16, ks, P3);
RC4...
对,这5个位置的乱数保存为B

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-19 13:13

我之前生成的全查表,好像只能解密WORD2003文档,我今天试验了一下WORD2000,从0X400处取出的B值不完全相符的,有区别,是不是需要判断WORD的版本,根据不同的版本到不同的地方取B值?还是之前生成的全查表只能解密W0RD2003的加密文档呢?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-19 20:21

可能是其他问题。从word97至word2003的加密机制都一样。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-20 22:37

jeffcjh:这几天我测试了WORD2003和WORD2002,都可以使用我生成的全查表来解密,但是WORD2000就有点问题,按照全查表的生成方法产生的B值是BB   DB   BB   A7   40,而在0X400处找到的B值却是
00000400h: BB DB 69 A6 40 ,能否抽空帮我看看是什么原因?麻烦您了。
加密的文档已经发送您的邮箱里了。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-21 02:10

你并没有错,我将你发来的密文解密后发现文件偏移0x400处的5字节为
00 00 D2 01 00
正好与你的观察结果一致。

这说明了两点:
1、word2000的加密机制仍然与其它版本相同;
2、直接取文件偏移0x400处的5字节作为乱数来进行查表,在某些情况下不对。

所以你需要在文件偏移0x200至0x3ff之间找找固定底码的位置,按照前面所说的交集来确定同时适用于Word和Excel的情况,这是最佳解决方案。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-21 12:56

定义两个偏移位置集合S1、S2:
S1 := {P | Word密报的偏移位置P的底码为某固定值};
S2 := {P | Excel密报的偏移位置P的底码为某固定值};

要想达到共享同一查表数据库的目标,只需两个集合之交集S1*S2不等于空集合即可。
一般来说,block只能为0,即均只能从文件偏移0x200的地方开始找固定底码位置。


有几个问题想确认一下:
1、S1与S2的交集是使用解密之后的文档来查找,而不是使用加密的文档来查找,是吗?
2、是不是从0x200-0x400的任何位置如果满足条件都可以作为S1与S2的交集?
3、这些交集,如果在加密后也为00,是不是就不能使用?
4、这些交集在加密后的文档中是不是不会再相同了?

我按照您说的方法,找了这几十个交集,我列出其中的12个,您看是否正确,如果行的话,我就取其中的5个来做B值:
299 29B 2AD 2AF 2B1 2B5 2B7 2B8 2C6 2C8 2CC 2CF。。。。。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-21 14:19

1、必须使用解密后的文件来查找位置,原因:Word/Excel加密时会根据情况对明文进行调整,故在原始明文中找出的位置是不可靠的;
2、位于文件偏移0x200--0x3ff之间的固定位置都是可以的,但靠前的位置为佳,因为计算输出B时效率自然要高些;
3、(这些交集,如果在加密后也为00,是不是就不能使用?)不知你的意思是啥。求交集时与加密已经无关了,见1;
4、见1。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-21 14:21

为方便理解,对两个位置集合重新说明如下(与原来本质上是一样的):
S1 := {P | Word密报解密后在字节偏移位置P的的数据为某固定值};
S2 := {P | Excel密报解密后在字节偏移位置P的数据为某固定值};

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-22 11:11

jeffcjh,有两个问题请教您:

第一个问题:是不是从0x200-0x400的任何位置如果满足条件都可以作为S1与S2的交集?

应该不是任何位置都满足条件的吧。
1、EXCEL分为记录头(包括记录类型和记录长度)是不用解密的,所以属于记录头的位置应该是不能作为交集部分的。
2、EXCEL的0x200--0x213这20个字节原封不动的复制到新文件中,也是不用解密的,所以这部分也是不能作为交集部分的。

所以满足交集的条件应该是:
1、0x200-0x400;
2、属于EXCEL记录体的部分。
是否是这样?

第二个问题:产生B值是否可以这样(找到P1-P5五个交集的位置)
RC4(K, 16, ks, 512);
B值等于(ks[P1],Ks[P2],Ks[P3],Ks[P4],Ks[P5])?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-22 13:42

你的两个理解都是对的,请按此进行。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-22 20:16

你的确对于我们正在讨论的技术还存在一些错误认识,应该可以理解。尽管我并没有实际去计算这个造表过程,但是我从数学方面作过分析,并且联.网.破.译.获得了成功,所以我一点都没有疑问,对于你不断提出的问题基本上都能进行分析。

没有别的意思,我是希望你能够在接受他人的某些帮助的条件下,更多地学会独立思考和分析能力,毕竟看雪论坛这种人未必很多吧。

可以确定地说,EXCEL与WORD可以使用同一个查表数据库,原因我前面已经表述得不少了,不再嗦。我仅针对你的疑问说几句吧,希望你自己琢磨琢磨。

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-22 20:19

不错,EXCEL加密文档的0x214--0x24D位置的这些数据在解密保存的文件中直接丢掉,但是这个根本不影响全查表的计算,它仅仅是为了让Excel软件能打开而已,否则你自己写个Excel文件解析程序都行。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-24 16:02

jeffcjh:我这几天都在分析这个问题,百思不得其解,按照我的分析思路,很难产生一个同时适合WORD和EXCEL的全查表,并且这个全查表的大小与之前我生成的只适合WORD的全查表的大小一样。您能否帮看看我的分析哪里出了问题:

    由于要使用同一个生成程序来生成WORD与EXCEL的全查表,那么就必须选取WORD与EXCEL获取B值的同一个位置,那么就必须满足下面几个条件:
1、BLOCK必须设置为0,并且只能是0x200--0x400的地方。这是由于我们根据A值在解密文档的时候,WORD与EXCEL的解密方式几乎一样,都是从0X200处开始解密,不同的地方就是WORD每次获取512字节,EXCEL每次获取1024字节,必须是在这两个的交集的地方,也就是0x200-0x400的地方获取B值。
2、在满足第一个条件的前提下,选取的交集的位置在解密时必须是需要解密的,而不能直接复制或者丢弃的,也就是说,对于EXCEL来说:a、记录头(包括记录类型和记录长度部分)是不能作为交集的选择部分的,b、0x214--0x24D这部分解密时是需要丢弃的,所以也不能作为交集的选择部分。c、其它不需要解密的部分也不能作为交集的选择位置。

    目前已经根据解密后的文档找出了S1与S2的5个交集的地方,假设为P1--P5,那么在生成全查表的过程中,使用RC4(key, 16, ks, 512)函数产生了一个512字节长度的数组,然后我们根据已知交集部分的位置来获取数组相应部分的值,也就是我们前面说的ks[P1]、ks[P2]、ks[P3]、ks[P4]、ks[P5]。现在我就在这个地方的思路被卡住了:
    因为p1-p5我们是根据解密后的文档来查找的,那么对于WORD的加密文档来说,解密的时候是一部分字节原封不动的拷贝到解密文档中,一部分字节需要解密,而没有要丢弃的部分,所以对于p1-p5的交集来说,不管在WORD的加密文档或者解密文档中,位置都是不变的,也就是说根据全查表生成的B值ks[P1]、ks[P2]、ks[P3]、ks[P4]、ks[P5]对应的就是WORD加密文档中相应位置的B值;
    而对于EXCEL的加密文档来说就比较复杂一些,解密的时候除了一部分字节原封不动的拷贝、一部分需要解密,还有一部分字节却是需要丢弃的。所以对于p1-p5的交集来说,在EXCEL的加密文档和解密文档中位置有可能会不相同,我们假设选择的P1-P5的交集部分都在被丢弃字节部分的后面,被丢弃字节的大小为58个字节,那么在EXCEL解密后的文档的交集部分P1、P2、P3、P4、P5,对应于EXCEL加密文档的位置就是P1+58、P2+58、P3+58、P4+58、P5+58,所以在产生全查表的时候,生成的B值所取的ks的数组的位置就是ks[P1+58]、ks[P2+58]、ks[P3+58]、ks[P4+58]、ks[P5+58](这个我做过测试,确实是只有这样产生的B值才能在EXCEL的加密文档中找到)。

    根据上面的分析,使用RC4(K, 16, ks, 512);函数生成ks值后:
对于WORD来说,B值是:(ks[P1],Ks[P2],Ks[P3],Ks[P4],Ks[P5]) 
对于Excel来说,B值则是:(ks[P1+58],Ks[P2+58],Ks[P3+58],Ks[P4+58],Ks[P5+58])
我想不明白怎样才能使用同一个程序来生成同时适合WORD与EXCEL的全查表。

  • 标 题:答复
  • 作 者:xiaoxinxx
  • 时 间:2008-12-24 16:12

上面分析的EXCEL的加密文档,是只有打开密码的,而如果还有修改密码的话,那么在0X214的位置还会增加4个字节,也就是说,根据我的分析结果,对于除了有打开密码,还有修改密码的EXCEL加密文档,最后产生的B值是
(ks[P1+58+4],Ks[P2+58+4],Ks[P3+58+4],Ks[P4+58+4],Ks[P5+58+4])
这样对于这三种不同的情况(WORD加密文档、只有打开密码的EXCEL加密文档、同时有打开密码及修改密码的EXCEL加密文档),必须要生成3份全查表才能够解密。显然,说明我的这种产生全查表的方法(或者说我的分析)是有问题的。实际应该是只用产生一份全查表就能够同时适合于WORD及EXCEL的各种加密情况的。jeffcjh,能否再次指点一二?

  • 标 题:答复
  • 作 者:jeffcjh
  • 时 间:2008-12-24 20:45

本来这不是一个什么问题,但既然你又再次表示了疑惑,我还是说一下吧。
首先需要澄清一点,Excel解密后某些记录要丢掉,这其实并不关解密的事(也就是说与乱数数量的多少无关,因为这些没有参与加密/解密的部分,也是要占乱数的位置的。如果你不能理解这点,就暂时不要多想吧。)

下面我以你发给我的Word和Excel解密文件为例,说明两个位置交集的概念。
前面是Word解密文件的某些字节,后面是Excel解密文件的某些字节(没有丢掉记录,它们仍然是要占位置的):

0x200: ECA5C100236009040000F852BF003400
0x210: 000000100000000000060000CE090000
0x220: 0E00626A626A6DA56DA5000000000000
0x230: 00000000000000000000000004081600
0x240: 321400000FCF00000FCF0000CD000000
0x250: 00000000190000000000000000000000
0x260: 000000000000000000000000FFFF0F00
0x270: 0000000000000000FFFF0F0000000000
0x280: 00000000FFFF0F000000000000000000
0x290: 0000000000000000A400340000005604
0x2a0: 000034000000560400008A0400000000


0x200: 0908100000060500E91FCD07C9C00000
0x210: 060300002F0036000100010001009F77
0x220: 09902E7CE8ADBF7BB427A422D47B0038
0x230: 2A6607927B2A8A2D7C16875E77A1004C
0x240: 7F578B42EB09F5B8519CC708851E2020
0x250: 20202020202020202020202020202020
0x260: 20202020202020202020202020202020
0x270: 20202020202020202020202020202020
0x280: 20202020202020202020202020202020
0x290: 202020202020202042000200B0046101
0x2a0: 02000000C00100003D01060001000200

我不知你是用什么原则确定的那5个位置P1-P5,我没看出规律来。实际上,这5个位置的选择是需要遵循某些特点的,一是尽量靠前面,不要到老后面去了;二是尽量集中在某一段,且构成一个等差级数为佳。

无论你说的Excel加密的情况有几种,我所说的位置交集都是很容易找到的。恕我不能把现成的答案告诉你,已经摆在面前了,请用心看看吧。