正常走,看到是一个32位的文件,无壳

然后先用IDA打开看看

其实,我打开看到代码蒙蒙的,很正常的用shift+f12看看字符串

但是还是一无所获【可能我菜鸡了】

然后又看了看main函数

感觉也对我来说也没有什么可以让我触动的地方

看了往上的WP后才知道 DialogFunc 这个函数有鬼

所以再main函数里面找到这个函数然后才开始了我的分析

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
INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4)
{
const char *v4; // esi
const char *v5; // edi
int v7[2]; // [esp+8h] [ebp-20030h] BYREF
int v8; // [esp+10h] [ebp-20028h]
int v9; // [esp+14h] [ebp-20024h]
int v10; // [esp+18h] [ebp-20020h]
int v11; // [esp+1Ch] [ebp-2001Ch]
int v12; // [esp+20h] [ebp-20018h]
int v13; // [esp+24h] [ebp-20014h]
int v14; // [esp+28h] [ebp-20010h]
int v15; // [esp+2Ch] [ebp-2000Ch]
int v16; // [esp+30h] [ebp-20008h]
CHAR String[65536]; // [esp+34h] [ebp-20004h] BYREF
char v18[65536]; // [esp+10034h] [ebp-10004h] BYREF

if ( a2 == 272 )
return 1;
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 == 1001 )
{
memset(String, 0, 0xFFFFu);
GetDlgItemTextA(hDlg, 1000, String, 0xFFFF);
if ( strlen(String) == 8 )
{
v7[0] = 90;
v7[1] = 74;
v8 = 83;
v9 = 69;
v10 = 67;
v11 = 97;
v12 = 78;
v13 = 72;
v14 = 51;
v15 = 110;
v16 = 103;
sub_4010F0(v7, 0, 10);
memset(v18, 0, 0xFFFFu);
v18[0] = String[5];
v18[2] = String[7];
v18[1] = String[6];
v4 = (const char *)sub_401000(v18, strlen(v18));
memset(v18, 0, 0xFFFFu);
v18[1] = String[3];
v18[0] = String[2];
v18[2] = String[4];
v5 = (const char *)sub_401000(v18, strlen(v18));
if ( String[0] == v7[0] + 34
&& String[1] == v10
&& 4 * String[2] - 141 == 3 * v8
&& String[3] / 4 == 2 * (v13 / 9)
&& !strcmp(v4, "ak1w")
&& !strcmp(v5, "V1Ax") )
{
MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
}
}
return 0;
}
if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
return 0;
EndDialog(hDlg, (unsigned __int16)a3);
return 1;
}

看到的是这样一串东西,哇哦好多,好难受…

根据网上说的经验之谈,这个if语句肯定就是逆向的点,也就是说:这个地方

下面有2个字符串比较的函数,所以肯定有一个flag 经过某些操作后和这个strcmp比较,如果正确的话就是flag

也就是说,flag经过变换变成了ak1w 和 V1Ax。至于是如何变换来的,这个就需要分析上面的代码来看看了。

看代码,根据我的总结:首先粗略的看一下流程,大概知道这个是在讲什么的,然后再一步一步的慢慢 分析每一步的作用【当遇到某一步,不太好静态分析出来的时候就需要使用OD动态调试一下】

ok 我们现在来看看

首先他是定于了一大变量,然后就是进行if判断,但是这2个if对我们逆向这个点,没有太大的作用,因为他们if后都是return ;就返回了,肯定程序不能走这里,所以就没有分析的价值。

然后就是第三个if

这个if肯定有作用,因为后面的代码都是再这个if里面的

第一句,memset 就是拷贝

下一句调用了一个API函数,这里先跳过,因为我不知道这个API函数是作什么的,反正就是调用了某一个函数。

又是下一句 判断String 是否等于8 这里,必须等于8,不然就没有什么意义了

看到下面是给一堆的变量赋值,这里,凭着我的直觉,这些变量在某种程度上有一定的联系,返回去看看它定义的地方。果然,定义的地方都是在一起的,说明什么?说明这个是一个数组。

