zoukankan      html  css  js  c++  java
  • 常用的静态反调试技术及其规避方法

    静态反调试虽然容易绕过,但是由于种类繁多,如果病毒结合了很多种静态反调试而对其了解不多的话,也不好办,所以了解更多的

    方法不至于束手无策.

    1.利用PEB的BeingDebugged 字段

      已知fs:[0x30]指向PEB, PEB地址+0x2 处的一个字节的数据表示是否在被调试,如果是1则是,0则不是

      当进程被附加时,系统会将该值置为1

    IsDebuggerPresent() API就是利用这个原理工作的:

    IsDebuggerPresent的反汇编代码:

    751E9E0A  mov         eax,dword ptr fs:[00000030h]  
    751E9E10  movzx       eax,byte ptr [eax+2]  
    751E9E14  ret  

    所以通过调试器启动后或附加后将该值修改为0即可规避

    2.Ldr的内存区域特征

    启动方式调试程序时,peb中的Ldr的内存是从堆中分配的,未使用的区域被大量填充0xfeeefeee.但附加方式却不会出现这种情况.

    例如来到Ldr处(peb+0xc):这里测试Ldr地址是0x00241ea0

     下拉:

    通过附加的方式则不会出现这种特征. 此外,这种特征在xp以上的系统就没有了

    3.Process Heap (peb+0x18)

    _heap结构节选:(xp sp3)

    其中Flags和ForceFlags字段被调试时将不同

    当正常运行时前者为0x2,后者为0x0, 启动调试时将变成其他值:

    附加后查看:

     此外该特征在xp以上系统将不存在.附加方式调试也不会出现. 规避方法就是修改这2个值

    4.NtGlobalFlag (peb+0x68)

    该字段正常运行和被附加调试时为0,被启动调试时为其他值

    5.NtQueryInformationProcess 

    原型:

    NTSTATUS NtQueryInformationProcess(

    HANDLE ProcessHandle,

    PROCESSINFOCLASS ProcessInformationClass,

    PVOID ProcessInformation,

    ULONG ProcessInformationLength,

    PULONG ReturnLength

    );

     第2个参数是个枚举类型. 主要有3个值与调试有关:

    ProcessDebugPort = 7

    ProcessDebugObjectHandle = 30

    ProcessDebugFlags  = 31

    ProcessInformationClass 参数为7时,ProcessInformation返回调试状态.

     即当处于非调试状态将传入变量置0,否则置0xffffffff

     同理,当ProcessInformationClass 参数为30时,ProcessInformation返回调试对象句柄

     即当调试状态时将传入变量置句柄值,否则置0

     此外,API CheckRemoteDebuggerPresent就是通过这个方式来检测是否存在调试器

    ProcessInformationClass 参数为31时,ProcessInformation返回调试标记

     即当调试状态时将传入变量置0,否则置1

    规避方法:在该API开头处直接改为ret  (后面可能还要加数字平衡栈),让它获取不到任何信息.如:

    ntdll中的代码:

    773DD300 mov eax,18h
    773DD305 call dword ptr fs:[0C0h]
    773DD30C ret 14h

    改为:

    773DD300 C2 1400 retn 0x14
    773DD303 90 nop
    773DD304 90 nop
    773DD305 64:FF15 C000000>call dword ptr fs:[0xC0]
    773DD30C C2 1400 retn 0x14

    6.基于调试环境: NtQuerySystemInformation

    当操作系统开启内核调试模式时,会有一定特征,可以通过NtQuerySystemInformation API来获取

    NTSTATUS NtQuerySystemInformation(
      SYSTEM_INFORMATION_CLASS SystemInformationClass,
      PVOID SystemInformation,
      ULONG SystemInformationLength,
      PULONG ReturnLength);
    SYSTEM_INFORMATION_CLASS是个枚举类型:

    当为0x23时为获取系统是否在被调试信息存放到第2个参数指向的结构中,该结构是2个1字节的结构,当处于调试时这2字节都会被写入1.

    规避方法同样是调试时修改API,让其直接返回

    7.NtQueryObject

    该API获取系统内核对象信息,原型:

    NTSTATUS NtQueryObject(
      _In_opt_  HANDLE                   Handle,
      _In_      OBJECT_INFORMATION_CLASS ObjectInformationClass,
      _Out_opt_ PVOID                    ObjectInformation,
      _In_      ULONG                    ObjectInformationLength,
      _Out_opt_ PULONG                   ReturnLength
    );

    第2个参数是个枚举类型:

    typedef enum _OBJECT_INFORMATION_CLASS {
    ObjectBasicInformation = 0,

    ObjectNameInformation = 1,
    ObjectTypeInformation = 2,

    ObjectAllTypesInformation =3,

    ObjectHandleInformation 
    } OBJECT_INFORMATION_CLASS;

    传入3即获取所有对象信息,然后检测是否存在调试对象

    规避方法:修改API开头代码直接返回.

    8. ZwSetInformationThread

    NTSTATUS ZwSetInformationThread(
      _In_ HANDLE          ThreadHandle,
      _In_ THREADINFOCLASS ThreadInformationClass,
      _In_ PVOID           ThreadInformation,
      _In_ ULONG           ThreadInformationLength
    );
    

     当第一个参数传入本线程句柄,第2个参数传入0x11,后2个参数传入0即可将本线程设置为隐藏,从而使调试器收不到调试事件而无法调试.

    9.DebugActiveProcessStop 

    BOOL DebugActiveProcessStop(
      DWORD dwProcessId);

    该API使进程从调试器中detach出来,最后调试和被调试进程都终止.

    10.TLS回调函数

    利用tls回调函数可以将以上方法利用起来.

    11.其他静态检测思路

    比如探测od窗口名,进程名, 是否运行在虚拟机中等等方式

  • 相关阅读:
    一小时学会前端工程化
    lodash学习资料
    关于《冬天时我喜欢靠近温暖的事》这首歌 (民谣在路上)
    往后余生(简单的歌词分享)
    如果觉得活的很累不妨进来看看(生活应该简简单单)
    《大学》全文及白话翻译
    原型设计模式 Prototype
    解释器模式 Interpreter
    copy on write,代理模式
    ado.net
  • 原文地址:https://www.cnblogs.com/freesec/p/6576647.html
Copyright © 2011-2022 走看看