• 标 题:周末灌水篇 (11千字)
  • 作 者:丁丁虾
  • 时 间:2000-10-28 12:19:2
  • 链 接:http://bbs.pediy.com

pusi Crackme 1.0 破解      (希望转载的时候保持完整)

【作者】      丁丁虾  ddxia/[CCG]
【E_mail】        ddxia@263.net (如果Crackme教学文章中有错,请来信:))
【Web】            http://go18.163.com/~ddxia
【目标】       pusi Crackme 1.0
【目标URL】        http://go18.163.com/~ddxia/crackme/pusicrackme1.0.zip
【工具】          W32dasm   

    很久都没有背诗啦!觉的有点对不起泱泱大国五千的文化,也没有这么可怕啦!只是
感到有些惭愧.......呵呵~~~~~~......人总是很矛盾的.......

【年代】:北宋 
【作者】:晏几道
【作品】:醉落魄         

    满街斜月,垂鞭自唱阳关彻。
    断尽柔肠思归切,
    都为人人,不许多时别。

    南桥昨夜风吹雪,
    短长亭下征尘歇。
    归时定有梅堪折。
    欲把离愁,细捻花枝说


    这个Crackme界面很简单,就是要求填写一个CODE,然后就检查它是否正确。所以破解
的工具,就是选择W32DASM就可以了。

    1、分析代码
:00401099 6A0A                    push 0000000A
:0040109B 6844304000              push 00403044  ----》存放我们输入CODE的地址
:004010A0 68B80B0000              push 00000BB8
:004010A5 FF3554304000            push dword ptr [00403054]
* Reference To: USER32.GetDlgItemTextA, Ord:0102h
                                  |
:004010AB E8D2000000              Call 00401182  ----》调用 GetDlgItemTextA
:004010B0 E814000000              call 004010C9  ----》进行比较判断

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401097(C)
|
:004010B5 EB09                    jmp 004010C0
:004010C9 56                      push esi
:004010CA 57                      push edi
:004010CB 51                      push ecx
:004010CC 33F6                    xor esi, esi
:004010CE 33FF                    xor edi, edi
:004010D0 B908000000              mov ecx, 00000008    ----》只对前8个CODE进行操作
:004010D5 BE44304000              mov esi, 00403044    ----》存放fake code地址
:004010DA 803632                  xor byte ptr [esi], 32 
:004010DD 46                      inc esi
:004010DE E2FA                    loop 004010DA        ----》循环8次 CODE XOR 32
:004010E0 BE44304000              mov esi, 00403044    ----》XOR后的结果地址
:004010E5 B904000000              mov ecx, 00000004    ----》循环4次 
:004010EA 8A06                    mov al, byte ptr [esi] --》取第1个CODE
:004010EC 8A5E01                  mov bl, byte ptr [esi+01]-》取第2个CODE
:004010EF 32C3                    xor al, bl          ----》进行XOR
:004010F1 88874C304000            mov byte ptr [edi+0040304C], al -》将结果存放到0040304C
:004010F7 83C602                  add esi, 00000002    ----》跳到第3个CODE
:004010FA 47                      inc edi              ----》结果指针加1
:004010FB E2ED                    loop 004010EA       
:004010FD BE4C304000              mov esi, 0040304C    ----》上面计算出4位结果
:00401102 8A06                    mov al, byte ptr [esi] --》取出第1位
:00401104 8A5E01                  mov bl, byte ptr [esi+01]-》取出第2位
:00401107 32C3                    xor al, bl          ----》第1位XOR第2位
:00401109 8A5E02                  mov bl, byte ptr [esi+02]-》取出第3位
:0040110C 8A4E03                  mov cl, byte ptr [esi+03]-》取出第4位
:0040110F 32D9                    xor bl, cl          ----》第3位XOR第4位
:00401111 32C3                    xor al, bl          ----》1^2结果XOR3^4结果
:00401113 B908000000              mov ecx, 00000008    ----》循环8次
:00401118 BE44304000              mov esi, 00403044    ----》经过XOR32的结果
:0040111D 3006                    xor byte ptr [esi], al --》(经过XOR32的结果)XOR(1^2结果XOR3^4结果)
:0040111F 46                      inc esi
:00401120 E2FB                    loop 0040111D
:00401122 B908000000              mov ecx, 00000008
:00401127 BE44304000              mov esi, 00403044    ----》经过变化的结果地址