下面就是一个sub_4010f0的函数,点过去看看

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
int __cdecl sub_4010F0(int a1, int a2, int a3)
{
int result; // eax
int i; // esi
int v5; // ecx
int v6; // edx

result = a3;
for ( i = a2; i <= a3; a2 = i )
{
v5 = 4 * i;
v6 = *(_DWORD *)(4 * i + a1);
if ( a2 < result && i < result )
{
do
{
if ( v6 > *(_DWORD *)(a1 + 4 * result) )
{
if ( i >= result )
break;
++i;
*(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
if ( i >= result )
break;
while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
{
if ( ++i >= result )
goto LABEL_13;
}
if ( i >= result )
break;
v5 = 4 * i;
*(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
}
--result;
}
while ( i < result );
}
LABEL_13:
*(_DWORD *)(a1 + 4 * result) = v6;
sub_4010F0(a1, a2, i - 1);
result = a3;
++i;
}
return result;
}

很明显,这个地方不好分析,我本身是准备用OD动态调试一下,看看这个地方到底是在干什么

但是由于我比较垃圾,调试不出来MD。

又去看了看WP , 发现它是它把重新写成了一个c代码,然后运行了一下

这里我们效仿一下

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
#include <stdio.h>
int __cdecl sub_4010F0(int s[], int a2, int a3)
{
int result; // eax a2 =0 a3 = 10
int i; // esi
int v5; // ecx
int v6; // edx

result = a3;
for (i = a2; i <= a3; a2 = i)
{
// v5 = 4 * i;
v5 = i;
v6 = s[i];
if (a2 < result && i < result)
{
do
{
if (v6 > s[result])
{
if (i >= result)
break;
++i;
s[v5] = s[result];
if (i >= result)
break;
while (s[i] <= v6)
{
if (++i >= result)
goto LABEL_13;
}
if (i >= result)
break;
v5 = i;
s[result] = s[i];
}
--result;
} while (i < result);
}
LABEL_13:
s[result] = v6;
sub_4010F0(s, a2, i - 1);
result = a3;
++i;
}
return result;
}

int main() {
int s[11] = { 'Z','J','S','E','C','a','N','H','3','n','g' };
sub_4010F0(s, 0, 10);
for (int i = 0; i < 11; i++) {
printf("%c", s[i]);
}
}

这里看到

1
*(_DWORD *)(4 * i + a1);

这个是变成了

1
s[i]

这里就不得不感谢一下

https://blog.csdn.net/afanzcf/article/details/119682630?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168562858016800226513434%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168562858016800226513434&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119682630-null-null.142^v88^control_2,239^v2^insert_chatgpt&utm_term=%E5%88%AE%E5%BC%80%E6%9C%89%E5%A5%96%20BUU&spm=1018.2226.3001.4187

这篇文章了

【这里不知道为什么,复制地址这么多….】

这里截取一下它的主要内容

image-20230601221625327

也就是这个公式

所以在原本的IDA中编译出来是4*i

但是在原先定义的时候,是用int 定义的,所以这里是一个int类型的数组,所以就需要4*1

但是写出来的时候就是[i]

image-20230601224627484

这样就知道原来的数组变成了:3CEHJNSZagn

对比一下之前的:ZJSECaNH3ng

很明显,这个是进行了一次排序。

接着往下看:看到一个初始化某个数组后,把这个数组放进了sub_401000函数

现在就是来看看sub_401000函数是干什么的

好吧,看了还是看不懂,本身想说利用上面的方法进行一次操作的

但是发现….【好吧,还是能力有限的问题】看了WP后知道,这里直接就猜到了base64编码

因为image-20230601222624080

这个

还有一种猜测的方式是:

image-20230601222746479

进去的是3个字符,但是最后比较的是4个字符。

3个变成了4个 猜测base64

OK 我们现在知道了

image-20230601223136467

解码

image-20230601223231949

得到的是WP1 和jMp

加上上面的string[0]和[1]来进行分析咯

1
2
String[0] == v7[0] + 34
String[1] == v10

v7[0] = ‘3’ + 34 = 85 = ‘U’

v10 = ‘J’

所以flag{UJWP1jMp}


补充

这里可以用IDA的动调

image-20230601233026054

也能得到这个

好舒服的IDA!!!!