这个软件是bithaha给我们新手出的题,现在把分析过程尽可能完整的写出来。希望能帮助到大家。
软件名称:Speed DVD Creator
下载地址:http://www.newhua.com/soft/47230.htm
任    务:需要找出来注册码。
首先,用OD加载这个软件,shift+f9,先让他运行起来,注册一下看看,输入pediy,55555555
当然这些是自己乱输的,肯定不对,我们就是让他弹出错误的提示。"Invalid username or registration code"看到这个
Sorry对话框了没?
接下来,就要使用OD的字符串查找功能,右键-->超级字符串参考-->查找 ASCII,弹出超级字符串参考窗体,在点右键-->查找"Invalid username or"
这里就找到了我们要找的字符串,双点找到串我们就来到程序中用到这个串的地方。F2下断。从新输入pediy,55555555,呵呵能断到说明我们找的是正确的
程序是走这里的。
00423C66   .  50            push    eax
00423C67   .  51            push    ecx
00423C68   .  C64424 1C 01  mov     byte ptr [esp+1C], 1
00423C6D   .  E8 3EFDFFFF   call    004239B0
00423C72   .  83C4 08       add     esp, 8
00423C75   .  85C0          test    eax, eax                         ;  检测eax是否为0,eax=1进入正确流程,那我们就要关注一下EAX怎么来的,EAX是上边函数的返回值.关注上边的函数.跟进看看
00423C77      75 18         jnz     short 00423C91                   ;  如果程序在这里不跳转将进入正确流程,否则就进入下边弹错误框的地方.
00423C79   .  6A 40         push    40
00423C7B   .  68 38FE4900   push    0049FE38                         ;  sorry
00423C80   .  68 0CFE4900   push    0049FE0C                         ;  invalid username or registration code
00423C85   .  8BCE          mov     ecx, esi
00423C87   .  E8 EF7E0400   call    0046BB7B
00423C8C   .  E9 A0000000   jmp     00423D31
00423C91   >  8B4E 5C       mov     ecx, dword ptr [esi+5C]
00423C94   .  8D5424 04     lea     edx, dword ptr [esp+4]
00423C98   .  51            push    ecx
00423C99   .  68 F0FD4900   push    0049FDF0                         ;  license to:%s
00423C9E   .  52            push    edx
00423C9F   .  E8 201E0400   call    00465AC4
00423CA4   .  8B4424 10     mov     eax, dword ptr [esp+10]
00423CA8   .  83C4 0C       add     esp, 0C
00423CAB   .  8BCE          mov     ecx, esi

进入 00423C6D   .  E8 3EFDFFFF   call    004239B0  看看。当然要先在这里下断才能跟进去看了。。。呵呵


004239B0  /$  56            push    esi
004239B1  |.  8B7424 0C     mov     esi, dword ptr [esp+C]
004239B5  |.  57            push    edi
004239B6  |.  8B7C24 0C     mov     edi, dword ptr [esp+C]
004239BA  |.  56            push    esi
004239BB  |.  57            push    edi
004239BC  |.  E8 0FFCFFFF   call    004235D0          
004239C1  |.  83C4 08       add     esp, 8
004239C4  |.  85C0          test    eax, eax
004239C6  |.  75 11         jnz     short 004239D9                   ;  注1                  
004239C8  |.  56            push    esi
004239C9  |.  57            push    edi
004239CA  |.  E8 E1F6FFFF   call    004230B0
004239CF  |.  83C4 08       add     esp, 8
004239D2  |.  85C0          test    eax, eax
004239D4  |.  75 03         jnz     short 004239D9        ;  注1
004239D6  |.  5F            pop     edi
004239D7  |.  5E            pop     esi
004239D8  |.  C3            retn
004239D9  |>  5F            pop     edi
004239DA  |.  B8 01000000   mov     eax, 1
004239DF  |.  5E            pop     esi
004239E0  \.  C3            retn

在这个函数里边有2个地方跳转能跳到4239DA处,mov eax,1才是正确流程。
那我们就要看看这两个函数了,第一个函数大概走了一下没有发现什么特别的操作。跟这个函数需要耐心。。。当时看的时候也有点犯晕。

