【文章标题】: Mister PiX 算法的简单分析
【文章作者】: qifeon
【软件名称】: Mister PiX 2.10
【下载地址】: 自己搜索下载
【保护方式】: 注册码
【使用工具】: od,peid
【操作平台】: winxp sp2
【软件介绍】: 可以在 newsgroup 里面寻找指定的图片。
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  一、分析过程
  
  1、Peid查壳,显示无壳。编程语言为Borland Delphi 4.0 - 5.0。
  
  2、试运行,输入“qifeon,12345”,有错误提示“”。
  
  3、od载入,查找字符串,没找到。Delphi程序,找到关键点方法很多,如按钮事件代码,F12暂停法等。这里我们使用下API函数下断的方法。
  
  既然有错误对话框,可以考虑使用MessageBoxExA或MessageBoxA,具体用哪个,需要测试,try and error。
  
  *****************************************************************************************************************************
  
  ctrl+N,找到名称位于 MrPix, 条目 309
   地址=0053E644
   区段=.idata
   类型=输入    (已知)
   名称=user32.MessageBoxExA
  
  ******************************************************************************************************************************
  
  右键“在输入函数上下断”,然后F9运行,出现异常,SHIFT+F9几次,出现注册框,输入“qifeon,12345”,点确定
  
  程序断下在系统领空,看堆栈
  
  *******************************************************************************************************************************
  
  0012D4A4   00F31EC8  ASCII "Warning"
  0012D4A8   005292EA  /CALL 到 MessageBoxExA 来自 MrPix.005292E5
  0012D4AC   000D0540  |hOwner = 000D0540 ('Mister PiX',class='TApplication')
  0012D4B0   00F34C4C  |Text = "Username or Private Key don't match.",CR,"Please check your entry."
  0012D4B4   00F31EC8  |Title = "Warning"
  0012D4B8   00000030  |Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
  0012D4BC   00120409  \LanguageID = 120409 (LANG_ENGLISH)
  0012D4C0   0012D5EC  指向下一个 SEH 记录的指针
  0012D4C4   0052930A  SE处理程序
  
  **********************************************************************************************************************************
  
  “Alt+F9”返回,点错误对话框后程序返回到自己代码内
  
  ***********************************************************************************************************************************
  005292E5  |.  E8 9EE1EDFF   call    <jmp.&user32.MessageBoxExA>      ; \MessageBoxExA
  005292EA  |.  8BD8          mov     ebx, eax                           返回处
  005292EC  |.  33C0          xor     eax, eax
  005292EE  |.  5A            pop     edx
  005292EF  |.  59            pop     ecx
  005292F0  |.  59            pop     ecx
  005292F1  |.  64:8910       mov     dword ptr fs:[eax], edx
  
  **************************************************************************************************************************************
  
  向上看,没有跳转可以跳过此对话框。还要继续回溯关键处。可以找到段首下断回溯,这里使用一种快捷些的方法。
  
  向下翻堆栈,找到
  
  0012D5CC  |00F34C4C  ASCII "Username or Private Key don't match.",CR,"Please check your entry."
  0012D5D0  |0012D601
  0012D5D4  |00F31EC8  ASCII "Warning"
  0012D5D8  |0004D87C
  0012D5DC  |00F34C4C  ASCII "Username or Private Key don't match.",CR,"Please check your entry."
  0012D5E0  |0012D704
  0012D5E4  |00514B6E  返回到 MrPix.00514B6E 来自 MrPix.00529134
  0012D5E8  |00000000
  
  ******************************************************************************************************************************************
  
  0左键点击012D5E4  处,右键“反汇编窗口跟随”来到
  
  ********************************************************************************************************************************************
  
  

