解题流程
下载程序
运行:
翻译为:
玩游戏
n是灯的序列号,m是灯的状态
如果第n个灯的m是1,它就亮,如果不是,它就灭
起初所有的灯都关上了
现在您可以输入n来更改其状态
但是你应该注意一件事,如果你改变Nth的状态p、 (N-1)th和(N+1)th的状态也改变
所有灯亮起时,flag将出现
现在,输入n
输入n,n(1-8)
就是输入一个1到8之间的数,例如1:就会改变周围的三个数的状态,令8、1、2三个数变亮,再输入一个2:也会改变2周围三个数的状态,令1、2熄灭,3亮起。多次输入后,最后8个数都亮起的时候就会输出flag。
方法一
逐渐输入1~8,得到flag
方法二
动态调试
先查壳
OD打开文件
右键 >> 搜索引擎 >> 智能搜索,一眼找到flag相关字符串"done!!! the flag is"
双击字符串找到对应的汇编指令,能推断出这是一个输出flag的函数,向上找到这个函数的入口地址为0099E940,因此只要让程序跳转到这里就能输出flag。
根据搜索到的字符串确定到输出flag函数的位置0099E940,点击可以看到显示“跳转来自 007A7AB4”,右键转到该地址。
又看到在007A7AB4位置显示“本地调用来自 007AF66C”,右键转到这个地址。
可以看到,在007AF66C地址的call指令之上有八个jnz指令,对应的是程序里八盏灯的明暗判断。
在各jnz指令处都设置断点。按F9运行程序,程序需输入1-8任意一数字,程序会运行到第一个jnz处的断点暂停。输入1的结果如下图:
这时看程序运行到时,对应的ZF标志寄存器值为多少,若为0则右键“置1”,然后运行。接下来的七个断点也是如此。
八个jnz处的断点位置z寄存器的值都为1,函数接着就会跳转到输出flag的函数。后面没有设置断点,直接继续运行就能得到flag。
注意: 这里用jnz去举例,jnz的判断检查Z位,当Z位是1的时候就不跳转,在Z位是0的时候就跳转
方法三
DA打开无壳
1.SHIFT+F12打开string窗口
2.ALT+T查找flag
3.双击查看该字符串的内存地址
变量位于只读数据区(rdata)
4.通过X键定位变量的交叉引用地址
F5查看伪代码(关键部分)
此IDA为IDAPro6.6
分析后是两步异或的过程
flag生成逻辑为:将v2 ~ v58各字符分别与v59 ~ v115进行异或,再与0x13u(十进制19)进行异或,所得的v2~58字符即为flag
5.Python对数据处理得到flag
方法五
修改源码
用OD打开,查找字符串“done!!! the flag is”找到输出flag的关键位置:
发现它是跳转来自 01077AB4。所以我们再往上转到 01077AB4:
01077AB4为跳转到flag的地址,后面修改的正为此地址01077AB4
0107E940=ConsoleA.0107E940 表明了它指向了输出flag的函数;本地调用来自 0107F66C说明它是由0107F66C调用的,所以我们再往回转到 0107F66C:
我们到了这,发现上面由8个JNZ,这不就是源代码里的8个判断吗?
一旦只要由一个判断不满足,程序就跳转到输出flag的函数的下一条去了,这样就不会输出flag而重新开始循环要求你输出n了:
所以我们要修改源代码令程序不管怎样都会进入输出flag的函数,这样我们只要运行程序就能得到flag了。将原来的“jmp 0107F4FB”(跳转到循环重新开始的位置)改为jmp 01077AB4(跳转到输出flag函数的位置),这样只要我们输入1~8直接的数,程序最后都为跳转到01077AB4(flag函数的入口地址):
建议:将jmp ConsoleA.01077AB4改为call ConsoleA.01077AB4
即不要跳到里面去
也可以在断点运行的过程修改跳转地址
保存到可执行文件,(没有直接保存的选项,所以需要右键 复制到可执行文件->选上
运行:
同样也得到flag。