【文章标题】: 一个利用SEH进行跳转的CrackME分析
【文章作者】: petnt
【作者邮箱】: petnt@sohu.com
【软件名称】: CM06 by Nooby
【下载地址】: 见附件
【保护方式】: 序列号
【使用工具】: OllyIce、计算器、笔、纸
【操作平台】: XpSp2
【软件介绍】: 利用SEH进行跳转,感觉非常不错的一个CrackMe
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
这几天在看有关Armadillo的文章,没想到四处碰壁,对我的目标软件只能敬而远之,可能我的能力还没有达到能研究壳的水平。为了增强对Crack的信心和兴趣,逐步增加自己的技术水平,只好继续CrackMe。没想到碰上这个CrackMe让我有了一种相见恨晚的感觉,从研究作者的思路中让我感觉到了无限的乐趣。分析过程中使我再一次体会到我的“名言”之真:破解是一门艺术,要学会欣赏。行了,不要乱扔东西:-),我们进入正题。
这个CrackMe是传统型的程序,我们可以用各种传统的方法断掉他。可能作者的意图仅仅是展示我们题中所提的想法,所以我遇到的困难并不多。GetWindowTextA下断,很容易找到关键的地方。
0042F627 . 55 push ebp
0042F628 . 8BEC mov ebp, esp
0042F62A . 6A FE push -2
0042F62C . 68 10C34300 push 0043C310
0042F631 . 68 20D34100 push 0041D320 ; 请留意这个地址
0042F636 . 64:A1 0000000>mov eax, fs:[0] ; 安装SEH Handler
0042F63C . 50 push eax
0042F63D . 51 push ecx
;;;;;;;;;;;;;;;;;;;;;此处省略部分内容;;;;;;;;;;;;;;;;;;;;;;;;
0042F6C7 . 8945 98 mov [ebp-68], eax
0042F6CA . 8B45 98 mov eax, [ebp-68]
0042F6CD . 8945 E4 mov [ebp-1C], eax
0042F6D0 . 6A 0A push 0A ; /Arg3 = 0000000A
0042F6D2 . FF75 D0 push dword ptr [ebp-30] ; |Arg2
0042F6D5 . 68 E8030000 push 3E8 ; |Arg1 = 000003E8
0042F6DA . 8B4D 94 mov ecx, [ebp-6C] ; |
0042F6DD . E8 92C1FDFF call 0040B874 ; \CM06.0040B874 获取用户名
0042F6E2 . 8945 C8 mov [ebp-38], eax
0042F6E5 . 6A 1E push 1E ; /Arg3 = 0000001E
0042F6E7 . FF75 D8 push dword ptr [ebp-28] ; |Arg2
0042F6EA . 68 E9030000 push 3E9 ; |Arg1 = 000003E9
0042F6EF . 8B4D 94 mov ecx, [ebp-6C] ; |
0042F6F2 . E8 7DC1FDFF call 0040B874 ; \CM06.0040B874 获取序列号
0042F6F7 . 48 dec eax
0042F6F8 . 48 dec eax
0042F6F9 . 8945 C0 mov [ebp-40], eax
0042F6FC . 8365 FC 00 and dword ptr [ebp-4], 0
0042F700 . 837D C8 04 cmp dword ptr [ebp-38], 4 ; 用户名不能小于4
0042F704 . 7C 0C jl short 0042F712
0042F706 . 837D C0 08 cmp dword ptr [ebp-40], 8
0042F70A . 7C 06 jl short 0042F712 ; 注册码不能 小于10
0042F70C . 8365 90 00 and dword ptr [ebp-70], 0
0042F710 . EB 07 jmp short 0042F719
0042F712 > C745 90 01000>mov dword ptr [ebp-70], 1
0042F719 > 6A 04 push 4
0042F71B . 58 pop eax
0042F71C . 33D2 xor edx, edx
0042F71E . F775 90 div dword ptr [ebp-70] ; 如果用户名,注册码都符合要求,将在此产生异常
0042F721 . 85C0 test eax, eax
0042F723 . 74 14 je short 0042F739
0042F725 . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
0042F727 . 68 70734300 push 00437370 ; |Title = "Error"
0042F72C . 68 78734300 push 00437378 ; |Text = "Username must >= 4 && Key must >= 10"
0042F731 . 6A 00 push 0 ; |hOwner = NULL
0042F733 . FF15 98244300 call [<&USER32.MessageBoxA>] ; \MessageBoxA
0042F739 > C745 FC FEFFF>mov dword ptr [ebp-4], -2
0042F740 . E9 A0020000 jmp 0042F9E5
0042F745 . 33C0 xor eax, eax
0042F747 . 40 inc eax
0042F748 . C3 retn
0042F749 . 8B65 E8 mov esp, [ebp-18] ; 上个异常返回点
0042F74C . 8B45 C0 mov eax, [ebp-40]
0042F74F . 99 cdq
0042F750 . F77D C8 idiv dword ptr [ebp-38]
0042F753 . 8955 C4 mov [ebp-3C], edx
0042F756 . 8365 B4 00 and dword ptr [ebp-4C], 0
0042F75A . EB 07 jmp short 0042F763
0042F75C > 8B45 B4 mov eax, [ebp-4C]
0042F75F . 40 inc eax
0042F760 . 8945 B4 mov [ebp-4C], eax
0042F763 > 8B45 B4 mov eax, [ebp-4C]
0042F766 . 3B45 C8 cmp eax, [ebp-38]
0042F769 . 7D 11 jge short 0042F77C ; 循环
0042F76B . 8B45 D0 mov eax, [ebp-30]
0042F76E . 0345 B4 add eax, [ebp-4C]
0042F771 . 0FBE00 movsx eax, byte ptr [eax]
0042F774 . 0345 DC add eax, [ebp-24]
0042F777 . 8945 DC mov [ebp-24], eax ; 用户名各位 和值
0042F77A .^ EB E0 jmp short 0042F75C
0042F77C > 8365 B0 00 and dword ptr [ebp-50], 0
0042F780 . EB 07 jmp short 0042F789
0042F782 > 8B45 B0 mov eax, [ebp-50]
0042F785 . 40 inc eax
0042F786 . 8945 B0 mov [ebp-50], eax
0042F789 > 8B45 B0 mov eax, [ebp-50]
0042F78C . 3B45 C0 cmp eax, [ebp-40]
0042F78F . 7D 11 jge short 0042F7A2
0042F791 . 8B45 D8 mov eax, [ebp-28]
0042F794 . 0345 B0 add eax, [ebp-50]
0042F797 . 0FBE00 movsx eax, byte ptr [eax]
0042F79A . 0345 BC add eax, [ebp-44]
0042F79D . 8945 BC mov [ebp-44], eax ; 注册码前 n-2 位 和值
0042F7A0 .^ EB E0 jmp short 0042F782
0042F7A2 > 6A 10 push 10 ; /Arg3 = 00000010
0042F7A4 . FF75 E0 push dword ptr [ebp-20] ; |Arg2
0042F7A7 . FF75 DC push dword ptr [ebp-24] ; |Arg1
0042F7AA . E8 50FEFFFF call 0042F5FF ; \CM06.0042F5FF
0042F7AF . 83C4 0C add esp, 0C ; 用户名和值转换成小写字符串
0042F7B2 . 6A 07 push 7
0042F7B4 . 59 pop ecx
0042F7B5 . 8B75 E0 mov esi, [ebp-20]
0042F7B8 . 8B7D E4 mov edi, [ebp-1C]
0042F7BB . F3:A5 rep movs dword ptr es:[edi], dword p>
0042F7BD . 66:A5 movs word ptr es:[edi], word ptr [esi>;
0042F7BF . 6A 10 push 10 ; /Arg3 = 00000010
0042F7C1 . FF75 E0 push dword ptr [ebp-20] ; |Arg2
0042F7C4 . FF75 BC push dword ptr [ebp-44] ; |Arg1
0042F7C7 . E8 33FEFFFF call 0042F5FF ; \CM06.0042F5FF
0042F7CC . 83C4 0C add esp, 0C ; 注册码和值 字符串形式
0042F7CF . 8B45 E0 mov eax, [ebp-20]
0042F7D2 . 8945 8C mov [ebp-74], eax
0042F7D5 . 8B45 8C mov eax, [ebp-74]
0042F7D8 . 8945 88 mov [ebp-78], eax
0042F7DB > 8B45 8C mov eax, [ebp-74]
0042F7DE . 8A00 mov al, [eax]
0042F7E0 . 8845 87 mov [ebp-79], al
0042F7E3 . FF45 8C inc dword ptr [ebp-74]
0042F7E6 . 807D 87 00 cmp byte ptr [ebp-79], 0
0042F7EA .^ 75 EF jnz short 0042F7DB
0042F7EC . 8B45 8C mov eax, [ebp-74]
0042F7EF . 2B45 88 sub eax, [ebp-78]
0042F7F2 . 8B4D 88 mov ecx, [ebp-78]
0042F7F5 . 894D 80 mov [ebp-80], ecx ; 注册码和值字串
0042F7F8 . 8985 7CFFFFFF mov [ebp-84], eax ; 字串长度
0042F7FE . 8B45 E4 mov eax, [ebp-1C]
0042F801 . 48 dec eax
0042F802 . 8985 78FFFFFF mov [ebp-88], eax
0042F808 > 8B85 78FFFFFF mov eax, [ebp-88]
0042F80E . 8A40 01 mov al, [eax+1]
0042F811 . 8885 77FFFFFF mov [ebp-89], al
0042F817 . FF85 78FFFFFF inc dword ptr [ebp-88]
0042F81D . 80BD 77FFFFFF>cmp byte ptr [ebp-89], 0
0042F824 .^ 75 E2 jnz short 0042F808
0042F826 . 8BBD 78FFFFFF mov edi, [ebp-88]
0042F82C . 8B75 80 mov esi, [ebp-80]
0042F82F . 8B85 7CFFFFFF mov eax, [ebp-84]
0042F835 . 8BC8 mov ecx, eax
0042F837 . C1E9 02 shr ecx, 2
0042F83A . F3:A5 rep movs dword ptr es:[edi], dword p>; 合并字串
0042F83C . 8BC8 mov ecx, eax
0042F83E . 83E1 03 and ecx, 3
0042F841 . F3:A4 rep movs byte ptr es:[edi], byte ptr>
0042F843 . 8B45 C0 mov eax, [ebp-40]
0042F846 . 99 cdq
0042F847 . F77D C8 idiv dword ptr [ebp-38]
0042F84A . 8945 D4 mov [ebp-2C], eax ; (Lofsn-2)/LofUser
0042F84D . 8B45 C0 mov eax, [ebp-40]
0042F850 . 2B45 C8 sub eax, [ebp-38]
0042F853 . 8945 B8 mov [ebp-48], eax ; (LofSn-2)-LofUser
0042F856 . 8B45 DC mov eax, [ebp-24] ; HezU
0042F859 . 0FAF45 C0 imul eax, [ebp-40] ; HezU*(LofSn-2)
0042F85D . 8B4D BC mov ecx, [ebp-44] ; HezS
0042F860 . 0FAF4D C8 imul ecx, [ebp-38] ; HezS*LofUser
0042F864 . 03C1 add eax, ecx ; 上两值相加 Num1
0042F866 . 8B4D C0 mov ecx, [ebp-40] ; LofSn-2
0042F869 . 0FAF4D C8 imul ecx, [ebp-38] ; (LofSn-2)*LofUser
0042F86D . 2BC1 sub eax, ecx ; Num1 - 上式结果 Num2
0042F86F . 0345 B8 add eax, [ebp-48] ; Num2+[(LofSn-2)-LofUser]
0042F872 . 8945 B8 mov [ebp-48], eax ; Num3
0042F875 . 8B45 DC mov eax, [ebp-24] ; HezU
0042F878 . 8B4D C0 mov ecx, [ebp-40] ; LofSn-2
0042F87B . D3E0 shl eax, cl ; 左移
0042F87D . 0345 B8 add eax, [ebp-48] ; Num3+移动结果= Num4
0042F880 . 8945 B8 mov [ebp-48], eax ; Num4
0042F883 . 8B45 BC mov eax, [ebp-44] ; HezS
0042F886 . 8B4D C8 mov ecx, [ebp-38] ; LofUser
0042F889 . D3E0 shl eax, cl ; 左移
0042F88B . 0345 B8 add eax, [ebp-48] ; Num4+移动结果=Num5
0042F88E . 8945 B8 mov [ebp-48], eax ; Num5
0042F891 . 8B45 DC mov eax, [ebp-24] ; HezU
0042F894 . 0FAF45 BC imul eax, [ebp-44] ; HezU*HezS
0042F898 . 8B4D B8 mov ecx, [ebp-48]
0042F89B . 2BC8 sub ecx, eax ; Num5-HezS*HezU
0042F89D . 894D B8 mov [ebp-48], ecx ; Num6
0042F8A0 . 8B45 D8 mov eax, [ebp-28]
0042F8A3 . 0345 C0 add eax, [ebp-40]
0042F8A6 . 50 push eax ; 后两位
0042F8A7 . E8 CBCEFEFF call 0041C777 ; 字符串 转 16进制
0042F8AC . 59 pop ecx
0042F8AD . 8B4D B8 mov ecx, [ebp-48]
0042F8B0 . 2BC8 sub ecx, eax ; Num6-十六进制
0042F8B2 . 894D B8 mov [ebp-48], ecx ; Num7
0042F8B5 . 6A 1E push 1E
0042F8B7 . 58 pop eax
0042F8B8 . 2B45 C0 sub eax, [ebp-40] ; 1E-(LofSn-2)
0042F8BB . 50 push eax
0042F8BC . 6A 00 push 0
0042F8BE . 8B45 D8 mov eax, [ebp-28]
0042F8C1 . 0345 C0 add eax, [ebp-40]
0042F8C4 . 50 push eax
0042F8C5 . E8 16D1FEFF call 0041C9E0
0042F8CA . 83C4 0C add esp, 0C
0042F8CD . 8B45 D8 mov eax, [ebp-28]
0042F8D0 . 83C0 05 add eax, 5
0042F8D3 . 50 push eax
0042F8D4 . E8 9ECEFEFF call 0041C777 ; 第6----(LofSn-2) 转16
0042F8D9 . 59 pop ecx
0042F8DA . 8B4D B8 mov ecx, [ebp-48]
0042F8DD . 2BC8 sub ecx, eax ; Num7- 转换结果
0042F8DF . 894D B8 mov [ebp-48], ecx ; Num8
0042F8E2 . 6A 06 push 6
0042F8E4 . 59 pop ecx
0042F8E5 . 33C0 xor eax, eax
0042F8E7 . 8B7D D8 mov edi, [ebp-28]
0042F8EA . 83C7 05 add edi, 5
0042F8ED . F3:AB rep stos dword ptr es:[edi]
0042F8EF . AA stos byte ptr es:[edi]
0042F8F0 . FF75 D8 push dword ptr [ebp-28]
0042F8F3 . E8 7FCEFEFF call 0041C777 ; 前5位
0042F8F8 . 59 pop ecx
0042F8F9 . 8B4D B8 mov ecx, [ebp-48]
0042F8FC . 2BC8 sub ecx, eax ; Num8-前5转换结果
0042F8FE . 894D B8 mov [ebp-48], ecx ; Num9
0042F901 . C745 FC 01000>mov dword ptr [ebp-4], 1
0042F908 . 56 push esi
0042F909 . FF75 B8 push dword ptr [ebp-48] ; /pModule
0042F90C . FF15 84224300 call [<&KERNEL32.GetModuleHandleA>] ; \GetModuleHandleA 假注册码将在此产生异常
0042F912 . 8945 AC mov [ebp-54], eax
0042F915 . 50 push eax
0042F916 . FF75 CC push dword ptr [ebp-34] ; /pOldProtect
0042F919 . 6A 40 push 40 ; |NewProtect = PAGE_EXECUTE_READWRITE
0042F91B . 68 FFFF0200 push 2FFFF ; |Size = 2FFFF (196607.)
0042F920 . FF75 AC push dword ptr [ebp-54] ; |Address
0042F923 . FF15 88224300 call [<&KERNEL32.VirtualProtect>] ; \VirtualProtect
0042F929 . C745 FC FEFFF>mov dword ptr [ebp-4], -2
0042F930 . EB 2C jmp short 0042F95E
0042F932 . 33C0 xor eax, eax
0042F934 . 40 inc eax
0042F935 . C3 retn
0042F936 . 8B65 E8 mov esp, [ebp-18] ; 上次异常返回点
0042F939 . FF75 D0 push dword ptr [ebp-30]
0042F93C . E8 B9C9FEFF call 0041C2FA
0042F941 . 59 pop ecx
0042F942 . FF75 D8 push dword ptr [ebp-28]
0042F945 . E8 B0C9FEFF call 0041C2FA
0042F94A . 59 pop ecx
0042F94B . C745 FC FEFFF>mov dword ptr [ebp-4], -2
0042F952 . E9 A0000000 jmp 0042F9F7 ; 在此跳出返回
好了,在此我们暂停一下。和一般的CrackMe不同,程序在对我们输入的用户名和注册码进行一些变换后,并没有看到我们期待的比较跳转。变换后的数据被作为一个参数传给了API,这不得不引起我们的怀疑,作者的意图是什么呢?假的注册码将在此API上产生异常,异常处理过后,程序又回到了消息循环。
再次审视出现在我们眼前的两个API,GetModuleHandleA,功能是获得某一模块的句柄,VirtualProtect,功能是改变某一内存地址处的保护属性。“某”指的可能是谁呢?当然最有可能的是自己!好了,在 0042F90C 上下断,改最后的变换结果为零(不明白原因的清参考MSDN中关于GetModuleHandle的解释)。继续跟踪:
0042F957 . C745 FC FEFFF>mov dword ptr [ebp-4], -2
0042F95E > C745 FC 02000>mov dword ptr [ebp-4], 2 ; Jmp到这里
0042F965 . 58 pop eax
0042F966 . 05 74F90200 add eax, 2F974
0042F96B . 66:C700 F7F0 mov word ptr [eax], 0F0F7 ; 改变 0042F974处的指令
0042F970 . 8BD8 mov ebx, eax
0042F972 . 58 pop eax
0042F973 . 53 push ebx
0042F974 . 90 nop ; 此处及下面的Nop 被改写成 F7F0 即 div eax
0042F975 . 90 nop ; 程序到这里又会产生异常
0042F976 . C745 FC FEFFF>mov dword ptr [ebp-4], -2
0042F97D . EB 5F jmp short 0042F9DE
0042F97F . 33C0 xor eax, eax
0042F981 . 40 inc eax
0042F982 . C3 retn
0042F983 8B65 E8 mov esp, [ebp-18] ; 上次异常的返回点
0042F986 83EC 04 sub esp, 4
0042F989 58 pop eax
0042F98A 33C9 xor ecx, ecx
0042F98C 83C0 50 add eax, 50
0042F98F 03C8 add ecx, eax
0042F991 B9 06000000 mov ecx, 6
0042F996 8B18 mov ebx, [eax]
0042F998 81F3 3F2F1F0F xor ebx, 0F1F2F3F
0042F99E 8918 mov [eax], ebx
0042F9A0 83C0 04 add eax, 4
0042F9A3 ^ E2 F1 loopd short 0042F996 ; 利用循环解密 42F9C4 - 42F9DC 处指令
0042F9A5 EB 1D jmp short 0042F9C4 ; 跳到我们期待的地方
0042F9A7 B9 06000000 mov ecx, 6
0042F9AC B8 C4F94200 mov eax, 0042F9C4
0042F9B1 8B18 mov ebx, [eax]
0042F9B3 81F3 3F2F1F0F xor ebx, 0F1F2F3F
0042F9B9 8918 mov [eax], ebx
0042F9BB 83C0 04 add eax, 4
0042F9BE ^ E2 F1 loopd short 0042F9B1 ; 利用循环恢复原来指令
0042F9C0 EB 23 jmp short 0042F9E5 ; 跳走返回
0042F9C2 90 nop
0042F9C3 90 nop
;;;;;;;;;;;;;;;;;;;;;;;;;;;解密前;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0042F9C4 55 push ebp
0042F9C5 2F das
0042F9C6 75 0F jnz short 0042F9D7
0042F9C8 57 push edi
0042F9C9 8F ??? ; 未知命令
0042F9CA 6C ins byte ptr es:[edi], dx
0042F9CB 4C dec esp
0042F9CC 3F aas
0042F9CD A4 movs byte ptr es:[edi], byte ptr [esi>
0042F9CE 52 push edx
0042F9CF 9B wait
0042F9D0 D7 xlat byte ptr [ebx+al]
0042F9D1 9E sahf
0042F9D2 6A F2 push -0E
0042F9D4 C0C4 CF rol ah, 0CF
0042F9D7 C8 7AD3E1 enter 0D37A, 0E1
0042F9DB F0:FFFF ??? ; 未知命令
;;;;;;;;;;;;;;;;;;;;;;;;;;;;解密后;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
0042F9C4 6A 00 push 0 ; 解密后跳到这里执行
0042F9C6 6A 00 push 0
0042F9C8 68 A0734300 push 004373A0 ; ASCII "Good job!" 瞧我们发现了什么?
0042F9CD 8B4D 94 mov ecx, [ebp-6C]
0042F9D0 E8 B175FDFF call 00406F86
0042F9D5 ^ EB D0 jmp short 0042F9A7 ; 提示正确后跳到恢复解密处
0042F9D7 C745 FC FEFFFFFF mov dword ptr [ebp-4], -2
0042F9DE C745 FC FEFFFFFF mov dword ptr [ebp-4], -2
0042F9DE C745 FC FEFFFFF>mov dword ptr [ebp-4], -2
0042F9E5 FF75 D0 push dword ptr [ebp-30] ; 正确返回处
0042F9E8 E8 0DC9FEFF call 0041C2FA
0042F9ED 59 pop ecx
0042F9EE FF75 D8 push dword ptr [ebp-28]
0042F9F1 E8 04C9FEFF call 0041C2FA
0042F9F6 59 pop ecx
0042F9F7 8B4D F0 mov ecx, [ebp-10]
0042F9FA 64:890D 0000000>mov fs:[0], ecx ; 恢复SEH链
0042FA01 59 pop ecx
0042FA02 5F pop edi
0042FA03 5E pop esi
0042FA04 5B pop ebx
0042FA05 C9 leave
0042FA06 C3 retn ; 程序返回
至此,我们已经了解了程序的流程及作者的意图,SEH技术我并不是很熟,所以异常处理函数也并未仔细分析,只是粗略的跟踪了一下,估计程序也仅仅是利用它做了几次并不明显的跳转。虽然程序中有几个可疑的Api,如GetTickCount,但并未感觉到anti的存在,可能是OllyICE的插件太强大了:),好了,下面我们分析算法,准备写出注册机。
下面将引用一些符号,其代表意义如下:
HezU = 用户名各位ASCII和值; HezS = 注册码前 n-2位和值(n为注册码长度);LofUser = 用户名长度 ;LofSn = 注册码长度 ;Num1.....Num9 = 中间数
计算过程如下:
Num1=HezU*(LofSn-2)+HezS*LofUser;
Num2=Num1-(LofSn-2)*LofUser;
Num3=Num2+[(LofSn-2)-LofUser];
Num4=Num3+[shl HezU,LofSn-2]
Num5=Num4+[shl HezS,LofUser]
Num6=Num5-HezS*HezU
Num7=Num6-注册码后两位字符转换成十进制
Num8=Num7-注册码中间字符转换成十进制(所谓中间即除去上面的后2和下面的前5)
Num9=Num8-注册码前5位字符转换成十进制
.if Num9=0
注册成功
.else
注册失败
.endif
这是一种将用户名和注册码混合运算再进行结果比较的算法,也就是说程序本身并没有产生正确注册码的过程,他也仅仅是把我们输入的注册码拿来进行了一次实验,结果对了就算成功。您可能马上想到了有效的办法,穷举他。但其长度最少都为10位,我并不想在这个问题上考验计算机的速度,看看有没有其他的办法。
我们测试下他的字符串转换成数字的函数,如果给定的字符串的第一位字符是除了 “+”“-” “0-9” 以外的字符的话,其结果是固定的数字0。好了,有了这个特点,我们重新考虑一下算法过程:如果我们能令转换结果为零,那么只要Num6=0就符合我们的条件了。这将产生重大的意义,因为在用户名已知的条件下,前6个中间数只与HezS和LofSn有关。我们只要假定注册码长度,就可以计算出HezS,在一定的条件下就可以给出注册码。
好了,我们假设注册码长度为10(下面再次简化符号 X = HezS ,L = LofUser,H = HezU):
则:8*H+X*L-8*L+8-L+2^8*H+X*2^L-X*H=0 整理 得出 X=(264*H+8-9*L)/(H-L-2^L)
如果得出的X/8是可显示的ASCII值的话,将得出X平均分配一下,就可得出注册码。但这里有两个问题:第一,平均分配之后,在关键位置上可能为数字或+ -符号。第二,X并不一定是整数。为了解决上面的问题,我们可以把要求提的更苛刻一些。
我们假定注册码的第1、6位为固定的字符,比如P 和 T。我们可以将得出X减去P\ T的ASCII值,在平均到6个位置上,第一个问题得以解决。
关于第二个问题,如果不能整除,Num6中将存有一定的余数,而不是零。我们再看注册码的后两位,这两位并不参与和值运算,所以这两位比较自由一些。呵呵,可能你已经想到了,把余数放到最后两位,不就能解决问题嘛。是的,如果放不下我们还有中间3位。为什么首选这两个位置,因为我们可以大致估计余数的大小,同时也是为了有更大的几率产生注册码。当选择中间3位的时候,我们将不得不在X中再次减去中间三位的ASCII码值,让得到X平均到4为上面。可能您又想到了,平均成小数怎么办,呵呵,我们把余数统一加在第一位就可以了,因为余数很小。
其实,把上面的想法赋予实践您就会发现,10位的注册码会得出很小的X,不足以产生可显示的字符。没关系,我们再看看注册码是11位的情况:
X=(521H+9-10L)/(H-L-2^L)
同样的思想,我们可以发现这回的X足以产生可显示字符了。
下面我们考虑一下极端情况,如果H很小,但L又很大,我们的分母很快就是负数了。如用户名为8个空格时,就会产生负数。如何处理呢?可能您已经嫌我罗嗦了,留下个问题吧。
其实上面的设想和计算过程是很令人享受的一个过程,虽然您看来可能有些乏味。拿着笔在纸上算啊算啊的,最后终于在自己的努力下得出了注册码,不是很享受吗?!有些时候,过程和结果同样很重要。
打住,收工。虽然附带的注册机漏洞百出,但他确实可以算出大部分短用户名的注册码。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2008年01月04日 20:18:39
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)