代码:
00514A54  /.  55            push    ebp                             段首
  00514A55  |.  8BEC          mov     ebp, esp
  00514A57  |.  81C4 F8FEFFFF add     esp, -108
  00514A5D  |.  53            push    ebx
  00514A5E  |.  33C9          xor     ecx, ecx
  00514A60  |.  898D F8FEFFFF mov     dword ptr [ebp-108], ecx
  00514A66  |.  894D FC       mov     dword ptr [ebp-4], ecx
  00514A69  |.  8BD8          mov     ebx, eax
  00514A6B  |.  33C0          xor     eax, eax
  00514A6D  |.  55            push    ebp
  00514A6E  |.  68 8F4B5100   push    00514B8F
  00514A73  |.  64:FF30       push    dword ptr fs:[eax]
  00514A76  |.  64:8920       mov     dword ptr fs:[eax], esp
  00514A79  |.  8D55 FC       lea     edx, dword ptr [ebp-4]
  00514A7C  |.  8B83 EC020000 mov     eax, dword ptr [ebx+2EC]
  00514A82  |.  E8 D908F2FF   call    00435360
  00514A87  |.  8B55 FC       mov     edx, dword ptr [ebp-4]           ;  用户名
  00514A8A  |.  A1 388D5300   mov     eax, dword ptr [538D38]
  00514A8F  |.  E8 00F2EEFF   call    00403C94
  00514A94  |.  8D55 FC       lea     edx, dword ptr [ebp-4]
  00514A97  |.  8B83 F0020000 mov     eax, dword ptr [ebx+2F0]
  00514A9D  |.  E8 BE08F2FF   call    00435360
  00514AA2  |.  8B45 FC       mov     eax, dword ptr [ebp-4]           ;  试炼码
  00514AA5  |.  33D2          xor     edx, edx
  00514AA7  |.  E8 8C41EFFF   call    00408C38                         ;  试炼码字符串转为整数保存在eax
  00514AAC  |.  8B15 248F5300 mov     edx, dword ptr [538F24]          ;  MrPix.0053D728
  00514AB2  |.  8902          mov     dword ptr [edx], eax             ;  eax值传到edx内指向的地址内
  00514AB4  |.  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]
  00514ABA  |.  8B15 388D5300 mov     edx, dword ptr [538D38]          ;  MrPix.0053D724
  00514AC0  |.  8B12          mov     edx, dword ptr [edx]             ;  用户名
  00514AC2  |.  B9 FF000000   mov     ecx, 0FF                         ;  0FFh即十进制256
  00514AC7  |.  E8 CCF3EEFF   call    00403E98                         ;  取用户名长度,如果超过256位,按256位计算
  00514ACC  |.  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]
  00514AD2  |.  8B15 248F5300 mov     edx, dword ptr [538F24]          ;  MrPix.0053D728
  00514AD8  |.  66:8B12       mov     dx, word ptr [edx]               ;  试炼码转换的整数值放入dx
  00514ADB  |.  E8 4061FFFF   call    0050AC20                         ;  关键CALL
  00514AE0  |.  84C0          test    al, al                           ;  标志位: al=1则注册成功, al=0则失败
  00514AE2  |.  74 46         je      short 00514B2A                   ;  关键跳转
  00514AE4  |.  6A 00         push    0
  00514AE6  |.  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]
  00514AEC  |.  50            push    eax
  00514AED  |.  A1 CC8D5300   mov     eax, dword ptr [538DCC]
  00514AF2  |.  8B00          mov     eax, dword ptr [eax]
  00514AF4  |.  B9 9C4B5100   mov     ecx, 00514B9C                    ;  :mister pix wurde erfolgreich freigeschaltet.\nvielen dank!
  00514AF9  |.  BA D84B5100   mov     edx, 00514BD8                    ;  ASCII 08,"UnlockOK"
  00514AFE  |.  E8 B9720100   call    0052BDBC
  00514B03  |.  8D95 FCFEFFFF lea     edx, dword ptr [ebp-104]
  00514B09  |.  8D85 F8FEFFFF lea     eax, dword ptr [ebp-108]
  00514B0F  |.  E8 4CF3EEFF   call    00403E60
  00514B14  |.  8B85 F8FEFFFF mov     eax, dword ptr [ebp-108]
  00514B1A  |.  66:8B0D E44B5>mov     cx, word ptr [514BE4]
  00514B21  |.  B2 02         mov     dl, 2
  00514B23  |.  E8 0C460100   call    00529134
  00514B28  |.  EB 44         jmp     short 00514B6E
  00514B2A  |>  6A 00         push    0
  00514B2C  |.  8D85 FCFEFFFF lea     eax, dword ptr [ebp-104]
  00514B32  |.  50            push    eax
  00514B33  |.  A1 CC8D5300   mov     eax, dword ptr [538DCC]
  00514B38  |.  8B00          mov     eax, dword ptr [eax]
  00514B3A  |.  B9 E84B5100   mov     ecx, 00514BE8                    ;  ASCII "PBenutzername oder Private Key stimmen nicht.\nBitte erpren Sie Ihre Eingabe."
  00514B3F  |.  BA 3C4C5100   mov     edx, 00514C3C                    ;  \nunlockfail
  00514B44  |.  E8 73720100   call    0052BDBC
  00514B49  |.  8D95 FCFEFFFF lea     edx, dword ptr [ebp-104]
  00514B4F  |.  8D85 F8FEFFFF lea     eax, dword ptr [ebp-108]
  00514B55  |.  E8 06F3EEFF   call    00403E60
  00514B5A  |.  8B85 F8FEFFFF mov     eax, dword ptr [ebp-108]
  00514B60  |.  66:8B0D E44B5>mov     cx, word ptr [514BE4]
  00514B67  |.  33D2          xor     edx, edx
  00514B69  |.  E8 C6450100   call    00529134
  00514B6E  |>  33C0          xor     eax, eax                         ;  返回处
  00514B70  |.  5A            pop     edx
  00514B71  |.  59            pop     ecx
  00514B72  |.  59            pop     ecx
  00514B73  |.  64:8910       mov     dword ptr fs:[eax], edx
  00514B76  |.  68 964B5100   push    00514B96
  00514B7B  |>  8D85 F8FEFFFF lea     eax, dword ptr [ebp-108]
  00514B81  |.  E8 BAF0EEFF   call    00403C40
  00514B86  |.  8D45 FC       lea     eax, dword ptr [ebp-4]
  00514B89  |.  E8 B2F0EEFF   call    00403C40
  00514B8E  \.  C3            retn
  
  **************************************************************************************************************************************************************
  显然,这里就是关键了。回溯的方法常常在调试里用到,段首下断就可以反复调试了。
  
  段首下断后运行中断后,单步
  
  00514ADB  处进入   call    0050AC20  
  
  **************************************************************************************************************************************************************** 
  
  0050AC20  /$  53            push    ebx
  0050AC21  |.  56            push    esi
  0050AC22  |.  57            push    edi
  0050AC23  |.  83C4 E8       add     esp, -18
  0050AC26  |.  8BF0          mov     esi, eax                         ;  用户名地址和长度传入esi
  0050AC28  |.  8D3C24        lea     edi, dword ptr [esp]
  0050AC2B  |.  33C9          xor     ecx, ecx
  0050AC2D  |.  8A0E          mov     cl, byte ptr [esi]               ;  用户名长度传入cl
  0050AC2F  |.  80F9 14       cmp     cl, 14                           ;  比较用户名长度是否小于20位?
  0050AC32  |.  72 02         jb      short 0050AC36                   ;  小于或等于按实际长度计算
  0050AC34  |.  B1 14         mov     cl, 14                           ;  大于20位则只取前20位
  0050AC36  |>  880F          mov     byte ptr [edi], cl               ;  用户名长度传送
  0050AC38  |.  46            inc     esi                              ;  esi增1
  0050AC39  |.  47            inc     edi                              ;  edi增1
  0050AC3A  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  用户名传送到edi指向地址内
  0050AC3C  |.  8BDA          mov     ebx, edx
  0050AC3E  |.  E8 D1FFFFFF   call    0050AC14                         ;  生成注册框内显示的pubkey,我们直接利用,算法此处不探讨。
  0050AC43  |.  8BD0          mov     edx, eax                         ;  edx=eax=pubkey
  0050AC45  |.  8BC4          mov     eax, esp
  0050AC47  |.  E8 10000000   call    0050AC5C                         ;  算法CALL
  0050AC4C  |.  66:3BD8       cmp     bx, ax                           ;  真码与假码相比较
  0050AC4F  |.  0F94C0        sete    al                               ;  相等则置al=1,否则为0
  0050AC52  |.  83C4 18       add     esp, 18
  0050AC55  |.  5F            pop     edi
  0050AC56  |.  5E            pop     esi
  0050AC57  |.  5B            pop     ebx
  0050AC58  \.  C3            retn
  
  *********************************************************************************************************************************
  
  单步,0050AC47  处  进入   call    0050AC5C 
  
  ***********************************************************************************************************************************
  
  0050AC5C  /$  53            push    ebx
  0050AC5D  |.  56            push    esi
  0050AC5E  |.  57            push    edi
  0050AC5F  |.  83C4 E8       add     esp, -18
  0050AC62  |.  8BF0          mov     esi, eax                         ;  用户名
  0050AC64  |.  8D3C24        lea     edi, dword ptr [esp]
  0050AC67  |.  33C9          xor     ecx, ecx
  0050AC69  |.  8A0E          mov     cl, byte ptr [esi]
  0050AC6B  |.  80F9 14       cmp     cl, 14
  0050AC6E  |.  72 02         jb      short 0050AC72
  0050AC70  |.  B1 14         mov     cl, 14
  0050AC72  |>  880F          mov     byte ptr [edi], cl
  0050AC74  |.  46            inc     esi
  0050AC75  |.  47            inc     edi
  0050AC76  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  0050AC78  |.  8BDA          mov     ebx, edx                         ;  ebx=edx=pubkey
  0050AC7A  |.  8BC4          mov     eax, esp                         ;  用户名及长度地址传入eax
  0050AC7C  |.  E8 13FFFFFF   call    0050AB94                         ;  算法CALL
  0050AC81  |.  66:81F3 82DE  xor     bx, 0DE82                        ;  bx= bx xor 0DE82h
  0050AC86  |.  66:33C3       xor     ax, bx                           ;  ax=ax xor bx
  0050AC89  |.  83C4 18       add     esp, 18
  0050AC8C  |.  5F            pop     edi
  0050AC8D  |.  5E            pop     esi
  0050AC8E  |.  5B            pop     ebx
  0050AC8F  \.  C3            retn
  
  **********************************************************************************************************************
  
  0050AC7C处进入call    0050AB94 
  
  ************************************************************************************************************************
  
  0050AB94  /$  53            push    ebx
  0050AB95  |.  56            push    esi
  0050AB96  |.  57            push    edi
  0050AB97  |.  83C4 D0       add     esp, -30
  0050AB9A  |.  8BF0          mov     esi, eax
  0050AB9C  |.  8D3C24        lea     edi, dword ptr [esp]
  0050AB9F  |.  33C9          xor     ecx, ecx
  0050ABA1  |.  8A0E          mov     cl, byte ptr [esi]
  0050ABA3  |.  80F9 14       cmp     cl, 14
  0050ABA6  |.  72 02         jb      short 0050ABAA
  0050ABA8  |.  B1 14         mov     cl, 14
  0050ABAA  |>  880F          mov     byte ptr [edi], cl
  0050ABAC  |.  46            inc     esi
  0050ABAD  |.  47            inc     edi
  0050ABAE  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr>
  0050ABB0  |.  8D5424 18     lea     edx, dword ptr [esp+18]
  0050ABB4  |.  8BC4          mov     eax, esp
  0050ABB6  |.  E8 91FEFFFF   call    0050AA4C                         ;  用户名长度小于4,则后面用'0'补充为4位
  0050ABBB  |.  8D5424 18     lea     edx, dword ptr [esp+18]
  0050ABBF  |.  8BC4          mov     eax, esp
  0050ABC1  |.  B1 14         mov     cl, 14
  0050ABC3  |.  E8 847FEFFF   call    00402B4C
  0050ABC8  |.  66:BE 0100    mov     si, 1                            ;  si=1
  0050ABCC  |.  33DB          xor     ebx, ebx
  0050ABCE  |.  8A1C24        mov     bl, byte ptr [esp]               ;  bl为用户名长度
  0050ABD1  |.  85DB          test    ebx, ebx                         ;  用户名是否为空?
  0050ABD3  |.  76 25         jbe     short 0050ABFA
  0050ABD5  |.  BF 01000000   mov     edi, 1                           ;  edi=1
  0050ABDA  |.  8D4C24 01     lea     ecx, dword ptr [esp+1]           ;  用户名地址传入ecx
  0050ABDE  |>  0FB7C6        /movzx   eax, si                         ;  eax=si,初始值为1
  0050ABE1  |.  40            |inc     eax                             ;  eax增1
  0050ABE2  |.  33D2          |xor     edx, edx                        ;  edx清零
  0050ABE4  |.  8A11          |mov     dl, byte ptr [ecx]              ;  用户名逐位送入dl
  0050ABE6  |.  F7EA          |imul    edx                             ;  eax=eax * edx
  0050ABE8  |.  F7EF          |imul    edi                             ;  eax=eax * edi
  0050ABEA  |.  BE FFFF0000   |mov     esi, 0FFFF                      ;  esi=0FFFFh
  0050ABEF  |.  33D2          |xor     edx, edx                        ;  edx清零
  0050ABF1  |.  F7F6          |div     esi                             ;  eax除以esi,商保存在eax,余数保存在edx
  0050ABF3  |.  8BF2          |mov     esi, edx                        ;  edx值传入esi
  0050ABF5  |.  47            |inc     edi                             ;  edi增1
  0050ABF6  |.  41            |inc     ecx                             ;  ecx增1
  0050ABF7  |.  4B            |dec     ebx                             ;  ebx减1
  0050ABF8  |.^ 75 E4         \jnz     short 0050ABDE                  ;  ebx值不为0则继续循环
  0050ABFA  |>  8BC6          mov     eax, esi                         ;  最后计算值传送入eax
  0050ABFC  |.  83C4 30       add     esp, 30
  0050ABFF  |.  5F            pop     edi
  0050AC00  |.  5E            pop     esi
  0050AC01  |.  5B            pop     ebx
  0050AC02  \.  C3            retn
  
  *****************************************************************************************************************************
  
  二、算法总结
  
       注册码private key 由 public key 及 用户名name经计算而生成,根据用户名name长度,又分为3种情况;
  
  1、用户名长度小于4,则后面用'0'补充为4位,参与计算;
  
   这个限制不明显,跟了几次才看到。容易漏掉。测试了一个国外的注册机。这点就被忽略了,算出来就是错误的了。
  
  2、用户名长度大于20则只取前20位参与计算,后面不参与验证。(用户名长度大于256,按256操作);
  
  3、用户名长度在4-20,则正常计算。
  
  
  **************************************************************************************************************************************
  
  三、C语言注册机代码
  
   偷了点懒,从程序提取部分汇编代码嵌在里面。
  
  
代码:
#include "stdio.h"
  #include "string.h"
  void main()
  {
    static char name[30]={'0','0','0','0'};
    int pubkey,reg,len;
    printf("please enter your name:"); 
    scanf("%s",name);
    printf("please enter your public key:");
    scanf("%d",&pubkey);
    len=strlen(name);
    if (len>=20)
    len=20;
    else if(len<4)
    {name[4]='\0';
      name[len]='0';
    len=4;}
    
      _asm
    {
      
      mov ebx,len
      mov edi,1
      mov si,1
      mov ecx,0      
      n1:
                  movzx   eax, si
                  inc     eax
                  xor     edx, edx
                  mov     dl, byte ptr [name+ecx]
                  imul    edx
                  imul    edi
                  mov     esi, 0xFFFF
                  xor     edx, edx                      
                  div     esi
                  mov     esi, edx
                  nc     edi
                  inc     ecx
                  dec     ebx
                 jnz n1
           xor esi,0xDE82
           xor esi,pubkey
           mov reg,esi
      
      
    }
    
  
    printf("Private key is:%d",reg);
      
  }