160CrackMe-006

本文最后更新于:2021-08-09 晚上

初探

打开程序如下看到OK是不可点击的,是一个灰色按钮。

点击about查看一下,可以看到我们需要让两个按钮都消失以便可以看到Ringzer0的logo

那么先想办法让OK变得可以点击吧。

分析

查看壳,发现未加壳,是用Delphi写的

使用API断点,给IsEnableWindow下断,但是发现怎么都无法断下来,说明肯定是有条件的,而当前还没有满足这个条件。

使用dedark工具帮忙查看,直接分析真的是太难找了,可以看到主要四个事件,这四个事件应该比较关键

根据函数地址找到函数下好断点之后,查看可以发现nomechange和codicechange几乎是一样的,将两处明显的跳转更改条件使跳转失效,让程序跑起来后都会断在之前下的API断点上。那么它们都是比较关键的地方。

第一个关键跳转都是判断eax+0x47这个地址的值是否等于0,而第二个跳转都是先调用了00442A3C这个函数。

nomechange:

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
00442E04  /.  55            push ebp                                 ;  nomeChange
00442E05 |. 8BEC mov ebp,esp
00442E07 |. 6A 00 push 0x0
00442E09 |. 6A 00 push 0x0
00442E0B |. 53 push ebx
00442E0C |. 8BD8 mov ebx,eax
00442E0E |. 33C0 xor eax,eax
00442E10 |. 55 push ebp
00442E11 |. 68 9B2E4400 push aLoNg3x_.00442E9B
00442E16 |. 64:FF30 push dword ptr fs:[eax]
00442E19 |. 64:8920 mov dword ptr fs:[eax],esp
00442E1C |. 8B83 D0020000 mov eax,dword ptr ds:[ebx+0x2D0]
00442E22 |. 8078 47 00 cmp byte ptr ds:[eax+0x47],0x0
00442E26 |. 75 0F jnz short aLoNg3x_.00442E37 ; 关键跳转1
00442E28 |. B2 01 mov dl,0x1
00442E2A |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]
00442E30 |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442E32 |. FF51 60 call dword ptr ds:[ecx+0x60] ; IsEnableWindow
00442E35 |. EB 49 jmp short aLoNg3x_.00442E80
00442E37 |> 8D55 FC lea edx,dword ptr ss:[ebp-0x4]
00442E3A |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442E40 |. E8 7B04FEFF call aLoNg3x_.004232C0
00442E45 |. 8B45 FC mov eax,dword ptr ss:[ebp-0x4] ; user32.75B17276
00442E48 |. 50 push eax
00442E49 |. 8D55 F8 lea edx,dword ptr ss:[ebp-0x8]
00442E4C |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC] ; comctl_1.74646957
00442E52 |. E8 6904FEFF call aLoNg3x_.004232C0
00442E57 |. 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
00442E5A |. 5A pop edx ; aLoNg3x_.0041E13E
00442E5B |. E8 DCFBFFFF call aLoNg3x_.00442A3C
00442E60 |. 84C0 test al,al
00442E62 |. 74 0F je short aLoNg3x_.00442E73 ; 关键跳转2
00442E64 |. B2 01 mov dl,0x1
00442E66 |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]
00442E6C |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442E6E |. FF51 60 call dword ptr ds:[ecx+0x60] ; IsEnableWindow
00442E71 |. EB 0D jmp short aLoNg3x_.00442E80
00442E73 |> 33D2 xor edx,edx
00442E75 |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]
00442E7B |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442E7D |. FF51 60 call dword ptr ds:[ecx+0x60]
00442E80 |> 33C0 xor eax,eax
00442E82 |. 5A pop edx ; aLoNg3x_.0041E13E
00442E83 |. 59 pop ecx ; aLoNg3x_.0041E13E
00442E84 |. 59 pop ecx ; aLoNg3x_.0041E13E
00442E85 |. 64:8910 mov dword ptr fs:[eax],edx
00442E88 |. 68 A22E4400 push aLoNg3x_.00442EA2
00442E8D |> 8D45 F8 lea eax,dword ptr ss:[ebp-0x8]
00442E90 |. BA 02000000 mov edx,0x2
00442E95 |. E8 4209FCFF call aLoNg3x_.004037DC
00442E9A \. C3 retn
00442E9B .^ E9 D803FCFF jmp aLoNg3x_.00403278
00442EA0 .^ EB EB jmp short aLoNg3x_.00442E8D
00442EA2 . 5B pop ebx ; aLoNg3x_.0041E13E
00442EA3 . 59 pop ecx ; aLoNg3x_.0041E13E
00442EA4 . 59 pop ecx ; aLoNg3x_.0041E13E
00442EA5 . 5D pop ebp ; aLoNg3x_.0041E13E
00442EA6 . C3 retn