进入这个4230b0函数以后,前边对用户名和密码进行了长度的验证。

0042314D  |.  F7D1          not     ecx
0042314F  |.  49            dec     ecx
00423150  |.  3BCD          cmp     ecx, ebp
00423152  |.  0F87 52010000 ja      004232AA                         ;比较用户名和密码的长度,名称不能比密码长。
00423158  |.  8BFB          mov     edi, ebx
0042315A  |.  8BCE          mov     ecx, esi
0042315C  |.  F2:AE         repne   scas byte ptr es:[edi]
0042315E  |.  F7D1          not     ecx
00423160  |.  49            dec     ecx
00423161  |.  0F84 43010000 je      004232AA           ;又是比较,如果让他跳走,那就失败了。
00423167  |.  8BFA          mov     edi, edx
00423169  |.  8BCE          mov     ecx, esi
0042316B  |.  F2:AE         repne   scas byte ptr es:[edi]
0042316D  |.  F7D1          not     ecx
0042316F  |.  49            dec     ecx
00423170  |.  0F84 34010000 je      004232AA        ;又是比较,如果让他跳走,那就失败了。
00423176  |.  894424 38     mov     dword ptr [esp+38], eax
0042317A  |>  8B5424 38     /mov     edx, dword ptr [esp+38]
0042317E  |.  8A82 E0FC4900 |mov     al, byte ptr [edx+49FCE0]
00423184  |.  8B15 D4424A00 |mov     edx, dword ptr [4A42D4]         ;  Speed_DV.004A42E8

