CrackMe001—Acid burn

第一次敲开二进制的大门 感觉老难了

一开始的弹窗

双击打开之后 我们发现他有一个弹窗

1
"hello you have to kill me"

我看这个弹窗很不爽 我想把它弄掉 在这之前先用exeinfope看一下有没有加壳 以及使用啥语言写的 好在没有加壳 使用的语言也只是Borland Delphi 所以我们可以用DelphiDecompiler这个东西反编译一下 看看他一些重要的函数地址在哪

之前以为可能是因为这个程序的弹窗先于程序本身执行的原因 找了半天确实没有在DeDe找到和这个弹窗有关的入口地址 于是我打算在OD里面找 后来才知道 之前在DeDe那边的Procedures里面找的那个叫按钮 就是按了才有弹窗的 和之前一开始就弹出来的那个不一样

因为是Delphi写的 弹窗调用的函数是MessageBox 我们如果想到那停下来 我们可以bp MessageBoxA 至于为什么嘛 慢慢看完

我们在这下了bp之后 F9运行一下 程序停在了7638AB20这个位置 这个不管他 我们看右下角的堆栈窗口 这个窗口hin重要

1
2
3
4
5
0019FDBC   0042A1AE  /CALL 到 MessageBoxA 来自 Acid_bur.0042A1A9
0019FDC0 00120906 |hOwner = 00120906 ('Acid burn',class='TApplication')
0019FDC4 0042F7BC |Text = "Welcome to this Newbies Crackme made by ACiD BuRN [CracKerWoRlD]"
0019FDC8 0042F7A0 |Title = "hello you have to kill me!"
0019FDCC 00000000 \Style = MB_OK|MB_APPLMODAL

是不是很眼熟 不仅如此 我们可以观察到MessageBoxA是从哪里调用的 我们Follow到相应位置 在0042A1A2那里

这一段 代表的就是MessageBoxA这个函数了 虽然我没写过Delphi 但是应该我们在写的时候 弹窗函数的命名是MessageBox 但是可能当这个函数被加载 堆进栈的时候 他的名字可能是MessageBoxA 也许吧至于怎么把他弄掉 把这一段全部NOP掉就行了

我其实用不了MessageBoxA 因为这个很容易和其他的弹窗冲突了 我可能会用来处理程序打头就出现的那种弹窗

Serial/Name

分析一波

我们要求输入Name以及Serial 然后他就会take it boy一下() 我们随便输入一些东西 看看回显是什么

1
2
Try Again!
Sorry,The serial is incorrect

嗯我们记住了这个字符串 我们去DeDe找找入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0042F998   55                     push    ebp
0042F999 8BEC mov ebp, esp
0042F99B 33C9 xor ecx, ecx
0042F99D 51 push ecx
0042F99E 51 push ecx
0042F99F 51 push ecx
0042F9A0 51 push ecx
0042F9A1 51 push ecx
0042F9A2 51 push ecx
0042F9A3 53 push ebx
0042F9A4 56 push esi
0042F9A5 8BD8 mov ebx, eax
0042F9A7 33C0 xor eax, eax
0042F9A9 55 push ebp

* Possible String Reference to: '楱5?胫^[嬪]肨ry Again!'

不想截图了 截图老累了 大致是通过这里判断出来 这个弹窗入口是在0042F998 自己也找一下叭 我们bp 0042F998 然后F9跑一下(Name和Serial都是233)

在输入完Serial和Name之后 take it boy点下去 OD里面程序也跑到了0042F998(因为我设置的断点) 我们F8一步步步入 同时注意观察堆栈情况

1
2
3
0042F9CD  |.  8B45 F0       mov eax,[local.4]
堆栈 ss:[0019F64C]=0258E65C, (ASCII "233")
eax=0258E65C, (ASCII "233")

这一行 把内存里面我们输入的Name给赋值给了eax寄存器 意味着就在这个附近会有一个比较的函数(推测) 继续F8 没几步也堆栈了我们输入的Serial 和刚刚那个差不多

