⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap6-2-4.htm.primary

📁 加密与解密,软件加密保护技术与解决方案,看雪文档!
💻 PRIMARY
📖 第 1 页 / 共 3 页
字号:
    +----&lt; byte string (or file) 字节串,(或是文件)<br>
    |<br>
    v 3 2 1 0 byte 字节<br>
    | +---+---+---+---+<br>
    XOR---&lt;| | | | | Register 记存器<br>
    | +---+---+---+---+<br>
    | |<br>
    | XOR<br>
    | ^<br>
    v +---+---|---+---+<br>
    | | | | | | Precomputed table 值表(用来进行操作)<br>
    | +---+---+---+---+<br>
    +---&gt;-: : : : :<br>
    +---+---+---+---+<br>
    | | | | |<br>
    +---+---+---+---+<br>
    (figure 2)</p>
  <p>'reflected' direct Table 算法:</p>
  <p> 由于这里有这样一个与之相对应的'反射'算法,事情显得复杂了.一个反射的值/记存器<br>
    就是将它的每一位以此串的中心位为标准对调形成的.例如:0111011001就是1001101110<br>
    的反射串. <br>
    他们提出'反射'是因为UART(一种操作IO的芯片)发送每一个字节时是先发最没用的0位,<br>
    最后再发最有意义的第七位.这与正常的位置是相逆的. <br>
    除了信息串不做反射以外,在进行下一步操作前,要将其于的数据都做反射处理.所以在<br>
    计算值表时,位向右移,且poly也是作过反射处理的.当然,在计算CRC时,记存器也要向右<br>
    移,而且值表也必须是反射过的. </p>
  <p> byte string (or file) --&gt;---+<br>
    | 1. 表中每一个入口都是反射的.<br>
    byte 3 2 1 0 V 2. 初始化记存器也是反射的.<br>
    +---+---+---+---+ | 3. 但是byte string中的数据不是反射的,<br>
    | | | | |&gt;---XOR 因为其他的都做过反射处理了. <br>
    +---+---+---+---+ |<br>
    | |<br>
    XOR V<br>
    ^ |<br>
    +---+---|---+---+ |<br>
    | | | | | | 值表<br>
    +---+---+---+---+ |<br>
    : : : : : &lt;---+<br>
    +---+---+---+---+<br>
    | | | | |<br>
    +---+---+---+---+<br>
    (figure 3)</p>
  <p>我们的算法如下:<br>
    1. 将记存器向右移动一个字节.<br>
    2. 将刚移出的哪个字节与byte string中的新字节做XOR运算,<br>
    得出一个指向值表table[0..255]的索引<br>
    3. 将索引所指的表值与记存器做XOR运算.<br>
    4. 如数据没有全部处理完,则跳到步骤1.</p>
  <p><br>
    下面是这个算法的简单的可执行汇编源码:</p>
  <p>完整的CRC-32标准所包含的内容:<br>
    Name : &quot;CRC-32&quot;<br>
    Width : 32<br>
    Poly : 04C11DB7<br>
    Initial value : FFFFFFFF<br>
    Reflected : True<br>
    XOR out with : FFFFFFFF</p>
  <p>作为对你好奇心的奖励, 这里是CRC-16标准: :)<br>
    Name : &quot;CRC-16&quot;<br>
    Width : 16<br>
    Poly : 8005<br>
    Initial value : 0000<br>
    Reflected : True<br>
    XOR out with : 0000</p>
  <p>'XOR out with' 是为了最终得到CRC而用来与记存器最后结果做XOR运算的值.<br>
    假如你想了解一些关于'reversed'逆向CRC poly的话,请看我的参考文章.<br>
    <br>
    我是在16位DOS模式下用的32位编码,因此你会在这个程序中看到很多32位与16位混合<br>
    的编码...当然这是很容易转换成纯32位编码的.注意这个程序是经过完整测试并且能够<br>
    正常运行的.下面的Java 和 C 代码都是由这个汇编代码而来的. <br>
    底下的这段程序就是用来计算CRC-32 table的:</p>
  <p> xor ebx, ebx ;ebx=0, 将被用做一个指针.<br>
    InitTableLoop:<br>
    xor eax, eax ;eax=0 为计算新的entry.<br>
    mov al, bl ;al&lt;-bl</p>
  <p> ;生成入口.<br>
    xor cx, cx<br>
    entryLoop:<br>
    test eax, 1<br>
    jz no_topbit<br>
    shr eax, 1<br>
    xor eax, poly<br>
    jmp entrygoon<br>
    no_topbit:<br>
    shr eax, 1<br>
    entrygoon:<br>
    inc cx<br>
    test cx, 8<br>
    jz entryLoop</p>
  <p> mov dword ptr[ebx*4 + crctable], eax<br>
    inc bx<br>
    test bx, 256<br>
    jz InitTableLoop</p>
  <p>注释: - crctable 是一个包含256个dword的数组.<br>
    - 由于使用反射算法,EAX被向右移.<br>
    - 因此最低的8位被处理了.</p>
  <p> 用Java和C写的代码如下(int is 32 bit):</p>
  <p>for (int bx=0; bx&lt;256; bx++){<br>
    int eax=0;<br>
    eax=eax&amp;0xFFFFFF00+bx&amp;0xFF; // 就是 'mov al,bl' 指令<br>
    for (int cx=0; cx&lt;8; cx++){<br>
    if (eax&amp;&amp;0x1) {<br>
    eax&gt;&gt;=1;<br>
    eax^=poly;<br>
    }<br>
    else eax&gt;&gt;=1;<br>
    }<br>
    crctable[bx]=eax;<br>
    }</p>
  <p>下面的汇编代码是用来计算CRC-32的:</p>
  <p> computeLoop:<br>
    xor ebx, ebx<br>
    xor al, [si]<br>
    mov bl, al<br>
    shr eax, 8<br>
    xor eax, dword ptr[4*ebx+crctable]<br>
    inc si<br>
    loop computeLoop</p>
  <p> xor eax, 0FFFFFFFFh</p>
  <p>注释: - ds:si 指向将要被处理的byte string信息流.<br>
    - cx 信息流的长度.<br>
    - eax 是当前的CRC.<br>
    - crctable是用来计算CRC的值表.<br>
    - 此例中记存器的初始值为: FFFFFFFF.<br>
    - 要将中间值与FFFFFFFFh做XOR才能得到CRC</p>
  <p>下面是Java和C写的代码:</p>
  <p> for (int cx=0; cx&gt;=8;<br>
    eax^=crcTable[ebx];<br>
    }<br>
    eax^=0xFFFFFFFF;</p>
  <p> 现在我们已经完成了本文的第一部分:CRC原理部分,所以如果你希望能够对CRC做更深<br>
    的研究,那么我建议你去读在本文最后给出连接上的资料,我读了.好了,终于到了本文最<br>
    有意思的部分,CRC的逆向分析!</p>
  <p><br>
    ------------------------------------------------------------------------------------<br>
    第二部分 CRC的逆向分析:</p>
  <p> 我遇到了很多障碍,当我思考如何破解CRC时.我试图使用一些特殊顺序的字节使CRC无效.<br>
    但我没有做到...后来我意识到这种方法是行不同的,因为CRC内建了一些处理过程,无论你<br>
    改变任何位它都不会出问题,真正的CRC就是在不断变化的,总是在变化的.找一些CRC程序,<br>
    你可以自己尝试一下. <br>
    现在我知道我只能'纠正'在CRC后面的那些我想改变的字节.所以我要构造一个字节序列,<br>
    它可以将CRC转化成任何我想要的样子! </p>
  <p>具体实现这个想法</p>
  <p>一个字节串? 01234567890123456789012345678901234567890123456789012<br>
    You want to change from ^ this byte to ^ this one.</p>
  <p>就是位置9-&gt;26.<br>
    同时我们需要额外的4个字节用来在最后恢复原始字节串.</p>
  <p> 当你计算CRC-32时,从0-8都没有问题,直到第9位,修补过的字节串会使CRC发生根本的改变.<br>
    即使当走过了第26位,以后的字节都没有改变,你也不可能在得到原始的CRC了,不可能了!你读<br>
    过后面的段落时就会明白为什么.间而言之,当你修改一个字节串时,要保证CRC不变. </p>
  <p>1. 计算并保存从1~9位的CRC.<br>
    2. 继续计算直到第27位还有额外的4字节并保存结果.<br>
    3. 用1的值来计算新的字节串和额外4字节的CRC(对应patch后的新的CRC值),并将之保存.<br>
    4. 现在我们得到了一个新的CRC,但是我们希望将它还原成原先的CRC,所以我们用逆向算法<br>
    来计算那额外的4字节.</p>
  <p>1~3就是实际的情况,下面你将学到最关键的部分4.</p>
  <p><br>
    '反转'CRC-16</p>
  <p> 我想,先来介绍计算逆CRC-16对于你来说会简单些.好的,我们现在处在一个恰当的位置,<br>
    在以修改代码后面,就是你想将CRC还原的地方.我们知道原始的CRC(是在patch代码之前计<br>
    算出来的)还有这个当前的记存器值.现在我们的目的就是计算可以改变当前记存器值到原<br>
    始记存器值的两个字节.首先,我们用正常的方法计算这两个未知字节的CRC.我们设他们为<br>
    X,Y.设记存器为a1,a0,只有0不能用来作为变量(00).:)在来看一下我们的CRC算法,figure<br>
    3,更好的理解下面我要做的.</p>
  <p>好,我们开始:</p>
  <p>用这两字节串'X Y' 字节是从左边开始被处理的.<br>
    记存器现在是a1 a0.<br>
    用'+'来表示XOR运算(和第一部分中用的一样)</p>
  <p>处理第一个字节, X:<br>
    a0+X 这是顶部字节的计算结果 (1)<br>
    b1 b0 这是(1)在表中索引对象.<br>
    00 a1 向右移动记存器.<br>
    00+b1 a1+b0 上面两行对应位做XOR运算.</p>
  <p>现在记存器为: (b1) (a1+b0)</p>
  <p>处理第二个字, Y:<br>
    (a1+b0)+Y 此轮顶部字节的计算结果(2)<br>
    c1 c0 这是(2)在表中的索引对象.<br>
    00 b1 向右移动记存器.<br>
    00+c1 b1+c0 上面两行对应位做XOR运算.</p>
  <p>最后记存器就是: (c1) (b1+c0)</p>
  <p>我用一点不同的方法来表示:</p>
  <p>a0 + X =(1) 在表中指向b1 b0.<br>
    a1 + b0 + Y =(2) 在表中指向c1 c0.<br>
    b1 + c0=d0 记存器中新的低位字节.<br>
    c1=d1 记存器中新的高位字节.<br>
    (1) (2)</p>
  <p>Wow! 请大家暂时记住上面的信息:)<br>
    别着急, 下面给出一个有具体值的例子.<br>
    <br>
    如果你想要的记存器的值是d1 d0(是原始的CRC),而且你知道在变换之前的记存器的值<br>
    (a1 a0)...那么你将要送如什么样的2个字节进记存器来做CRC计算呢? <br>
    好了,现在我们的工作应该从幕后走到台前来了.d0一定是bi+c0,并且d1一定是c1...<br>
    但是这到底是怎么回事,我听到你这样问了,你能知道b1和c0的值吗???你还记得哪个值表<br>
    吗?你只需要在表中查找c0 c1这个字的值就可以了因为你知道c1.所以你需要编写一个查<br>
    找程序.假如你找到了这个值,一定要记住这个值的索引,因为这就是找出未知的两个顶部<br>
    字节,举例来说:(1)和(2)! <br>
    所以,现在你找到了c1 c0,那么如何来得到b1 b0呢?如果b1+c0=d0那么b1=d0+c0!如前所<br>
    述,现在你用哪个查找程序在表中查b1 b0的值.现在我们得到了所有计算X和Y所需要的值.<br>
    Cool huh? <br>
    a1+b0+Y=(2) so Y=a1+b0+(2)<br>
    a0+X=(1) so X=a0+(1)</p>
  <p><br>
    实例.</p>
  <p>让我们来看看这个具体值的例子:<br>
    -register before: (a1=)DE (a0=)AD<br>
    -wanted register: (d1=)12 (d0=)34<br>
    在附录的CRC-16的表中查找以12开头值的入口.这里入口38h的值为12C0.试这找一找是否还<br>
    有以12开头的值的入口.你不可能在找到的,因为我们计算每一中顶部字节组合而得的值的<br>
    入口,一共是256个值,记住!<br>
    现在我们知道(2)=38,c1=12,c0=C0,所以b1=C0+34=F4,现在查找以F4开头的b1的入口.这里<br>
    入口4Fh的值是F441.<br>
    我们还知道 (1)=4F,b1=F4,b0=41,现在所有我们需要的都已经清楚了,接下来我们计算X,Y.</p>
  <p>Y=a1+b0+(2)=DE+41+38=A7<br>
    X=a0+(1) =AD+4F =E2</p>
  <p>结论:将CRC 记存器的值从 DEAD 变为 1234 我们需要这两个字节 E2 A7 (以此顺序).</p>
  <p> 你看,破解CRC校验你需要反向计算,还有要记住的就是计算过程中的值.当你在用汇编编写<br>
    查找表程序时,要注意intel在小模式中是反向存储值的.现在你可能已经明白如何去破解这个<br>
    CRC-16了...下面介绍如何在CRC-32中实现.</p>
  <p><br>
    破解 CRC-32</p>
  <p>现在我们来看CRC-32,和CRC-16是一样容易的(可能一样的不容易你认为).这里你操作的对象<br>
    是4个字节的而不是2字节的.继续向下看,将它与上面CRC-16版本做对比.</p>
  <p>设4字节串 X Y Z W , 从左边开始处理.<br>
    设记存器为 a3 a2 a1 a0<br>
    注意a3是MSB,而a0是LSB</p>
  <p>处理第一个字节, X:<br>
    a0+X 这是顶部字节的计算结果(1).<br>
    b3 b2 b1 b0 这是(1)在表中索引对象序列.<br>
    00 a3 a2 a1 右移记存器.<br>
    00+b3 a3+b2 a2+b1 a1+b0 上面两行对应位做XOR运算.</p>
  <p>现在记存器是: (b3) (a3+b2) (a2+b1) (a1+b0)</p>
  <p>Processing second byte, Y:<br>
    (a1+b0)+Y 这是顶部字节的计算结果(2).<br>
    c3 c2 c1 c0 这是(2)在表中索引对象序列.<br>
    00 b3 a3+b2 a2+b1 右移记存器.<br>
    00+c3 b3+c2 a3+b2+c1 a2+b1+c0 上面两行对应位做XOR运算.</p>
  <p>现在记存器是: (c3) (b3+c2) (a3+b2+c1) (a2+b1+c0)</p>
  <p>Processing third byte, Z:<br>
    (a2+b1+c0)+Z 这是顶部字节的计算结果(3).<br>
    d3 d2 d1 d0 这是(3)在表中索引对象序列.<br>
    00 c3 b3+c2 a3+b2+c1 右移记存器.<br>
    00+d3 c3+d2 b3+c2+d1 a3+b2+c1+d0 上面两行对应位做XOR运算.</p>
  <p>现在记存器是: (d3) (c3+d2) (b3+c2+d1) (a3+b2+c1+d0)</p>
  <p>Processing fourth byte, W:<br>
    (a3+b2+c1+d0)+W 这是顶部字节的计算结果(4).<br>
    e3 e2 e1 e0 这是(4)在表中索引对象序列.<br>
    00 d3 c3+d2 b3+c2+d1 右移记存器.<br>
    00+e3 d3+e2 c3+d2+e1 b3+c2+d1+e0 上面两行对应位做XOR运算.</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -