【文章标题】: APISpy v2.5 Crack过程分享
【文章作者】: 秋风寒
【软件名称】: APISpy v2.5
【软件大小】: 69k
【下载地址】: 自己搜索下载
【加壳方式】: Petite 1.2 -> (c)1998 Ian Luck (h) *
【保护方式】: 注册码
【编写语言】: VC++6.0
【使用工具】: OD, PEid
【软件介绍】: 能够监控应用程序执行API函数。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  最近使用到了该软件,每次启动都提示注册,保存结果时,只能保存前10条,很是郁闷,决定拿他开个刀,练练手。
  1、用PEid查看,显示是Petite 1.2 -> (c)1998 Ian Luck (h) * 加的壳, 用Peid的通用脱壳插件脱壳后,再次用Peid
     查看,显示为VC++6.0编写的,呵呵,我的最爱啊。
  2、执行脱壳后的程序,程序能正常运行,但是OD载入后,点注册对话框,填了注册信息后,按确定,OD报内存不可读错误,
     然后程序退出,怀疑有反调试。
  3、决定代壳调试试试。
  4、OD载入源程序,填注册码,确定,发现一切正常,开来没有凡调试。
  5、查找当前模块中的名称,然后在GetDlgItemTextA, GetWindowTextA的每个参考上下断点,
     然后填注册码,确定后停在下面这个函数处(在这里可能需要在CPU窗口单击右键,选择分析->分析代码,来让代码显示正常),
  004051D0  /$  8B4424 08     mov     eax, dword ptr [esp+8]
  004051D4  |.  53            push    ebx
  004051D5  |.  56            push    esi
  004051D6  |.  83F8 01       cmp     eax, 1
  004051D9  |.  57            push    edi
  004051DA  |.  0F85 81000000 jnz     00405261
  004051E0  |.  8B7424 10     mov     esi, dword ptr [esp+10]
  004051E4  |.  8B1D D0914000 mov     ebx, dword ptr [<&USER32.GetDlgI>;  USER32.GetDlgItemTextA        
  004051EA  |.  6A 4E         push    4E                               ; /Count = 4E (78.)
  004051EC  |.  68 C0C34000   push    0040C3C0                         ; |Buffer = apis32.0040C3C0
  004051F1  |.  68 F1030000   push    3F1                              ; |ControlID = 3F1 (1009.)
  004051F6  |.  56            push    esi                              ; |hWnd
  004051F7  |.  FFD3          call    ebx                              ; \GetDlgItemTextA            ;断在这里
  004051F9  |.  85C0          test    eax, eax                         
  004051FB  |.  74 76         je      short 00405273                   ;检查注册码长度
  004051FD  |.  BF C0C34000   mov     edi, 0040C3C0                    ;  ASCII "qiufenghan"
  00405202  |.  83C9 FF       or      ecx, FFFFFFFF
  00405205  |.  33C0          xor     eax, eax
  00405207  |.  F2:AE         repne   scas byte ptr es:[edi]
  00405209  |.  F7D1          not     ecx
  0040520B  |.  49            dec     ecx
  0040520C  |.  51            push    ecx
  0040520D  |.  68 C0C34000   push    0040C3C0                         ;  ASCII "qiufenghan"
  00405212  |.  68 88A64000   push    0040A688                         ;  ASCII "UserKey"
  00405217  |.  E8 D4010000   call    004053F0                         ;  把注册码保存在注册表中,键名为UserKey
  0040521C  |.  83C4 0C       add     esp, 0C
  0040521F  |.  6A 4E         push    4E
  00405221  |.  68 C0C34000   push    0040C3C0                         ;  ASCII "qiufenghan"
  00405226  |.  68 F0030000   push    3F0
  0040522B  |.  56            push    esi
  0040522C  |.  FFD3          call    ebx
  0040522E  |.  85C0          test    eax, eax                         ; 检测用户名长度
  00405230  |.  74 41         je      short 00405273
  00405232  |.  BF C0C34000   mov     edi, 0040C3C0                    ;  ASCII "qiufenghan"
  00405237  |.  83C9 FF       or      ecx, FFFFFFFF
  0040523A  |.  33C0          xor     eax, eax
  0040523C  |.  F2:AE         repne   scas byte ptr es:[edi]
  0040523E  |.  F7D1          not     ecx
  00405240  |.  49            dec     ecx
  00405241  |.  51            push    ecx
  00405242  |.  68 C0C34000   push    0040C3C0                         ;  ASCII "qiufenghan"
  00405247  |.  68 78A64000   push    0040A678                         ;  ASCII "UserName"
  0040524C  |.  E8 9F010000   call    004053F0                         ; 把用户名保存在注册表理,键名为UserName
  00405251  |.  83C4 0C       add     esp, 0C
  00405254  |.  6A 01         push    1                                ; /Result = 1
  00405256  |.  56            push    esi                              ; |hWnd
  00405257  |.  FF15 68914000 call    dword ptr [<&USER32.EndDialog>]  ; \EndDialog
  0040525D  |.  5F            pop     edi
  0040525E  |.  5E            pop     esi
  0040525F  |.  5B            pop     ebx
  00405260  |.  C3            retn
  00405261  |>  83F8 02       cmp     eax, 2
  00405264  |.  75 0D         jnz     short 00405273
  00405266  |.  8B4424 10     mov     eax, dword ptr [esp+10]
  0040526A  |.  6A 00         push    0                                ; /Result = 0
  0040526C  |.  50            push    eax                              ; |hWnd
  0040526D  |.  FF15 68914000 call    dword ptr [<&USER32.EndDialog>]  ; \EndDialog
  00405273  |>  5F            pop     edi
  00405274  |.  5E            pop     esi
  00405275  |.  5B            pop     ebx
  00405276  \.  C3            retn
  
  这时发现把用户把注册信息保存在注册表中后关闭了对话框,然后跟踪开始进入事件处理循环,把代码跟丢了。
  不过既然知道注册信息存在注册表里,呵呵就容易多了。找出注册算法的很重要的一步就是找到注册信息是怎么存放的。
  在继续处理以前我们先来看看函数  004053F0的内容, 很显然是个写注册表的功能。
  004053F0  /$  56            push    esi
  004053F1  |.  68 20B74000   push    0040B720                         ; /pHandle = apis32.0040B720
  004053F6  |.  68 3F000F00   push    0F003F                           ; |Access = KEY_ALL_ACCESS
  004053FB  |.  6A 00         push    0                                ; |Reserved = 0
  004053FD  |.  68 90A64000   push    0040A690                         ; |Subkey = "SOFTWARE\APIS32"
  00405402  |.  68 02000080   push    80000002                         ; |hKey = HKEY_LOCAL_MACHINE
  00405407  |.  FF15 08904000 call    dword ptr [<&ADVAPI32.RegOpenKey>; \RegOpenKeyExA
  0040540D  |.  85C0          test    eax, eax
  0040540F  |.  74 32         je      short 00405443
  00405411  |.  68 24B74000   push    0040B724                         ; /pDisposition = apis32.0040B724
  00405416  |.  68 20B74000   push    0040B720                         ; |pHandle = apis32.0040B720
  0040541B  |.  6A 00         push    0                                ; |pSecurity = NULL
  0040541D  |.  68 3F000F00   push    0F003F                           ; |Access = KEY_ALL_ACCESS
  00405422  |.  6A 00         push    0                                ; |Options = REG_OPTION_NON_VOLATILE
  00405424  |.  68 90A64000   push    0040A690                         ; |Class = "SOFTWARE\APIS32"
  00405429  |.  6A 00         push    0                                ; |Reserved = 0
  0040542B  |.  68 90A64000   push    0040A690                         ; |Subkey = "SOFTWARE\APIS32"
  00405430  |.  68 02000080   push    80000002                         ; |hKey = HKEY_LOCAL_MACHINE
  00405435  |.  FF15 10904000 call    dword ptr [<&ADVAPI32.RegCreateK>; \RegCreateKeyExA
  0040543B  |.  85C0          test    eax, eax
  0040543D  |.  74 04         je      short 00405443
  0040543F  |.  33C0          xor     eax, eax
  00405441  |.  5E            pop     esi
  00405442  |.  C3            retn
  00405443  |>  8B7424 10     mov     esi, dword ptr [esp+10]
  00405447  |.  8B4424 0C     mov     eax, dword ptr [esp+C]
  0040544B  |.  8B4C24 08     mov     ecx, dword ptr [esp+8]
  0040544F  |.  8B15 20B74000 mov     edx, dword ptr [40B720]
  00405455  |.  56            push    esi                              ; /BufSize
  00405456  |.  50            push    eax                              ; |Buffer
  00405457  |.  6A 00         push    0                                ; |ValueType = REG_NONE
  00405459  |.  6A 00         push    0                                ; |Reserved = 0
  0040545B  |.  51            push    ecx                              ; |ValueName
  0040545C  |.  52            push    edx                              ; |hKey => 88
  0040545D  |.  FF15 0C904000 call    dword ptr [<&ADVAPI32.RegSetValu>; \RegSetValueExA
  00405463  |.  A1 20B74000   mov     eax, dword ptr [40B720]
  00405468  |.  50            push    eax                              ; /hKey => 00000088 (window)
  00405469  |.  FF15 00904000 call    dword ptr [<&ADVAPI32.RegCloseKe>; \RegCloseKey
  0040546F  |.  8BC6          mov     eax, esi
  00405471  |.  5E            pop     esi
  00405472  \.  C3            retn
6、为了一劳永逸的找到注册算法,决定不再在填写注册码的对话框的地方下功夫,因为有些程序是在填写的时候只
   做验证部分,在启动的时候做全部验证。
   这次用OD载入脱壳后的程序,先在RegQueryValueExA上下断点。
   当参数ValueName的值为userCode时停下(可以对RegQueryValueExA下条件断点),连续按Ctrl+F9《按3次》直到程序返回到
   00402460  |.  68 2000CC00   push    0CC0020                          ; /ROP = SRCCOPY
  00402465  |.  6A 00         push    0                                ; |YSrc = 0
  00402467  |.  6A 00         push    0                                ; |XSrc = 0
  00402469  |.  8B55 DC       mov     edx, dword ptr [ebp-24]          ; |
  0040246C  |.  52            push    edx                              ; |hSrcDC
  0040246D  |.  8B45 F0       mov     eax, dword ptr [ebp-10]          ; |
  00402470  |.  50            push    eax                              ; |Height
  00402471  |.  8B4D EC       mov     ecx, dword ptr [ebp-14]          ; |
  00402474  |.  51            push    ecx                              ; |Width
  00402475  |.  8B55 08       mov     edx, dword ptr [ebp+8]           ; |
  00402478  |.  8B42 04       mov     eax, dword ptr [edx+4]           ; |
  0040247B  |.  50            push    eax                              ; |YDest
  0040247C  |.  8B4D 08       mov     ecx, dword ptr [ebp+8]           ; |
  0040247F  |.  8B11          mov     edx, dword ptr [ecx]             ; |
  00402481  |.  52            push    edx                              ; |XDest
  00402482  |.  8B45 E0       mov     eax, dword ptr [ebp-20]          ; |
  00402485  |.  50            push    eax                              ; |hDestDC
  00402486  |.  FF15 28904000 call    dword ptr [<&GDI32.BitBlt>]      ; \BitBlt
  0040248C  |.  E8 AF2B0000   call    00405040                         ;  判断是否注册 
  ;连续按CTRL+F9程序回到这里,感觉这里可能就要做最后的跳转了 
  00402491  |.  EB 01         jmp     short 00402494                   ;    <<==
  00402493  |   B8            db      B8
  00402494  |>  0AC0          or      al, al
  ;其实这段函数要被执行3次,如果这里只是改标志寄存器的位置,然后step by来查看,在后面执行sleep后
  ;会再次跟进Window消息处理过程中,如果你在此处没有下断点,按F9执行后,程序还是报注册失败。
  00402496  |.  74 02         je      short 0040249A                   ;  爆破点
  00402498  |.  EB 09         jmp     short 004024A3
  0040249A  |>  C745 D0 D4A04>mov     dword ptr [ebp-30], 0040A0D4     ;  unregistered
  004024A1  |.  EB 61         jmp     short 00402504
  004024A3  |>  BF 4CA04000   mov     edi, 0040A04C                    ;  registered to
  004024A8  |.  BA 20BD4000   mov     edx, 0040BD20                    ;  this  copy  of  apis32  is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
  004024AD  |.  83C9 FF       or      ecx, FFFFFFFF
  004024B0  |.  33C0          xor     eax, eax
  004024B2  |.  F2:AE         repne   scas byte ptr es:[edi]
  004024B4  |.  F7D1          not     ecx
  004024B6  |.  2BF9          sub     edi, ecx
  004024B8  |.  8BF7          mov     esi, edi
  004024BA  |.  8BC1          mov     eax, ecx
  004024BC  |.  8BFA          mov     edi, edx
  004024BE  |.  C1E9 02       shr     ecx, 2
  004024C1  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  004024C3  |.  8BC8          mov     ecx, eax
  004024C5  |.  83E1 03       and     ecx, 3
  004024C8  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  004024CA  |.  BF C0C34000   mov     edi, offset <用户名>                ;  a
  004024CF  |.  BA 20BD4000   mov     edx, 0040BD20                    ;  this  copy  of  apis32  is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
  004024D4  |.  83C9 FF       or      ecx, FFFFFFFF
  004024D7  |.  33C0          xor     eax, eax
  004024D9  |.  F2:AE         repne   scas byte ptr es:[edi]
  004024DB  |.  F7D1          not     ecx
  004024DD  |.  2BF9          sub     edi, ecx
  004024DF  |.  8BF7          mov     esi, edi
  004024E1  |.  8BD9          mov     ebx, ecx
  004024E3  |.  8BFA          mov     edi, edx
  004024E5  |.  83C9 FF       or      ecx, FFFFFFFF
  004024E8  |.  33C0          xor     eax, eax
  004024EA  |.  F2:AE         repne   scas byte ptr es:[edi]
  004024EC  |.  83C7 FF       add     edi, -1
  004024EF  |.  8BCB          mov     ecx, ebx
  004024F1  |.  C1E9 02       shr     ecx, 2
  004024F4  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  004024F6  |.  8BCB          mov     ecx, ebx
  004024F8  |.  83E1 03       and     ecx, 3
  004024FB  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  004024FD  |.  C745 D0 20BD4>mov     dword ptr [ebp-30], 0040BD20     ;  this  copy  of  apis32  is\n\nu n r e g i s t e r e d\n\nregistration info can be found in file reginfo.txt
  00402504  |>  6A 00         push    0                                ; /Alignment = TA_LEFT|TA_TOP
  00402506  |.  8B45 E0       mov     eax, dword ptr [ebp-20]          ; |
  00402509  |.  50            push    eax                              ; |hDC
  0040250A  |.  FF15 30904000 call    dword ptr [<&GDI32.SetTextAlign>>; \SetTextAlign

7、先在我们看看00405040函数,来找到注册算法。
  00405040  /$  51            push    ecx
  00405041  |.  53            push    ebx
  00405042  |.  55            push    ebp
  00405043  |.  56            push    esi
  00405044  |.  57            push    edi
  00405045  |.  6A 50         push    50
  00405047  |.  68 40B74000   push    offset <序列号>                     ;  b
  0040504C  |.  68 88A64000   push    0040A688                         ;  userkey
  00405051  |.  E8 1A030000   call    00405370
  00405056  |.  83C4 0C       add     esp, 0C
  00405059  |.  83F8 10       cmp     eax, 10                          ;  注册码长度为>=16
  0040505C  |.  7D 08         jge     short 00405066
  0040505E  |.  33C0          xor     eax, eax
  00405060  |.  5F            pop     edi
  00405061  |.  5E            pop     esi
  00405062  |.  5D            pop     ebp
  00405063  |.  5B            pop     ebx
  00405064  |.  59            pop     ecx
  00405065  |.  C3            retn
  00405066  |>  6A 2F         push    2F
  00405068  |.  68 C0C34000   push    offset <用户名>                     ;  a
  0040506D  |.  68 78A64000   push    0040A678                         ;  username
  00405072  |.  E8 F9020000   call    00405370
  00405077  |.  83C4 0C       add     esp, 0C
  0040507A  |.  83F8 05       cmp     eax, 5                           ;  用户名长度>=5
  0040507D  |.  7D 08         jge     short 00405087
  0040507F  |.  33C0          xor     eax, eax
  00405081  |.  5F            pop     edi
  00405082  |.  5E            pop     esi
  00405083  |.  5D            pop     ebp
  00405084  |.  5B            pop     ebx
  00405085  |.  59            pop     ecx
  00405086  |.  C3            retn
  ;把注册码拷贝到一个另一个全局缓冲区中,我们称之为code_buf2,原来的称之为code_buf1
  00405087  |>  BF 40B74000   mov     edi, offset <序列号>                ;  b
  0040508C  |.  83C9 FF       or      ecx, FFFFFFFF
  0040508F  |.  33C0          xor     eax, eax
  00405091  |.  C605 51B74000>mov     byte ptr [40B751], 0
  00405098  |.  F2:AE         repne   scas byte ptr es:[edi]
  0040509A  |.  F7D1          not     ecx
  0040509C  |.  2BF9          sub     edi, ecx
  0040509E  |.  8BC1          mov     eax, ecx
  004050A0  |.  8BF7          mov     esi, edi
  004050A2  |.  BF 54B74000   mov     edi, 0040B754
  004050A7  |.  C1E9 02       shr     ecx, 2
  004050AA  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  004050AC  |.  8BC8          mov     ecx, eax
  004050AE  |.  33C0          xor     eax, eax
  004050B0  |.  83E1 03       and     ecx, 3
  004050B3  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  ;删除code_buf2中第9个字母
  004050B5  |.  BF 49B74000   mov     edi, 0040B749                    ;  ASCII "AE7201C"
  004050BA  |.  83C9 FF       or      ecx, FFFFFFFF
  004050BD  |.  F2:AE         repne   scas byte ptr es:[edi]
  004050BF  |.  F7D1          not     ecx
  004050C1  |.  2BF9          sub     edi, ecx
  004050C3  |.  8BD1          mov     edx, ecx
  004050C5  |.  8BF7          mov     esi, edi
  004050C7  |.  BF 5CB74000   mov     edi, 0040B75C
  004050CC  |.  C1E9 02       shr     ecx, 2
  004050CF  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  004050D1  |.  8BCA          mov     ecx, edx
  004050D3  |.  83E1 03       and     ecx, 3
  004050D6  |.  32DB          xor     bl, bl
  004050D8  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  
  
  004050DA  |.  BE 41B74000   mov     esi, 0040B741                   ;code_buf1
  004050DF  |.  BF 54B74000   mov     edi, 0040B754                   ;code_buf2
  ;要求注册码去掉第9个字母后的字符为大写字母或数字,然后两个一起当一个16进制字节来处理,
  ;处理结果为8个字节,依次保存在code_buf1中
  004050E4  |>  57            /push    edi                             ;  for(int i=0; i<8; i++) {esi[i] = strToex[edi] ^ (50h + i);}
  004050E5  |.  E8 E6010000   |call    <StrtoHex>
  004050EA  |.  8ACB          |mov     cl, bl
  004050EC  |.  83C4 04       |add     esp, 4
  004050EF  |.  80C1 50       |add     cl, 50
  004050F2  |.  83C7 02       |add     edi, 2
  004050F5  |.  32C1          |xor     al, cl
  004050F7  |.  FEC3          |inc     bl
  004050F9  |.  8846 FF       |mov     byte ptr [esi-1], al
  004050FC  |.  C606 00       |mov     byte ptr [esi], 0
  004050FF  |.  46            |inc     esi
  00405100  |.  80FB 08       |cmp     bl, 8
  00405103  |.^ 72 DF         \jb      short 004050E4
  
  00405105  |.  68 54B74000   push    0040B754                            ;  code_buf2
  0040510A  |.  68 40B74000   push    offset <序列号>                     ;  b
  0040510F  |.  E8 EC010000   call    00405300                            ;另一个处理序列号的函数,我们后面载分析
  ; 把用户名保存复制到一个全局缓冲区中,我们称之为name_buf2, 如果用户名长度<8,则两个用户名接起来
  ; 取前8个字母
  00405114  |.  BF C0C34000   mov     edi, offset <用户名>                ;  a
  00405119  |.  83C9 FF       or      ecx, FFFFFFFF
  0040511C  |.  33C0          xor     eax, eax
  0040511E  |.  83C4 08       add     esp, 8
  00405121  |.  F2:AE         repne   scas byte ptr es:[edi]
  00405123  |.  F7D1          not     ecx
  00405125  |.  2BF9          sub     edi, ecx
  00405127  |.  33ED          xor     ebp, ebp
  00405129  |.  8BD1          mov     edx, ecx
  0040512B  |.  8BF7          mov     esi, edi
  0040512D  |.  BF 5EB74000   mov     edi, 0040B75E                    ;  ASCII "qiufenghan"
  00405132  |.  C1E9 02       shr     ecx, 2
  00405135  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  00405137  |.  8BCA          mov     ecx, edx
  00405139  |.  83E1 03       and     ecx, 3
  0040513C  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  0040513E  |.  BF C0C34000   mov     edi, offset <用户名>                ;  a
  00405143  |.  83C9 FF       or      ecx, FFFFFFFF
  00405146  |.  F2:AE         repne   scas byte ptr es:[edi]
  00405148  |.  F7D1          not     ecx
  0040514A  |.  49            dec     ecx
  0040514B  |.  80F9 08       cmp     cl, 8
  0040514E  |.  884C24 10     mov     byte ptr [esp+10], cl
  00405152  |.  73 30         jnb     short 00405184                   ;  用户名长度是否等于8
  00405154  |.  8B5424 10     mov     edx, dword ptr [esp+10]
  00405158  |.  BF C0C34000   mov     edi, offset <用户名>                ;  a
  0040515D  |.  81E2 FF000000 and     edx, 0FF
  00405163  |.  83C9 FF       or      ecx, FFFFFFFF
  00405166  |.  81C2 5EB74000 add     edx, 0040B75E                    ;  ASCII "qiufenghan"
  0040516C  |.  F2:AE         repne   scas byte ptr es:[edi]
  0040516E  |.  F7D1          not     ecx
  00405170  |.  2BF9          sub     edi, ecx
  00405172  |.  8BC1          mov     eax, ecx
  00405174  |.  8BF7          mov     esi, edi
  00405176  |.  8BFA          mov     edi, edx
  00405178  |.  C1E9 02       shr     ecx, 2
  0040517B  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>
  0040517D  |.  8BC8          mov     ecx, eax
  0040517F  |.  83E1 03       and     ecx, 3
  00405182  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  如果用户名长读小于8,则连接用户名。
  00405184  |>  C605 66B74000>mov     byte ptr [40B766], 0             ;  取用户名的前8个字母
  
  ;for(i=0; i<8; i++)
  ;{
  ;  if(code_buf2[i] >= 0x20)
  ;     ebx += code_buf2[i] ^ name_buf2[i];   //route1
  ;  else
  ;     ebx += code_buf2[i] | name_buf2[i];   //route2
  ;}
  ;  后面我们知道,要ebx等于0才算注册成功。ebx的值为8个字节的和,不可能溢出
  ;  所以只能每个加数为0才可以
  ;  因为用户名中不可能有为0的字节,所以只要进入路径2中的值不可能为0,
  ;  所以循环只能完全执行路径一,因为只有两个相同的数异或为0,所以用户名中只能有小写
  ; 字母(字节值大于20h的字母)。其实就是说此时code_buf2的值就是用户名
  0040518B  |.  B9 54B74000   mov     ecx, 0040B754                   ;code_buf2
  00405190  |.  BE 08000000   mov     esi, 8
  00405195  |>  8A01          /mov     al, byte ptr [ecx]
  00405197  |.  3C 20         |cmp     al, 20
  00405199  |.  73 0E         |jnb     short 004051A9
  0040519B  |.  33D2          |xor     edx, edx
  0040519D  |.  25 FF000000   |and     eax, 0FF
  004051A2  |.  8A51 0A       |mov     dl, byte ptr [ecx+A]
  004051A5  |.  0BD0          |or      edx, eax
  004051A7  |.  EB 0C         |jmp     short 004051B5
  004051A9  |>  33D2          |xor     edx, edx
  004051AB  |.  25 FF000000   |and     eax, 0FF
  004051B0  |.  8A51 0A       |mov     dl, byte ptr [ecx+A]
  004051B3  |.  33D0          |xor     edx, eax
  004051B5  |>  03EA          |add     ebp, edx
  004051B7  |.  41            |inc     ecx
  004051B8  |.  4E            |dec     esi
  004051B9  |.^ 75 DA         \jnz     short 00405195
  
  ;如果ebp为0,则认为注册成功
  004051BB  |.  33C0          xor     eax, eax
  004051BD  |.  5F            pop     edi
  004051BE  |.  85ED          test    ebp, ebp
  004051C0  |.  5E            pop     esi
  004051C1  |.  5D            pop     ebp
  004051C2      0F94C0        sete    al
  004051C5  |.  5B            pop     ebx
  004051C6  |.  59            pop     ecx
  004051C7  \.  C3            retn
8、先在我们看看函数00405300做什么事
  00405300  /$  53            push    ebx
  00405301  |.  55            push    ebp
  00405302  |.  8B6C24 10     mov     ebp, dword ptr [esp+10]          ;  arg2
  00405306  |.  56            push    esi
  00405307  |.  57            push    edi
  00405308  |.  8B7C24 14     mov     edi, dword ptr [esp+14]          ;  arg1
  0040530C  |.  33C9          xor     ecx, ecx
  0040530E  |.  2BFD          sub     edi, ebp
  00405310  |.  897C24 18     mov     dword ptr [esp+18], edi          ;  arg2
  00405314  |.  EB 04         jmp     short 0040531A
  
  00405316  |>  8B7C24 18     /mov     edi, dword ptr [esp+18]
  0040531A  |>  8D3429         lea     esi, dword ptr [ecx+ebp]
  0040531D  |.  33D2          |xor     edx, edx
  0040531F  |.  B8 01000000   |mov     eax, 1
  00405324  |.  C74424 14 070>|mov     dword ptr [esp+14], 7           ;  arg1
  0040532C  |.  8A1437        |mov     dl, byte ptr [edi+esi]
  0040532F  |.  8BFA          |mov     edi, edx
  ;求一个数的7次方%0x8899的结果
  00405331  |>  8BD7          |/mov     edx, edi
  00405333  |.  0FAFC2        ||imul    eax, edx
  00405336  |.  3D 99880000   ||cmp     eax, 8899
  0040533B  |.  7E 0A         ||jle     short 00405347
  0040533D  |.  99            ||cdq
  0040533E  |.  BB 99880000   ||mov     ebx, 8899
  00405343  |.  F7FB          ||idiv    ebx
  00405345  |.  8BC2          ||mov     eax, edx
  00405347  |>  8B5424 14     ||mov     edx, dword ptr [esp+14]
  0040534B  |.  4A            ||dec     edx
  0040534C  |.  895424 14     ||mov     dword ptr [esp+14], edx
  00405350  |.^ 75 DF         |\jnz     short 00405331
  
  00405352  |.  99            |cdq
  00405353  |.  BF BB000000   |mov     edi, 0BB
  00405358  |.  F7FF          |idiv    edi
  0040535A  |.  41            |inc     ecx
  0040535B  |.  83F9 08       |cmp     ecx, 8
  0040535E  |.  8816          |mov     byte ptr [esi], dl
  00405360  |.  C60429 00     |mov     byte ptr [ecx+ebp], 0
  00405364  |.^ 7C B0         \jl      short 00405316
  00405366  |.  5F            pop     edi
  00405367  |.  5E            pop     esi
  00405368  |.  5D            pop     ebp
  00405369  |.  5B            pop     ebx
  0040536A  \.  C3            retn
  该函数实际是把参数1中的每个字节的7次方模0x8899的结果再模0xbb的结果保存在参数2中相应的位置。
9、我们再来看看程序中的StrToHex的实现
  004052D0 >/$  8B4C24 04     mov     ecx, dword ptr [esp+4]
  004052D4  |.  8A01          mov     al, byte ptr [ecx]
  004052D6  |.  3C 39         cmp     al, 39
  004052D8  |.  7E 04         jle     short 004052DE
  004052DA  |.  04 C9         add     al, 0C9
  004052DC  |.  EB 02         jmp     short 004052E0
  004052DE  |>  04 D0         add     al, 0D0
  004052E0  |>  8A49 01       mov     cl, byte ptr [ecx+1]
  004052E3  |.  80F9 39       cmp     cl, 39
  004052E6  |.  7E 09         jle     short 004052F1
  004052E8  |.  C0E0 04       shl     al, 4
  004052EB  |.  80E9 37       sub     cl, 37
  004052EE  |.  0AC1          or      al, cl
  004052F0  |.  C3            retn
  004052F1  |>  C0E0 04       shl     al, 4
  004052F4  |.  80E9 30       sub     cl, 30
  004052F7  |.  0AC1          or      al, cl
  004052F9  \.  C3            retn
  可见这个函数功能并不完善,它要求str只能是数字或大写字母
10、先在注册算法清楚了
  a、用户名需要大于等于5各字节,序列号为17个以上字节
  b、用户名小于8个字符时,需要连接自己组成长于8个字符的串,用户名只使用前8个字符。我们称为name。
  c、注册码的第9个字符将被抛弃。
  d、把注册码当作16进制数串恢复为8个字节值,多余的抛弃。我们称为code,
  e、(pow(code[i] ^ (0x50 + i), 7) % 0x8899 ) % 0xBB == name[i]
11、一个注册机参考实现如下:
  int APIs32KeyGen(char* name)
  {
    int len = strlen(name);
    if(len< 5)
    {
      printf("用户名长度必须大于4.\n");
      return 1;
    }
  
  
    char* lName = new char[len * 2 + 1];
    if(lName == NULL)
    {
      printf("内存不足.\n");
      return 1;
    }
  
    //TODO check是否全为小写字母
  
    ::strcpy(lName, name);
    ::strcpy(lName + len, name);
    lName[len * 2] = '\0';
  
    unsigned char res[8];
    bool find = true;
    for(int n=0; n <8; n++)
    {
      find = false;
      for(unsigned char i=2; i<=0xFF; i++)
      {
        unsigned int k = 1;
        for(int m=0; m<7; m++)
        {
          k *= i;
          if(k > 0x8899)
          {
            k %= 0x8899;
          }
        }
        if((k % 0xBB) == lName[n])
        {
          res[n] = i ^ (0x50 + n);
          find = true;
          break;
        }
      }
  
      if(find == false)
      {
        break;
      }
  
    }
  
    if(find)
    {
      printf("用户名%s的注册码为:", name);
      char buf[18];
      ::sprintf(buf, "%02x%02x%02x%02x=%02x%02x%02x%02x", res[0], res[1], res[2], res[3], res[4], res[5], res[6], res[7]); 
      ::strupr(buf);
      printf("%s", buf);
    }
    else
    {
      printf("未能为用户名%s找到注册码", name);
    }
    printf("\n");
  
    delete [] lName;
    return 0;
  }

12、终于完成了。
   

--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年01月07日 下午 07:36:12