【文章作者】: 网络断魂
【软件名称】: Xnview v1.93.1
【下载地址】: http://www.crsky.com/soft/1187.html
【加壳方式】: ASPack 2.12b -> Alexey Solodovnikov
【保护方式】: 序列号
【编写语言】: Microsoft Visual C++ 6.0
【使用工具】: PEID,OD,
【操作平台】: XP SP3,
【软件介绍】: 国外软件,非常棒的图像查看程序。支持150种图片格式, 除一般的查看、浏览、幻灯显示等功能外,还自带30多面滤镜,方便编辑修改; 可以批量转换文件格式

,创建缩略图并生成网页,还可自己制作GIF, 小巧实用。
【作者声明】: 菜鸟学习算法,失误之处敬请诸位大侠赐教!



一、ESP定律脱壳,由消息断点找到关键函数

00566BA0   .  81EC 68010000 sub     esp, 168
00566BA6   .  8D4424 68     lea     eax, dword ptr [esp+68]
00566BAA   .  56            push    esi
00566BAB   .  8BB424 700100>mov     esi, dword ptr [esp+170]
00566BB2   .  57            push    edi
00566BB3   .  8B3D EC966A00 mov     edi, dword ptr [<&user32.GetDlgI>;  USER32.GetDlgItemTextA
00566BB9   .  68 00010000   push    100                              ; /Count = 100 (256.)
00566BBE   .  50            push    eax                              ; |Buffer
00566BBF   .  68 D0070000   push    7D0                              ; |ControlID = 7D0 (2000.)
00566BC4   .  56            push    esi                              ; |hWnd
00566BC5   .  FFD7          call    edi                              ; \GetDlgItemTextA
00566BC7   .  8D4C24 10     lea     ecx, dword ptr [esp+10]
00566BCB   .  6A 20         push    20                               ; /Count = 20 (32.)
00566BCD   .  51            push    ecx                              ; |Buffer
00566BCE   .  68 D1070000   push    7D1                              ; |ControlID = 7D1 (2001.)
00566BD3   .  56            push    esi                              ; |hWnd
00566BD4   .  FFD7          call    edi                              ; \GetDlgItemTextA
00566BD6   .  8A4424 70     mov     al, byte ptr [esp+70]            ;  //送用户名第一位
00566BDA   .  84C0          test    al, al                           ;  //较验用户名是否为空
00566BDC   .  0F84 3A010000 je      00566D1C                         ;  //为空则跳,跳往注册失败
00566BE2   .  8A4424 10     mov     al, byte ptr [esp+10]            ;  //送假码第一位
00566BE6   .  84C0          test    al, al                           ;  //较验注册码是否为空
00566BE8   .  0F84 2E010000 je      00566D1C                         ;  //为空则跳,跳往注册失败
00566BEE   .  8D5424 08     lea     edx, dword ptr [esp+8]           ;  //F5A0堆栈送给EDX
00566BF2   .  8D4424 70     lea     eax, dword ptr [esp+70]          ;  //用户名送给EAX,(堆栈F608)
00566BF6   .  52            push    edx                              ;  //EDX入栈
00566BF7   .  50            push    eax                              ;  //EAX入栈(用户名入栈,准备参于运算了)
00566BF8   .  E8 B3B5F9FF   call    005021B0                         ;  //关键CALL,跟进
00566BFD   .  8D4C24 18     lea     ecx, dword ptr [esp+18]          ;  //注册码送给ECX(堆栈F5A8)
00566C01   .  51            push    ecx                              ;  //入栈
00566C02   .  E8 7CB60200   call    00592283                         ;  //注册码转换为十六进制值
00566C07   .  8B4C24 14     mov     ecx, dword ptr [esp+14]          ;  //用户名计算值送给ECX
00566C0B   .  83C4 0C       add     esp, 0C
00566C0E   .  3BC8          cmp     ecx, eax                         ;  //关键比较,
00566C10      74 5D         je      short 00566C6F                   ;  //相等则跳往注册成功,(这里必须跳,不跳则错误)
00566C12   .  A1 086E7300   mov     eax, dword ptr [736E08]
00566C17   .  8D5424 30     lea     edx, dword ptr [esp+30]
00566C1B   .  6A 40         push    40                               ; /Count = 40 (64.)
00566C1D   .  52            push    edx                              ; |Buffer
00566C1E   .  68 93130000   push    1393                             ; |RsrcID = STRING "Invalid registration"
00566C23   .  50            push    eax                              ; |hInst => 00F60000
00566C24   .  FF15 7C976A00 call    dword ptr [<&user32.LoadStringA>>; \LoadStringA
00566C2A   .  6A 10         push    10                               ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00566C2C   .  8D4C24 34     lea     ecx, dword ptr [esp+34]          ; |
00566C30   .  68 6CEA7200   push    0072EA6C                         ; |Title = ""
00566C35   .  51            push    ecx                              ; |Text
00566C36   .  56            push    esi                              ; |hOwner
00566C37   .  FF15 0C976A00 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
00566C3D   .  68 D0070000   push    7D0                              ; /ControlID = 7D0 (2000.)
00566C42   .  56            push    esi                              ; |hWnd
00566C43   .  FF15 04976A00 call    dword ptr [<&user32.GetDlgItem>] ; \GetDlgItem
00566C49   .  50            push    eax                              ; /hWnd
00566C4A   .  FF15 48976A00 call    dword ptr [<&user32.SetFocus>]   ; \SetFocus
00566C50   .  68 6CEA7200   push    0072EA6C                         ; /Text = ""
00566C55   .  68 D1070000   push    7D1                              ; |ControlID = 7D1 (2001.)
00566C5A   .  56            push    esi                              ; |hWnd
00566C5B   .  FF15 00976A00 call    dword ptr [<&user32.SetDlgItemTe>; \SetDlgItemTextA
00566C61   .  5F            pop     edi
00566C62   .  B8 01000000   mov     eax, 1
00566C67   .  5E            pop     esi
00566C68   .  81C4 68010000 add     esp, 168
00566C6E   .  C3            retn
00566C6F   >  8D5424 70     lea     edx, dword ptr [esp+70]
00566C73   .  68 00010000   push    100
00566C78   .  52            push    edx
00566C79   .  68 D0070000   push    7D0
00566C7E   .  56            push    esi
00566C7F   .  FFD7          call    edi
00566C81   .  8D4424 10     lea     eax, dword ptr [esp+10]
00566C85   .  6A 20         push    20
00566C87   .  50            push    eax
00566C88   .  68 D1070000   push    7D1
00566C8D   .  56            push    esi
00566C8E   .  FFD7          call    edi
00566C90   .  8D4C24 70     lea     ecx, dword ptr [esp+70]
00566C94   .  51            push    ecx
00566C95   .  68 DC957000   push    007095DC                         ;  licensename
00566C9A   .  6A 00         push    0
00566C9C   .  E8 4F37F7FF   call    004DA3F0
00566CA1   .  8D5424 1C     lea     edx, dword ptr [esp+1C]
00566CA5   .  52            push    edx
00566CA6   .  68 CC957000   push    007095CC                         ;  licensenumber
00566CAB   .  6A 00         push    0
00566CAD   .  E8 3E37F7FF   call    004DA3F0
00566CB2   .  A1 106E7300   mov     eax, dword ptr [736E10]
00566CB7   .  83C4 18       add     esp, 18
00566CBA   .  C705 286E7300>mov     dword ptr [736E28], 1
00566CC4   .  6A 01         push    1                                ; /Flags = MF_BYCOMMAND|MF_GRAYED|MF_STRING
00566CC6   .  68 F2000000   push    0F2                              ; |ItemID = F2 (242.)
00566CCB   .  50            push    eax                              ; |/hWnd => 001D0884 ('XnView - [浏览器 - F:\下载\Xn...',class='XmainClass')
00566CCC   .  FF15 F0956A00 call    dword ptr [<&user32.GetMenu>]    ; |\GetMenu
00566CD2   .  50            push    eax                              ; |hMenu
00566CD3   .  FF15 5C976A00 call    dword ptr [<&user32.EnableMenuIt>; \EnableMenuItem
00566CD9   .  8B15 086E7300 mov     edx, dword ptr [736E08]          ;  xnviewzh.00F60000
00566CDF   .  8D4C24 30     lea     ecx, dword ptr [esp+30]
00566CE3   .  6A 40         push    40                               ; /Count = 40 (64.)
00566CE5   .  51            push    ecx                              ; |Buffer
00566CE6   .  68 94130000   push    1394                             ; |RsrcID = STRING "Registration successful.

Thank you for purchasing XnView."
00566CEB   .  52            push    edx                              ; |hInst => 00F60000
00566CEC   .  FF15 7C976A00 call    dword ptr [<&user32.LoadStringA>>; \LoadStringA
00566CF2   .  6A 40         push    40                               ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00566CF4   .  8D4424 34     lea     eax, dword ptr [esp+34]          ; |
00566CF8   .  68 6CEA7200   push    0072EA6C                         ; |Title = ""
00566CFD   .  50            push    eax                              ; |Text
00566CFE   .  56            push    esi                              ; |hOwner
00566CFF   .  FF15 0C976A00 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
00566D05   .  6A 00         push    0                                ; /Result = 0
00566D07   .  56            push    esi                              ; |hWnd
00566D08   .  FF15 F0966A00 call    dword ptr [<&user32.EndDialog>]  ; \EndDialog
00566D0E   .  5F            pop     edi
00566D0F   .  B8 01000000   mov     eax, 1
00566D14   .  5E            pop     esi
00566D15   .  81C4 68010000 add     esp, 168
00566D1B   .  C3            retn
00566D1C   >  8B15 086E7300 mov     edx, dword ptr [736E08]          ;  xnviewzh.00F60000
00566D22   .  8D4C24 30     lea     ecx, dword ptr [esp+30]
00566D26   .  6A 40         push    40                               ; /Count = 40 (64.)
00566D28   .  51            push    ecx                              ; |Buffer
00566D29   .  68 93130000   push    1393                             ; |RsrcID = STRING "Invalid registration"
00566D2E   .  52            push    edx                              ; |hInst => 00F60000
00566D2F   .  FF15 7C976A00 call    dword ptr [<&user32.LoadStringA>>; \LoadStringA
00566D35   .  6A 10         push    10                               ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
00566D37   .  8D4424 34     lea     eax, dword ptr [esp+34]          ; |
00566D3B   .  68 6CEA7200   push    0072EA6C                         ; |Title = ""
00566D40   .  50            push    eax                              ; |Text
00566D41   .  56            push    esi                              ; |hOwner
00566D42   .  FF15 0C976A00 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA
00566D48   .  5F            pop     edi
00566D49   .  B8 01000000   mov     eax, 1
00566D4E   .  5E            pop     esi
00566D4F   .  81C4 68010000 add     esp, 168
00566D55   .  C3            retn

二、由00566BF8   call    005021B0    ;  //关键CALL,跟进来到:(这里是用户名计算部份)

005021B0  /$  8B5424 04     mov     edx, dword ptr [esp+4]           ;  //用户名送给EDX
005021B4  |.  53            push    ebx
005021B5  |.  55            push    ebp
005021B6  |.  56            push    esi
005021B7  |.  57            push    edi
005021B8  |.  8BFA          mov     edi, edx                         ;  //用户名送给EDI
005021BA  |.  83C9 FF       or      ecx, FFFFFFFF                    ;  //ECX=FFFFFFFF
005021BD  |.  33C0          xor     eax, eax                         ;  //EAX清零(用于搜索用户名中是否有0)
005021BF  |.  F2:AE         repne   scas byte ptr es:[edi]           ;  //循环搜索字符
005021C1  |.  F7D1          not     ecx                              ;  //ECX取反,得出(用户名长度+1)的值
005021C3  |.  49            dec     ecx                              ;  //ECX-1,得到用户名长度
005021C4  |.  BE 188A7000   mov     esi, 00708A18                    ;  //ESI=00708A18
005021C9  |.  8BE9          mov     ebp, ecx                         ;  //用户名长度送给EBP
005021CB  |.  B9 05000000   mov     ecx, 5                           ;  //ECX=5
005021D0  |.  BF 90087300   mov     edi, 00730890                    ;  //EDI=00730890
005021D5  |.  F3:A5         rep     movs dword ptr es:[edi], dword p>;  //00708A18中的内容(密码表)送给00730890地址中
005021D7  |.  8BF0          mov     esi, eax                         ;  //ESI=EAX=0
005021D9  |.  74 21         je      short 005021FC
005021DB  |>  8A0C16        /mov     cl, byte ptr [esi+edx]          ;  //依次送用户名的ASCII值给CL
005021DE  |.  8AD9          |mov     bl, cl                          ;  //ASCII值送给BL
005021E0  |.  3298 90087300 |xor     bl, byte ptr [eax+730890]       ;  //ASCII值与相应位数上的固定值异或运算
005021E6  |.  40            |inc     eax                             ;  //EAX+1,用于比较是否到第五位
005021E7  |.  83F8 05       |cmp     eax, 5                          ;  //EAX与5比较,(看来第5位是特殊)
005021EA  |.  881C16        |mov     byte ptr [esi+edx], bl          ;  //异或值替换ASCII值
005021ED  |.  8888 8F087300 |mov     byte ptr [eax+73088F], cl       ;  //ASCII值替换固定值,这两行就是字符交换
005021F3  |.  75 02         |jnz     short 005021F7                  ;  //不等则跳,
005021F5  |.  33C0          |xor     eax, eax                        ;  //若EAX=5即第五位时,EAX清零,进行第二轮交换
005021F7  |>  46            |inc     esi                             ;  //标志位+1,用于取下一位
005021F8  |.  3BF5          |cmp     esi, ebp                        ;  //标志位与长度比较,看是否循环完
005021FA  |.^ 72 DF         \jb      short 005021DB                  ;  //小于则跳,未完继续(循环1)
005021FC  |>  33FF          xor     edi, edi                         ;  //EDI清零
005021FE  |.  33C9          xor     ecx, ecx                         ;  //ECX清零
00502200  |.  85ED          test    ebp, ebp                         ;  //较验用户名长度是否为空
00502202  |.  76 26         jbe     short 0050222A                   ;  //为空则跳(标志小于等于0则跳)
00502204  |>  8A9F 95087300 /mov     bl, byte ptr [edi+730895]       ;  //依次取固定值给BL(从第六位固定值开始取)
0050220A  |.  8BF5          |mov     esi, ebp                        ;  //用户名长度送给ESI
0050220C  |.  2BF1          |sub     esi, ecx                        ;  //长度-ECX(ECX初值为0)
0050220E  |.  4E            |dec     esi                             ;  //再-1,这三行代码用来从倒数第一位依次往前取值
0050220F  |.  8A0416        |mov     al, byte ptr [esi+edx]          ;  //第一次循环交换后的用户名倒数第一位开始依次送给AL,
00502212  |.  32D8          |xor     bl, al                          ;  //与固定值异或运算
00502214  |.  47            |inc     edi                             ;  //EDI+1,比较是否到了第五位
00502215  |.  881C16        |mov     byte ptr [esi+edx], bl
00502218  |.  8887 94087300 |mov     byte ptr [edi+730894], al       ;  //这两行也是字符交换
0050221E  |.  83FF 05       |cmp     edi, 5                          ;  //EDI与5比较,看是否为第5位
00502221  |.  75 02         |jnz     short 00502225                  ;  //不是则跳
00502223  |.  33FF          |xor     edi, edi                        ;  //是第5位则EDI清零,进行第二轮交换
00502225  |>  41            |inc     ecx                             ;  //标志位加1,
00502226  |.  3BCD          |cmp     ecx, ebp                        ;  //标志位与长度比较,看是否取完
00502228  |.^ 72 DA         \jb      short 00502204                  ;  //未完继续(循环2)
0050222A  |>  33F6          xor     esi, esi                         ;  //ESI清零
0050222C  |.  33FF          xor     edi, edi                         ;  //EDI清零
0050222E  |.  85ED          test    ebp, ebp                         ;  //用户名是否为空
00502230  |.  76 21         jbe     short 00502253                   ;  //为空则跳
00502232  |>  8A0417        /mov     al, byte ptr [edi+edx]          ;  //循环二交换后的用户名ASCII值依次送给AL
00502235  |.  8A8E 9A087300 |mov     cl, byte ptr [esi+73089A]       ;  //依次取固定值送给CL,第11位固定值开始取值
0050223B  |.  32C8          |xor     cl, al                          ;  //固定值与ASCII值异或运算
0050223D  |.  46            |inc     esi                             ;  //ESI+1,用来比较是否到了第5位,(第二轮较换)
0050223E  |.  880C17        |mov     byte ptr [edi+edx], cl
00502241  |.  8886 99087300 |mov     byte ptr [esi+730899], al       ;  //这两行代码交换值
00502247  |.  83FE 05       |cmp     esi, 5                          ;  //ESI与5比较
0050224A  |.  75 02         |jnz     short 0050224E                  ;  //不等则跳,
0050224C  |.  33F6          |xor     esi, esi                        ;  //若相等则ESI清零,进行第二轮交换
0050224E  |>  47            |inc     edi                             ;  //EDI+1
0050224F  |.  3BFD          |cmp     edi, ebp                        ;  //标志位与用户名长度比较,
00502251  |.^ 72 DF         \jb      short 00502232                  ;  //此循环(循环3)功能同循环1,从固定值的第11位开始替换
00502253  |>  33FF          xor     edi, edi                         ;  //EDI清零
00502255  |.  33C9          xor     ecx, ecx                         ;  //ECX清零
00502257  |.  85ED          test    ebp, ebp                         ;  //用户名是否为空
00502259  |.  76 26         jbe     short 00502281                   ;  //为空则跳
0050225B  |>  8A9F 9F087300 /mov     bl, byte ptr [edi+73089F]       ;  //依次取固定值送给BL,从固定值第16位开始取值
00502261  |.  8BF5          |mov     esi, ebp                        ;  //用户名长度送给ESI
00502263  |.  2BF1          |sub     esi, ecx                        ;  //ESI-EBP,EBP初始值为零
00502265  |.  4E            |dec     esi                             ;  //再-1,这三行代码用来从倒数第一位依次往前取值
00502266  |.  8A0416        |mov     al, byte ptr [esi+edx]          ;  //依次取循环3后的用户名ASCII值送给AL,从后往前取值
00502269  |.  32D8          |xor     bl, al                          ;  //ASCII值与固定值异或运算
0050226B  |.  47            |inc     edi                             ;  //EDI+1,用于比较是否到了第五位以便进行第二轮交换
0050226C  |.  881C16        |mov     byte ptr [esi+edx], bl
0050226F  |.  8887 9E087300 |mov     byte ptr [edi+73089E], al       ;  //这两行代码进行值的交换
00502275  |.  83FF 05       |cmp     edi, 5                          ;  //EDI与5比较,
00502278  |.  75 02         |jnz     short 0050227C                  ;  //不等则跳,
0050227A  |.  33FF          |xor     edi, edi                        ;  //若相等则EDI清零,进行第二轮交换
0050227C  |>  41            |inc     ecx                             ;  //ECX+1
0050227D  |.  3BCD          |cmp     ecx, ebp                        ;  //与长度比较
0050227F  |.^ 72 DA         \jb      short 0050225B                  ;  //此循环(循环4)功能同循环2,从固定值第16位开始交换
00502281  |>  8B7C24 18     mov     edi, dword ptr [esp+18]          ;  //堆栈地址F5A0送给EDI
00502285  |.  33C0          xor     eax, eax                         ;  //EAX清零
00502287  |.  85ED          test    ebp, ebp                         ;  //较验用户名是否为空
00502289  |.  C707 00000000 mov     dword ptr [edi], 0               ;  //堆栈清零,用于存储4次循环后的 前4位值的 累加值
0050228F  |.  76 17         jbe     short 005022A8                   ;  //为空则跳
00502291  |>  8BC8          /mov     ecx, eax                        ;  //ECX=EAX(标志位)
00502293  |.  83E1 03       |and     ecx, 3                          ;  // ECX AND 3,(4位一循环)
00502296  |.  8A1C39        |mov     bl, byte ptr [ecx+edi]          ;  //依次送每一位累加值给BL
00502299  |.  8D3439        |lea     esi, dword ptr [ecx+edi]        ;  //存储地址送给ESI
0050229C  |.  8A0C10        |mov     cl, byte ptr [eax+edx]          ;  //依次取用户名4次循环交换后的值给CL
0050229F  |.  02D9          |add     bl, cl                          ;  //累加
005022A1  |.  40            |inc     eax                             ;  //EAX+1,用于取下一位
005022A2  |.  3BC5          |cmp     eax, ebp                        ;  //与用户名比较
005022A4  |.  881E          |mov     byte ptr [esi], bl              ;  //相加值送入堆栈中
005022A6  |.^ 72 E9         \jb      short 00502291                  ;  //未完继续(4位一循环,对前面几次循环的值进行累加)
005022A8  |>  5F            pop     edi
005022A9  |.  5E            pop     esi
005022AA  |.  5D            pop     ebp
005022AB  |.  5B            pop     ebx
005022AC  \.  C3            retn

三、由00566C02  call    00592283  ;  //注册码转换为十六进制值函数
00592283  /$  53            push    ebx                              ;  //这个函数用于将注册码转换为十六进制值
00592284  |.  55            push    ebp
00592285  |.  56            push    esi
00592286  |.  57            push    edi
00592287  |.  8B7C24 14     mov     edi, dword ptr [esp+14]          ;  //注册码送给EDI
0059228B  |>  833D 8C727100>/cmp     dword ptr [71728C], 1           ;  //[71728C]中的值(初值为1)与1比较
00592292  |.  7E 0F         |jle     short 005922A3                  ;  //小于等于则跳
00592294  |.  0FB607        |movzx   eax, byte ptr [edi]
00592297  |.  6A 08         |push    8
00592299  |.  50            |push    eax
0059229A  |.  E8 7C240000   |call    0059471B
0059229F  |.  59            |pop     ecx
005922A0  |.  59            |pop     ecx
005922A1  |.  EB 0F         |jmp     short 005922B2
005922A3  |>  0FB607        |movzx   eax, byte ptr [edi]             ;  //依次取注册码ASCII值送给EAX
005922A6  |.  8B0D 80707100 |mov     ecx, dword ptr [717080]         ;  //[717080]中的值(字符表地址)送给ECX
005922AC  |.  8A0441        |mov     al, byte ptr [ecx+eax*2]        ;  //取字符表中的值送给AL
005922AF  |.  83E0 08       |and     eax, 8                          ;  //EAX AND 8(无效地址:709C-90A4、70CA)
005922B2  |>  85C0          |test    eax, eax                        ;  //是否为空(无效ASCII值为9-D、20)
005922B4  |.  74 03         |je      short 005922B9                  ;  //为空则跳(只要第一个为有效字符就跳出循环,否则清除)
005922B6  |.  47            |inc     edi                             ;  //取下一位
005922B7  |.^ EB D2         \jmp     short 0059228B                  ;  //这一个循环是较验注册码字符的有效性,把开始处的无效字符清除
005922B9  |>  0FB637        movzx   esi, byte ptr [edi]              ;  //取注册码第一位ASCII值送给ESI
005922BC  |.  47            inc     edi                              ;  //EDI加1
005922BD  |.  83FE 2D       cmp     esi, 2D                          ;  //ASCII值与2D(-)比较
005922C0  |.  8BEE          mov     ebp, esi                         ;  //ASCII值送给EBP
005922C2  |.  74 05         je      short 005922C9                   ;  //相等则跳
005922C4  |.  83FE 2B       cmp     esi, 2B                          ;  //ASCII值与2B(+)比较
005922C7  |.  75 04         jnz     short 005922CD                   ;  //不等则跳
005922C9  |>  0FB637        movzx   esi, byte ptr [edi]              ;  //若相等,则ASCII值送给ESI
005922CC  |.  47            inc     edi                              ;  //EDI+1,取下一位
005922CD  |>  33DB          xor     ebx, ebx                         ;  //不为(+)号跳来此处,EBX清零
005922CF  |>  833D 8C727100>/cmp     dword ptr [71728C], 1           ;  //[71728C]中的值(初值为1)与1比较
005922D6  |.  7E 0C         |jle     short 005922E4                  ;  //小于等于则跳
005922D8  |.  6A 04         |push    4
005922DA  |.  56            |push    esi
005922DB  |.  E8 3B240000   |call    0059471B
005922E0  |.  59            |pop     ecx
005922E1  |.  59            |pop     ecx
005922E2  |.  EB 0B         |jmp     short 005922EF
005922E4  |>  A1 80707100   |mov     eax, dword ptr [717080]         ;  //[717080]中的值(固定值)送给EAX
005922E9  |.  8A0470        |mov     al, byte ptr [eax+esi*2]        ;  //字符表中的值送给AL
005922EC  |.  83E0 04       |and     eax, 4                          ;  //EAX AND 4(有效字符表:70EA-70FC)
005922EF  |>  85C0          |test    eax, eax                        ;  //是否为空(有效ASCII值:30-39,说明注册码必为数字)
005922F1  |.  74 0D         |je      short 00592300                  ;  //为空则跳,跳了就挂了
005922F3  |.  8D049B        |lea     eax, dword ptr [ebx+ebx*4]      ;  //EAX=EBX*5(EBX初始值为0)
005922F6  |.  8D5C46 D0     |lea     ebx, dword ptr [esi+eax*2-30]   ;  //EBX=ESI+EAX*2-30  (ESI为注册码的ASCII值)
005922FA  |.  0FB637        |movzx   esi, byte ptr [edi]             ;  //注册码ASCII值送给ESI
005922FD  |.  47            |inc     edi                             ;  //EDI+1,取下一位注册码
005922FE  |.^ EB CF         \jmp     short 005922CF                  ;  //字符串有效性较验的循环
00592300  |>  83FD 2D       cmp     ebp, 2D                          ;  //ASCII值与2D(-)比较
00592303  |.  8BC3          mov     eax, ebx                         ;  //EAX=EBX=0
00592305  |.  75 02         jnz     short 00592309                   ;  //不等则跳
00592307  |.  F7D8          neg     eax                              ;  //若相等则EAX取补,为FFFFFFFF
00592309  |>  5F            pop     edi
0059230A  |.  5E            pop     esi
0059230B  |.  5D            pop     ebp
0059230C  |.  5B            pop     ebx
0059230D  \.  C3            retn

四、软件运用到的几个表:

(1)、字符有效性较验用到的表:

0071708A  20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00   . . . . . . . .
0071709A  20 00 28 00 28 00 28 00 28 00 28 00 20 00 20 00   .(.(.(.(.(. . .
007170AA  20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00   . . . . . . . .
007170BA  20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00   . . . . . . . .
007170CA  48 00 10 00 10 00 10 00 10 00 10 00 10 00 10 00  H........
007170DA  10 00 10 00 10 00 10 00 10 00 10 00 10 00 10 00  ........
007170EA  84 00 84 00 84 00 84 00 84 00 84 00 84 00 84 00  ????????
007170FA  84 00 84 00 10 00 10 00 10 00 10 00 10 00 10 00  ??......
0071710A  10 00 81 00 81 00 81 00 81 00 81 00 81 00 01 00  .??????.
0071711A  01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00  ........
0071712A  01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00  ........
0071713A  01 00 01 00 01 00 10 00 10 00 10 00 10 00 10 00  ........
0071714A  10 00 82 00 82 00 82 00 82 00 82 00 82 00 02 00  .??????.
0071715A  02 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00  ........
0071716A  02 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00  ........
0071717A  02 00 02 00 02 00 10 00 10 00 10 00 10 00 20 00  ....... .

(2)、用户名循环计算时用到的表:(4个循环,每个循环用到5个数值)

00708A18  AA 89 C4 FE 46 78 F0 D0 03 E7 F7 FD F4 E7 B9 B5  宁Fx鹦琪绻
00708A28  1B C9 50 73                                      s.


五、算法总结:

1、循环1:

依次取用户名ASCII值与密码表1-5位(AA 89 C4 FE 46 )对应值进行异或,异或后的值替换用户名的ASCII值,同时用户名的ASCII值替换对应位置的固定值,每五位一次循环,直

到用户名计算完。

2、循环2:

依次取循环1计算后的用户名值(从倒数第一位开始依次往前取)与密码表第6-10位(78 F0 D0 03 E7)对应值进行异或,异或后的值替换用户名值,用户名值替换对应位置的固定

值,每五位一次循环,直到用户名计算完。

3、循环3:

依次取循环2计算后的用户名值与密码表第11-15位(F7 FD F4 E7 B9)对应值进行异或,异或后的值替换用户名值,用户名值替换对应位置的固定值,每五位一次循环,直到用户

名计算完。

4、循环4:

依次取循环3计算后的用户名值(从倒数第一位开始依次往前取)与密码表第16-20位(B5 1B C9 50 73)对应值进行异或,异或后的值替换用户名值,用户名值替换对应位置的固

定值,每五位一次循环,直到用户名计算完。

5、循环5

依次取循环4计算后用户名值进行累加,1、5、9、13、……位相加作为累加值的第一位;2、6、10、14、……位相加作为累加值第二位;3、7、11、15、……位相加作为累加值的

第3位;4、8、12、16、……位相加作为累加值的第4位;(每4位一循环);累加值作为一个数值(从高到低排),计作A1。A1转换为十进数就是真码!

6、关键比较:注册码转换为十六进制值记作Y; A1==Y 则注册成功,否则注册失败!

六:注册机源码(代码写的太土了,各位大侠不要见笑)复制内容到剪贴板代码:
void C测试Dlg::OnBnClickedOk()
{
        CString Yhm,Zcm,ZcmTemp;                          //定义用户名、注册码字符串
        _int64 ZcmInt1 = 0;                           //定义大整数
        CString str1,str2,str3,str4;              //定义4个字符串,用来将循环5中的4个值转换为16进制字符串
        int biao1[5] = {0xAA,0x89,0xC4,0xFE,0x46};//密码表1
        int biao2[5] = {0x78,0xF0,0xD0,0x03,0xE7};//密码表2
        int biao3[5] = {0xF7,0xFD,0xF4,0xE7,0xB9};//密码表3
        int biao4[5] = {0xB5,0x1B,0xC9,0x50,0x73};//密码表4
        int YhmLength = 0;                        //定义用户名长度
        int YhmAscii[100] = {0};                  //定义用户名ASCII值表,长度100,
        GetDlgItemText(IDC_EDIT1,Yhm);            //从输入框1中获取输入的用户名
        YhmLength = Yhm.GetLength();              //取用户名长度
        if (YhmLength<1)                          //若用户名长度小于1,则提示,
        {
                MessageBox("请输入用户名!");
                return;
        }
        if (YhmLength>99)                         //若用户名长度大于99,则超出用户名ASCII值表,提示,
        {
                MessageBox("你的用户名不用这么长吧?");
                return;
        }

        for (int i = 0;i<YhmLength;i++)           //循环将用户名转换为ASCII值,存入用户名ASCII值表中
        {
                YhmAscii[i] = (int)Yhm[i];
        }


        for (int i = 0;i < YhmLength;i++)        //循环1
        {
                int temp = YhmAscii[i];
                YhmAscii[i] = biao1[i%5]^YhmAscii[i];
                YhmAscii[i] = LOBYTE(YhmAscii[i]);
                biao1[i%5] = temp;
        }

        for (int i = YhmLength;i>0;i--)           //循环2
        {
                int temp = YhmAscii[i-1];
                YhmAscii[i-1] = biao2[(YhmLength-i)%5]^YhmAscii[i-1];
                YhmAscii[i-1] = LOBYTE(YhmAscii[i-1]);
                biao2[(YhmLength-i)%5] = temp;
        }

        for (int i = 0;i < YhmLength;i++)        //循环3
        {
                int temp = YhmAscii[i];
                YhmAscii[i] = biao3[i%5]^YhmAscii[i];
                YhmAscii[i] = LOBYTE(YhmAscii[i]);
                biao3[i%5] = temp;
        }

        for (int i = YhmLength;i>0;i--)           //循环4
        {
                int temp = YhmAscii[i-1];
                YhmAscii[i-1] = biao4[(YhmLength-i)%5]^YhmAscii[i-1];
                YhmAscii[i-1] = LOBYTE(YhmAscii[i-1]);
                biao4[(YhmLength-i)%5] = temp;
        }

        int YhmAscii2[4] = {0};                   //定义一个4位的整数数组,用于存储累加值
        for (int i = 0;i<YhmLength;i++)           //循环5
        {
                YhmAscii2[i%4] = YhmAscii2[i%4] + YhmAscii[i];
                YhmAscii2[i%4] = LOBYTE(YhmAscii2[i%4]);
        }

        str1.Format("%.2x",YhmAscii2[0]);
        str2.Format("%.2x",YhmAscii2[1]);
        str3.Format("%.2x",YhmAscii2[2]);
        str4.Format("%.2x",YhmAscii2[3]);

        ZcmTemp = str4 + str3 + str2 + str1;      //从高位到低位拼接字符串
        ZcmInt1 = strtoul(ZcmTemp, NULL, 16);               //将16进制字符串转换为大整数
        
        Zcm.Format("%I64d",ZcmInt1);

        SetDlgItemText(IDC_EDIT2,Zcm);            //输出注册码

}