1 Acid burn

1.Acid burn

寻找MessageBox

我们的目的是找到序列号或者序列号的计算规则,分析的目标是找到正确的目标函数,再分析函数的功能。首先用onlydbg加载并调试程序,点击check it,弹出窗口,我们要去定位窗口调用的位置,因为我们需要依据这个MessageBox定位判断函数;

image-20220925212526777

搜索所有模块间的调用,

image-20220926091650656

找到MessageBoxA,在所有调用设置断点

image-20220926091820658

我们可以分析出弹窗调用发生在地址0x42A1A9 call <jmp.&user32.MessageBoxA> ; \MessageBoxA

image-20220926094033087

追溯判断逻辑

保留这个断点,再次运行程序,点击check it! 可以发现在右下角堆栈处找到最近一条Return语句:

0019F704 |0042FB37 返回到 Acid_bur.0042FB37 来自 Acid_bur.0042A170

右键Follow in Disassm…(反汇编跟随),

image-20220926094953267

如下代码:

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
0042FACD  |.  E8 466CFDFF   call Acid_bur.00406718
0042FAD2 |. FF75 E8 push [local.6]
0042FAD5 |. 68 C8FB4200 push Acid_bur.0042FBC8 ; UNICODE "-"
0042FADA |. FF75 F8 push [local.2]
0042FADD |. 8D45 F4 lea eax,[local.3]
0042FAE0 |. BA 05000000 mov edx,0x5
0042FAE5 |. E8 C23EFDFF call Acid_bur.004039AC
0042FAEA |. 8D55 F0 lea edx,[local.4]
0042FAED |. 8B83 E0010000 mov eax,dword ptr ds:[ebx+0x1E0]
0042FAF3 |. E8 60AFFEFF call Acid_bur.0041AA58
0042FAF8 |. 8B55 F0 mov edx,[local.4]
0042FAFB |. 8B45 F4 mov eax,[local.3]
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
0042FB0C |. BA D8FB4200 mov edx,Acid_bur.0042FBD8
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
0042FB21 |. B9 74FB4200 mov ecx,Acid_bur.0042FB74 ; ASCII 54,"ry Again!"
0042FB26 |. BA 80FB4200 mov edx,Acid_bur.0042FB80 ; ASCII 53,"orry , The serial is incorect !"
0042FB2B |. A1 480A4300 mov eax,dword ptr ds:[0x430A48]
0042FB30 |. 8B00 mov eax,dword ptr ds:[eax]
0042FB32 |. E8 39A6FFFF call Acid_bur.0042A170
0042FB37 |> 33C0 xor eax,eax

看到了提示框显示的字符串,那么错误提示弹窗应该是发生在这里,注意到0x42FB1F,以及

0042FB03 75 1A jnz short Acid_bur.0042FB1F

可以推断出jnz处的判断与弹窗关系密切,尝试将这里nop掉,并取消MessageboxA的断点,并点击check it运行;

image-20220926095910347

虽然序列号是随意输入的,但依然得到了正确弹窗,说明0x42FB03就是我们找到的判断位置,恢复指令,继续分析。

image-20220926100005478

断点调试,寻找序列号

将该位置之前的几处调用设置断点,call,继续check it,并F8单步,观察寄存器值的变化;image-20220926100421741

运行到最后一个call之前,在寄存器中发现了错误的序列号和疑似正确的序列号‘CW-7954-CRACKED’,这个序列号是不是就是我们要找的呢?

image-20220926100801994

果然,我们尝试换用户名,会发现改序列号是变化的,是根据用户名计算的;

尝试保留序列号不变,改变用户名,会发现只要第一个字符是a,序列号永远是对的,说明改序列号是根据第一位计算出来的;

接下来去分析计算规则;

image-20220926101020421

分析计算规则

接下来用IDA静态分析计算规则,直接跳转到我们分析出的0x42FB03,

image-20220926102226469

按空格查看控制流图,发现了两处try again以及一处good job,根据汇编代码,可以得到这样的结论,

  • 数据段dword_43176C与4做了比较,大于4(jge)才可能到达good job!并且在输入用户名和序列号时,我们能够发现用户名长度必须大于4个字符;

  • 并且发现了imul指令,有符号乘法,dword_431750与eax做乘法,并且赋值给了dword_431750;

  • 接着执行了mov和add,这段代码很容易看出是将两个数加了起来,也就是乘积的结果乘以2;

image-20220925203654268

再次回到OD,在乘积这里每一行下断点,主要追踪EAX和dword_431750的值,运行代码check it!;

