逆向学习笔记(4)——动态反调试技术

1.SEH异常处理

windows中存在许多的异常处理类型,如下:

EXCEPTION_DATATYPE_MISALIGNMENT        (0x80000002)
EXCEPTION_BREAKPOINT                   (0x80000003)   断点异常
EXCEPTION_SINGLE_STEP                  (0x80000004)   单步执行
EXCEPTION_ACCESS_VIOLATION             (0x80000005)   非法访问内存
EXCEPTION_IN_PAGE_ERROR                (0x80000006)
EXCEPTION_ILLEGAL_INSTRUCTION          (0x8000001D)   无法识别的指令
EXCEPTION_NONCONTINUABLE_EXCEPTION     (0x80000025)
EXCEPTION_INVALID_DISPOSITION          (0x80000026)
EXCEPTION_ARRAY_BOUNDS_EXCEEDED        (0x8000008C)
EXCEPTION_FLT_DENORMAL_OPERAND         (0x8000008D)
EXCEPTION_INT_DIVIDE_BY_ZERO           (0x80000094)   除法运算分母为0
...

而反调试技术则可以利用异常处理机制来进行反调试处理。

1)在异常处理过程函数中进行静态反调试判断。例如判断PEB的调试标识等。

2)利用异常处理机制进行动态反调试。

如果程序处于调试状态时,在程序抛出异常后,会优先派发给调试器进行处理。此时就可以利用这一点进行反调试处理。如下代码:

00401000    PUSH EBP
00401001    MOV EBP, ESP
00401003    PUSH EBX
00401004    PUSH DynAD_SE.004099A0
00401009    CALL DynAD_SE.00401077
0040100E    ADD ESP, 4
00401011    PUSH DynAD_SE.0040102C
00401016    PUSH DWORD PTR FS:[0]
0040101D    MOV DWORD PTR FS:[0], ESP
00401024    INT3
00401025    MOV EAX, -1
0040102A    JMP EAX
0040102C    MOV EAX, DWORD PTR SS:[ESP+C]      //这里是异常处理函数
00401031    MOV EBX, DynAD_SE.00401040
00401036    MOV DWORD PTR DS:[EAX+B8], EBX
0040103D    XOR EAX, EAX
0040103F    RETN
00401040    POP DWORD PTR FS:[0]
00401047    ADD ESP, 4
0040104A    PUSH DynAD_SE.004099B4
0040104F    CALL DynAD_SE.00401077
00401054    ADD ESP, 4
00401057    POP EBX
00401058    POP EBP
00401059    RETN

如果异常处理函数没有执行的话,JMP EAX就会导致进程崩溃。因为在异常处理函数中,将EIP设置为了00401040。这就是典型的利用异常机制进行的反调试(调试器优先处理异常),如果跳过程序自己的SEH处理,可能就会导致崩溃的问题。同样,反调试可以不选择让程序崩溃,而是让其进入一大段混乱的代码中,让调试者迷失在其中。

2.SetUnhandledExceptionFilter()

当进程发生异常处理时,如果进程中没有处理异常的SEH函数,则会调用系统默认的异常函数。而SetUnhandledExceptionFilter()函数则允许设定这个默认函数。定义如下:

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
    __in LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
);

lpTopLevelExceptionFilter函数定义如下:

typedef struct _EXCEPTION_POINTERS{
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
}EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

LONG TopLevelExceptionFilter(PEXCEPTION_POINTERS pExcept);

这里的处理函数需要返回上一个异常处理函数地址。

通常反调试就会在新的异常处理函数中进行调试状态判断,从而干扰调试工作。

3.时间测量法

时间测量主要是判断时间差,如果时间差过大,则有可能进程处于调试状态。因为调试执行耗时要比正常运行大的多。

其中获取时间的方法有如下几种方法:

1)Counter based method

RDTSC(RDTSC是一个汇编指令,执行后可获取当前时间,大小为64位。EDX存放高32位,EAX存放低32位)

kernel32!QueryPerformanceCounter() / ntdll!NtQueryPerformanceCounter()

kernetl32!GetTickCount()

而以上三种获取时间的精准度,靠上面的相对会更高。

2)Time based method

timeGetTime()

_ftime()

4.陷阱标识

陷阱标识指的是EFLAGS寄存器的第九个比特位(index:8)。

 

 

其中的单步标识就是陷阱标识(Trap Flag)。

当TF值为1时,CPU将进入单步调试模式。在单步执行模式中,CPU执行1条指令后就会触发一个异常EXCEPTION_SINGLE_SETP。然后陷阱标识就会自动清零。由于单步调试会抛出EXCEPTION_SINGLE_SETP异常,所以可以利用这一点进行SEH反调试处理。

例子如下,因为陷阱标识位无法直接修改,所以通过压栈的方式进行修改。

PUSHFD                         ;这个就是将EFALGS压栈
OR DWORD PTR SS:[ESP], 100     ;对栈中的位数据进行修改,TF至1,触发单步异常。
POPFD

5.INT 2D

INT 2D原为内核模式中用来触发断点异常的指令,也可以在用户模式下触发异常。但程序调试运行时不会触发异常,只是忽略。所以这种差异就会被利用在反调试之中。INT 2D有下面两个特征:

1)自动忽略下一条指令的第一个字节

在调试模式中执行完INT 2D后,下一条指令的第一个字节就会被自动忽略掉。

0040101E    CD 2D        INT 2D
00401020    B8 EB5D0000  MOV EAX, 5DE8
00401025    8D18         LEA EAX, DWORD PTR DS:[EAX]
00401027    83C3 10      ADD EBX, 10

执行完INT 2D后会自动忽略B8,下一条指令就变成了JMP SHORT 00401080(CB 5D)

00401021    EB 5D        JMP SHORT 00401080
00401023    0000         ADD BYTE PTR DS:[EAX], AL
00401025    8D18         LEA EBX, DWORD PTR DS:[EAX]
00401027    83C3 10      ADD EBX, 10

像这样基于INT 2D的反调试技术能够形成较强的代码混淆(Obfuscated Code)效果。

(改变代码字节顺序扰乱程序代码的方法称为代码混淆技术,常被用于动态反调试中)

2)一直运行到断点处

INT 2D指令的另一个特征是,使用SetInto(F7)或SetOver(F8)命令跟踪INT 2D指令时,程序不会停在其下条指令开始的地方,而是一直运行,直到遇到断点,就像使用RUN(F9)命令运行程序一样。

6.0xCC探测

程序调试过程中,我们一般会设置许多的软件断点。断点对应的x86指令为“0xCC”。若能检测到该指令,即可判断程序是否处于调式状态。基于这一想法的反调试技术称为“0xCC探测”技术。

但该技术准确度不够,因为数据中可能也同样包含有CC。

7.API断点

当设置API断点时,API的开始部分的第一个字节会被设置为0xCC,所以可以通过探测这些API上的断点来判断当前程序是否处于调试状态。

8.比较校验和

该方法主要是通过对比一个区域的校验和值(CRC)来判断是否被人下过断点。因为当你下断点时,会将断点处的值改为0xCC,调试器之所以看不到,是为了方便调试故意隐藏了。但内存中的断点位置却是0xCC。所以可以对比同一区域的校验和值,来判断是不是被人下了断点。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤月丶星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值