文章总结: 这篇文章详细分析了一个简单的RE逆向工程迷宫题,通过IDA静态分析Linux程序,理解其输入验证机制和迷宫移动逻辑。文章展示了如何识别文件类型、分析主函数逻辑、理解输入格式要求、还原迷宫布局,并解释了四种字符对应不同方向移动的原理。这是一篇实用的逆向工程教程,适合CTF初学者学习二进制安全分析技巧。 综合评分: 88 文章分类: 逆向分析,CTF,二进制安全

一道简单的RE迷宫题
Calparrot
看雪学苑
2025年10月19日 18:00 上海

首先使用工具查看文件信息,是Linux系统下的一个文件,而且没有打包,很正常的程序。
不想动态分析啊,动态分析很依赖操作系统的嘛,用IDA查看文件。函数也很简单,一个初始化跳转到main函数,然后就可以分析函数内容了。其实说是逆向还是在这里主要看代码。这里为了方便逐一分析代码就直接粘贴过来了。
__int64 __fastcall main(__int64 a1, char **a2, char **a3){ const char *v3; // rsi signed __int64 v4; // rbx signed int v5; // eax char v6; // bp char v7; // al const char *v8; // rdi __int64 v10; // [rsp+0h] [rbp-28h] v10 = 0LL; puts("Input flag:"); scanf("%s", &s1, 0LL);
这里可以看到要求用户输入,存储在s1里面,0LL是一个多余的参数,可以不用管。
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 ) 这里处理用户输入,主要的判断条件有三个: 1.判断输入长度是否为24, 2.将v3赋值为”nctf{“,把s1的前五个字符与”nctf{“进行比较,其中5uLL是一个参数,表示前5,无符号,LongLong型, 3.&byte_6010BF + 24地址处的内容是否为”}“,也就是ASCII码125。 {LABEL_22: puts("Wrong flag!"); 前面条件不符就直接失败了啊。 exit(-1); } v4 = 5LL; v4被赋值为5,LL表示5是一个LongLong型。 if ( strlen(&s1) - 1 > 5 ) { while ( 1 ) { v5 = *(&s1 + v4); 这里就比较好懂了,接下来要从用户输入的第6个字符开始分析。 v6 = 0; if ( v5 > 78 ) { v5 = (unsigned __int8)v5; 为什么v5要做这么一个操作呢,v5在这里要确保字符在这里被解析成一个无符号字节,如果是负的可能有意外结果。 if ( (unsigned __int8)v5 == 79 ) 一、O { v7 = sub_400650((char *)&v10 + 4, v3); goto LABEL_14; } if ( v5 == 111 ) 二、o { v7 = sub_400660((char *)&v10 + 4, v3); goto LABEL_14; } } else { v5 = (unsigned __int8)v5; if ( (unsigned __int8)v5 == 46 ) 三、. { v7 = sub_400670(&v10, v3); goto LABEL_14; } if ( v5 == 48 ) 四、0 { v7 = sub_400680((int *)&v10);LABEL_14: v6 = v7; goto LABEL_15; } }
上面标注序号的地方就是逐个处理用户输入的字符的判断条件,对应了四种字符。每个条件后跟随的语句都对v7进行赋值,然后跳转至LABLE_14,先看v7是什么。
v7的赋值都调用了一个sub_什么什么的函数,随便点一个进去看看。
bool __fastcall sub_400650(_DWORD *a1){ int v1; // eax v1 = (*a1)--; return v1 > 0;}
这里还不知道是干什么的,但是大概可以看出来这里的返回值是一个布尔值,先往下走查看v7发挥了什么作用,也就是每一次调用的那个LABLE_14。在LABLE_14中,v7的值被给了v6,随后跳转至LABLE_15。这里可以看到有一个跳转是返回了之前报错失败的地方,大概能猜到这里是一个错误处理。
LABEL_15: v3 = (const char *)HIDWORD(v10); if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) ) goto LABEL_22;
接下来就是一个用户输入的移动,因为v4就相当于一个指针,先查看有没有到输入的末尾,然后再根据v6(也就是上面的v7)来再次做一个判断,如果上面的v7是TRUE就能接着执行,否则就输出”Wrong flag!“。
if ( ++v4 >= strlen(&s1) - 1 ) { if ( v6 ) break;LABEL_20: v8 = "Wrong flag!"; goto LABEL_21; } } } if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 ) goto LABEL_20;
这个if条件很关键,它告诉了v10的一些信息,这里取了v10的低32位((signed int)v10强制转换为32位有符号整数,也就是低32位)和v10的高32位(SHIDWORD(v10)取有符号v10的高32位),而这整个表达式8 * (signed int)v10 + SHIDWORD(v10)就是一个二维数组的索引计算,这就能猜到了,asc_601060其实就是储存着迷宫信息的二维数组,而在这里知道了v10(前面sub_什么什么的参数)也就能猜出v7储存的就是移动操作的返回值,上面的每一个if下控制的就是不同按键的移动方式。
v8 = "Congratulations!";LABEL_21: puts(v8); return 0LL;}
现在大概能知道整个程序是在干嘛了,查看asc_601060信息,因为8 * (signed int)v10 + SHIDWORD(v10)式子,也能知道每8个字符一行。

这个就是查看的信息,还原迷宫就是:
******
* * *
*** * **
** * **
* *# *
** *** *
** *
********
格式问题,有点不好看啊,把这个迷宫走出来就能得到flag了,不过至于上面每个字符对应的是往哪里走,可以结合v10的意义来判断,有两个参数是有v10+4的,大概可以判断操作的是y轴方向,所以对应的是上下移动,另外两个就是左右移动了,具体的还需要进入函数内部分析。就比如sub_400650,里面有一个–操作,y轴数值减小向上移动,也就是上移动函数,接下来几个也是同理。
#

看雪ID:Calparrot
https://bbs.kanxue.com/user-home-1032907.htm
*本文为看雪论坛优秀文章,由 Calparrot 原创,转载请注明来自看雪社区

报名中!看雪·第九届安全开发者峰会(SDC 2025)
往期推荐
无”痕”加载驱动模块之傀儡驱动 (上)
为 CobaltStrike 增加 SMTP Beacon
隐蔽通讯常见种类介绍
buuctf-re之CTF分析
物理读写/无附加读写实验


球分享

球点赞

球在看

点击阅读原文查看更多
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论