codicechange:

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
73
00442C78  /.  55            push ebp                                 ;  codiceChange
00442C79 |. 8BEC mov ebp,esp
00442C7B |. 33C9 xor ecx,ecx
00442C7D |. 51 push ecx
00442C7E |. 51 push ecx
00442C7F |. 51 push ecx
00442C80 |. 51 push ecx
00442C81 |. 53 push ebx
00442C82 |. 56 push esi
00442C83 |. 8BD8 mov ebx,eax
00442C85 |. 33C0 xor eax,eax
00442C87 |. 55 push ebp
00442C88 |. 68 562D4400 push aLoNg3x_.00442D56
00442C8D |. 64:FF30 push dword ptr fs:[eax]
00442C90 |. 64:8920 mov dword ptr fs:[eax],esp
00442C93 |. 8D55 F8 lea edx,dword ptr ss:[ebp-0x8]
00442C96 |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442C9C |. E8 1F06FEFF call aLoNg3x_.004232C0
00442CA1 |. 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
00442CA4 |. 8D55 FC lea edx,dword ptr ss:[ebp-0x4]
00442CA7 |. E8 ACFCFBFF call aLoNg3x_.00402958
00442CAC |. 8BF0 mov esi,eax
00442CAE |. 837D FC 00 cmp dword ptr ss:[ebp-0x4],0x0
00442CB2 |. 74 18 je short aLoNg3x_.00442CCC
00442CB4 |. 8D55 F4 lea edx,dword ptr ss:[ebp-0xC]
00442CB7 |. 8BC6 mov eax,esi
00442CB9 |. E8 8249FCFF call aLoNg3x_.00407640
00442CBE |. 8B55 F4 mov edx,dword ptr ss:[ebp-0xC]
00442CC1 |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442CC7 |. E8 2406FEFF call aLoNg3x_.004232F0
00442CCC |> 8B83 D0020000 mov eax,dword ptr ds:[ebx+0x2D0]
00442CD2 |. 8078 47 00 cmp byte ptr ds:[eax+0x47],0x0
00442CD6 |. 75 0F jnz short aLoNg3x_.00442CE7 ; 关键跳转1
00442CD8 |. B2 01 mov dl,0x1
00442CDA |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC] ; comctl_1.74646957
00442CE0 |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442CE2 |. FF51 60 call dword ptr ds:[ecx+0x60] ; IsEnableWindow
00442CE5 |. EB 49 jmp short aLoNg3x_.00442D30
00442CE7 |> 8D55 F8 lea edx,dword ptr ss:[ebp-0x8]
00442CEA |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442CF0 |. E8 CB05FEFF call aLoNg3x_.004232C0
00442CF5 |. 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
00442CF8 |. 50 push eax
00442CF9 |. 8D55 F0 lea edx,dword ptr ss:[ebp-0x10]
00442CFC |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]
00442D02 |. E8 B905FEFF call aLoNg3x_.004232C0
00442D07 |. 8B45 F0 mov eax,dword ptr ss:[ebp-0x10]
00442D0A |. 5A pop edx ; aLoNg3x_.0041E13E
00442D0B |. E8 2CFDFFFF call aLoNg3x_.00442A3C
00442D10 |. 84C0 test al,al
00442D12 |. 74 0F je short aLoNg3x_.00442D23 ; 关键跳转2
00442D14 |. B2 01 mov dl,0x1
00442D16 |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC] ; comctl_1.74646957
00442D1C |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442D1E |. FF51 60 call dword ptr ds:[ecx+0x60] ; IsEnableWindow
00442D21 |. EB 0D jmp short aLoNg3x_.00442D30
00442D23 |> 33D2 xor edx,edx
00442D25 |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC] ; comctl_1.74646957
00442D2B |. 8B08 mov ecx,dword ptr ds:[eax] ; aLoNg3x_.0044282C
00442D2D |. FF51 60 call dword ptr ds:[ecx+0x60]
00442D30 |> 33C0 xor eax,eax
00442D32 |. 5A pop edx ; aLoNg3x_.0041E13E
00442D33 |. 59 pop ecx ; aLoNg3x_.0041E13E
00442D34 |. 59 pop ecx ; aLoNg3x_.0041E13E
00442D35 |. 64:8910 mov dword ptr fs:[eax],edx
00442D38 |. 68 5D2D4400 push aLoNg3x_.00442D5D
00442D3D |> 8D45 F0 lea eax,dword ptr ss:[ebp-0x10]
00442D40 |. E8 730AFCFF call aLoNg3x_.004037B8
00442D45 |. 8D45 F4 lea eax,dword ptr ss:[ebp-0xC]
00442D48 |. E8 6B0AFCFF call aLoNg3x_.004037B8
00442D4D |. 8D45 F8 lea eax,dword ptr ss:[ebp-0x8]
00442D50 |. E8 630AFCFF call aLoNg3x_.004037B8
00442D55 \. C3 retn

