【破文标题】Knight's Crackme#1破解分析
【破文作者】逍遥风
【破解工具】OD 计算器
【破解平台】WINXP
【软件名称】Knight's Crackme#1
【软件大小】14K
【原版下载】http://www.crackmes.de/users/knight/knights_crackme1/
【保护方式】UPX
【软件简介】My first crackme :)
Don't know what to say more. Get it and see everything on your own."
Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows
Language: C/C++
----------------------------------------------------------------------
很简单的UPX壳,脱壳后再用0D载入
任意输入注册信息
注册名:lovetc
注册码:1234567
断点很好下就不多说了
----------------------------------------------------------------------
根据错误提示来到这里:
0040111C FF15 B0504000 call dword ptr [<&USER32.GetWindowT>; 取注册名位数。
00401122 BB F3030000 mov ebx, 3F3
00401127 8945 FC mov dword ptr [ebp-4], eax ; 储存注册名的位数
0040112A 53 push ebx
0040112B FF75 08 push dword ptr [ebp+8]
0040112E FFD6 call esi
00401130 50 push eax
00401131 FF15 B0504000 call dword ptr [<&USER32.GetWindowT>; 取输入的注册码的位数
00401137 8BF0 mov esi, eax ; 使ESI=EAX,即保存输入的注册码的位数
00401139 8B45 FC mov eax, dword ptr [ebp-4] ; 使EAX等于注册名的位数
0040113C 85C0 test eax, eax ; 检验是否输入了注册名
0040113E 0F84 26010000 je 0040126A ; 没有输入注册名就跳向失败
00401144 85F6 test esi, esi ; 检验是否输入了注册码
00401146 0F84 1E010000 je 0040126A ; 没有输入注册码就跳向失败
0040114C 83F8 05 cmp eax, 5 ; 注册名位数与5比较
0040114F 7D 11 jge short 00401162 ; 注册名小于5位就出现错误提示
----------------------------------------------------------------------
004011A6 56 push esi ; 来到这里
004011A7 E8 E4010000 call 00401390 ; 对注册码格式的处理(跟进)
004011AC 84C0 test al, al
004011AE 0F84 8F000000 je 00401243
004011B4 8066 04 00 and byte ptr [esi+4], 0
004011B8 8066 09 00 and byte ptr [esi+9], 0
----------------------------------------------------------------------跟进“对注册码格式的处理”的那个CALL
004013B4 8B7D 08 mov edi, dword ptr [ebp+8] ; 取出输入的注册码
004013B7 0FB647 04 movzx eax, byte ptr [edi+4] ; 取输入的注册码的第5位
004013BB F6D0 not al
004013BD C1E0 04 shl eax, 4
004013C0 0AC4 or al, ah
004013C2 3A47 09 cmp al, byte ptr [edi+9] ; 检查注册码的第5位和第10位是否相等
004013C5 75 4A jnz short 00401411
004013C7 0FB647 09 movzx eax, byte ptr [edi+9] ; 取注册码的第10位
004013CB F6D0 not al
004013CD C1E0 04 shl eax, 4
004013D0 0AC4 or al, ah
004013D2 3A47 04 cmp al, byte ptr [edi+4] ; 检查注册码的第5位和第10位是否相等
004013D5 75 3A jnz short 00401411
004013D7 B9 03000000 mov ecx, 3 ; 使ECX等于3
004013DC 8B75 08 mov esi, dword ptr [ebp+8] ; 使ESI等于输入的注册码
004013DF 33DB xor ebx, ebx ; EBX清零
004013E1 BA 04000000 mov edx, 4 ; 使EDX等于4
004013E6 8A06 mov al, byte ptr [esi] ; 取注册码的第一位
004013E8 3C 30 cmp al, 30
004013EA 7C 25 jl short 00401411
004013EC 3C 46 cmp al, 46
004013EE 7F 21 jg short 00401411
004013F0 3C 39 cmp al, 39
004013F2 7E 04 jle short 004013F8
004013F4 3C 41 cmp al, 41
004013F6 7C 19 jl short 00401411
004013F8 46 inc esi ; 每计算一次ESI+1(即取下一位)
004013F9 4A dec edx ; 每计算一次EDX-1
004013FA ^ 75 EA jnz short 004013E6 ; 循环计算
004013FC 021E add bl, byte ptr [esi] ; 注册码的第10位和第5位相加
004013FE 46 inc esi
004013FF ^ E2 E0 loopd short 004013E1
00401401 83C3 24 add ebx, 24
00401404 81CB 81000000 or ebx, 81
0040140A FEC3 inc bl
0040140C 0F94C0 sete al
0040140F EB 02 jmp short 00401413
00401411 33C0 xor eax, eax
00401413 8945 FC mov dword ptr [ebp-4], eax
00401416 61 popad
00401417 8B45 FC mov eax, dword ptr [ebp-4]
0040141A C9 leave
0040141B C2 0400 retn 4
从这段代码可以得知:注册码必须为14位,第5位和第10位必须是“-”
所以:将注册码改为1234-5678-6789。
---------------------------------------------------------------------通过了格式验证后来到这里:
004011BC 56 push esi
004011BD E8 10FFFFFF call 004010D2 ; 取注册码的第一部分
004011C2 8BF8 mov edi, eax ; 使EDI等于注册码的第一部分(前四位)
004011C4 8D46 05 lea eax, dword ptr [esi+5] ; 使EAX等于注册码的第2部分(中间四位)
004011C7 50 push eax
004011C8 897D E8 mov dword ptr [ebp-18], edi ; 储存注册码的第1部分
004011CB E8 02FFFFFF call 004010D2 ; 取注册码的第二部分
004011D0 8BD8 mov ebx, eax ; 使EBX等于注册码的第2部分
004011D2 8D46 0A lea eax, dword ptr [esi+A] ; 使EAX等于注册码的第3部分(最后四位)
004011D5 50 push eax
004011D6 895D EC mov dword ptr [ebp-14], ebx ; 储存注册码的第2部分
004011D9 E8 F4FEFFFF call 004010D2 ; 取注册码的第三部分
004011DE B9 00100000 mov ecx, 1000 ; 使ECX等于0x1000
004011E3 83C4 0C add esp, 0C
004011E6 3BF9 cmp edi, ecx ; 注册码的前4位与0x1000相比较
004011E8 8945 F0 mov dword ptr [ebp-10], eax ; 储存注册码的第3部分
004011EB 7C 56 jl short 00401243 ; 注册码的第一部分要大于1000
004011ED 3BD9 cmp ebx, ecx ; 比较注册码的第2部分
004011EF 7C 52 jl short 00401243 ; 注册码的第二部分要大于1000
004011F1 3BC1 cmp eax, ecx ; 比较注册码的第3部分
004011F3 7C 4E jl short 00401243 ; 注册码的第三部分要大于1000
004011F5 3BFB cmp edi, ebx ; 注册码的第一部分与第二部分比较
004011F7 7E 4A jle short 00401243 ; 注册码的第1部分必须大于第2部分
004011F9 3BF8 cmp edi, eax ; 注册码的第一部分与第三部分比较
004011FB 7E 46 jle short 00401243 ; 注册码的第1部分必须大于第3部分
004011FD 3BD8 cmp ebx, eax ; 注册码的第二部分与第三部分比较
004011FF 7E 42 jle short 00401243 ; 注册码的第2部分必须大于第3部分
00401201 FF75 FC push dword ptr [ebp-4] ; 取输入的注册名
00401204 E8 87FEFFFF call 00401090 ; 对注册名的处理(跟进)
这段代码要求注册码的3部分满足:第一部分大于第二部分大于第三部分
所以根据要求将注册码改为:6789-5678-1234
----------------------------------------------------------------------
跟进对注册名处理的CALL。
00401090 53 push ebx ; 来到这里
00401091 56 push esi
00401092 57 push edi
00401093 8B7C24 10 mov edi, dword ptr [esp+10] ; 使EDI等于注册名
00401097 57 push edi
00401098 33DB xor ebx, ebx ; EBX清零
0040109A E8 81030000 call 00401420 ; 取注册名的位数
0040109F 33F6 xor esi, esi ; ESI清零
004010A1 59 pop ecx ; ECX等于注册名
004010A2 85C0 test eax, eax
004010A4 7E 26 jle short 004010CC
004010A6 0FBE143E movsx edx, byte ptr [esi+edi] ; 取注册名每一位的ASCII码
004010AA 8BCA mov ecx, edx ; 使ECX=EDX
004010AC 81F2 AA000000 xor edx, 0AA ; 注册名每一位的ASCII码与0AA做XOR运算(结果设为B)
004010B2 C1F9 04 sar ecx, 4 ; 注册名每一位的ASCII码右移(结果设为C)
004010B5 0FAFD1 imul edx, ecx ; 将两个处理的结果相乘(结果设为D)B*C=D
004010B8 0FAFD1 imul edx, ecx ; 将D再与C相乘得到E(D*C=E)
004010BB 8BCE mov ecx, esi
004010BD 83E1 01 and ecx, 1
004010C0 C1E1 02 shl ecx, 2
004010C3 D3E2 shl edx, cl
004010C5 03DA add ebx, edx ; 将每一步得到的E相加得到En
004010C7 46 inc esi ; 每计算一次ESI+1
004010C8 3BF0 cmp esi, eax ; 计算完了吗?
004010CA ^ 7C DA jl short 004010A6 ; 继续循环计算
004010CC 5F pop edi
004010CD 8BC3 mov eax, ebx ; 使EAX等于En
通过一系列计算得到En
例如:lovetc所计算出的En等于5C1B2。
----------------------------------------------------------------------
返回到这里:
0040120B 8D45 E8 lea eax, dword ptr [ebp-18] ; 储存计算后的结果En
0040120E 57 push edi
0040120F 6A 02 push 2
00401211 6A 00 push 0
00401213 50 push eax
00401214 E8 09FEFFFF call 00401022 ; 关键CALL,跟进
00401219 83C4 14 add esp, 14
0040121C 84C0 test al, al
0040121E 74 23 je short 00401243
00401220 57 push edi ; EDI等于En
00401221 6A 02 push 2
00401223 8D45 EC lea eax, dword ptr [ebp-14]
00401226 6A 00 push 0
00401228 50 push eax
00401229 E8 F4FDFFFF call 00401022 ; 关键CALL,跟进
0040122E 83C4 10 add esp, 10
00401231 84C0 test al, al
00401233 74 0E je short 00401243
00401235 6A 00 push 0
00401237 68 A8604000 push 004060A8 ; success
0040123C 68 6C604000 push 0040606C ; congratulations, you did it.\nnow write keygen and tutorial.
00401241 EB 0C jmp short 0040124F
00401243 6A 00 push 0
00401245 68 64604000 push 00406064 ; haha
0040124A 68 54604000 push 00406054 ; get lost looser
----------------------------------------------------------------------
来到关键CALL
00401022 55 push ebp
00401023 8BEC mov ebp, esp
00401025 51 push ecx
00401026 51 push ecx
00401027 8B55 14 mov edx, dword ptr [ebp+14]
0040102A 56 push esi
0040102B 8B75 08 mov esi, dword ptr [ebp+8]
0040102E 57 push edi
0040102F 52 push edx
00401030 8955 F8 mov dword ptr [ebp-8], edx
00401033 FF75 10 push dword ptr [ebp+10]
00401036 56 push esi
00401037 E8 C4FFFFFF call 00401000
0040103C 83C4 0C add esp, 0C
0040103F 84C0 test al, al
00401041 75 49 jnz short 0040108C
00401043 8B45 0C mov eax, dword ptr [ebp+C]
00401046 3B45 10 cmp eax, dword ptr [ebp+10]
00401049 74 3B je short 00401086
0040104B 8B3C86 mov edi, dword ptr [esi+eax*4]
0040104E 8D48 01 lea ecx, dword ptr [eax+1]
00401051 894D 0C mov dword ptr [ebp+C], ecx
00401054 8BF7 mov esi, edi
00401056 33C9 xor ecx, ecx
00401058 8955 14 mov dword ptr [ebp+14], edx
0040105B F7DE neg esi
0040105D 8B45 14 mov eax, dword ptr [ebp+14]
00401060 0175 14 add dword ptr [ebp+14], esi
00401063 50 push eax
00401064 03CF add ecx, edi
00401066 FF75 10 push dword ptr [ebp+10]
00401069 894D FC mov dword ptr [ebp-4], ecx
0040106C FF75 0C push dword ptr [ebp+C]
0040106F FF75 08 push dword ptr [ebp+8]
00401072 E8 ABFFFFFF call 00401022
00401077 83C4 10 add esp, 10
0040107A 84C0 test al, al
0040107C 75 0E jnz short 0040108C
0040107E 8B4D FC mov ecx, dword ptr [ebp-4]
00401081 3B4D F8 cmp ecx, dword ptr [ebp-8]
00401084 ^ 7C D7 jl short 0040105D
00401086 32C0 xor al, al
00401088 5F pop edi
00401089 5E pop esi
0040108A C9 leave
0040108B C3 retn
关键CALL的作用就是用
对En和输入的注册码第一部分进行取余计算:例:5C1B2 % 6789。
得到的结果作为注册码第2部分
再用:En和上一步计算的结果进行取余计算:结果作为注册码第三部分。
但是注册码的三部分必须满足1>2>3,且3部分都要大于1000
所以关键就是要找到一个合适的四位数作为注册码的第1部分。
例如:8000。
首先:5C1B2 % 8000=41b2
然后:5C1B2 % 41b2=1c66
所以注册名lovetc对应的
注册码就是8000-41b2-1c66
--------------------------------------------------------------------
整个过程比较简单,问题的关键就是找到一个合适4位字符作为注册码的第一部分。
找那个合适的数很是麻烦,最后为了方便起见
注册码是用后来找到的KEYGEN计算出来的(见谅)
---------------------------------------------------------------------
【版权声明】本文只为交流,转载清保留作者及文章完整性
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: