WinIMP软件是和WinRAR、WinZIP等类似的一款压缩打包软件,而其独有的.imp格式的压缩率远高于ZIP格式,和RAR也是各有千秋,而它的自解压格式更是我的至爱,时至今日仍然不比其它同类软件逊色。

七年前,小楼大侠曾经写过一篇与它相关的算法文章,可能是受当时的工具所限,却不理想。而dr0大侠倒是丢了个注册机外(感谢你的注册机),从此再无与 WinIMP 注册算法相关的信息了。

这两天无聊,再次把这个软件拖入了OD中,呵呵,机缘巧合,居然给看懂了(也许是受到刚分析ReadBook1.51plus的影响,呵呵),写此文章,留作纪念!也纪念这个优秀的、却被人淡忘的、不再继续开发的软件!


好,我们开始分析,通过错误提示信息“the keys do not match the names...”,由字符串参考方式,我们轻松的来到了这里:
004260DA  |.  68 28CC4400   push    winimp32.0044CC28

顺着它,往上查找,来到了这个call的开始处,F2键下断后,F9键运行软件,然后打开注册窗口,输入一组实验码:

Name: aCaFeeL
Key1: 1234567
Key2: 7654321


然后点击‘OK’按钮,便在OD中断了下来,来到如下位置:

》》》》》》》》
00426013  /$  53            push    ebx                              ; 被断在了这里
00426014  |.  51            push    ecx
00426015  |.  52            push    edx
00426016  |.  56            push    esi
00426017  |.  57            push    edi
00426018  |.  C8 240000     enter   24, 0
0042601C  |.  89C6          mov     esieax
0042601E  |.  68 00010000   push    100                              ; /Count = 100 (256.)
00426023  |.  68 603C4500   push    winimp32.00453C60                ; |Buffer = winimp32.00453C60
00426028  |.  6A 65         push    65                               ; |ControlID = 65 (101.)
0042602A  |.  50            push    eax                              ; |hWnd
0042602B  |.  31DB          xor     ebxebx                         ; |
0042602D  |.  2E:FF15 A0D74>call    dword ptr cs:[<&USER32.GetDlgIte>; \得到注册名
00426034  |.  C745 FC 00000>mov     dword ptr [ebp-4], 0
0042603B  |.  B8 603C4500   mov     eax, winimp32.00453C60           ;  注册名 -> eax
00426040  |.  EB 04         jmp     short winimp32.00426046
00426042  |>  83E3 03       /and     ebx, 3                          ;  ebx = ebx and $3
00426045  |.  40            |inc     eax                             ;  取注册名的下一个字符
00426046  |>  8038 00        cmp     byte ptr [eax], 0               ;  结果是否为空?
00426049  |.  74 1C         |je      short winimp32.00426067         ;  结束检查才跳
0042604B  |.  8038 20       |cmp     byte ptr [eax], 20              ;  是否为空格
0042604E  |.^ 74 F2         |je      short winimp32.00426042         ;  如若是
00426050  |.  8038 2E       |cmp     byte ptr [eax], 2E              ;  是否为符号.
00426053  |.^ 74 ED         |je      short winimp32.00426042         ;  如若是
00426055  |.  0FB638        |movzx   edibyte ptr [eax]             ;  依次取注册名字符码 -> edi
00426058  |.  89DA          |mov     edxebx
0042605A      8A8F 10114500 mov     clbyte ptr [edi+451110]        ;  cl := [edi + 451110]所指码数//从451110开始的一张表
00426060  |.  43            |inc     ebx                             ;  ebx = ebx + 1
00426061  |.  004C2A FC     |add     byte ptr [edx+ebp-4], cl        ;  tempA := tempA + cl;//edx由ebx赋值,注意and 3后的结果
00426065  |.^ EB DB         \jmp     short winimp32.00426042         ;  上面这个结果tempA将和后面的结果tempB比较,判断是否成功
00426067  |>  6A 0C         push    0C                               ; /Count = C (12.)
00426069  |.  8D45 DC       lea     eaxdword ptr [ebp-24]          ; |
0042606C  |.  50            push    eax                              ; |Buffer
0042606D  |.  6A 66         push    66                               ; |ControlID = 66 (102.)
0042606F  |.  56            push    esi                              ; |hWnd
00426070  |.  BB 10000000   mov     ebx, 10                          ; |
00426075  |.  2E:FF15 A0D74>call    dword ptr cs:[<&USER32.GetDlgIte>; \得到Key1
0042607C  |.  8D45 DC       lea     eaxdword ptr [ebp-24]          ;  Key1
0042607F  |.  31D2          xor     edxedx
00426081  |.  E8 CE130100   call    winimp32.00437454                ;  key1 -> eax
00426086  |.  6A 0C         push    0C                               ; /Count = C (12.)
00426088  |.  8945 F4       mov     dword ptr [ebp-C], eax           ; |
0042608B  |.  8D45 DC       lea     eaxdword ptr [ebp-24]          ; |
0042608E  |.  50            push    eax                              ; |Buffer
0042608F  |.  6A 67         push    67                               ; |ControlID = 67 (103.)
00426091  |.  56            push    esi                              ; |hWnd
00426092  |.  C745 F8 00000>mov     dword ptr [ebp-8], 0             ; |
00426099  |.  BB 10000000   mov     ebx, 10                          ; |
0042609E  |.  2E:FF15 A0D74>call    dword ptr cs:[<&USER32.GetDlgIte>; \得到Key2
004260A5  |.  8D45 DC       lea     eaxdword ptr [ebp-24]
004260A8  |.  31D2          xor     edxedx
004260AA  |.  E8 A5130100   call    winimp32.00437454                ;  key2 -> eax
004260AF  |.  8B55 F4       mov     edxdword ptr [ebp-C]           ;  key1 -> edx
004260B2  |.  8945 F8       mov     dword ptr [ebp-8], eax
004260B5  |.  81FA 00000001 cmp     edx, 1000000                     ;  edx = key1,不能小于1000000
004260BB  |.  72 16         jb      short winimp32.004260D3
004260BD  |.  3D 00000001   cmp     eax, 1000000                     ;  eax = key2,不能小于1000000
004260C2  |.  72 0F         jb      short winimp32.004260D3
004260C4  |.  89D0          mov     eaxedx                         ;  key1 -> eax(key1/key2互换)
004260C6  |.  8B55 F8       mov     edxdword ptr [ebp-8]           ;  key2 -> edx(key1/key2互换)
004260C9  |.  E8 D9010000   call    winimp32.004262A7                ;  ×××算法Call×××::F7进入×××
004260CE  |.  3B45 FC       cmp     eaxdword ptr [ebp-4]           ;  eax结果(tempB) = 上面的循环结果(tempA) ?
004260D1  |.  74 18         je      short winimp32.004260EB          ;  相等便成功,之后保存注册相关的信息
004260D3  |>  6A 30         push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004260D5  |.  68 30D24400   push    winimp32.0044D230                ; |Title = "WinImp"
004260DA  |.  68 28CC4400   push    winimp32.0044CC28                ; |Text = "The keys do not match ..."
004260DF  |.  56            push    esi                              ; |hOwner
004260E0  |.  2E:FF15 0CD84>call    dword ptr cs:[<&USER32.MessageBo>; \注册错误对话框
004260E7  |.  31C0          xor     eaxeax
004260E9  |.  EB 68         jmp     short winimp32.00426153
004260EB  |>  BB 603C4500   mov     ebx, winimp32.00453C60           ;  ASCII "aCaFeeL"
004260F0  |.  BA 98DA4400   mov     edx, winimp32.0044DA98           ;  ASCII "Register"
004260F5  |.  B8 D8DA4400   mov     eax, winimp32.0044DAD8           ;  ASCII "Options"
004260FA  |.  E8 D868FFFF   call    winimp32.0041C9D7
004260FF  |.  31F6          xor     esiesi
00426101  |.  31C0          xor     eaxeax
00426103  |>  8D78 01       /lea     edidword ptr [eax+1]
00426106  |.  57            |push    edi
00426107  |.  68 A8DA4400   |push    winimp32.0044DAA8               ;  ASCII "Key%d"
0042610C  |.  8D45 E8       |lea     eaxdword ptr [ebp-18]
0042610F  |.  50            |push    eax
00426110  |.  E8 1B090100   |call    winimp32.00436A30
00426115  |.  83C4 0C       |add     esp, 0C
00426118  |.  FF742E F4     |push    dword ptr [esi+ebp-C]
0042611C  |.  68 A8E64400   |push    winimp32.0044E6A8               ;  ASCII "%X"
00426121  |.  8D45 DC       |lea     eaxdword ptr [ebp-24]
00426124  |.  50            |push    eax
00426125  |.  8D5D DC       |lea     ebxdword ptr [ebp-24]
00426128  |.  8D55 E8       |lea     edxdword ptr [ebp-18]
0042612B  |.  E8 00090100   |call    winimp32.00436A30
00426130  |.  83C4 0C       |add     esp, 0C
00426133  |.  B8 D8DA4400   |mov     eax, winimp32.0044DAD8          ;  ASCII "Options"
00426138  |.  83C6 04       |add     esi, 4
0042613B  |.  E8 9768FFFF   |call    winimp32.0041C9D7
00426140  |.  89F8          |mov     eaxedi
00426142  |.  83FF 02       |cmp     edi, 2
00426145  |.^ 7C BC         \jl      short winimp32.00426103
00426147  |.  C605 52134500>mov     byte ptr [451352], 1
0042614E  |.  B8 01000000   mov     eax, 1
00426153  |>  C9            leave
00426154  |.  5F            pop     edi
00426155  |.  5E            pop     esi
00426156  |.  5A            pop     edx
00426157  |.  59            pop     ecx
00426158  |.  5B            pop     ebx
00426159  \.  C3            retn
》》》》》》》》



可能大家也都注意到了:

0042605A      8A8F 10114500 mov     clbyte ptr [edi+451110]

这里的byte ptr [edi+451110],我们顺着来到 00451110 后,会发现这是一张字符码对应表格,长度为:(4x4)x16 = 256,格式如下:

00451110   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  ...
..
00451120   10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F  
00451130   20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F   !"#$%&'()*+,-./
00451140   30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  0123456789:;<=>?
00451150   40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F  @abcdefghijklmno
00451160   70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F  pqrstuvwxyz[\]^_
00451170   60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F  `abcdefghijklmno
00451180   70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F  pqrstuvwxyz{|}~
00451190   80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F   琋桻S梀rX沍絔
004511A0   90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F  `渃eCg焛辦痭^pM
004511B0   A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF  rNⅲぅΗī?嗳釂
004511C0   B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF  氨渤吹斗腹夯冀究
004511D0   C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF  懒旅呐魄壬仕掏蜗
004511E0   D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF  醒矣哉肿刭谯茌捱
004511F0   E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF  噌忏溴骁栝觌祉铒
00451200   F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF  瘃蝮趱鲼鈱鉐??

通过分析上面的这张表格,我们会发现,这张表格的主要作用便是:不管你输入的注册名字符是否为大写字母,他都通过这张表格将注册名全部转换为小写字母。

而 00426042~00426065 处的循环算法我用 delphi+kol/mck 源码表示,则为如下形式:

》》》》》》》》
  for i:=0 to 3 do sum[i] := $00; //初始化变量sum
  Tebx := 0;
  for i:=1 to length(RegName) do
    begin
      if (ord(RegName[i])=$20) or (ord(RegName[i])=$2E)
      then Tebx := (Tebx and $3)
      else begin
             sum[Tebx] := sum[Tebx]  + key[ord(RegName[i]) and $FF];
             Tebx := Tebx + 1;
             Tebx := (Tebx and $3);
           end;
    end;
  sumAll := int2hex(sum[3],2)+int2hex(sum[2],2)+int2hex(sum[1],2)+int2hex(sum[0],2);
  tempA  := Hex2Int('$' + sumAll);        //得到的前部分的结果(RegName -> TempA)
》》》》》》》》

上面的算法举列来说就是:

比如我输入的注册名为:aCaFeeL,则查找到上面我给出来的‘字符码对应表格’中相应的ASCII码就是:61 63 61 66 65 65 6C;sum[0]=61,sum[1]=63,sum[2]=61,sum[3]=66;然后又开始从sum[0]开始累加,即:sum[0]=61+65=C6,sum[1]=63+65=C8,sum[2]=61+6C=CD,sum[3]=66;则结果在内存窗口中为:sum[0]=C6 sum[1]=C8 sum[2]=CD sum[3]=66,故实际为十六进制的:$66CDC8C6 数字,暂且命名为tempA吧!



走过上面的循环运算后,我们继续F8键向下分析,来到这里后:

》》》》》》》》
004260AA  |.  E8 A5130100   call    winimp32.00437454                ;  key2 -> eax
004260AF  |.  8B55 F4       mov     edxdword ptr [ebp-C]           ;  key1 -> edx
004260B2  |.  8945 F8       mov     dword ptr [ebp-8], eax
004260B5  |.  81FA 00000001 cmp     edx, 1000000                     ;  edx = hex(key1),不能小于1000000
004260BB  |.  72 16         jb      short winimp32.004260D3
004260BD  |.  3D 00000001   cmp     eax, 1000000                     ;  eax = hex(key2),不能小于1000000
004260C2  |.  72 0F         jb      short winimp32.004260D3
004260C4  |.  89D0          mov     eaxedx                         ;  key1 -> eax(key1/key2互换)
004260C6  |.  8B55 F8       mov     edxdword ptr [ebp-8]           ;  key2 -> edx(key1/key2互换)
004260C9  |.  E8 D9010000   call    winimp32.004262A7                ;  ×××算法Call×××::F7进入×××
004260CE  |.  3B45 FC       cmp     eaxdword ptr [ebp-4]           ;  eax结果(tempB) = 上面的循环结果(tempA) ?
004260D1  |.  74 18         je      short winimp32.004260EB          ;  成功后保存注册相关的信息
004260D3  |>  6A 30         push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
》》》》》》》》



我们知道了,Key1、Key2的数值都必须大于$1000000才行,而满足上述条件后,我们便来到了后面部分的算法相关的call子程序了,这便是:

004260C9  |.  E8 D9010000   call    winimp32.004262A7

我们需要进入到这个子程序中一探究竟,按F7键进入后,来到了这里:

》》》》》》》》
004262A7  /$  53            push    ebx
004262A8  |.  51            push    ecx
004262A9  |.  56            push    esi
004262AA  |.  89C1          mov     ecxeax                         ;  key1 -> ecx
004262AC  |.  89D3          mov     ebxedx                         ;  key2 -> ebx
004262AE  |.  8B15 64A74400 mov     edxdword ptr [44A764]          ;  $E8B8D413 -> edx
004262B4  |.  E8 74FFFFFF   call    winimp32.0042622D                ;  ::F7进入::(注意:只要eax的结果)
004262B9  |.  89C6          mov     esieax                         ;  (运算结果eax)TempB -> (esi下面要用)
004262BB  |.  89DA          mov     edxebx
004262BD  |.  BB 20000000   mov     ebx, 20
004262C2  |.  89C8          mov     eaxecx                         ;  key1 -> eax
004262C4  |.  31C9          xor     ecxecx
004262C6  |.  E8 B3080100   call    winimp32.00436B7E                ;  key2 -> eax
004262CB  |.  31F0          xor     eaxesi                         ;  tempB = hex(key2) xor TempB(esi上面算法中得到的值)
004262CD  |.  5E            pop     esi                              ;  如要注册成功,则必须: TempA = TempB
004262CE  |.  59            pop     ecx                              ;  即推出:Key2 = TempA xor TempB;
004262CF  |.  5B            pop     ebx
004262D0  \.  C3            retn
》》》》》》》》



通过上面的代码,我们看到后半部分的关键算法便在:

004262B4  |.  E8 74FFFFFF   call    winimp32.0042622D

的这个子call中,所以走到这里后,F7键进入,来到了如下的地方:

》》》》》》》》
0042622D  /$  53            push    ebx
0042622E  |.  51            push    ecx
0042622F  |.  56            push    esi
00426230  |.  57            push    edi
00426231  |.  C8 040000     enter   4, 0
00426235  |.  52            push    edx
00426236  |.  F645 F8 01    test    byte ptr [ebp-8], 1
0042623A  |.  75 07         jnz     short winimp32.00426243
0042623C  |.  B9 01000000   mov     ecx, 1
00426241  |.  EB 02         jmp     short winimp32.00426245
00426243  |>  89C1          mov     ecxeax                         ;  ecx = eax = key1
00426245  |>  C745 FC 02000>mov     dword ptr [ebp-4], 2             ;  $2 -> [ebp-4]
0042624C  |.  89C7          mov     edieax                         ;  edi = eax = key1
0042624E  |.  EB 09         jmp     short winimp32.00426259
00426250  |>  D165 FC       /shl     dword ptr [ebp-4], 1            ;  [ebp-4] = [ebp-4] shl 1
00426253  |.  837D FC 00    |cmp     dword ptr [ebp-4], 0            ;  ? = 0
00426257  |.  74 46         |je      short winimp32.0042629F
00426259  |>  8B35 60A74400  mov     esidword ptr [44A760]         ;  $F527789F -> esi
0042625F  |.  89F8          |mov     eaxedi
00426261  |.  89FA          |mov     edxedi                        ;  下面是大数运算
00426263  |.  F7E2          |mul     edx                             ;  edx <- (edi*edi) 无符号乘法,结果送eax/edx
00426265  |.  39D6          |cmp     esiedx                        ;  $F527789F 与 edx 结果比较
00426267  |.  77 0A         |ja      short winimp32.00426273         ;  $F527789F > edx 结果,便跳转
00426269  |.  89C3          |mov     ebxeax
0042626B  |.  89D0          |mov     eaxedx
0042626D  |.  31D2          |xor     edxedx
0042626F  |.  F7F6          |div     esi
00426271  |.  89D8          |mov     eaxebx
00426273  |>  F7F6          |div     esi                             ;  上面的乘积 div $F527789F 无符号除法
00426275  |.  8B75 F8       |mov     esidword ptr [ebp-8]          ;  $E8B8D413 -> esi
00426278  |.  89D0          |mov     eaxedx                        ;  除法余数 -> eax
0042627A  |.  89D7          |mov     ediedx                        ;  -> edi
0042627C  |.  8575 FC       |test    dword ptr [ebp-4], esi          ;  [ebp-4] and $E8B8D413 = 0 ??
0042627F  |.^ 74 CF         |je      short winimp32.00426250         ;  =0,跳
00426281  |.  8B35 60A74400 |mov     esidword ptr [44A760]         ;  $F527789F -> esi
00426287  |.  89CA          |mov     edxecx                        ;  key1 -> edx
00426289  |.  F7E2          |mul     edx                             ;  eax * edx
0042628B  |.  39D6          |cmp     esiedx                        ;  $F527789F 与 edx 结果比较
0042628D  |.  77 0A         |ja      short winimp32.00426299         ;  $F527789F > edx 结果,便跳转
0042628F  |.  89C3          |mov     ebxeax
00426291  |.  89D0          |mov     eaxedx
00426293  |.  31D2          |xor     edxedx
00426295  |.  F7F6          |div     esi
00426297  |.  89D8          |mov     eaxebx
00426299  |>  F7F6          |div     esi                             ;  无符号 eax div $F527789F
0042629B  |.  89D1          |mov     ecxedx                        ;  edx -> ecx 最终结果
0042629D  |.^ EB B1         \jmp     short winimp32.00426250
0042629F  |>  89C8          mov     eaxecx                         ;  最终结果ecx -> eax
004262A1  |.  C9            leave
004262A2  |.  5F            pop     edi
004262A3  |.  5E            pop     esi
004262A4  |.  59            pop     ecx
004262A5  |.  5B            pop     ebx
004262A6  \.  C3            retn
004262A7  /$  53            push    ebx
004262A8  |.  51            push    ecx
004262A9  |.  56            push    esi
004262AA  |.  89C1          mov     ecxeax                         ;  key1 -> ecx
004262AC  |.  89D3          mov     ebxedx                         ;  key2 -> ebx
004262AE  |.  8B15 64A74400 mov     edxdword ptr [44A764]          ;  $E8B8D413 -> edx
004262B4  |.  E8 74FFFFFF   call    winimp32.0042622D                ;  ::F7进入::(注意:只要eax的结果)
004262B9  |.  89C6          mov     esieax                         ;  (运算结果eax)TempB -> (esi下面要用)
004262BB  |.  89DA          mov     edxebx
004262BD  |.  BB 20000000   mov     ebx, 20
004262C2  |.  89C8          mov     eaxecx                         ;  key1 -> eax
004262C4  |.  31C9          xor     ecxecx
004262C6  |.  E8 B3080100   call    winimp32.00436B7E                ;  key2 -> eax
004262CB  |.  31F0          xor     eaxesi                         ;  tempA = tempB = hex(key2) xor TempB(esi上面算法中得到的值)
004262CD  |.  5E            pop     esi                              ;  即是:Key2 = TempA xor TempB;
004262CE  |.  59            pop     ecx
004262CF  |.  5B            pop     ebx
004262D0  \.  C3            retn
》》》》》》》》



由上面的代码,我们知道了它的算法形式如下:

》》》》》》》》
  Key1 := hex2int('$' + KeyCode1);
  Tecx := Key1;
  Tebp := $2;
  Tedi := Key1;
  goto cz59;
cz50:
  Tebp := Tebp shl $1;
  if (Tebp - 0) = 0 then goto cz9F;
cz59:
  Tesi := $F527789F;
  Teax := Tedi;
  Tedx := Tedi;
  // Tedx_eax := Teax * Tedx;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    MUL  EDX
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz59:  '+int2hex(Tedx,8));
  if Tesi > Tedx then goto cz73;
  Tebx := Teax;
  Teax := Tedx;
  Tedx := Tedx xor Tedx;
//Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz73:  '+int2hex(Tedx,8));
  Teax := Tebx;
cz73:
//Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz73:  '+int2hex(Tedx,8));
  Tesi := $E8B8D413;
  Teax := Tedx;
  Tedi := Tedx;
  if (Tebp and Tesi)=0 then goto cz50;
  Tesi := $F527789F;
  Tedx := Tecx;
//Tedx_eax := Teax * Tedx;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    MUL  EDX
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz73:  '+int2hex(Tedx,8));
  if Tesi > Tedx then goto cz99;
  Tebx := Teax;
  Teax := Tedx;
  Tedx := Tedx xor Tedx;
//Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz73:  '+int2hex(Tedx,8));
  Teax := Tebx;
cz99:
//Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;                                 //showmessage('cz73:  '+int2hex(Tedx,8));
  Tecx := Tedx;
  goto cz50;
cz9F:
  TempB := Tecx;                          //得到的后部分的结果(KeyCode1 ->TempB)
》》》》》》》》


在分析上面的这个算法前,我们已知道:
》》》》》》》》
004262C2  |.  89C8          mov     eaxecx                         ;  key1 -> eax
004262C4  |.  31C9          xor     ecxecx
004262C6  |.  E8 B3080100   call    winimp32.00436B7E                ;  key2 -> eax
004262CB  |.  31F0          xor     eaxesi                         ;  tempB = hex(key2) xor TempB(esi上面算法中得到的值)
004262CD  |.  5E            pop     esi                              ;  如要注册成功,则必须: TempA = TempB
004262CE  |.  59            pop     ecx                              ;  即推出:Key2 = TempA xor TempB;
004262CF  |.  5B            pop     ebx
004262D0  \.  C3            retn
》》》》》》》》



也就是说:Key2的值是由上面分析并得到的tempA(由 注册名 运算后得到)和tempB(由 Key1 运算后得到)异或之后得到的,通过上面的完整分析,我们便可以写出一个完整的注册机来玩玩了,呵呵!注册机(Delphi + KOL/MCK)源代码如下:(已写成为一个string函数格式,方便你的调用和修改,嘿嘿 :)

                                                      //WinIMP v1.11注册算法
function WinIMP_sn(RegName, KeyCode1: string): string;//定义为string函数
var
  i, ii : integer;
  TempA, TempB, Key1 : longInt;
  Tesi, Tedi, Teax, Tebx, Tecx, Tedx, Tebp : cardinal;
  sumALL,strEDX, strEAX, strEDX_EAX : string;
  sum : array [0 .. 3] of byte;
label
  cz50, cz59, cz73, cz99, cz9F;
const
  key : array[0 .. 255] of byte =                     //字符表常量,不变
       ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F,
        $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
        $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F,
        $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F,
        $40,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F,
        $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$5B,$5C,$5D,$5E,$5F,
        $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6A,$6B,$6C,$6D,$6E,$6F,
        $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7A,$7B,$7C,$7D,$7E,$7F,
        $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8A,$8B,$8C,$8D,$8E,$8F,
        $90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9A,$9B,$9C,$9D,$9E,$9F,
        $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7,$A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF,
        $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$BA,$BB,$BC,$BD,$BE,$BF,
        $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF,
        $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7,$D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF,
        $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7,$E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF,
        $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7,$F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF);
begin
  if RegName='' then
    begin
      showmessage('输入的 注册名 不能为空!');
      exit;
    end;
  for i:=0 to 3 do sum[i] := $00; //初始化变量sum
  ii := 0; //初始化变量ii
  for i:=1 to length(RegName) do  //开始循环计算:
    begin
      if (ord(RegName[i])=$20) or (ord(RegName[i])=$2E)
      then ii := (ii and $3)
      else begin
             sum[ii] := sum[ii] + key[ord(RegName[i]) and $FF];//取字符表中的相应值
             ii := ii + 1;
             ii := (ii and $3);
           end;
    end;
  sumAll := int2hex(sum[3],2)+int2hex(sum[2],2)+int2hex(sum[1],2)+int2hex(sum[0],2);
  TempA  := Hex2Int('$' + sumAll);        //得到的前部分的结果(RegName -> TempA)

  Key1 := hex2int('$' + KeyCode1);
  Tecx := Key1;
  Tebp := $2;
  Tedi := Key1;
  goto cz59;
cz50:
  Tebp := Tebp shl $1;
  if (Tebp - 0) = 0 then goto cz9F;
cz59:
  Tesi := $F527789F;
  Teax := Tedi;
  Tedx := Tedi;
  // Tedx_eax := Teax * Tedx;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    MUL  EDX
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
  if Tesi > Tedx then goto cz73;
  Tebx := Teax;
  Teax := Tedx;
  Tedx := Tedx xor Tedx;
  //Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
  Teax := Tebx;
cz73:
  //Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
  Tesi := $E8B8D413;
  Teax := Tedx;
  Tedi := Tedx;
  if (Tebp and Tesi)=0 then goto cz50;
  Tesi := $F527789F;
  Tedx := Tecx;
  //Tedx_eax := Teax * Tedx;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    MUL  EDX
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
  if Tesi > Tedx then goto cz99;
  Tebx := Teax;
  Teax := Tedx;
  Tedx := Tedx xor Tedx;
  //Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
cz99:
  //Tedx := Tedx_eax mod Tesi;
  asm
    MOV  ESI,[Tesi]
    MOV  EAX,[Teax]
    MOV  EDX,[Tedx]
    DIV  ESI
    mov  [Teax],EAX
    mov  [Tedx],EDX
  end;
  Tecx := Tedx;
  goto cz50;
cz9F:
  TempB := Tecx;                          //得到的后部分的结果(KeyCode1 ->TempB)

  Result := int2hex((TempA xor TempB),8); //最终返回的 KeyCode2 结果是由 TempA xor TempB 后得到的
end;



好了,就到这里结束吧!分析难免有不当之处,还望大家给我指出来!


放上一组可用的Key:

name: aCaFeeL
key1: ABF8FB42
key2: 8DB47F89


注册机的算法在多台机器上使用不同注册名通过验证,但没有时间再优化它了,应该不存在bug的问题,附件中为我打包后的注册机源代码。

另:如果问我这次分析最大的收获是什么?我会说,那就是学会了如何将大数运算的高位数和低位数分配到相应的EDX和EAX中了!别笑,呵呵!