尝试在eax+0x47这下硬件写入断点,发现并不能断下来,说明还是没有满足某个条件。

看第二个关键函数,可以看到一个计算,通过用户名算出serial,懒得再解释了QAQ,直接看下面代码吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00442A8E  |.  B8 01000000   mov eax,0x1
00442A93 |> 8B4D FC /mov ecx,dword ptr ss:[ebp-0x4] ; user32.75B17276
00442A96 |. 0FB64C01 FF |movzx ecx,byte ptr ds:[ecx+eax-0x1]
00442A9B |. 8B75 FC |mov esi,dword ptr ss:[ebp-0x4] ; user32.75B17276
00442A9E |. 0FB63406 |movzx esi,byte ptr ds:[esi+eax]
00442AA2 |. 0FAFCE |imul ecx,esi
00442AA5 |. 0FAFC8 |imul ecx,eax
00442AA8 |. 03D9 |add ebx,ecx
00442AAA |. 40 |inc eax
00442AAB |. 4A |dec edx
00442AAC |.^ 75 E5 \jnz short aLoNg3x_.00442A93
00442AAE |> 8B45 F8 mov eax,dword ptr ss:[ebp-0x8]
00442AB1 |. E8 BA4BFCFF call aLoNg3x_.00407670
00442AB6 |. 2BD8 sub ebx,eax
00442AB8 |. 81FB 9A020000 cmp ebx,0x29A
00442ABE |. 75 04 jnz short aLoNg3x_.00442AC4
1
2
3
4
5
6
7
8
9
10
int len = strlen(szname);
int sum = len;
int temp = 1;
for (int i = 0; i < len - 1; i++) {
sum = ((szname[i] * szname[i + 1]) * temp) + sum;
temp++;
}
int serial;
serial = sum - 0x29A;
printf("%d\n", serial);

输入发现OK按钮已经亮了

点击OK按钮发现,没有用,codice清0,然后OK又灰色了。

