BUUCTF 不一样的flag 1详细解析

迷宫!!!!!!!!!!!!!

好吧,一开始确实没看出来

题目提示:

是不是做习惯了常规的逆向题目?试试这道题,看你在能不能在程序中找到真正的flag!注意:flag并非是flag{XXX}形式,就是一个’字符串‘,考验眼力的时候到了!

注意:得到的 flag 请包上 flag{} 提交

0x02 ida查看并快速找到字符串步骤

1.解压后,用ida打开,shift+f12快捷键字符串搜索,发现可疑字符串

image-20260423220826728

2.双击字符串,有窗口跳出新界面,

鼠标点击黄色字体,再按下x,进行交叉搜索

image-20260423220946415

跳出新窗口,点击ok查看

image-20260423221118256

3.又进入新界面,按快捷键f5反汇编

image-20260423221200411

即可查看字符串所在具体的代码

image-20260423221254605

0x03 分析代码

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
74
75
76
77
78
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
// v3 数组共 29 字节。
// 前面部分存地图字符串,v3[25] 开始的 4 字节被当作 int 使用,记录“行坐标”。
char v3[29];
int v4; // 列坐标 (y)
int v5; // 存储用户输入的指令 (1, 2, 3, 4)
int i;
// v7 在栈上的位置紧跟在 v3 后面,这种布局在下标计算时非常关键
_BYTE v7[12];

__main();

// 初始化坐标和地图
v3[26] = 0;
*(_WORD *)&v3[27] = 0; // 这两行确保了以 v3[25] 为起始的 DWORD 初始值为 0
v4 = 0; // 初始列坐标为 0

// 将迷宫地图存入 v3
// 字符串长度 25,刚好可以看作一个 5x5 的方阵
strcpy(v3, "*11110100001010000101111#");

while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);

// --- 移动逻辑 ---
if ( v5 == 2 ) // 输入 2:向下走
{
++*(_DWORD *)&v3[25]; // 行坐标 +1
}
else if ( v5 > 2 )
{
if ( v5 == 3 ) // 输入 3:向左走
{
--v4; // 列坐标 -1
}
else
{
if ( v5 != 4 ) // 输入不是 4 则退出(非法输入)
LABEL_13:
exit(1);
++v4; // 输入 4:向右走,列坐标 +1
}
}
else // 输入 1:向上走
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25]; // 行坐标 -1
}

// --- 边界检查 ---
for ( i = 0; i <= 1; ++i )
{
// 检查行坐标和列坐标是否超出 0-4 的范围 (5x5 迷宫)
if ( *(_DWORD *)&v3[4 * i + 25] > 4u )
exit(1);
}

// --- 碰撞检测与终点判断 ---
// 这里的 v7[...] 看起来很怪,其实是编译器计算偏移后的结果
// 它等价于检查:地图字符串[行坐标 * 5 + 列坐标]
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' ) // 如果踩到 '1'
exit(1); // 撞墙,游戏结束

if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' ) // 如果踩到 '#'
{
puts("\nok, the order you enter is the flag!"); // 到达终点
exit(0);
}
}
}
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
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char v3[29]; // [esp+17h] [ebp-35h] BYREF
int v4; // [esp+34h] [ebp-18h]
int v5; // [esp+38h] [ebp-14h] BYREF
int i; // [esp+3Ch] [ebp-10h]
_BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF

__main();
v3[26] = 0;
*(_WORD *)&v3[27] = 0;
v4 = 0;
strcpy(v3, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);
if ( v5 == 2 )
{
++*(_DWORD *)&v3[25];
}
else if ( v5 > 2 )
{
if ( v5 == 3 )
{
--v4;
}
else
{
if ( v5 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(_DWORD *)&v3[4 * i + 25] > 4u )
exit(1);
}
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}
1
2
3
4
5
*1111
01000
01010
00010
1111#