这个CrackMe很简单,但是简单不代表白痴,个人认为这个CM还是有一定意义的(具体是什么我最后再说^_^)。
对先最简单的方法,字符串查找。看能不能发现什么线索。
00401000 /$ 81EC D0070000 sub esp, 7D0
00401006 |. 68 70704000 push 00407070 ; can you guess the code:
0040100B |. E8 AA010000 call 004011BA
00401010 |. 8D4424 04 lea eax, dword ptr [esp+4]
00401014 |. 50 push eax
00401015 |. E8 56010000 call 00401170
0040101A |. 8D4C24 08 lea ecx, dword ptr [esp+8]
0040101E |. 51 push ecx
0040101F |. E8 3C000000 call 00401060 ; call后不远处有个跳转,很经典的关键call。F7跟进去。
00401024 |. 83C4 0C add esp, 0C
00401027 |. 85C0 test eax, eax
00401029 |. 74 16 je short 00401041
0040102B |. 68 48704000 push 00407048 ; good! the key is your input o(^o^)o\n
00401030 |. E8 85010000 call 004011BA
00401035 |. 83C4 04 add esp, 4
00401038 |. 33C0 xor eax, eax
0040103A |. 81C4 D0070000 add esp, 7D0
00401040 |. C3 retn
00401041 |> 68 30704000 push 00407030 ; you don't guess it~\n
00401046 |. E8 6F010000 call 004011BA
0040104B |. 83C4 04 add esp, 4
0040104E |. 33C0 xor eax, eax
00401050 |. 81C4 D0070000 add esp, 7D0
00401056 \. C3 retn
00401060 /$ 83EC 10 sub esp, 10
00401063 |. A1 8C704000 mov eax, dword ptr [40708C] ; 指向加密的key的第一个字符
00401068 |. 8B0D 90704000 mov ecx, dword ptr [407090] ; 指向加密key的第5个字符
0040106E |. 53 push ebx ; 这样的push除了保护现场外,还有临时变量的作用。
0040106F |. 894424 04 mov dword ptr [esp+4], eax
00401073 |. 66:A1 9870400>mov ax, word ptr [407098] ; 指向加密key的倒数第2个字符
00401079 |. 894C24 08 mov dword ptr [esp+8], ecx
0040107D |. 8A0D 9A704000 mov cl, byte ptr [40709A] ; 指向加密key的末尾,空字符的地方。
00401083 |. 56 push esi
00401084 |. 8B7424 1C mov esi, dword ptr [esp+1C] ; esi指向我们输入的序列号
00401088 |. 57 push edi
00401089 |. 66:894424 18 mov word ptr [esp+18], ax
0040108E |. 884C24 1A mov byte ptr [esp+1A], cl
00401092 |. 8BFE mov edi, esi ; 准备计算字符串的长度
00401094 |. 83C9 FF or ecx, FFFFFFFF
00401097 |. 33C0 xor eax, eax
00401099 |. 8B15 94704000 mov edx, dword ptr [407094]
0040109F |. F2:AE repne scas byte ptr es:[edi] ; 重复串操作,直到ecx为0
004010A1 |. F7D1 not ecx
004010A3 |. 49 dec ecx ; ecx为真实长度,就是我们输入的序列号的长度。
004010A4 |. 895424 14 mov dword ptr [esp+14], edx
004010A8 |. 8BD1 mov edx, ecx
004010AA |. 8D7C24 0C lea edi, dword ptr [esp+C] ; 也是计算字符串长度,计算的是加密key
004010AE |. 83C9 FF or ecx, FFFFFFFF
004010B1 |. F2:AE repne scas byte ptr es:[edi]
004010B3 |. F7D1 not ecx
004010B5 |. 49 dec ecx ; ecx为真实的长度
004010B6 |. 3BD1 cmp edx, ecx ; 输入的序列号长度一定要是14位
004010B8 |. 0F85 9C000000 jnz 0040115A ; 如果2个字符串长度不相等,则直接失败。
004010BE |. 8BFE mov edi, esi ; 准备计算假序列号的长度
004010C0 |. 83C9 FF or ecx, FFFFFFFF ; 计算字符串长度,其实这个就是strlen 优化编译后的代码
004010C3 |. 33D2 xor edx, edx ; 清零edx,为下面的循环做准备,也就是初始化变量为0.
004010C5 |. F2:AE repne scas byte ptr es:[edi]
004010C7 |. F7D1 not ecx
004010C9 |. 49 dec ecx ; 保存着真实的字符串长度
004010CA |. 74 19 je short 004010E5 ; 如果长度为0,跳走
004010CC |> 8A0432 /mov al, byte ptr [edx+esi] ; 对假序列号逐个处理
004010CF |. 8BFE |mov edi, esi
004010D1 |. 34 20 |xor al, 20 ; 字符逐个与0x20做异或运算,应该就是解密了。
004010D3 |. 83C9 FF |or ecx, FFFFFFFF ; 经典对白,又要计算字符串长度了
004010D6 |. 880432 |mov byte ptr [edx+esi], al ; 解密后保存
004010D9 |. 33C0 |xor eax, eax
004010DB |. 42 |inc edx ; 递增,到这里明白了,原来edx还有做字符串数组索引的作用。
004010DC |. F2:AE |repne scas byte ptr es:[edi]
004010DE |. F7D1 |not ecx
004010E0 |. 49 |dec ecx ; 保存着字符串长度
004010E1 |. 3BD1 |cmp edx, ecx ; 比较看解密完了没有,没有就继续。
004010E3 |.^ 72 E7 \jb short 004010CC
004010E5 |> 8D7C24 0C lea edi, dword ptr [esp+C] ; 计算加密key的长度
004010E9 |. 83C9 FF or ecx, FFFFFFFF ; 又要计算字符长度了
004010EC |. 33C0 xor eax, eax
004010EE |. 33D2 xor edx, edx
004010F0 |. F2:AE repne scas byte ptr es:[edi]
004010F2 |. F7D1 not ecx
004010F4 |. 49 dec ecx ; ecx保存着长度
004010F5 |. 74 1D je short 00401114 ; 为零就跑了
004010F7 |> 8A4414 0C /mov al, byte ptr [esp+edx+C] ; 逐个字符处理加密key。
004010FB |. 8D7C24 0C |lea edi, dword ptr [esp+C]
004010FF |. 04 FB |add al, 0FB ; 每个字符的ASCII值加上0xFB
00401101 |. 83C9 FF |or ecx, FFFFFFFF
00401104 |. 884414 0C |mov byte ptr [esp+edx+C], al
00401108 |. 33C0 |xor eax, eax
0040110A |. 42 |inc edx
0040110B |. F2:AE |repne scas byte ptr es:[edi]
0040110D |. F7D1 |not ecx
0040110F |. 49 |dec ecx
00401110 |. 3BD1 |cmp edx, ecx ; 循环处理每个字符
00401112 |.^ 72 E3 \jb short 004010F7
00401114 |> 8D7C24 0C lea edi, dword ptr [esp+C] ; 这回是计算经过处理后的加密key的长度
00401118 |. 83C9 FF or ecx, FFFFFFFF
0040111B |. 33C0 xor eax, eax
0040111D |. 33D2 xor edx, edx
0040111F |. F2:AE repne scas byte ptr es:[edi]
00401121 |. F7D1 not ecx
00401123 |. 49 dec ecx ; 保存着长度
00401124 |. 74 28 je short 0040114E ; 不能为0,要不就跑了
00401126 |. 8D4424 0C lea eax, dword ptr [esp+C]
0040112A |. 2BF0 sub esi, eax
0040112C |> 8A5C14 0C /mov bl, byte ptr [esp+edx+C] ; [esp+C]指向的是处理后的key的地址,edx用来做索引
00401130 |. 8D4414 0C |lea eax, dword ptr [esp+edx+C]
00401134 |. 8A0C06 |mov cl, byte ptr [esi+eax] ; [esi]指向处理后的假key的首地址,eax用来做索引
00401137 |. 3ACB |cmp cl, bl ; 逐个字节比较
00401139 |. 75 1F |jnz short 0040115A ; 不相等就跳向失败
0040113B |. 8D7C24 0C |lea edi, dword ptr [esp+C]
0040113F |. 83C9 FF |or ecx, FFFFFFFF
00401142 |. 33C0 |xor eax, eax
00401144 |. 42 |inc edx
00401145 |. F2:AE |repne scas byte ptr es:[edi]
00401147 |. F7D1 |not ecx
00401149 |. 49 |dec ecx
0040114A |. 3BD1 |cmp edx, ecx
0040114C |.^ 72 DE \jb short 0040112C
0040114E |> 5F pop edi
0040114F |. 5E pop esi
00401150 |. B8 01000000 mov eax, 1
00401155 |. 5B pop ebx
00401156 |. 83C4 10 add esp, 10
00401159 |. C3 retn
0040115A |> 5F pop edi
0040115B |. 5E pop esi
0040115C |. 33C0 xor eax, eax
0040115E |. 5B pop ebx
0040115F |. 83C4 10 add esp, 10
00401162 \. C3 retn
A = 假码 ^ 0x20;
B = 加密key + 0xFB;
if (A == B)
成功,返回TRUE
else
失败,返回FALSE
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)