大概到这里的时候 我们看到了他堆栈了一个字符串

1
0019F650   026FE698  ASCII "CW-4018-CRACKED"

大胆猜测他就是用来比较的那个Serial 不过我们先放着 继续往下 就在刚刚那个位置往下一点点 不截图了

1
2
3
4
5
6
7
8
9
10
0042FAFE  |.  E8 F93EFDFF   call Acid_bur.004039FC
0042FB03 |. /75 1A jnz short Acid_bur.0042FB1F
0042FB05 |. |6A 00 push 0x0
0042FB07 |. |B9 CCFB4200 mov ecx,Acid_bur.0042FBCC ; Congratz !!
0042FB0C |. |BA D8FB4200 mov edx,Acid_bur.0042FBD8 ; Good job dude =)
0042FB11 |. |A1 480A4300 mov eax,dword ptr ds:[0x430A48]
0042FB16 |. |8B00 mov eax,dword ptr ds:[eax]
0042FB18 |. |E8 53A6FFFF call Acid_bur.0042A170
0042FB1D |. |EB 18 jmp short Acid_bur.0042FB37
0042FB1F |> \6A 00 push 0x0

我们可以分析出来 他首先call了Acid_bur.004039FC这个函数 然后紧随着这个的就是jnz(jmp if not zero) 我猜这个函数就是 比较我们的Serial是不是正确 正确就返回0 就不跳转 就输出Congratz !! 如果不对就返回一个1 那就跳转 很明显当我们输入不正确Serial的时候 OD上面显示跳转已实现 保险起见 我们去IDA上面看一下这个函数

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
int __fastcall sub_4039FC(int result, int *a2)
{
int *v2; // esi
int *v3; // edi
unsigned int v4; // eax
unsigned int v5; // edx
bool v6; // cc
unsigned int v7; // edx
unsigned int v8; // edx
int v9; // ecx
int v10; // ebx
char v11; // [esp-4h] [ebp-10h]

v2 = (int *)result;
v3 = a2;
if ( (int *)result != a2 )
{
if ( result )
{
if ( a2 )
{
v4 = *(_DWORD *)(result - 4);
v5 = *(a2 - 1);
v6 = v4 <= v5;
result = v4 - v5;
if ( v6 )
v5 += result;
v11 = v5;
v7 = v5 >> 2;
if ( v7 )
{
while ( *v2 == *v3 )
{
v8 = v7 - 1;
if ( !v8 )
{
++v2;
++v3;
goto LABEL_13;
}
if ( v2[1] != v3[1] )
return result;
v2 += 2;
v3 += 2;
v7 = v8 - 1;
if ( !v7 )
goto LABEL_13;
}
}
else
{
LABEL_13:
if ( (v11 & 3) == 0
|| (v9 = *v2, v10 = *v3, (unsigned __int8)*v2 == (unsigned __int8)*v3)
&& ((v11 & 3) == 1 || BYTE1(v9) == BYTE1(v10) && ((v11 & 3) == 2 || (v9 & 0xFF0000) == (v10 & 0xFF0000))) )
{
result *= 2;
}
}
}
else
{
result = *(_DWORD *)(result - 4);
}
}
else
{
result = -*(a2 - 1);
}
}
return result;
}

虽然我没看明白整个函数逻辑 但是我看到了

1
if ( (int *)result != a2 )

最大的那个if 条件就是如果result!=a2 那么走下面的if 如果等于就直接返回了 并且Label_13也是在那个if里面触发的 也就是说如果这个if没进 返回值就是0 而没进的条件就是相等

咋搞呢

咋搞也简单 我们不是jnz吗 我们随便输一个数 把jnz改成jz就行了 或者干脆更直接一点 直接把jnz给nop掉就行了 然后直接重开F9一波就行了 当然或者直接输入

1
Serial=CW-4018-CRACKED

也是可以的

这个CrackMe001 差点没给我直接劝退了QAQ