这个地方有3个跳转,如果跳转出去就是说你输入的用户名或者密码的长度不符合软件要求。(看完后你就知道用户名和密码是一一对应的。)
继续下走。~~~~
004230B0  /$  6A FF         push    -1
004230B2  |.  68 A01C4800   push    00481CA0                         ;  柑7i; SE 处理程序安装
004230B7  |.  64:A1 0000000>mov     eax, dword ptr fs:[0]            ;  在这里就是关于异常处理的安装有兴趣的可以看看关于SEH的介绍
004230BD  |.  50            push    eax
004230BE  |.  64:8925 00000>mov     dword ptr fs:[0], esp
004230C5  |.  83EC 14       sub     esp, 14
004230C8  |.  8B4424 24     mov     eax, dword ptr [esp+24]
004230CC  |.  53            push    ebx
004230CD  |.  55            push    ebp
004230CE  |.  56            push    esi
004230CF  |.  57            push    edi
004230D0  |.  50            push    eax                              ;  ASCII "pediy"----参数用户名
004230D1  |.  8D4C24 18     lea     ecx, dword ptr [esp+18]
004230D5  |.  E8 D9520400   call    004683B3                         ;  在IDA里边看他只有一个参数.那就是上边的EAX
004230DA  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
004230DE  |.  C74424 2C 000>mov     dword ptr [esp+2C], 0
004230E6  |.  E8 382A0400   call    00465B23
004230EB  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
004230EF  |.  E8 E3290400   call    00465AD7
004230F4  |.  6A 20         push    20
004230F6  |.  8D4C24 18     lea     ecx, dword ptr [esp+18]          ;  名
004230FA  |.  E8 76560400   call    00468775
004230FF  |.  8B4C24 38     mov     ecx, dword ptr [esp+38]          ;  密码
00423103  |.  8BD8          mov     ebx, eax
00423105  |.  51            push    ecx
00423106  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
0042310A  |.  E8 A4520400   call    004683B3
0042310F  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
00423113  |.  C64424 2C 01  mov     byte ptr [esp+2C], 1
00423118  |.  E8 062A0400   call    00465B23
0042311D  |.  8D4C24 10     lea     ecx, dword ptr [esp+10]
00423121  |.  E8 B1290400   call    00465AD7
00423126  |.  6A 20         push    20
00423128  |.  8D4C24 14     lea     ecx, dword ptr [esp+14]
0042312C  |.  E8 44560400   call    00468775
00423131  |.  8BD0          mov     edx, eax
00423133  |.  83CE FF       or      esi, FFFFFFFF
00423136  |.  8BFA          mov     edi, edx                         ;  edi 密码
00423138  |.  8BCE          mov     ecx, esi
0042313A  |.  33C0          xor     eax, eax
0042313C  |.  895424 20     mov     dword ptr [esp+20], edx
00423140  |.  F2:AE         repne   scas byte ptr es:[edi]
00423142  |.  F7D1          not     ecx
00423144  |.  49            dec     ecx
00423145  |.  8BFB          mov     edi, ebx
00423147  |.  8BE9          mov     ebp, ecx
00423149  |.  8BCE          mov     ecx, esi
0042314B  |.  F2:AE         repne   scas byte ptr es:[edi]
0042314D  |.  F7D1          not     ecx
0042314F  |.  49            dec     ecx
00423150  |.  3BCD          cmp     ecx, ebp
00423152  |.  0F87 52010000 ja      004232AA                         ;  比较用户名和密码的长度
00423158  |.  8BFB          mov     edi, ebx
0042315A  |.  8BCE          mov     ecx, esi
0042315C  |.  F2:AE         repne   scas byte ptr es:[edi]
0042315E  |.  F7D1          not     ecx
00423160  |.  49            dec     ecx
00423161  |.  0F84 43010000 je      004232AA
00423167  |.  8BFA          mov     edi, edx
00423169  |.  8BCE          mov     ecx, esi
0042316B  |.  F2:AE         repne   scas byte ptr es:[edi]
0042316D  |.  F7D1          not     ecx
0042316F  |.  49            dec     ecx
00423170  |.  0F84 34010000 je      004232AA
00423176  |.  894424 38     mov     dword ptr [esp+38], eax          ;  循环变量,对应42325c  inc eax
0042317A  |>  8B5424 38     /mov     edx, dword ptr [esp+38]
0042317E  |.  8A82 E0FC4900 |mov     al, byte ptr [edx+49FCE0]       ;  从49fce0取值,ebx在哪加的呢?找找看,看上边一句,ESP+38,谁改变了ESP+38
00423184  |.  8B15 D4424A00 |mov     edx, dword ptr [4A42D4]         ;  Speed_DV.004A42E8
0042318A  |.  884424 18     |mov     byte ptr [esp+18], al
0042318E  |.  895424 34     |mov     dword ptr [esp+34], edx
00423192  |.  8BFB          |mov     edi, ebx                        ;  开始计算用户名称的长度
00423194  |.  83C9 FF       |or      ecx, FFFFFFFF
00423197  |.  33C0          |xor     eax, eax
00423199  |.  33ED          |xor     ebp, ebp
0042319B  |.  F2:AE         |repne   scas byte ptr es:[edi]
0042319D  |.  F7D1          |not     ecx
0042319F  |.  49            |dec     ecx                             ;  得到用户名称的长度
004231A0  |.  C64424 2C 02  |mov     byte ptr [esp+2C], 2
004231A5  |.  74 4F         |je      short 004231F6
004231A7  |>  8A042B        |/mov     al, byte ptr [ebx+ebp]         ;  ebx是字符串"pediy"基地址,ebp在后边有+1
004231AA  |.  33F6          ||xor     esi, esi                       ;  这里给esi置0,就是循环里边的i=0啊.
004231AC  |>  3A0475 78FC49>||/cmp     al, byte ptr [esi*2+49FC78]   ;  依次比较p e d i y
004231B3  |.  74 08         |||je      short 004231BD                ;  如果取得的字符和里边的字符相等--跳出
004231B5  |.  46            |||inc     esi                           ;  不相等i++;
004231B6  |.  83FE 34       |||cmp     esi, 34                       ;  i<0x34
004231B9  |.^ 7C F1         ||\jl      short 004231AC                ;  小于的话继续下一次.
004231BB  |.  EB 11         ||jmp     short 004231CE                 ;  如果在这里边找不到的话,跳转
004231BD  |>  8A0C75 79FC49>||mov     cl, byte ptr [esi*2+49FC79]    ;  这里是49fc79和49fc78查一个字节,说明如果找到和pediy中一个字符相等的,取他下一个字符.
004231C4  |.  51            ||push    ecx                            ;  参数压栈,把得到的数放到结果里边
004231C5  |.  8D4C24 38     ||lea     ecx, dword ptr [esp+38]        ;  存放结果的地址
004231C9  |.  E8 7A550400   ||call    00468748
004231CE  |>  83FE 34       ||cmp     esi, 34                        ;  0x34是什么呢?大小写字母一共26*2=0x34啊.所以输入用户名的时候应该有判定是否输入的是字符,否则这里算法怎么过啊?
004231D1  |.  75 0E         ||jnz     short 004231E1
004231D3  |.  8B5424 18     ||mov     edx, dword ptr [esp+18]
004231D7  |.  8D4C24 34     ||lea     ecx, dword ptr [esp+34]
004231DB  |.  52            ||push    edx
004231DC  |.  E8 67550400   ||call    00468748                       ;  填充,关注一下参数就知道函数大概意思了。
004231E1  |>  8BFB          ||mov     edi, ebx
004231E3  |.  83C9 FF       ||or      ecx, FFFFFFFF
004231E6  |.  33C0          ||xor     eax, eax
004231E8  |.  45            ||inc     ebp                            ;  这里不是EBP+1吗?以取得pediy下一个字符
004231E9  |.  F2:AE         ||repne   scas byte ptr es:[edi]
004231EB  |.  F7D1          ||not     ecx
004231ED  |.  49            ||dec     ecx                            ;  计算长度啊,我们做练习的时候用过吧.
004231EE  |.  3BE9          ||cmp     ebp, ecx                       ;  比较用户名称长度和循环次数
004231F0  |.^ 72 B5         |\jb      short 004231A7
004231F2  |.  8B5424 34     |mov     edx, dword ptr [esp+34]         ;  到这里算法我想都清楚了吧
004231F6  |>  8B42 F8       |mov     eax, dword ptr [edx-8]
004231F9  |.  83F8 10       |cmp     eax, 10                         ;  比较0x10注册码要满足0x10?继续跟~~
004231FC  |.  7D 34         |jge     short 00423232
004231FE  |.  B9 10000000   |mov     ecx, 10
00423203  |.  8D5424 1C     |lea     edx, dword ptr [esp+1C]
00423207  |.  2BC8          |sub     ecx, eax
00423209  |.  51            |push    ecx
0042320A  |.  52            |push    edx
0042320B  |.  B9 54894A00   |mov     ecx, 004A8954                   ;  GkesVcnrTpAQsXwK
00423210  |.  E8 8F240400   |call    004656A4
00423215  |.  50            |push    eax
00423216  |.  8D4C24 38     |lea     ecx, dword ptr [esp+38]
0042321A  |.  C64424 30 03  |mov     byte ptr [esp+30], 3
0042321F  |.  E8 39550400   |call    0046875D                        ;  用上边的串填充剩下不满0x10以后的数.到这已经是注册码了
00423224  |.  8D4C24 1C     |lea     ecx, dword ptr [esp+1C]         ;  eax=12ada4  看eax里边存放地址里边的值,.
00423228  |.  C64424 2C 02  |mov     byte ptr [esp+2C], 2
0042322D  |.  E8 13510400   |call    00468345
00423232  |>  8B4424 20     |mov     eax, dword ptr [esp+20]
00423236  |.  8B4C24 34     |mov     ecx, dword ptr [esp+34]
0042323A  |.  50            |push    eax                             ; /Arg2
0042323B  |.  51            |push    ecx                             ; |(initial cpu selection)
0042323C  |.  E8 B4F90200   |call    00452BF5                        ; \Speed_DV.00452BF5
00423241  |.  83C4 08       |add     esp, 8
00423244  |.  8D4C24 34     |lea     ecx, dword ptr [esp+34]
00423248  |.  85C0          |test    eax, eax
0042324A  |.  C64424 2C 01  |mov     byte ptr [esp+2C], 1
0042324F      74 1B         je      short 0042326C
00423251  |.  33F6          |xor     esi, esi
00423253  |.  E8 ED500400   |call    00468345
00423258  |.  8B4424 38     |mov     eax, dword ptr [esp+38]
0042325C  |.  40            |inc     eax
0042325D  |.  83F8 03       |cmp     eax, 3
00423260  |.  894424 38     |mov     dword ptr [esp+38], eax
00423264  |.^ 0F8C 10FFFFFF \jl      0042317A                        ;  外部大循环(在还原代码的时候,没有包括这部分)
0042326A  |.  EB 0A         jmp     short 00423276
0042326C  |>  BE 01000000   mov     esi, 1
00423271  |.  E8 CF500400   call    00468345
00423276  |>  8D4C24 10     lea     ecx, dword ptr [esp+10]



