网络断魂 发表于 2008-3-18 00:24

Xnview v1.93.1 算法分析 + 注册机源码

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

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

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

005021B0 /$ 8B5424 04   mov   edx, dword ptr       ; //用户名送给EDX
005021B4 |. 53      pushebx
005021B5 |. 55      pushebp
005021B6 |. 56      pushesi
005021B7 |. 57      pushedi
005021B8 |. 8BFA   mov   edi, edx             ; //用户名送给EDI
005021BA |. 83C9 FF    or   ecx, FFFFFFFF          ; //ECX=FFFFFFFF
005021BD |. 33C0   xor   eax, eax             ; //EAX清零(用于搜索用户名中是否有0)
005021BF |. F2:AE   repnescas byte ptr es:      ; //循环搜索字符
005021C1 |. F7D1   not   ecx               ; //ECX取反,得出(用户名长度+1)的值
005021C3 |. 49      dec   ecx               ; //ECX-1,得到用户名长度
005021C4 |. BE 188A7000mov   esi, 00708A18          ; //ESI=00708A18
005021C9 |. 8BE9   mov   ebp, ecx             ; //用户名长度送给EBP
005021CB |. B9 05000000mov   ecx, 5            ; //ECX=5
005021D0 |. BF 90087300mov   edi, 00730890          ; //EDI=00730890
005021D5 |. F3:A5   rep   movs dword ptr es:, dword p>; //00708A18中的内容(密码表)送给00730890地址中
005021D7 |. 8BF0   mov   esi, eax             ; //ESI=EAX=0
005021D9 |. 74 21   je   short 005021FC
005021DB |> 8A0C16    /mov   cl, byte ptr    ; //依次送用户名的ASCII值给CL
005021DE |. 8AD9   |mov   bl, cl             ; //ASCII值送给BL
005021E0 |. 3298 90087300 |xor   bl, byte ptr     ; //ASCII值与相应位数上的固定值异或运算
005021E6 |. 40      |inc   eax               ; //EAX+1,用于比较是否到第五位
005021E7 |. 83F8 05    |cmp   eax, 5             ; //EAX与5比较,(看来第5位是特殊)
005021EA |. 881C16    |mov   byte ptr , bl   ; //异或值替换ASCII值
005021ED |. 8888 8F087300 |mov   byte ptr , 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   testebp, ebp             ; //较验用户名长度是否为空
00502202 |. 76 26   jbe   short 0050222A          ; //为空则跳(标志小于等于0则跳)
00502204 |> 8A9F 95087300 /mov   bl, byte ptr     ; //依次取固定值给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    ; //第一次循环交换后的用户名倒数第一位开始依次送给AL,
00502212 |. 32D8   |xor   bl, al             ; //与固定值异或运算
00502214 |. 47      |inc   edi               ; //EDI+1,比较是否到了第五位
00502215 |. 881C16    |mov   byte ptr , bl
00502218 |. 8887 94087300 |mov   byte ptr , 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   testebp, ebp             ; //用户名是否为空
00502230 |. 76 21   jbe   short 00502253          ; //为空则跳
00502232 |> 8A0417    /mov   al, byte ptr    ; //循环二交换后的用户名ASCII值依次送给AL
00502235 |. 8A8E 9A087300 |mov   cl, byte ptr     ; //依次取固定值送给CL,第11位固定值开始取值
0050223B |. 32C8   |xor   cl, al             ; //固定值与ASCII值异或运算
0050223D |. 46      |inc   esi               ; //ESI+1,用来比较是否到了第5位,(第二轮较换)
0050223E |. 880C17    |mov   byte ptr , cl
00502241 |. 8886 99087300 |mov   byte ptr , 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   testebp, ebp             ; //用户名是否为空
00502259 |. 76 26   jbe   short 00502281          ; //为空则跳
0050225B |> 8A9F 9F087300 /mov   bl, byte ptr     ; //依次取固定值送给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    ; //依次取循环3后的用户名ASCII值送给AL,从后往前取值
00502269 |. 32D8   |xor   bl, al             ; //ASCII值与固定值异或运算
0050226B |. 47      |inc   edi               ; //EDI+1,用于比较是否到了第五位以便进行第二轮交换
0050226C |. 881C16    |mov   byte ptr , bl
0050226F |. 8887 9E087300 |mov   byte ptr , 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    ; //堆栈地址F5A0送给EDI
00502285 |. 33C0   xor   eax, eax             ; //EAX清零
00502287 |. 85ED   testebp, ebp             ; //较验用户名是否为空
00502289 |. C707 00000000 mov   dword ptr , 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    ; //依次送每一位累加值给BL
00502299 |. 8D3439    |lea   esi, dword ptr     ; //存储地址送给ESI
0050229C |. 8A0C10    |mov   cl, byte ptr    ; //依次取用户名4次循环交换后的值给CL
0050229F |. 02D9   |add   bl, cl             ; //累加
005022A1 |. 40      |inc   eax               ; //EAX+1,用于取下一位
005022A2 |. 3BC5   |cmp   eax, ebp            ; //与用户名比较
005022A4 |. 881E   |mov   byte ptr , 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 call00592283 ; //注册码转换为十六进制值函数
00592283 /$ 53      pushebx               ; //这个函数用于将注册码转换为十六进制值
00592284 |. 55      pushebp
00592285 |. 56      pushesi
00592286 |. 57      pushedi
00592287 |. 8B7C24 14   mov   edi, dword ptr    ; //注册码送给EDI
0059228B |> 833D 8C727100>/cmp   dword ptr , 1      ; //中的值(初值为1)与1比较
00592292 |. 7E 0F   |jle   short 005922A3         ; //小于等于则跳
00592294 |. 0FB607    |movzxeax, byte ptr
00592297 |. 6A 08   |push8
00592299 |. 50      |pusheax
0059229A |. E8 7C240000|call0059471B
0059229F |. 59      |pop   ecx
005922A0 |. 59      |pop   ecx
005922A1 |. EB 0F   |jmp   short 005922B2
005922A3 |> 0FB607    |movzxeax, byte ptr        ; //依次取注册码ASCII值送给EAX
005922A6 |. 8B0D 80707100 |mov   ecx, dword ptr    ; //中的值(字符表地址)送给ECX
005922AC |. 8A0441    |mov   al, byte ptr     ; //取字符表中的值送给AL
005922AF |. 83E0 08    |and   eax, 8             ; //EAX AND 8(无效地址:709C-90A4、70CA)
005922B2 |> 85C0   |testeax, eax            ; //是否为空(无效ASCII值为9-D、20)
005922B4 |. 74 03   |je   short 005922B9         ; //为空则跳(只要第一个为有效字符就跳出循环,否则清除)
005922B6 |. 47      |inc   edi               ; //取下一位
005922B7 |.^ EB D2   \jmp   short 0059228B         ; //这一个循环是较验注册码字符的有效性,把开始处的无效字符清除
005922B9 |> 0FB637    movzxesi, byte ptr        ; //取注册码第一位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    movzxesi, byte ptr        ; //若相等,则ASCII值送给ESI
005922CC |. 47      inc   edi               ; //EDI+1,取下一位
005922CD |> 33DB   xor   ebx, ebx             ; //不为(+)号跳来此处,EBX清零
005922CF |> 833D 8C727100>/cmp   dword ptr , 1      ; //中的值(初值为1)与1比较
005922D6 |. 7E 0C   |jle   short 005922E4         ; //小于等于则跳
005922D8 |. 6A 04   |push4
005922DA |. 56      |pushesi
005922DB |. E8 3B240000|call0059471B
005922E0 |. 59      |pop   ecx
005922E1 |. 59      |pop   ecx
005922E2 |. EB 0B   |jmp   short 005922EF
005922E4 |> A1 80707100|mov   eax, dword ptr    ; //中的值(固定值)送给EAX
005922E9 |. 8A0470    |mov   al, byte ptr     ; //字符表中的值送给AL
005922EC |. 83E0 04    |and   eax, 4             ; //EAX AND 4(有效字符表:70EA-70FC)
005922EF |> 85C0   |testeax, eax            ; //是否为空(有效ASCII值:30-39,说明注册码必为数字)
005922F1 |. 74 0D   |je   short 00592300         ; //为空则跳,跳了就挂了
005922F3 |. 8D049B    |lea   eax, dword ptr    ; //EAX=EBX*5(EBX初始值为0)
005922F6 |. 8D5C46 D0   |lea   ebx, dword ptr ; //EBX=ESI+EAX*2-30 (ESI为注册码的ASCII值)
005922FA |. 0FB637    |movzxesi, byte ptr        ; //注册码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 = {0xAA,0x89,0xC4,0xFE,0x46};//密码表1
    int biao2 = {0x78,0xF0,0xD0,0x03,0xE7};//密码表2
    int biao3 = {0xF7,0xFD,0xF4,0xE7,0xB9};//密码表3
    int biao4 = {0xB5,0x1B,0xC9,0x50,0x73};//密码表4
    int YhmLength = 0;            //定义用户名长度
    int YhmAscii = {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 = (int)Yhm;
    }


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

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

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

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

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

    str1.Format("%.2x",YhmAscii2);
    str2.Format("%.2x",YhmAscii2);
    str3.Format("%.2x",YhmAscii2);
    str4.Format("%.2x",YhmAscii2);

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

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

}

Hmily 发表于 2008-3-18 00:26

辛苦!

网络断魂 发表于 2008-3-18 00:26

引用第1楼Hmily于2008-03-18 00:26发表的 :
辛苦!
都你害的,弄这软件我花了一天多的时间

Squn 发表于 2008-3-18 00:29


.// 我要学算法。。。
.// 5555

Hmily 发表于 2008-3-18 00:31

姐姐找断魂哥哥做动画给你看,挖哈哈!

Fate 发表于 2008-3-18 01:13

註冊機好像很難寫.
偶都寫不出來!~

reding 发表于 2008-3-18 01:39

收下了。

carson 发表于 2008-3-18 02:46

哇,好东东,收下好好学学

hippo 发表于 2008-3-18 10:09

厉害!这个要弄一天时间 佩服

hileesys 发表于 2008-3-18 12:19

感谢!劳动付出!
页: [1] 2 3 4 5
查看完整版本: Xnview v1.93.1 算法分析 + 注册机源码