* Possible StringData Ref from Data Obj ->"qYyBELGood Work Cracker"
                                  |
:0040112C BF08304000              mov edi, 00403008    ----》进行比较的字节地址
                      [403008] 71 18 59 1B 79 42 45 4C

:00401131 8A06                    mov al, byte ptr [esi]
:00401133 3A07                    cmp al, byte ptr [edi]
:00401135 751D                    jne 00401154        ----》如果不相等就GAME OVER
:00401137 46                      inc esi
:00401138 47                      inc edi
:00401139 E2F6                    loop 00401131
:0040113B 6A40                    push 00000040        ----》成功的对话框

* Possible StringData Ref from Data Obj ->"Crackme 1.0"
                                  |
:0040113D 6835304000              push 00403035
:00401142 6810304000              push 00403010
:00401147 FF3554304000            push dword ptr [00403054]

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:0040114D E83C000000              Call 0040118E
:00401152 EB17                    jmp 0040116B

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401135(C)
|
:00401154 6A30                    push 00000030    -----》失败的对话框

* Possible StringData Ref from Data Obj ->"Crackme 1.0"
                                  |
:00401156 6835304000              push 00403035

* Possible StringData Ref from Data Obj ->"Bad Serial, Sorry!"
                                  |
:0040115B 6822304000              push 00403022
:00401160 FF3554304000            push dword ptr [00403054]

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:00401166 E823000000              Call 0040118E

    2、AcTion
      Crack的第一大大招,乾坤大挪移,
:00401133 3A07                    cmp al, byte ptr [edi]
:00401135 751D                    jne 00401154        ----》如果不相等就GAME OVER
                                  ^^^^^^^^^^^^---》修改为nop nop (9090)

          太简单了!!!收工  (众人倒.........口吐白沫.........:)
          呵呵~~~~~~~~

          想一想我们如何通过编程,计算出正确的结果。开始的时候,我也懵了,不知道
如何下手,虽然上面的分析头头是道,但编写KeyGen是第二次哦!!(若有什么不正确的地
方,请告诉我:)
          左看右看,上想下思,终于找到一个突破口。呵呵~~~~~ 在哪里呢????


:00401113 B908000000              mov ecx, 00000008    ----》循环8次
:00401118 BE44304000              mov esi, 00403044    ----》经过XOR32的结果
:0040111D 3006                    xor byte ptr [esi], al --》(经过XOR32的结果)XOR(1^2结果XOR3^4结果)
:0040111F 46                      inc esi
:00401120 E2FB                    loop 0040111D       
          xor byte ptr [esi], al----》就是这句啦!al 的值,如果按上面,用数学公式
逆推的化,我肯定要晕,想想当年数学能过就OK了 呵呵~~~~~ 想不到,如今确要用上。读书
的时候,什么都多学一点,今天看来并不坏 :) 
          COME ON!我们可以采用穷尽法,al (0x00--> 0xFF)也就是255次,不多不多:)
于是第一次就写出下面这个程序,目的就是让最后要比较的结果XOR al XOR 0x32,循环255
次,并把结果显示出来,筛一筛,看一看,合法的字符有没有 :)
#include <stdio.h>

unsigned char Table[8] = { 0x71,0x18,0x59,0x1B,0x79,0x42,0x45,0x4C};
unsigned char Code[8];


void main(void)
{
    unsigned char i=0x00;
    int n;
    do
    {
      for(n=0;n<8;n++)
        Code[n]=Table[n]^i^0x32    ;
      printf("Code output: %s\n",Code);
    i++;
    } while(i < 0xFF);
}

    呵呵~~~~ 看了几分钟结果,有点运气,找到了正确的CODE:Z3r0Ring ---》因为它
太眼熟了(外国的一位有名的CRACK大师) :)
       
    收工!!(被众人群殴.........鼻青脸肿.....成了虾总......晕倒.......)

        既然我们能计算出正确的CODE,何不按照程序的计算方法,编程成程序,再按分析
代码的情况,计算一番。于是就有了以下的程序 呵呵~~~~~

#include <stdio.h>

