第一步 查壳,本题是32位,有壳,进行脱壳。
第二步 这里的 jnz 指令会实现一个跳转,并且下面的0EC85D78Bh被标红了,应该是一个不存在的地址,这些东西就会导致IDA无法正常反汇编出原始代码,也称为花指令。(如下图)
我们把先把jnz指令右键nop,之后再将call指令变成数据再进行下一步nop。
点击call指令,按D数据化后尝试先把第一个数据nop掉,之后尝试建立主函数,如果不行的话再将下一个数据也nop掉。
nop完后从这里开始到00401128,按p构建main函数。
构建后是这个样子,我们跟进main
这里有关本题解决花指令的方法详情前参考这篇文章:
[HDCTF2019]Maze(考点:去花)_[hdctf2019]maze 题解-CSDN博客
第三步 按tab键转换(红色的不用管,可能是我脏字节没弄干净,不影响)。
分析一下这段代码:
其中终点为(5,-4),因此后面显示congratulations的字样。
函数调用和输入读取
- sub_401140(aGoThroughTheMa);
- 调用函数 sub_401140 并传入参数 aGoThroughTheMa,这可能是一个提示或指示信息。
- v5 = scanf("%14s", v7);
- 使用 scanf 从标准输入读取最多14个字符的字符串到变量 v7 中,并将读取的字符数赋值给 v5。
循环处理用户输入
- for (i = 0; i <= 13; ++i)
- 遍历用户输入的每个字符(最多14个),进行相应的处理。
- switch (v7[i]) 根据当前字符 v7[i] 的值,执行不同的操作:
- default: continue;
- 对于其他字符,继续下一次循环。
- case 'w': ++dword_40807C;
- 如果字符是 'w',则增加变量 dword_40807C 的值。
- case 's': --dword_40807C;
- 如果字符是 's',则减少变量 dword_40807C 的值。
- case 'd': ++*(_DWORD *)asc_408078;
- 如果字符是 'd',则增加 asc_408078 指向的 DWORD 类型的值。
- case 'a': --*(_DWORD *)asc_408078;
- 如果字符是 'a',则减少 asc_408078 指向的 DWORD 类型的值。
- default: continue;
结果判断
- if (*(_DWORD *)asc_408078 == 5 && dword_40807C == -4)
- 检查 asc_408078 指向的值是否为5,并且 dword_40807C 的值是否为-4。这两个条件可能代表了玩家需要达到的目标状态。
- 成功与否的处理
- 成功 (true 分支)
- sub_401140(aCongratulation);
- 调用 sub_401140 并传入 aCongratulation,可能用于显示恭喜信息。
- sub_401140(aHereIsTheFlagF);
- 调用 sub_401140 并传入 aHereIsTheFlagF,可能用于显示成功获得的奖励或标志。
- sub_401140(aCongratulation);
- 失败 (else 分支)
- sub_401140(aTryAgain);
- 调用 sub_401140 并传入 aTryAgain,提示用户再次尝试。
- sub_401140(aTryAgain);
- 成功 (true 分支)
返回值
- return 0;
- 函数返回0,通常表示程序执行成功。
我们在代码中发现“a”“s”“d”“w”四个操作对应我们键盘上的四个按键,这是迷宫问题的典型特征。
跟进一下asc_408078(或dword_40807C),得到如下信息:
a和d控制左右,w和s控制上下,因此asc对应横着的第几列,dword对应竖着的第几行
上图告诉我们,起点为(7,0)。
我们推测:+对应的是起点,F对应的是终点(之前的迷宫题目也是差不多的)
第四步 编写脚本
分析一下脚本:
- 变量定义和查找:
- maze 是一个包含迷宫字符的字符串。
- sid 和 eid 分别是字符 '+' 和 'F' 在 maze 中的索引位置。
- 计算行和列:
- ex, ey 被定义为 -4 和 5。这些值在代码中的具体含义不明确,但看起来像是尝试定义某种“步长”或“方向”。
- c = (eid - ey) // (-ex) 计算列数。这里的计算方式比较特殊,看起来是尝试根据某种规则来确定列宽。
- r = len(maze) // c 计算行数,即迷宫的总长度除以每行的字符数。
- 输出迷宫:
- 循环从 0 到 r,每次循环打印从 c*i 到 c*(i+1) 的子字符串,这应该是尝试将一维字符串按照每行 c 个字符分割成多行。
r = 7 (即7行)
c = 10(即10列)
为了方便读者理解F的位置ex,ey =(5,-4)我在下面的图上标出了坐标轴,类似于把该迷宫放在第四象限。
flag{ssaaasaassdddw}