BUUCTF 不一样的flag 1详细解析
迷宫!!!!!!!!!!!!!
好吧,一开始确实没看出来
题目提示:
是不是做习惯了常规的逆向题目?试试这道题,看你在能不能在程序中找到真正的flag!注意:flag并非是flag{XXX}形式,就是一个’字符串‘,考验眼力的时候到了!
注意:得到的 flag 请包上 flag{} 提交
0x02 ida查看并快速找到字符串步骤
1.解压后,用ida打开,shift+f12快捷键字符串搜索,发现可疑字符串

2.双击字符串,有窗口跳出新界面,
鼠标点击黄色字体,再按下x,进行交叉搜索

跳出新窗口,点击ok查看

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

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

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#
|