来到论坛很久了,但是一直都没有成功破解过。
于是找到一个看雪论坛上以前的一个很简单的CrackMe试试,终于成功了。
发上来与大家一同分享我的喜悦,由于注释是调试的时候为了方便写的,所以有点乱。
请大家批评指正,不要笑话我。
【软件】: crackme6.exe crackme6.rar 不好意思,忘了作者是谁了
【作者】: cxxhcj
【软件大小】: 8.47k
【正文】:
首先运行crackme,发现没有错误提示
用PEiD查壳发现是ASPack,脱掉后用OD加载,尝试对GetDlgItemTextA下断,运气不错断下来了,来到取得name处
00401539 |. E8 FA010000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
0040153E |. 89C3 mov ebx, eax ;
00401540 |. 09DB or ebx, ebx ; len_name != 0;
00401542 |. 75 04 jnz short 00401548
00401544 |. 31C0 xor eax, eax
00401546 |. EB 50 jmp short 00401598
00401548 |> BF BC020000 mov edi, 2BC
0040154D |. BE 30000000 mov esi, 30
00401552 |. B8 48000000 mov eax, 48
00401557 |. 99 cdq
00401558 |. F7FB idiv ebx ; S = 48H / len_name;
0040155A |. 29C6 sub esi, eax ; X = 30H - S;
0040155C |. 8D34B6 lea esi, dword ptr [esi+esi*4] ; X *= 5;
0040155F |. 29F7 sub edi, esi ; Y = 2BCH - X;
00401561 |. 6BFF 6B imul edi, edi, 6B ; Y *= 6BH;
00401564 |. 81EF 6CCF0000 sub edi, 0CF6C ; Y -= 0CF6CH;
0040156A |. 81FF 00230000 cmp edi, 2300 ; Y < 2300H
00401570 |. 7F 08 jg short 0040157A
00401572 |. 81FF 90010000 cmp edi, 190 ; Y > 190H
00401578 |. 7D 04 jge short 0040157E
0040157A |> 31C0 xor eax, eax
0040157C |. EB 1A jmp short 00401598
为了方便自己设了一些变量S,X,Y
这里是一个不等式:190H<6BH*[2BCH-5(30H-48H/len_name)]-CF6CH<2300H
解得 3 < len_name < 9,是name长度的限制
可以通过修改零标志通过
继续往下可以找到爆破点:
00401589 |. E8 77FDFFFF call 00401305 ; serial读入以及相关算法
0040158E |. 83C4 0C add esp, 0C
00401591 |. 09C0 or eax, eax
00401593 |. 74 03 je short 00401598 ; 关键跳
00401595 |. 31C0 xor eax, eax
00401597 |. 40 inc eax ; 返回1则成功
进入serial算法部分:
004013AF |. E8 84030000 call <jmp.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA
004013B4 |. 09C0 or eax, eax ;
004013B6 |. 0F84 48010000 je 00401504 ; Serial判空
004013BC |. B8 CF110000 mov eax, 11CF
004013C1 |. 0FB68D E1FCFF>movzx ecx, byte ptr [ebp-31F] ; A = Serial第一个字符ASCII;
004013C8 |. 99 cdq
004013C9 |. F7F9 idiv ecx
004013CB |. 83FA 17 cmp edx, 17 ; 11CF % A == 17H;
004013CE |. 74 07 je short 004013D7
004013D0 |. 31C0 xor eax, eax
11CFH对serial第一个字符的ASCII码取余应为17H,'T'字符可行
继续向下走可以发现形如Txxxxxx-xx的字符串,试过之后发现不是注册码,应该是中间产物,继续分析代码:
004013D7 |> \31DB xor ebx, ebx ; 中间产物算法开始
004013D9 |. EB 0B jmp short 004013E6
004013DB |> 8B45 10 /mov eax, dword ptr [ebp+10] ; N_A_S = name所有字符ASCII相加
004013DE |. 0FBE0418 |movsx eax, byte ptr [eax+ebx]
004013E2 |. 0145 FC |add dword ptr [ebp-4], eax
004013E5 |. 43 |inc ebx
004013E6 |> 3B5D 0C cmp ebx, dword ptr [ebp+C]
004013E9 |.^ 7C F0 \jl short 004013DB
004013F2 |> /8B55 10 /mov edx, dword ptr [ebp+10]
004013F5 |. |0FBE3C1A |movsx edi, byte ptr [edx+ebx] ; 取name[i]字符,i 即 ebx;
004013F9 |. |8B75 FC |mov esi, dword ptr [ebp-4] ; 取N = N_A_S;
004013FC |. |89D9 |mov ecx, ebx ; m = i;
004013FE |. |C1E1 02 |shl ecx, 2 ; m *= 4;
00401401 |. |89DA |mov edx, ebx
00401403 |. |42 |inc edx ; j = i + 1;
00401404 |. |29D1 |sub ecx, edx ; m -= j;
00401406 |. |0FB68C0D E1FE>|movzx ecx, byte ptr [ebp+ecx-11F] ; 取字母c = 'A' + m,无对应字母时,取0
0040140E |. |89FA |mov edx, edi
00401410 |. |31CA |xor edx, ecx ; c ^= name[i];
00401412 |. |89F1 |mov ecx, esi
00401414 |. |0FAFCB |imul ecx, ebx ; E = N * i;
00401417 |. |29F1 |sub ecx, esi ; E -= N;
00401419 |. |89CE |mov esi, ecx ; N = E;
0040141B |. |83F6 FF |xor esi, FFFFFFFF ; N ^= FFFFFFFFH;
0040141E |. |8DB432 4D0100>|lea esi, dword ptr [edx+esi+14D] ; N = c + N + 14DH;
00401425 |. |8B4D 0C |mov ecx, dword ptr [ebp+C] ; l = len_name;
00401428 |. |89DA |mov edx, ebx ; n = i;
0040142A |. |83C2 03 |add edx, 3 ; n += 3;
0040142D |. |0FAFCA |imul ecx, edx ; l *= n;
00401430 |. |0FAFCF |imul ecx, edi ; l *= name[i];
00401433 |. |89F0 |mov eax, esi
00401435 |. |01C8 |add eax, ecx ; N += l;
00401437 |. |B9 0A000000 |mov ecx, 0A ;
0040143C |. |31D2 |xor edx, edx ;
0040143E |. |F7F1 |div ecx ;
00401440 |. |83C2 30 |add edx, 30 ; n = N % 0AH + 30H;
00401443 |. |88941D FCFEFF>|mov byte ptr [ebp+ebx-104], dl
0040144A |. |0FB6BC1D FCFE>|movzx edi, byte ptr [ebp+ebx-104] ; l = n & FFH;
00401452 |. |81F7 ACAD0000 |xor edi, 0ADAC ; l ^= 0ADACH;
00401458 |. |89DE |mov esi, ebx
0040145A |. |83C6 02 |add esi, 2
0040145D |. |89F8 |mov eax, edi
0040145F |. |0FAFC6 |imul eax, esi ; a = l * (i + 2);
00401462 |. |B9 0A000000 |mov ecx, 0A
00401467 |. |99 |cdq
00401468 |. |F7F9 |idiv ecx ;
0040146A |. |83C2 30 |add edx, 30 ; n = a % 0AH + 30H;
0040146D |. |88941D FCFEFF>|mov byte ptr [ebp+ebx-104], dl ; n & FFH 存入temp[i]
00401474 |. |43 |inc ebx ; i++;
00401475 |> |3B5D 0C cmp ebx, dword ptr [ebp+C] ; 循环len_name次
00401478 |.^\0F8C 74FFFFFF \jl 004013F2
00401484 |. 50 push eax ;
00401485 |. 6A 54 push 54 ; 'T'
00401487 |. 8D85 DCFBFFFF lea eax, dword ptr [ebp-424] ;
0040148D |. 50 push eax ; |Format
0040148E |. 8D85 E1FBFFFF lea eax, dword ptr [ebp-41F] ; |
00401494 |. 50 push eax ; |s "%c%s"
00401495 |. E8 CE020000 call <jmp.&USER32.wsprintfA> ; \wsprintfA
以上算法形成第一步中间码,即Ttemp的形式,继续往下:
0040149F |. 0FAF45 FC imul eax, dword ptr [ebp-4] ; A = N_A_S * len_name;
004014A3 |. B9 64000000 mov ecx, 64
004014A8 |. 99 cdq
004014A9 |. F7F9 idiv ecx ;
004014AB |. 89D7 mov edi, edx
004014AD |. 83C7 30 add edi, 30 ; D = A % 64H + 30H
004014B0 |. 57 push edi ; D当做参数
004014B1 |. 8DBD E1FBFFFF lea edi, dword ptr [ebp-41F]
004014B7 |. 57 push edi ;
004014B8 |. 8DBD D6FBFFFF lea edi, dword ptr [ebp-42A] ;
004014BE |. 57 push edi ; |Format
004014BF |. 8DBD E1FDFFFF lea edi, dword ptr [ebp-21F] ; |
004014C5 |. 57 push edi ; |s "%s-%d"
004014C6 |. E8 9D020000 call <jmp.&USER32.wsprintfA> ; \wsprintfA
以上算法形成最终中间码,即Ttemp-D的形式,接着往下:
004014DE |. 50 push eax ; 中间注册码长度
004014DF |. 8D85 E1FCFFFF lea eax, dword ptr [ebp-31F]
004014E5 |. 50 push eax ; 输入的注册码
004014E6 |. 8D85 E1FDFFFF lea eax, dword ptr [ebp-21F]
004014EC |. 50 push eax ; 中间注册码
004014ED |. E8 D0FDFFFF call 004012C2 ; 比较算法
出现输入的注册码,此时的call即是比较函数,F7进入call:
004012C8 |. 8B5D 10 mov ebx, dword ptr [ebp+10] ; 中间码长度len
004012CB |. 31F6 xor esi, esi
004012CD |. 46 inc esi ; 循环len-1次
004012CE |. EB 29 jmp short 004012F9
004012D0 |> 8B55 08 /mov edx, dword ptr [ebp+8]
004012D3 |. 0FBE3C32 |movsx edi, byte ptr [edx+esi] ; 取中间码esi处的字符c
004012D7 |. 89F8 |mov eax, edi
004012D9 |. 83F0 20 |xor eax, 20 ;
004012DC |. B9 0A000000 |mov ecx, 0A
004012E1 |. 99 |cdq
004012E2 |. F7F9 |idiv ecx ;
004012E4 |. 89D7 |mov edi, edx
004012E6 |. 83C7 30 |add edi, 30 ; c = (c^20H) % 0AH + 30H;
004012E9 |. 8B55 0C |mov edx, dword ptr [ebp+C]
004012EC |. 0FBE1432 |movsx edx, byte ptr [edx+esi] ; 取输入的注册码相应字符d
004012F0 |. 39D7 |cmp edi, edx ; d == c;由此可见c即是真正的注册码相应字符
004012F2 |. 74 04 |je short 004012F8
004012F4 |. 31C0 |xor eax, eax
004012F6 |. EB 08 |jmp short 00401300
004012F8 |> 46 |inc esi
004012F9 |> 39DE cmp esi, ebx
004012FB |.^ 7C D3 \jl short 004012D0
将算法整理后,可以很容易写出注册机:
#include<stdio.h>
#include<string.h>
main()
{
int len_name, N_A_S, len_serial, i;
char name[20], serial[100], temp[100], temp1[100];
INPUT: printf("请输入name:"); scanf("%s", name);
len_name = strlen(name);
if(len_name == 0 || len_name <= 3 || len_name >=9){
printf("name长度应在4-8!\n");
goto INPUT;
}
N_A_S = 0;
for(i = 0; i < len_name; i++){
N_A_S += name[i];
}
for(i = 0; i < len_name; i++){
char c, R;
int m, N, l;
m = 3*i - 1;
if(m < 0 || m > 25) c = '\0';
else c = 'A' + m;
R = c ^ name[i];
N = N_A_S;
N *= i - 1;
N ^= -1;
N += R + 0x14D;
l = (i+3)*len_name*name[i];
N += l;
l = (N % 0xA + 0x30) & 0xFF;
l ^= 0xADAC;
N = (l*(i+2))%0xA + 0x30;
temp[i] = N & 0xFF;
}
temp[i] = '\0';
sprintf(temp1, "T%s", temp);
i = (N_A_S * len_name) % 0x64 + 0x30;
sprintf(temp, "%s-%d", temp1, i);
printf("中间码:%s\n", temp);
len_serial = strlen(temp);
for(i = 1; i < len_serial; i++){
serial[i] = (temp[i] ^ 0x20) % 0xA + 0x30;
}
serial[0] = 'T';
serial[i] = '\0';
printf("注册码:%s\n", serial);
system("pause");
return 0;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)