从OK按钮入手,发现刚进来的第一个跳转就是熟悉的判断条件,说明程序并不是直接点击OK的,在这之前肯定还有一个条件要满足的。先继续在这里看一下,修改这个条件往下走,可以看到第二个跳转,修改这个跳转,按钮就会小时,经过分析之前这个函数就是算法。

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
00442D64  /.  55            push ebp
00442D65 |. 8BEC mov ebp,esp
00442D67 |. 6A 00 push 0x0
00442D69 |. 53 push ebx
00442D6A |. 8BD8 mov ebx,eax
00442D6C |. 33C0 xor eax,eax
00442D6E |. 55 push ebp
00442D6F |. 68 ED2D4400 push aLoNg3x_.00442DED
00442D74 |. 64:FF30 push dword ptr fs:[eax]
00442D77 |. 64:8920 mov dword ptr fs:[eax],esp
00442D7A |. 8B83 D0020000 mov eax,dword ptr ds:[ebx+0x2D0]
00442D80 |. 8078 47 01 cmp byte ptr ds:[eax+0x47],0x1 ; 熟悉的地址
00442D84 |. 75 12 jnz short aLoNg3x_.00442D98
00442D86 |. BA 002E4400 mov edx,aLoNg3x_.00442E00 ; UNICODE "0"
00442D8B |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442D91 |. E8 5A05FEFF call aLoNg3x_.004232F0
00442D96 |. EB 3F jmp short aLoNg3x_.00442DD7
00442D98 |> 8D55 FC lea edx,dword ptr ss:[ebp-0x4]
00442D9B |. 8B83 E0020000 mov eax,dword ptr ds:[ebx+0x2E0]
00442DA1 |. E8 1A05FEFF call aLoNg3x_.004232C0
00442DA6 |. 8B45 FC mov eax,dword ptr ss:[ebp-0x4]
00442DA9 |. E8 C248FCFF call aLoNg3x_.00407670
00442DAE |. 50 push eax
00442DAF |. 8D55 FC lea edx,dword ptr ss:[ebp-0x4]
00442DB2 |. 8B83 DC020000 mov eax,dword ptr ds:[ebx+0x2DC]
00442DB8 |. E8 0305FEFF call aLoNg3x_.004232C0
00442DBD |. 8B45 FC mov eax,dword ptr ss:[ebp-0x4]
00442DC0 |. 5A pop edx ; 0018F8D4
00442DC1 |. E8 DAFDFFFF call aLoNg3x_.00442BA0 ; 算法
00442DC6 |. 84C0 test al,al
00442DC8 |. 74 0D je short aLoNg3x_.00442DD7
00442DCA |. 33D2 xor edx,edx
00442DCC |. 8B83 CC020000 mov eax,dword ptr ds:[ebx+0x2CC]
00442DD2 |. E8 D903FEFF call aLoNg3x_.004231B0
00442DD7 |> 33C0 xor eax,eax
00442DD9 |. 5A pop edx ; 0018F8D4
00442DDA |. 59 pop ecx ; 0018F8D4
00442DDB |. 59 pop ecx ; 0018F8D4
00442DDC |. 64:8910 mov dword ptr fs:[eax],edx
00442DDF |. 68 F42D4400 push aLoNg3x_.00442DF4
00442DE4 |> 8D45 FC lea eax,dword ptr ss:[ebp-0x4]
00442DE7 |. E8 CC09FCFF call aLoNg3x_.004037B8
00442DEC \. C3 retn

进入算法进行查看,可以看到一个通过注册码求用户名的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
00442C09  |.  0FB64430 FF   |movzx eax,byte ptr ds:[eax+esi-0x1]     ;  获取最后一位
00442C0E |. F7E8 |imul eax ; 平方
00442C10 |. 0FBFC0 |movsx eax,ax
00442C13 |. F7EE |imul esi ; 乘以长度/长度不断-1
00442C15 |. B9 19000000 |mov ecx,0x19
00442C1A |. 99 |cdq
00442C1B |. F7F9 |idiv ecx
00442C1D |. 83C2 41 |add edx,0x41 ; 除以0x19余数+0x41
00442C20 |. 58 |pop eax ; 0018F8D4
00442C21 |. 8810 |mov byte ptr ds:[eax],dl
00442C23 |. 4E |dec esi
00442C24 |. 85F6 |test esi,esi
00442C26 |.^ 75 D1 \jnz short aLoNg3x_.00442BF9
00442C28 |> 8B45 F4 mov eax,dword ptr ss:[ebp-0xC]
00442C2B |. 8B55 FC mov edx,dword ptr ss:[ebp-0x4]
00442C2E |. E8 110FFCFF call aLoNg3x_.00403B44 ; 与输入的用户名进行比较
00442C33 |. 75 17 jnz short aLoNg3x_.00442C4C

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
char name[20];
itoa(serial, name,10);
int len = strlen(name);
int a = len;
for (int i = 0; i < len; i++) {
int temp = name[a-1] * name[a-1];
temp = temp * a;
temp = temp % 0x19;
temp = temp + 0x41;
name[a - 1] = temp;
a = a - 1;
}
printf("%s\n", name);

现在就剩下最后一个事件,CancellaClick

进去查看,发现里面没有那个熟悉的地址,那么基本上那个地址的赋值应该就是在这里了吧,只有一个跳转,修改条件后,最早下的硬件断点终于断下来了。那么查看一下算法的过程。

