今天碰到一个题目,用od调试的时候总会莫名奇妙地自己退出,最后查百度才知道原来里面有个反调试函数
题目是一个windows下的可执行文件
先直接运行程序看一下
居然直接出现了一个flag窗口,但是里面的flag却是乱码。这里猜想程序可能对真正的flag进行了加密。
拖到peid中发现没有壳
先拖入ida静态分析
我们可以看到程序的第16行有一个MessageBoxA函数,这个应该就是弹出我们的乱码的flag的窗口的代码了。但是我们要的是明文的flag。推测这种用窗口弹出乱码flag的题目肯定也能让它弹出一个明文flag的窗口,所以我们推测应该有一个解码的函数将乱码flag解码成真正的flag。这个函数应该就是sub_401000。
我们往上可以看到在第10行有个if判断语句,里面第一个函数跟进去会发现它是固定返回0的,这是一个或语句,所以再看第二个函数,这个函数就是反调试函数了。
IsDebuggerPresent函数
该函数辉再程序运行时判断程序是否正在被调试器调试,如果是,则返回一个非0值,且退出程序,如果不是则返回一个0值。
所以如果我们直接运行该函数,由于两个函数都返回0,那么if语句里面的代码将不会被执行,直接运行下面弹出窗口的程序。由于我们直接运行程序时弹出的flag是乱码,所以我们可以判断if语句里面的代码可能是解码的。而当我们在od或者其他调试器中调试时,isDebuggerPresent函数辉检测到程序正在被调试从而退出程序。因此我们的思路就是绕过这个判断然后直接运行解码程序,然后再弹出窗口。
我们再看看汇编代码
我们可以看到在执行反调试函数的那个代码块有个跳转是跳到之前猜测的sub_401000那里的。所以我们应该让程序跳转到这个地方,但是这个地方的代码执行完后它并不会跳转到我们的弹出窗口的函数那里,而是直接退出了,所以我们还得让它后面再跳转到 loc_4010b9 这个地方。
然后我们拖到od中动态调试一下
首先进来的时候函数是停在这里的,然后下面有个跳转,跳转后再一步步跟进,最后一个call语句来到了我们刚刚分析的地方
注释我已经打上了,但是这里还是分析一下。
红线圈起来的部分对应ida中红线圈起来的部分。test命令将寄存器AX与自己进行and运算,它不会产生结果,但是会影响标志寄存器的标志位zf ,如果AX为0,则ZF变为1,反之则为0。而 jnz 命令跳转的依据是zf=0,jz跳转的依据是zf=1。
调试时会看到AX中的数据是0,所以这个跳转不会执行,从而直接执行下面的反调试函数,因此这里我们待会要将它修改一下。
这一段可以看到是和ida 中的 loc_401096 这一段对应的,所以里面的call 9.01001000就是解码函数了,所以我们要让代码执行到这里,而这段代码下面还有一个int 3 中断,这个会让我们程序停下来,待会也要把它去掉。
继续往下,10010A3那里还有一个跳转直接跳过了我们弹出窗口的函数,所以这个地方我们也要修改,然后下面我们看到有两个messageboxa,messageboxa函数接受4个参数,第二个是标题,第三个是弹窗内容。如果我们运行第一个messageboxa会发现弹出的窗口是空的
因此正确答案应该再在第二个窗口中。最后我们将代码修改
然后运行程序
得到 flag!