unsigned char Table[8] = { 0x71,0x18,0x59,0x1B,0x79,0x42,0x45,0x4C};
unsigned char Code[12];
unsigned char Temp[9];
void main(void)
{
    unsigned char i=0x00;
    unsigned char x;
    int n;
    Temp[8]=NULL;
    do
    {
      for(n=0;n<8;n++) {
        Code[n]=Table[n]^i^0x32    ; //穷尽法计算出CODE
        Temp[n]=Code[n];            //临时存放
      }
//+++++++++++++++++++++++++++++++++++++++++++++++++ 
//:004010D0              mov ecx, 00000008    ----》只对前8个CODE进行操作
//:004010D5              mov esi, 00403044    ----》存放fake code地址
//:004010DA              xor byte ptr [esi], 32 
//:004010DD              inc esi
//:004010DE              loop 004010DA        ----》循环8次 CODE XOR 32
//+++++++++++++++++++++++++++++++++++++++++++++++++
      for(n=0;n<8;n++)
        Code[n]=Code[n]^0x32;   

//+++++++++++++++++++++++++++++++++++++++++++++++++
//:004010EA                mov al, byte ptr [esi] --》取第1个CODE
//:004010EC                mov bl, byte ptr [esi+01]-》取第2个CODE
//:004010EF                xor al, bl          ----》进行XOR
//:004010F1                mov byte ptr [edi+0040304C], al -》将结果存放到0040304C
//:004010F7                add esi, 00000002    ----》跳到第3个CODE
//:004010FA                inc edi              ----》结果指针加1
//:004010FB                loop 004010EA       
//+++++++++++++++++++++++++++++++++++++++++++++++++
      for(n=0;n<4;n++)
        Code[8+n]=Code[n*2]^Code[n*2+1];

//+++++++++++++++++++++++++++++++++++++++++++++++++
//:004010FD                  mov esi, 0040304C    ----》上面计算出4位结果
//:00401102                  mov al, byte ptr [esi] --》取出第1位
//:00401104                  mov bl, byte ptr [esi+01]-》取出第2位
//:00401107                  xor al, bl          ----》第1位XOR第2位
//:00401109                  mov bl, byte ptr [esi+02]-》取出第3位
//:0040110C                  mov cl, byte ptr [esi+03]-》取出第4位
//:0040110F                  xor bl, cl          ----》第3位XOR第4位
//:00401111                  xor al, bl          ----》1^2结果XOR3^4结果
//+++++++++++++++++++++++++++++++++++++++++++++++++
      x=(Code[8]^Code[9])^(Code[10]^Code[11]);

      Code[8]=NULL;

//+++++++++++++++++++++++++++++++++++++++++++++++++
//:00401113                    mov ecx, 00000008    ----》循环8次
//:00401118                    mov esi, 00403044    ----》经过XOR32的结果
//:0040111D                    xor byte ptr [esi], al --》(经过XOR32的结果)XOR(1^2结果XOR3^4结果)
//:0040111F                    inc esi
//:00401120                    loop 0040111D
//:00401122                    mov ecx, 00000008
//:00401127                    mov esi, 00403044    ----》经过变化的结果地址
//
//* Possible StringData Ref from Data Obj ->"qYyBELGood Work Cracker"
//                                  |
//:0040112C                    mov edi, 00403008    ----》进行比较的字节地址
//                      [403008] 71 18 59 1B 79 42 45 4C
//
//:00401131                    mov al, byte ptr [esi]
//:00401133                    cmp al, byte ptr [edi]
//:00401135                    jne 00401154        ----》如果不相等就GAME OVER
//:00401137                    inc esi
//:00401138                    inc edi
//:00401139                    loop 00401131
//+++++++++++++++++++++++++++++++++++++++++++++++++
      for(n=0;n<8;n++){
      if (Table[n] != (Code[n]^x)) break;
      if (n==7)     printf("Code output: %s\n",Temp);
    }
    i++;
    } while(i < 0xFF);
}

    3总结:穷尽法在写注册机中可是经常用的。关键是如何寻找到穷尽什么东东,然后
再反过来证明,直至得到最后的结果。

      收工可以啦吧 !!! 呵呵~~~~~~ (啊没有时间啦!我要出去玩了:))

                           
                时间:2000.10.27 23:29