【汇编】反调试之Fake F8

前言:功能键F7和F8在DTDEBUG工具中,都是用来执行指令的,那他们有什么区别呢?下面将为大家讲解在调试阶段F7和F8的区别,以及如何做到简单的反调试。

1、F7/F8的区别

        F7:单步步入

        F8:单步步过

        单步步入与单步步过的区别:F7/F8在普通的指令上是没有任何区别的,都是一步一步往下执行,区别就在于CALL这个指令上。

        F7:F7执行call指令的时候会先跳转到call指令里存放的EIP(下一步执行指令的地址),然后再往下一步一步执行。

        F8:F8执行call指令的时候会从call指令中的EIP开始一下子执行到ret。

2、调试器实现原理

​ 断点:        0xCC

​ 单步步入:设置EFLAGS的TF位

​ 单步步过:在下一行设置断点

3、断点

        1、如何设置断点?

                快捷键F2

        2、断点的功能

                程序执行到断点就会停下来,其实当我们把exe拖进来之后,程序停止时的EIP中的地址就是一个断点。

        3、断点的本质是什么?

               断点的本质其实是指令INT 3,当CPU执行的时候,见到INT 3 的时候就会停下来,停在调试器里。

                当我们F2设置断点的时候,那么这一行汇编对应的机器码的第一个字节就已经被改写为 0xCC ,尽管调试器不会显示,但是实际上已经进行了更改,调试器在执行到这里检测到了 0xCC 之后就会断下。(0xCC是int 3 的机器码。)

4、CALL和RET指令

         CALL指令:将call指令后的值存入EIP(下一次执行的地址),然后当前call语句下一行的地址存入esp栈指针寄存器中,最后栈指针-4。其原理可以通过两个指令实现。

        假设:CALL 0x401141

 

         F7运行,不能使用F8,因为我们还没做RET。

        结果:

        

        分析:一个CALL 0x401141本质上就是:

JMP 401141H
MOV dword ptr ds:[esp-4],401131H -- 这一行应该在401141的地方执行
SUB esp,4

         RET指令:返回。将当前esp内存放的值取出,放入eip变为下一次执行的地址,然后esp+4。 

        F8执行两次。

        RET指令就是返回到当前堆栈中存放的地址,原理如下:

JMP dword ptr ds:[esp]
ADD esp,4        -- 这一行应该在上一步esp中的地址执行

 

5、简单的反调试Fake F8

        Fake F8就和他的名字一样Fake:欺骗,也就是骗别人使用F8进行调试,因为F7是一步一步的执行,但是F8是一下子执行到RET。

        演示:F7

        执行一次:

 

        执行两次:

 

        执行三次:

 

        执行四次:

 

        演示:F8 

        执行一次:

 

        

        我们就是可以通过F8一下子会执行完,但F7是一步一步的执行这一特性,如果说F8执行CALL开始到RET返回的中间,堆栈中的值做了修改,那么RET的时候,返回的就是堆栈中此时的地址,这样的话你就做到了反调试。

        比如:CALL 0x233244,然后这条指令所在的地方假如是:0x233000,假设它的下一个指令地址是:0x233001。

        那么它会跳到233244这个地址,执行233244地址中的指令 ,然后将233001存入堆栈中,以便之后的返回。假设此时233244地址中的指令是:mov dword ptr ds:[esp],11223344H

        那么他就会修改堆栈中的值为11223344,这个时候如果执行到RET指令,就会跳转到11223344地址去执行指令,这个时候就到了人生地不熟的地方了,调试员也会懵逼,这就做到了最简单的反调试。

        那么,是否会有疑问说:那这样的话一直摁F7不就行了,大不了不用F8。

        不行,因为实际做反调试的时候,并不仅是这么简简单单的几条指令就返回。我们可以在从单个CALL指令跳转到的地址到RET之前,再次调用CALL跳转到其他地址。也就是一个CALL之后到RET返回之前,可以在多弄几个CALL,然后第二波的CALL中再多弄几个CALL,直到最后可能有几个或者几十个CALL指令,然后每条CALL指令之后到RET指令之前都设置几百个或者几万个没用的指令,比如mov来mov去的那种。最终只在一个CALL和RET之间是可以正常返回的,也就是说没有修改堆栈的地址,其他CALL到RET中,都设置有修改堆栈值的命令。

        这样一来,面对成千上万的指令,而且基本都是没用的,如果调试员还是一直F7,那么执行了几万条指令都没用,估计会气的受不了,但是如果他认为这个call语句中不会有错,摁下了F8,那么其中一条语句就会把他带到人生地不熟的地方,这样他就被骗了。

        这是一个特别基础的反调试,本人不是从事该行业,只是看了一些教程,有些懵,所以记录了下来,如果有错,还望大佬指正。

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值