image-20220926103855606 image-20220926103953955 image-20220926104041611 image-20220926105656855

我们可以发现EAX的变化,abcds->0x61->0xF89->0x1F12, EAX的值先是被保存到了dword_431750,后又在0x42FAC8处赋值给EAX;

  • abcds是输入的用户名name;
  • 0x61十进制为97,是a的ascii码;
  • 0xF89十进制为3977,3977除以97的值为41,之,3977还要再乘以2;
  • 0x1F12十进制为7954,3977*2的结果;
  • 注意到7954和序列号‘CW-7954-CRACKED’中的数字部分一样;

计算规则是:首字符的ascii码值*41*2?

我们在IDA中查看伪代码,验证我们分析到的规则:找到了dword_431750的值确实为41,并且找到了乘积运算,不仅如此,我们还发现str_CW和str_CRACKED以及str__(下划线),

说明我们分析的规则是正确的。

image-20220926110804490

附:伪代码

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
// 按钮点击事件的函数完整伪代码
// 参数a1是EAX的值,也就是用户名,
int __usercall TNS_BitBtn1Click@<eax>(int a1@<eax>, int a2@<ebx>, int a3@<esi>)
{
int v3; // ebx
int v4; // esi
int v5; // esi
int v6; // ecx
char v7; // zf
unsigned int v9; // [esp-14h] [ebp-2Ch]
void *v10; // [esp-10h] [ebp-28h]
int *v11; // [esp-Ch] [ebp-24h]
int v12; // [esp-8h] [ebp-20h]
int v13; // [esp-4h] [ebp-1Ch]
int v14; // [esp+0h] [ebp-18h]
int v15; // [esp+4h] [ebp-14h]
int *v16; // [esp+8h] [ebp-10h]
int v17; // [esp+Ch] [ebp-Ch]
int v18; // [esp+10h] [ebp-8h]
int v19; // [esp+14h] [ebp-4h]
int savedregs; // [esp+18h] [ebp+0h]

v17 = 0;
v16 = 0;
v15 = 0;
v14 = 0;
v13 = a2;
v12 = a3;
v3 = a1;
v11 = &savedregs;
v10 = &loc_42FB67;
v9 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v9);
dword_431750 = 0x29; // 41
sub_41AA58(*(_DWORD *)(a1 + 476), &v16);// v16的值
dword_43176C = sub_403AB0(v16);// 用户名长度
sub_41AA58(*(_DWORD *)(v3 + 476), &v16);
v4 = 7 * *(unsigned __int8 *)v16;
sub_41AA58(*(_DWORD *)(v3 + 0x1DC), &v15);
dword_431754 = 16 * *(unsigned __int8 *)(v15 + 1) + v4;
sub_41AA58(*(_DWORD *)(v3 + 0x1DC), &v16);
v5 = 11 * *((unsigned __int8 *)v16 + 3);
sub_41AA58(*(_DWORD *)(v3 + 0x1DC), &v15);
dword_431758 = 14 * *(unsigned __int8 *)(v15 + 2) + v5;
if ( sub_406930(dword_43176C) >= 4 )// 比较用户名长度
{
sub_41AA58(*(_DWORD *)(v3 + 476), &v16);
dword_431750 *= *(unsigned __int8 *)v16;//乘以v16
dword_431750 *= 2; //乘以2
sub_403708(&v19, &str_CW[1]);
sub_403708(&v18, &str_CRACKED[1]);
sub_406718();
sub_4039AC(&v17, 5, v6, &str___0[1], v14, &str___0[1], v18);
sub_41AA58(*(_DWORD *)(v3 + 480), &v16);
sub_4039FC(v17, v16);
if ( v7 )
sub_42A170(*off_430A48, "Good job dude =)", "Congratz !!", 0);
else
sub_42A170(*off_430A48, "Sorry , The serial is incorect !", "Try Again!", 0);
}
else
{
sub_42A170(*off_430A48, "Sorry , The serial is incorect !", "Try Again!", 0);
}
__writefsdword(0, v9);
v11 = (int *)&loc_42FB6E;
sub_403670(&v14);
sub_403694(&v15, 2);
return sub_403694(&v17, 3);
}

image-20220925210312090

1
2
3
4
5
6
7
8
9
void Decryption(char* mima)
{
char szBuff[260];
unsigned long data = (unsigned long)mima[0];
data *= 0X29;
data *= 2;
sprintf(szBuff, "CW-%d-CRACKED", data);
printf("%s \r\n", szBuff);
}

最终结果为CW-s-CRACKED

s为用户名的第一个字符的ascii码值*0x29*2