160个CrackMe之034

MASM32 / TASM32编写,无壳,是一个Keyfile验证方式,界面打开窗口空白,file菜单只有一个exit,help菜单也只有一个About说明。

crackme标注的验证方式是Keyfile,所以直接搜索字符串,可以搜索到“CRACKME3.KEY”,明显的Key文件,同时还有"Good work cracker!“及"Crackedby: Now try the next crackme!“字符串,估计是成功后标志。直接双击“CRACKME3.KEY”来到代码处:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
00401016  |.  6A 00         push 0x0                                  ; /hTemplateFile = NULL
00401018  |.  68 80000000   push 0x80                                 ; |Attributes = NORMAL
0040101D  |.  6A 03         push 0x3                                  ; |Mode = OPEN_EXISTING
0040101F  |.  6A 00         push 0x0                                  ; |pSecurity = NULL
00401021  |.  6A 03         push 0x3                                  ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00401023  |.  68 000000C0   push 0xC0000000                           ; |Access = GENERIC_READ|GENERIC_WRITE
00401028  |.  68 D7204000   push Cruehead.004020D7                    ; |CRACKME3.KEY
0040102D  |.  E8 76040000   call <jmp.&KERNEL32.CreateFileA>          ; \CreateFileA
00401032  |.  83F8 FF       cmp eax,-0x1
00401035  |.  75 0C         jnz short Cruehead.00401043
00401037  |>  68 0E214000   push Cruehead.0040210E                    ;  CrackMe v3.0
0040103C  |.  E8 B4020000   call Cruehead.004012F5
00401041  |.  EB 6B         jmp short Cruehead.004010AE               ;  打开文件失败的jmp
00401043  |>  A3 F5204000   mov dword ptr ds:[0x4020F5],eax
00401048  |.  B8 12000000   mov eax,0x12                              ;  读取文件的最大字节数
0040104D  |.  BB 08204000   mov ebx,Cruehead.00402008
00401052  |.  6A 00         push 0x0                                  ; /pOverlapped = NULL
00401054  |.  68 A0214000   push Cruehead.004021A0                    ; |pBytesRead = Cruehead.004021A0
00401059  |.  50            push eax                                  ; |BytesToRead = 0x0
0040105A  |.  53            push ebx                                  ; |Buffer = 7FFDC000
0040105B  |.  FF35 F5204000 push dword ptr ds:[0x4020F5]              ; |hFile = NULL
00401061  |.  E8 30040000   call <jmp.&KERNEL32.ReadFile>             ; \ReadFile
00401066  |.  833D A0214000>cmp dword ptr ds:[0x4021A0],0x12          ;  读到的文件字节数
0040106D  |.^ 75 C8         jnz short Cruehead.00401037               ;  要求大小为0x12字节
0040106F  |.  68 08204000   push Cruehead.00402008
00401074  |.  E8 98020000   call Cruehead.00401311
00401079  |.  8135 F9204000>xor dword ptr ds:[0x4020F9],0x12345678
00401083  |.  83C4 04       add esp,0x4
00401086  |.  68 08204000   push Cruehead.00402008

分析此块汇编代码:

  1. CreateFileA参数Mode = OPEN_EXISTING == 0x0,也就是打开已存在的文件,若文件不存在,函数返回-1,是用来验证Key文件是否存在的。
  2. ReadFile函数读取文件内容,参数pBytesRead = Cruehead.004021A0是读取文件返回的字节数,接下来一句代码cmp dword ptr ds:[0x4021A0],0x12,如果读取的字节数不等于0x12(18)个,则跳至失败处。

于是我们在CrackMe目录下新建一个文件CRACKME3.KEY,并写入不少于18个字节的数据,内容如下。再次载入程序,在ReadFile后代码进行跟踪。

