本人刚学crack,水平十分有限.不足之处,还请大虾多多指教!
由于经常熬夜,今天早上起床喉咙特别不舒服,头晕的厉害,感冒了.外面烈日灼烧,给人一种懒洋洋的状态,但想到"革命尚未成功,同志仍需努力" <^.^ 呵呵~开个玩笑> 于是马上开机,起来搞学习.下载了一个crackme,想分析其算法,搞了一上午,才写下这篇文章.
好了,闲话不多说了.下面切入正题!
查找字符串,根据提示成功信息下断
输入用户名:abcdef 假码:abcdefghij12345678.<为什么写这么长,就要看后面的限制>
运行程序,被断在这里:
004011BD |. 66:A5 movs word ptr es:[edi], word ptr [esi]
004011BF |. 6A 45 push 45 ; /Count = 45 (69.)
004011C1 |. 50 push eax ; |Buffer = 0012F984
004011C2 |. A4 movs byte ptr es:[edi], byte ptr [esi] ; |
004011C3 |. 8B3D A8404000 mov edi, dword ptr [<&USER32.GetDlgIte>; |USER32.GetDlgItemTextA
004011C9 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
004011CE |. 51 push ecx ; |hWnd
004011CF |. FFD7 call edi ; \GetDlgItemTextA
004011D1 |. 8BF0 mov esi, eax
004011D3 |. 85F6 test esi, esi
004011D5 |. 0F84 4B010000 je 00401326
004011DB |. 83FE 40 cmp esi, 40 ; 用户名长度在1-64之间
004011DE |. 0F87 42010000 ja 00401326
004011E4 |. 8B45 08 mov eax, dword ptr [ebp+8]
004011E7 |. 8D55 94 lea edx, dword ptr [ebp-6C]
004011EA |. 6A 13 push 13 ; /Count = 13 (19.)
004011EC |. 52 push edx ; |Buffer
004011ED |. 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)
004011F2 |. 50 push eax ; |hWnd
004011F3 |. FFD7 call edi ; \GetDlgItemTextA
004011F5 |. 6BC0 03 imul eax, eax, 3
004011F8 |. C1E0 02 shl eax, 2
004011FB |. 05 CD000000 add eax, 0CD
00401200 |. 8945 FC mov dword ptr [ebp-4], eax
00401203 |. 817D FC A5010000 cmp dword ptr [ebp-4], 1A5 ; 假码的长度必须等于18
0040120A |. 0F85 BC000000 jnz 004012CC
00401210 |. 33C0 xor eax, eax
00401212 |. 8A45 94 mov al, byte ptr [ebp-6C] ; 假码字符依次入al
00401215 |. 84C0 test al, al
00401217 |. 74 13 je short 0040122C
00401219 |. 8D4D 94 lea ecx, dword ptr [ebp-6C]
0040121C |> 3C 30 /cmp al, 30 ; 检查是否有特殊字符
0040121E |. 0F82 C6000000 |jb 004012EA
00401224 |. 8A41 01 |mov al, byte ptr [ecx+1]
00401227 |. 41 |inc ecx
00401228 |. 84C0 |test al, al
0040122A |.^ 75 F0 \jnz short 0040121C
0040122C |> \E8 CFFDFFFF call 00401000
00401231 |. 8D85 2CFFFFFF lea eax, dword ptr [ebp-D4] ; 用户名存入eax
00401237 |. 50 push eax
00401238 |. E8 43FEFFFF call 00401080 ; 关键call<1>
0040123D |. 8945 FC mov dword ptr [ebp-4], eax
00401240 |. E8 BBFDFFFF call 00401000
00401245 |. 8D8D 2CFFFFFF lea ecx, dword ptr [ebp-D4]
0040124B |. 56 push esi
0040124C |. 51 push ecx
0040124D |. E8 BEFDFFFF call 00401010 ; 关键call<2>
00401252 |. 83C4 0C add esp, 0C
00401255 |. 33C9 xor ecx, ecx
关键call<1>:
00401080 /$ 55 push ebp
00401081 |. 8BEC mov ebp, esp
00401083 |. 51 push ecx
00401084 |. 53 push ebx
00401085 |. 56 push esi
00401086 |. 57 push edi
00401087 |. 68 80504000 push 00405080 ; 字符串1 "eheh"
0040108C |. 6A 00 push 0
0040108E |. E8 ADFFFFFF call 00401040 ; 关键call<3> 设此方法为T计算
00401093 |. 83C4 08 add esp, 8
00401096 |. 8BD8 mov ebx, eax ; "eheh"经过T计算后结果ZX
继续跟进call<3>:
00401040 /$ 8B4C24 04 mov ecx, dword ptr [esp+4] ; 设此计算方法为 T
00401044 |. 56 push esi
00401045 |. 8B7424 0C mov esi, dword ptr [esp+C] ; "eheh"
00401049 |. 33C0 xor eax, eax
0040104B |. 33D2 xor edx, edx
0040104D |. 8A4431 03 mov al, byte ptr [ecx+esi+3] ; 取最后一个字符"h"
00401051 |. 8A5431 02 mov dl, byte ptr [ecx+esi+2] ; 取"e"
00401055 |. C1E0 08 shl eax, 8
00401058 |. 03C2 add eax, edx ; 结果记为x1
0040105A |. 33D2 xor edx, edx
0040105C |. 8A5431 01 mov dl, byte ptr [ecx+esi+1] ; 第二个"h"
00401060 |. C1E0 08 shl eax, 8 ; x1右移8位
00401063 |. 03C2 add eax, edx ; x1右移8位+"h"asc值结果为x2
00401065 |. 33D2 xor edx, edx
00401067 |. 8A1431 mov dl, byte ptr [ecx+esi]
0040106A |. 5E pop esi
0040106B |. C1E0 08 shl eax, 8
0040106E |. 03C2 add eax, edx ; x2右移8位+"e"的asc码结果记为ZX
00401070 \. C3 retn
返回至这里:
00401093 |. 83C4 08 add esp, 8
00401096 |. 8BD8 mov ebx, eax ; "eheh"经过T计算后结果ZX
00401098 |. E8 63FFFFFF call 00401000
0040109D BF 70504000 mov edi, 00405070 ; 字符串2 " is a whore."
004010A2 |. 83C9 FF or ecx, FFFFFFFF
004010A5 |. 33C0 xor eax, eax
004010A7 |. F2:AE repne scas byte ptr es:[edi]
004010A9 |. F7D1 not ecx
004010AB |. 2BF9 sub edi, ecx
004010AD |. 8BF7 mov esi, edi
004010AF |. 8B7D 08 mov edi, dword ptr [ebp+8]
004010B2 |. 8BD1 mov edx, ecx
004010B4 |. 83C9 FF or ecx, FFFFFFFF
004010B7 |. F2:AE repne scas byte ptr es:[edi]
004010B9 |. 8BCA mov ecx, edx
004010BB |. 4F dec edi
004010BC |. C1E9 02 shr ecx, 2
004010BF |. F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]; 取字符串2.四字节的倍数长度存入地址12F98A处
004010C1 |. 8BCA mov ecx, edx
004010C3 |. 83E1 03 and ecx, 3
004010C6 |. F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]; 未取完的字符加载
004010C8 |. 33FF xor edi, edi
004010CA |. 33F6 xor esi, esi
004010CC |> 8B45 08 /mov eax, dword ptr [ebp+8] ; 上面是把字符串2连接到用户名的后面,字符串3
004010CF |. 50 |push eax
004010D0 |. 56 |push esi
执行完了返回这里:
004010D1 |. E8 6AFFFFFF |call 00401040 ; 关键call<4>
跟进去:
00401040 /$ 8B4C24 04 mov ecx, dword ptr [esp+4] ; 此计算方法为 T
00401044 |. 56 push esi
00401045 |. 8B7424 0C mov esi, dword ptr [esp+C] ; "abcdef is a whore"
00401049 |. 33C0 xor eax, eax
0040104B |. 33D2 xor edx, edx
0040104D |. 8A4431 03 mov al, byte ptr [ecx+esi+3] ; 倒序取字符
00401051 |. 8A5431 02 mov dl, byte ptr [ecx+esi+2]
00401055 |. C1E0 08 shl eax, 8
00401058 |. 03C2 add eax, edx
0040105A |. 33D2 xor edx, edx
0040105C |. 8A5431 01 mov dl, byte ptr [ecx+esi+1]
00401060 |. C1E0 08 shl eax, 8
00401063 |. 03C2 add eax, edx
00401065 |. 33D2 xor edx, edx
00401067 |. 8A1431 mov dl, byte ptr [ecx+esi]
0040106A |. 5E pop esi
0040106B |. C1E0 08 shl eax, 8
0040106E |. 03C2 add eax, edx
00401070 \. C3 retn
004010D1 |. E8 6AFFFFFF |call 00401040 ; 这个就是call<4> T计算 计算15次
004010D6 |. 8B8E 30504000 |mov ecx, dword ptr [esi+405030]
004010DC |. 83C4 08 |add esp, 8
004010DF |. 33CF |xor ecx, edi
004010E1 |. 03C1 |add eax, ecx
004010E3 |. 8945 FC |mov dword ptr [ebp-4], eax
004010E6 |. C145 FC 07 |rol dword ptr [ebp-4], 7
004010EA |. 8B45 FC |mov eax, dword ptr [ebp-4] ; 此时eax中的值设为Dn(n=1,2,3..)
004010ED |. 83C6 04 |add esi, 4 ; An为异或后的值
004010F0 |. 33D8 |xor ebx, eax ; An(n=2,3,4..)与Dn(b=2,3,4..)的值异或15次后值设为AT
004010F2 |. 47 |inc edi
004010F3 |. 83FE 40 |cmp esi, 40
004010F6 |.^ 7C D4 \jl short 004010CC
004010F8 |. 5F pop edi
004010F9 |. 8BC3 mov eax, ebx
004010FB |. 5E pop esi
004010FC |. 5B pop ebx
004010FD |. 8BE5 mov esp, ebp
004010FF |. 5D pop ebp
00401100 \. C3 retn
返回来到这里:
0040123D |. 8945 FC mov dword ptr [ebp-4], eax
00401240 |. E8 BBFDFFFF call 00401000
00401245 |. 8D8D 2CFFFFFF lea ecx, dword ptr [ebp-D4]
0040124B |. 56 push esi
0040124C |. 51 push ecx
0040124D |. E8 BEFDFFFF call 00401010 ; 去掉用户名后缀" is a whore"
00401252 |. 83C4 0C add esp, 0C
00401255 |. 33C9 xor ecx, ecx
00401257 |> /8B45 FC /mov eax, dword ptr [ebp-4] ; 上次计算出来的结果AT参与生成表的计算
0040125A |. |33D2 |xor edx, edx
0040125C |. |BE 1A000000 |mov esi, 1A
00401261 |. |F7F6 |div esi ; 设ATsn除以1A后的余数为bn(n=1,2,3...)
00401263 |. |8A9415 10FFFFFF |mov dl, byte ptr [ebp+edx-F0]
0040126A |. |88540D C8 |mov byte ptr [ebp+ecx-38], dl ; 从表1取第bn位数值
0040126E |. |8B45 FC |mov eax, dword ptr [ebp-4]
00401271 |. |C1E0 03 |shl eax, 3 ; AT左移3位后的值 ATn(n=1,2,3,..)
00401274 |. |BA 45230100 |mov edx, 12345
00401279 |. |F7E8 |imul eax ; ATn*12345+12345的值设为ATsn(n=1,2,3..)
0040127B |. |03C2 |add eax, edx
0040127D |. |8945 FC |mov dword ptr [ebp-4], eax
00401280 |. |41 |inc ecx
00401281 |. |83F9 12 |cmp ecx, 12 ; 一系列复杂的运算只为生成一张新表 记为BD2
00401284 |.^\72 D1 \jb short 00401257
00401286 |. E8 75FDFFFF call 00401000
0040128B |. 33C0 xor eax, eax
0040128D |> 8A4C05 94 /mov cl, byte ptr [ebp+eax-6C] ; 假码字符依次入cl
00401291 |. 8A5405 C8 |mov dl, byte ptr [ebp+eax-38] ; 表BD2对应字符依次入dl
00401295 |. 80E9 30 |sub cl, 30
00401298 |. 32D1 |xor dl, cl
0040129A |. 885405 C8 |mov byte ptr [ebp+eax-38], dl
0040129E |. 40 |inc eax
0040129F |. 83F8 12 |cmp eax, 12
004012A2 |.^ 72 E9 \jb short 0040128D ; 假码与表BD2进行计算生成表BD3
004012A4 |. E8 57FDFFFF call 00401000
004012A9 |. 8D55 C8 lea edx, dword ptr [ebp-38]
004012AC |. 52 push edx
004012AD |. E8 5EFEFFFF call 00401110 ; 关键call <5>
004012B2 |. E8 49FDFFFF call 00401000
004012B7 |. 8D45 C8 lea eax, dword ptr [ebp-38]
004012BA |. 68 14514000 push 00405114 ; 真码压栈
004012BF |. 50 push eax ; 表BD4
004012C0 |. E8 6BFEFFFF call 00401130 ; 逐位进行比较
004012C5 |. 83C4 0C add esp, 0C
004012C8 |. 85C0 test eax, eax
004012CA |. 75 3C jnz short 00401308
004012CC |> 8B4D 08 mov ecx, dword ptr [ebp+8]
004012CF |. 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
004012D1 |. 68 0C514000 push 0040510C ; |Title = "Error"
004012D6 |. 68 FC504000 push 004050FC ; |Text = "Bad Serial :o("
004012DB |. 51 push ecx ; |hOwner
004012DC |. FF15 AC404000 call dword ptr [<&USER32.MessageBoxA>] ; \MessageBoxA
004012E2 |. 5F pop edi
004012E3 |. 33C0 xor eax, eax
004012E5 |. 5E pop esi
004012E6 |. 8BE5 mov esp, ebp
004012E8 |. 5D pop ebp
004012E9 |. C3 retn
004012EA |> 8B55 08 mov edx, dword ptr [ebp+8]
004012ED |. 6A 10 push 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
004012EF |. 68 0C514000 push 0040510C ; |Title = "Error"
004012F4 |. 68 FC504000 push 004050FC ; |Text = "Bad Serial :o("
004012F9 |. 52 push edx ; |hOwner
004012FA |. FF15 AC404000 call dword ptr [<&USER32.MessageBoxA>] ; \MessageBoxA
00401300 |. 5F pop edi
00401301 |. 33C0 xor eax, eax
00401303 |. 5E pop esi
00401304 |. 8BE5 mov esp, ebp
00401306 |. 5D pop ebp
00401307 |. C3 retn
跟进call<5>:
00401110 /$ 8B4C24 04 mov ecx, dword ptr [esp+4]
00401114 |. 33C0 xor eax, eax
00401116 |> 8A1408 /mov dl, byte ptr [eax+ecx]
00401119 |. 32D0 |xor dl, al
0040111B |. 881408 |mov byte ptr [eax+ecx], dl
0040111E |. 40 |inc eax
0040111F |. 83F8 12 |cmp eax, 12 ; 由BD3建立一张新表BD4
00401122 |.^ 72 F2 \jb short 00401116
00401124 \. C3 retn
执行完了之后返回至地址00401000
到这里为止,我们对该crackme得算法已经分析完了,大致过程是这样的:
0>表BD1是固定的:KEYGENNING4NEWBIES
1>用户名长度L,0<L<=64 假码长度必须18位.
2>倒序取字符"eheh"进行转换[("h"*2^8+"e")*2^8+"h"]*2^8+"e" "h","e"为对应的ASC码的值 结果设为 ZX
3>把字符串" is a whore."连接到用户名的后面组成字符串3
4>字符串3经过T运算15次,An(n=2,3,4...) xor Dn(n=2,3,4...) 异或10次后的值设为AT
5>AT左移3位得到AT1,AT1左移3位得到AT2,以此类推...ATn(n=1,2,3...)
ATn*12345+12345后的值设为ATSn(n=1,2,3..)
ATSn 除以 1A 得到的余数为bn(n=1,2,3...)
6>从表1取第bn位的数值,依次排列生成表单BD2
7>设假码每一位的字符的ASC码对应Jn(n=1,2,3...) 表单BD2每一位对应的ASC码Bn(n=1,2,3...) (Jn-30) xor Bn=CMn(n=1,2,3...),把CMn的值转换成字符,依次连接起来,建立BD3
8>表单BD3每位字符与它的数位减一的值进行异或得到结果,转换成字符,依次排列于是 表单BD4建成了
9>把BD4与BD1进行比较 相等就成功!
要想BD4=BD1,就需要逆推注册码! 假设BD1=BD4,往上逆推,BD4每位字符的ASC码与(0,1,2,3...17)异或,得到BD3
<输入注册码的每位字符-30> xor <BD2中对应字符> =<BD3中对应字符> 因为BD3逆推出来了,BD2也算出来了 所以
<BD3中对应字符> xor <BD2对应字符> +30 后 把对应ASC码转换成字符就是真的注册码了!
计算过程有点复杂,所以在逆推注册码的时候要用到指令计算器,OD命令行.不能错掉一个字符,因为是逐位进行比较了.
注册名:abcdef
注册码:2<O9:A6L=8?:N=6:DM
注:算法分析完了,但是发现一个bug,24 xor 55 +30 =A1 在ASC码表找不到相应的字符.(就是注册码中的"?").
由于本人经验不足,文中有些地方让你感到很别扭,造成你阅读上的不便.请原谅!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)