饨篦 发表于 5 天前

逆向常见反调试合集

反调试

  前文写过,花指令通常干扰静态分析,而反调试与之相反,主要为了干扰动态调试。
1.反调试简介

  反调试是一种用于阻碍程序动态调试的技术,首先大致说明一下反调试的工作原理。
  在操作系统内部提供了一些API,用于调试器调试。当调试器调用这些API时系统就会在被调试的进程内存中留下与调试器相关的信息。一部分信息是可以被抹除的,也有一部分信息是难以抹除的。
  当调试器附加到目标程序后,用户的很多行为将优先被调试器捕捉和处理。其中大部分是通过异常捕获通信的,包括断点的本质就是异常。如果调试器遇到不想处理的信息,一种方式是忽略,另一种方式是交给操作系统处理。
  那么目前为止,程序就有两种方式检测自己是否被调试:

[*]检测内存中是否有调试器的信息。
[*]通过特定的指令或触发特定异常,检测返回结果。
  通常来说,存在反调试的程序,当检测到自身处于调试状态时,就会控制程序绕过关键代码,防止关键代码被调试,或者干脆直接退出程序。


2.API反调试

  Windows内部提供了一些用于检测调试器的API。
  其中一个API是 IsDebuggerPresent,原型为:
BOOL IsDebuggerPresent();  返回值为1表示当前进程被调试的状态,反之为0.
  另一个常用的API是CheckRemoteDebuggerPresent,原型为:
BOOL CheckRemoteDebuggerPresent(HANDLE hProcess, PBOOL pbDebuggerPresent);  返回值为1表示当前进程被调试的状态,反之为0.

3.PEB反调试

  当程序处于3环(低权限)时, FS: 寄存器指向TEB(Thread Environment Block),即线程环境块结构体,TEB向后偏移0x30字节的位置保存的是PEB(Process Environment Block ),即进程环境块的结构体地址。PEB中的部分成员是与调息相关的成员,当调试器通过 Windows提供的API调试目标程序时,Windows会将一部分调试信息写人这个结构体中。
kd>dt_TEB
nt! _TEB
        ...
        +0x030 ProcessEnvironmentBlock :Ptr32_PEB
        ...
kd>dt_TEB
        ...
        +0x002 BeingDebugged        :UChar       
        ...
        +Ox018 ProcessHeap        :Ptr32 Void       
        ...
        +0x068 NtGlobalF1ag        :Uint4B
    ...  本处只介绍这两个结构体中几个重要的成员,若是想在实际调试时查看其他成员的具体内容,其中一种方法是使用WinDbg调试内核。
  在PEB结构体中中,BeingDebugged、ProcessHeap、NtGlobalFlag是与调试信息相关的三个重要成员。

[*]BeingDebugged:当进程处于被调试状态时,值为1,否则为0。
[*]ProcessHeap:指向Heap结构体,偏移0xC处为Flags成员,偏移0x10处为ForceFlags成员。通常情况下,Flags的值为2.ForceFlags的值为0,当进程被调试时会发生改变
[*]NGlobalFlag:占四个字节,默认值为0。当进程处于被调试状态时,第一个字节会被置为0x70。
  通过FS.Base能够定位到TEB,再通过TEB+0x30能够定位PEB。通过在内存中检测或修改相关成员的值,便可达到反试、反反调试的效果。

4.TLS反调试

  TLS (Thread Local Storage),即线程局部存储是Windows提供的一种处理机制,每进行一次线程切换,便会调用一次TLS回调。它本意是想给每个线程都提供访问全局变量的机会。例如,需要统计当前程序进行了多少次线程切换,但并不想让其他线程访问到这个计数变量,使用TLS进行计数,便能够解决这个问题,一个程序能设置多个TLS.
  由于进程在启动时至少需要创建一个线程来运行,因此在调用main函数前就会调用一次 TLS 回调。利用这个特点,在TLS回调中写入与反调试相关的代码,便可悄无声息地令调试器失效。
#include #include // TLS回调函数定义void NTAPI TLS_Callback(PVOID DllHandle, DWORD Reason, PVOID Reserved) {    if (Reason == DLL_PROCESS_ATTACH) {      // 检测是否存在调试器      if (IsDebuggerPresent()) {            std::cout
页: [1]
查看完整版本: 逆向常见反调试合集