1.题目介绍

  描述:听说运行就能拿到Flag,不过菜鸡运行的结果不知道为什么是乱码
  来源:CSAW CTF 2014
  场景:暂无
  附件:可执行文件,文件名“0453d21297a743e199d8a7de75179e52.exe”

2.文件分析

  使用Exeinfo PE分析得知该exe文件没有加壳,为32位,可能是Microsoft Visual Studio 2010版本编写的。

  程序打开,会弹出一个对话框,对话框标题是“Flag”,显示出来的文字是乱码。点击任意一个按钮后程序退出。

3.逆向分析

  话不多说,直接将这个exe文件拖动到IDA Pro中分析。分析得到的反汇编代码如下。这里定义了3条路径,每条路径用红色方框框定,如下图所示。

  分别是路径1、路径2、路径3。
  其中,
  路径1:没有哪段代码能够跳转到路径1,可能是多余的。
  路径2:调用了MessageBoxA函数,用于弹出对话框。那么程序执行可能是按照路径2走的。
  路径3:对ecx寄存器进行多次加法后,调用中断INT 3,再执行一个sub_401000函数,最后跳转到下面的路径,结束程序。
  但是在调试的过程中碰到了一个问题,路径1、2、3上面的方框里,有一段指令call ds:IsDebuggerPresent,说明程序里调用了一个判断当前状态程序是否被调试的函数。在插入断点并逐步执行时,程序指令走的路径3,并且在指令INT 3处时,IDA会报错,提示“1A109A:软件断点异常(x86模拟)(程序代码 4000001f,线程id 7128)”

  随后再按下逐语句执行的快捷键F7F8,IDA又会弹出一个窗口。提示“异常处理:此次执行在异常产生后恢复,您想把异常传递给应用程序吗? 如果选择‘是’,应用程序的异常处理器(有一个的话)将会被执行。 应用程序的控制可能会丢失。”(下方的蓝色斜体字:“更改对异常的定义”)

  无论选择什么选项,之后的指令都无法再执行了。总之,指令卡在这里了,只能退出程序。还有值得注意的一点,附加调试并退出程序后,原来路径3中的函数“sub_401000”会改变地址(名字也改变了),不过没关系,笔者对照了前后函数中的反汇编代码,没有发现任何变化,读者在调试时试着对比一下。
  看来接下来是搞不出flag哟,其实不然,笔者在这里记录下当时的思路。

3.1 思路1

  路径3走不通,为何不试试路径2?路径2上方的代码如下

1
2
3
call    ds:IsDebuggerPresent
test eax, eax
jz short loc_1A10B9

  JZ是跳转指令,全称Jump if Zero,为0时跳转到另外的地址,不为0时继续执行下方的指令。这里的JZ指令依据eax的值来决定是否跳转。所以为了使程序走路径2,在逐语句执行的时候将eax寄存器的值改为0(在执行到 test eax,eax 时修改)。(eax值为1,则走路径3)如下图所示。

  随后再执行路径2中的指令。令人失望的是,寄存器并没有出现所谓的flag。仍然是调用了MessageBoxA函数,弹出的窗口依然显示的乱码。

3.2 思路2

  虽然可以通过修改寄存器的值让程序执行路径2,但是观察寄存器后我们并没有得到想要的结果。路径1就不用想了,根本就没有代码能够跳转到路径1。而路径3执行的时候调试器会报错。其实不用担心,报错主要是因为那句坑爹的指令INT 3,这是中断指令,可以将其用nop指令替换掉,不会对程序造成影响。nop指令相当于占位符,机器遇见这条指令不会做任何操作。
  选定INT 3指令那一行,在菜单栏中选择“Edit(编辑)”,再选择“Patch Program(给程序打补丁)”,最后选择“Assemble...(汇编)”。在弹出的对话框中,填入“nop”指令,点击OK就行。

  其实在点击OK之后这个对话框又会弹出一次,是更改下一条指令。这时点击“Cancel”即可。路径3更改后如下所示。

  为了保证nop指令已经写入到程序,需要再次选定菜单栏中的“Edit(编辑)”,“Patch Program(给程序打补丁)”,最后选择“Apply patches to input file...(将补丁应用到输入文件)”,弹出对话框。

  还有两个勾选框分别为“创建备份”,“恢复原始字节”,根据实际情况来勾选,此处笔者就不勾选了。
  最后重新把程序拖动到IDA加载,依然逐语句执行进入路径3,跟踪寄存器edx的值,就能够得到flag。

  最终flag为“flag{reversing_is_not_that_hard!}

总结

  IDA指令更改;绕过反调试技巧;