还有一种情况就是用户名大于0x10的时候他要继续循环,数字也可以。

对于我来说还原全部代码还有点困难。耐心的考验啊~~主要还是掌握技巧。
以后我会继续努力的。时间有点仓促暂时只能做这么多了。
感谢Aker 大菜 bithaha还有组员对我的支持。:)感动ing
/***************************************************************************************************************************************
部分还原代码如下:
/*************************************************************/
  /*  username字符串输入的时候只能是大小写字母,长度小于16个字符。
  
    o_out字符数组里边是存放最后的注册码。
   */
  /*************************************************************/
  char username[]="Second";
  int nameLength=sizeof(username)-1;
  if(nameLength>0x10)
  {
    AfxMessageBox("名称过长");
    return;
  }
  //用到的一个全局数据区域。
  BYTE b_49fc78[0x80]={
    0x61, 0x43, 0x62, 0x78, 0x63, 0x69, 0x64, 0x49, 0x65, 0x41,
    0x66, 0x58, 0x67, 0x4D, 0x68, 0x6B, 0x69, 0x45, 0x6A, 0x56, 
    0x6B, 0x5A, 0x6C, 0x65, 0x6D, 0x52, 0x6E, 0x79, 0x6F, 0x42, 
    0x70, 0x4B, 0x71, 0x64, 0x72, 0x54, 0x73, 0x53, 0x74, 0x50, 
    0x75, 0x57, 0x76, 0x6C, 0x77, 0x6A, 0x78, 0x44, 0x79, 0x48, 
    0x7A, 0x46, 0x41, 0x7A, 0x42, 0x71, 0x43, 0x70, 0x44, 0x4F, 
    0x45, 0x6B, 0x46, 0x67, 0x47, 0x59, 0x48, 0x6D, 0x49, 0x74, 
    0x4A, 0x61, 0x4B, 0x72, 0x4C, 0x51, 0x4D, 0x6E, 0x4E, 0x73, 
    0x4F, 0x75, 0x50, 0x55, 0x51, 0x47, 0x52, 0x4A, 0x53, 0x4C, 
    0x54, 0x4E, 0x55, 0x62, 0x56, 0x63, 0x57, 0x66, 0x58, 0x68, 
    0x59, 0x6F, 0x5A, 0x77, 0x41, 0x4D, 0x42, 0x00, 0x47, 0x6B, 
    0x65, 0x73, 0x56, 0x63, 0x6E, 0x72, 0x54, 0x70, 0x41, 0x51, 
    0x73, 0x58, 0x77, 0x4B, 0x00, 0x00, 0x00, 0x00
  };
  char o_out[100]={0};
  int j=0;
  do
  {
    for(int i=0;i<0x34;i++)
    {
      if(username[j]==b_49fc78[i*2])
      {
        o_out[j]=b_49fc78[i*2+1];
        j++;
        break;
      }
    }
  }while(j<nameLength);
  
  int otherLen=0x10-nameLength;
  for(int x=0;x<otherLen;x++)
  {
    o_out[nameLength+x]=b_49fc78[x+0x6c];
  }
  AfxMessageBox(_T(o_out));