进入函数查看,可以看到具体的算法,是一个通过用户名求注册码的过程。

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
00442B20  |.  83F8 05       cmp eax,0x5                              ;  判断输入的name是否大于5
00442B23 |. 7E 53 jle short aLoNg3x_.00442B78
00442B25 |. 8B45 FC mov eax,dword ptr ss:[ebp-0x4]
00442B28 |. 0FB640 04 movzx eax,byte ptr ds:[eax+0x4] ; 获取name第五位
00442B2C |. B9 07000000 mov ecx,0x7
00442B31 |. 33D2 xor edx,edx
00442B33 |. F7F1 div ecx ; 除以7
00442B35 |. 8BC2 mov eax,edx ; 余数
00442B37 |. 83C0 02 add eax,0x2
00442B3A |. E8 E1FEFFFF call aLoNg3x_.00442A20 ; 阶乘
00442B3F |. 8BF0 mov esi,eax
00442B41 |. 33DB xor ebx,ebx
00442B43 |. 8B45 FC mov eax,dword ptr ss:[ebp-0x4]
00442B46 |. E8 E90EFCFF call aLoNg3x_.00403A34
00442B4B |. 85C0 test eax,eax
00442B4D |. 7E 16 jle short aLoNg3x_.00442B65
00442B4F |. BA 01000000 mov edx,0x1
00442B54 |> 8B4D FC /mov ecx,dword ptr ss:[ebp-0x4]
00442B57 |. 0FB64C11 FF |movzx ecx,byte ptr ds:[ecx+edx-0x1] ; 逐位获取
00442B5C |. 0FAFCE |imul ecx,esi
00442B5F |. 03D9 |add ebx,ecx ; user32.75B16D51
00442B61 |. 42 |inc edx
00442B62 |. 48 |dec eax
00442B63 |.^ 75 EF \jnz short aLoNg3x_.00442B54
00442B65 |> 2B5D F8 sub ebx,dword ptr ss:[ebp-0x8] ; 减去注册码十六进制
00442B68 |. 81FB 697A0000 cmp ebx,0x7A69
00442B6E |. 75 04 jnz short aLoNg3x_.00442B74
00442B70 |. B3 01 mov bl,0x1 ; 关键的赋值
00442B72 |. EB 06 jmp short aLoNg3x_.00442B7A
00442B74 |> 33DB xor ebx,ebx
00442B76 |. EB 02 jmp short aLoNg3x_.00442B7A

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = szname[4] % 0x7;
a = a + 2;
int num = 1;
for (int i = 1; i <= a; i++) {
num = num * i;
}
int len = strlen(szname);
int sum = 0;
for (int i = 0; i < len; i++) {
sum += szname[i] * num;
}
int serial;
serial = sum - 0x7A69;
printf("%d\n", serial);
return serial;

当经过了这个判断之后,那个地址就会被赋值,同时cancle按钮也会消失,ok按钮会常亮。

那么整体的流程就很清楚,首先要通过用户名计算一个注册码输入cancle按钮消失,ok变亮,然后再通过注册码计算出一个用户名输入后,ok消失,完成注册

注册机编写

完整注册机代码如下:

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
#include <stdio.h>
#include <Windows.h>
#include <string.h>

int CancleClick(char* szname) {
int a = szname[4] % 0x7;
a = a + 2;
int num = 1;
for (int i = 1; i <= a; i++) {
num = num * i;
}
int len = strlen(szname);
int sum = 0;
for (int i = 0; i < len; i++) {
sum += szname[i] * num;
}
int serial;
serial = sum - 0x7A69;
printf("%d\n", serial);
return serial;
}
void CodiceChange(char* szname) {
int len = strlen(szname);
int sum = len;
int temp = 1;
for (int i = 0; i < len - 1; i++) {
sum = ((szname[i] * szname[i + 1]) * temp) + sum;
temp++;
}
int serial;
serial = sum - 0x29A;
printf("%d\n", serial);
}
void OkClick(int serial) {
char name[20];
itoa(serial, name,10);
int len = strlen(name);
int a = len;
for (int i = 0; i < len; i++) {
int temp = name[a-1] * name[a-1];
temp = temp * a;
temp = temp % 0x19;
temp = temp + 0x41;
name[a - 1] = temp;
a = a - 1;
}
printf("%s\n", name);
}
int main() {
char name[20];
gets_s(name, 20);
printf("让cancle消失,通过用户名求出的serial\n");
int serial = CancleClick(name);
printf("-------------------------\n");
printf("仅仅只是显示OK按钮\n");
CodiceChange(name);
printf("-------------------------\n");
printf("让OK消失,通过serial:%d\n求出的用户名\n",serial);
OkClick(serial);

return 0;
}

cancle按钮

OK按钮

总结

程序共有三个算法

  • nomechange和codicechange里的,仅仅只是让OK亮起来
  • cancleClick里的,消失cancle按钮,赋值给那个关键地方,OK亮起
  • OKClick里的,让OK按钮消失

不知道nomechange和codicechange里的算法有什么用,感觉没必要。。。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!