1
2
00000000h: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0D 0E ; ................
00000010h: 0F 10 11                                        ; ...                                  ; 4..
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
00401000 >/$  6A 00         push 0x0                                  ; /pModule = NULL
00401002  |.  E8 7D040000   call <jmp.&KERNEL32.GetModuleHandleA>     ; \GetModuleHandleA
00401007  |.  A3 E9204000   mov dword ptr ds:[0x4020E9],eax
0040100C  |.  C705 F9204000>mov dword ptr ds:[0x4020F9],0x0           ;  设置为0
00401016  |.  6A 00         push 0x0                                  ; /hTemplateFile = NULL
00401018  |.  68 80000000   push 0x80                                 ; |Attributes = NORMAL
0040101D  |.  6A 03         push 0x3                                  ; |Mode = OPEN_EXISTING
0040101F  |.  6A 00         push 0x0                                  ; |pSecurity = NULL
00401021  |.  6A 03         push 0x3                                  ; |ShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE
00401023  |.  68 000000C0   push 0xC0000000                           ; |Access = GENERIC_READ|GENERIC_WRITE
00401028  |.  68 D7204000   push Cruehead.004020D7                    ; |CRACKME3.KEY
0040102D  |.  E8 76040000   call <jmp.&KERNEL32.CreateFileA>          ; \CreateFileA
00401032  |.  83F8 FF       cmp eax,-0x1
00401035  |.  75 0C         jnz short Cruehead.00401043
00401037  |>  68 0E214000   push Cruehead.0040210E                    ;  CrackMe v3.0
0040103C  |.  E8 B4020000   call Cruehead.004012F5
00401041  |.  EB 6B         jmp short Cruehead.004010AE               ;  打开文件失败的jmp
00401043  |>  A3 F5204000   mov dword ptr ds:[0x4020F5],eax
00401048  |.  B8 12000000   mov eax,0x12                              ;  读取文件的最大字节数
0040104D  |.  BB 08204000   mov ebx,Cruehead.00402008
00401052  |.  6A 00         push 0x0                                  ; /pOverlapped = NULL
00401054  |.  68 A0214000   push Cruehead.004021A0                    ; |pBytesRead = Cruehead.004021A0
00401059  |.  50            push eax                                  ; |BytesToRead = 0x0
0040105A  |.  53            push ebx                                  ; |Buffer = NULL
0040105B  |.  FF35 F5204000 push dword ptr ds:[0x4020F5]              ; |hFile = 00000044 (window)
00401061  |.  E8 30040000   call <jmp.&KERNEL32.ReadFile>             ; \ReadFile
00401066  |.  833D A0214000>cmp dword ptr ds:[0x4021A0],0x12          ;  读到的文件字节数
0040106D  |.^ 75 C8         jnz short Cruehead.00401037               ;  要求大小为0x12字节
0040106F  |.  68 08204000   push Cruehead.00402008                    ;  读到的数据
00401074  |.  E8 98020000   call Cruehead.00401311                    ;  数据计算
00401079  |.  8135 F9204000>xor dword ptr ds:[0x4020F9],0x12345678
00401083  |.  83C4 04       add esp,0x4
00401086  |.  68 08204000   push Cruehead.00402008                    ;  计算的数据
0040108B  |.  E8 AC020000   call Cruehead.0040133C                    ;  再计算:0xE ~ 0x12的4字节 =》 0x100F0E0D
00401090  |.  83C4 04       add esp,0x4
00401093  |.  3B05 F9204000 cmp eax,dword ptr ds:[0x4020F9]           ;  进行数值比较
00401099  |.  0f94c0        sete al
0040109C  |.  50            push eax
0040109D  |.  84C0          test al,al
0040109F  |.^ 74 96         je short Cruehead.00401037
004010A1  |.  68 0E214000   push Cruehead.0040210E                    ;  CrackMe v3.0
004010A6  |.  E8 9B020000   call Cruehead.00401346
004010AB  |.  83C4 04       add esp,0x4
004010AE  |>  6A 00         push 0x0                                  ; /Title = NULL
004010B0  |.  68 28214000   push Cruehead.00402128                    ; |No need to disasm the code!
004010B5  |.  E8 9A030000   call <jmp.&USER32.FindWindowA>            ; \FindWindowA
004010BA  |.  0BC0          or eax,eax
004010BC  |.  74 01         je short Cruehead.004010BF
004010BE  |.  C3            retn

00401311  /$  33C9          xor ecx,ecx                               ;  ecx = 0
00401313  |.  33C0          xor eax,eax                               ;  eax = 0
00401315  |.  8B7424 04     mov esi,dword ptr ss:[esp+0x4]            ;  数据
00401319  |.  B3 41         mov bl,0x41
0040131B  |>  8A06          /mov al,byte ptr ds:[esi]
0040131D  |.  32C3          |xor al,bl
0040131F  |.  8806          |mov byte ptr ds:[esi],al
00401321  |.  46            |inc esi
00401322  |.  FEC3          |inc bl
00401324  |.  0105 F9204000 |add dword ptr ds:[0x4020F9],eax
0040132A  |.  3C 00         |cmp al,0x0
0040132C  |.  74 07         |je short Cruehead.00401335
0040132E  |.  FEC1          |inc cl
00401330  |.  80FB 4F       |cmp bl,0x4F
00401333  |.^ 75 E6         \jnz short Cruehead.0040131B
00401335  |>  890D 49214000 mov dword ptr ds:[0x402149],ecx
0040133B  \.  C3            retn

0040133C  /$  8B7424 04     mov esi,dword ptr ss:[esp+0x4]            ;  计算的数据
00401340  |.  83C6 0E       add esi,0xE
00401343  |.  8B06          mov eax,dword ptr ds:[esi]
00401345  \.  C3            retn

通过分析得出将文件的0~11字节进行计算,结果与12~17的数值进行比较,相等及成功!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

int main() {
	unsigned int ecx = 0;
	unsigned int nuber = 0;

	unsigned char data[18] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0D, 0x0E, 0x0F, 0x10};
	unsigned char* ptr_data = data;
	unsigned char bl = 0x41;

	while (true) {
		
		unsigned char al = *ptr_data;
		al ^= bl;
		*ptr_data = al;
		ptr_data++;
		bl++;
		nuber += al;

		if (al == 0) {
			break;
		}
		ecx++;

		if (bl == 0x4f) {
			break;
		}
	}
	
	nuber ^= 0x12345678;
	
	ptr_data = data + 0xE;

	unsigned int key;
	memcpy((void*)&key, (void*)ptr_data, 4);

	if (nuber == key) {
		printf("Success\n");
	}
	else {
		printf("Error\n");
	}

	return 0;
}

更改文件内容如下:

1
2
00000000h: 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E F8 55 ; ..............鳸
00000010h: 34 12 11                                        ; 4..
0%