恶意代码分析-第十六章-反调试技术

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37809075/article/details/82556473

目录

笔记

实验

Lab16-1

Lab16-2

Lab16-3


笔记

反调试技术:识别是否被调试,或者让调试器失效。

探测windows调试器

       Windows API:IsDebuggerPresent-->查询进程块环境块PEB中的IsDebugged标志

                               CheckRemoteDebuggerPresent-->检测本地机器中的一个进程是否运行在调试器中,也可以通过传递自身进程句柄来探测自己是否被调试

                            NtQueryInformationProcess-->Ntdll.dll中的一个原生的API,NtQueryInformationProcess(句柄,进程信息类型),第二个参数设置为0x7,会告诉这个句柄的标识是否正在被调试。

                               OutputDebugString-->在调试器中显示一个字符串,事先设置一个错误码。

      手动检测调试器:手动检测数据结构

                                  1.检测BeingDebugged           

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged; //被调试状态
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

BYTE BeingDebugged //,这里就是记录程序的调试状态的,(1代表被调试,0代表没有被调试) 我们可以使用 BOOL WINAPI IsDebuggerPresent(void);这个函数来检测是否有调试器存在,返回非0值代表被调试,如果返回0代表没有被调试。                   

76A9A720 64 A1 30 00 00 00    mov         eax,dword ptr fs:[00000030h]  //获取PEB结构基地址
76A9A726 0F B6 40 02          movzx       eax,byte ptr [eax+2]                       //根据PEB结构,我们知道是取
76A9A72A C3                   ret 

            PEB结构在TEB结构的0x30偏移的地方,也就是fs:[0x30]处可以取到PEB的基地址。

解决方法:手动改0标志,设置BeingDebugged属性为0

                                              2.检测ProcessHeap

Reserved4数组中一个未公开的位置叫做ProcessHeap,位于PEB结构的0x18处,第一个堆头部都有一个属性来指明这个堆是否在调试中创建。这些属性叫ForceFlags(堆头部偏移量为0x10/0x44处)和Flags(堆头部偏移量为0x0c/0x40处)。

解决办法:手动修改ProcessHeap值

                                  3.检测NTGlobalFlag

调试器中启动进程与正常模式下启动进程有些不同,所以创建内存堆的方式也不同,使用PEB结构偏移量0x68的位置决定如何创建堆结构。如果值为0x70就是正在运行。

解决办法:手动修改ProcessHeap属性

            系统痕迹检测:注册表,查找文件目录,进程列表,FindWindow

默认情况下是Dr.Watson,当被调试时,可能变为OllyDbg

识别调试器的行为

            INT扫描:在代码中查找0xCC

                                repne scasb扫描代码CC,解决的办法就是应用硬件断点

           代码校验和检查:CRC循环冗余校验或者MD5

      时钟检测:被调试的时候,代码的运行速度会降低。 rdstc(0x0F31)-->返回至系统启动以来的时间。QueryPerformanceCounter函数和GetTickCount函数有同样的功能

                                                  一种方法记录操作前后的时间戳,比较这两个时间戳:查看两次调用 rdstc的差值是否大于0xFF

                                                  一种方法记录一个异常前后的时间戳。                                             

干扰调试器功能

        使用TLS回调:在程序入口点之前执行的代码是TLS回调。TLS是Windows的一个存储类。TLS运行每个线程维护一个用TLS声明的专有变量。实现TLS回调时,会在PE头部保包含一个.tls段。

                                               解决:Ctrl+E查看所有二进制的入口点,每一个TLS回调函数都有一个前缀字符串TlsCallback。

                                                          OD Options --> Debugging Options --> Events,设置System break-point为第一个暂停的位置

         使用异常:使用异常来破坏或者探测调试器,多数调试不把异常传递给应用程序,这时来探测调试器。

                                               解决:把所有异常传递给应用程序。

         插入中断:在合法指令序列插入中断,破坏程序正常运行

                           1.插入INT3

设置一个新的SEH,然后调用INT 3

                           2.插入INT 2D --->内核调试器设置断点的方法

                           3.插入ICE断点--->会产生一个单步异常,所以在遇到这个指令时,不要使用单步。

调试器漏洞

         PE头漏洞

        1.PE头中的NumberOfRvaAndSize属性是后面DataDirectory数组中的元素个数,当大于0x10时,Windows加载器会忽略,而OD将会崩溃(Bad or Unknown 32-bit Executable File)错误。

        2.当SizeOfRawData不合法调试就会报错(File contains too much data)。因为Windows加载器加载时会比较VirtualSize和SizeOfRawData的大小,取小的加载到内存。而调试器直接会选SizeOfRawData的值

         OutputDebugString漏洞:格式化字符串漏洞,%s会崩溃。

 

实验

Lab16-1

检测BeingDebugged为1正在调试状态。fs:30的位置线程环境块

 检测ProcessHeap是否为0

检测NTGlobalFlag

这个插件可以很好的去抵抗这些反调试技术,或者手动dump fs:[30]+2

Lab16-2

查看导出函数。Ctrl+K 程序有两个入口点,第一个函数的功能是查看是否有OLLYDBG调试器,用于反调试。并且第一个函数位于TLS节中,先于start函数执行。禁用这个反调试技术是把exit的函数调用变成NOP,或者选上一个例子的PHantOm插件。

创建一个线程CreateThread,然后调用比较字符串函数strncmp。可以在OD里面载入发现要比较的字符串是bzrr,实际上这个字符串是不正确的。其中压入的一个参数是encode_password,应该是一个正确的字符串。现在跟入CreateThread创建的StartAddress函数。

StartAddress

关于encode_password的移位操作,说明这是一个解密函数

检测BeingDebugged是否为调试状态,要对抗这个反调试,就需要bl恒为0

byte_40A968参与了运算 

byte_40A968在第二条语句被修改了

先将3039定义为一个错误码,然后利用一个OutputDebugStringA输出一个b,然后得到这个错误码与刚刚定义的错误码进行比较。这里的区别是在调试中的错误码就是3039,所以会有一个自增的操作,而在DOS窗口中,这个错误码不是3039,所以不会有自增操作。这里也实现反调试的功能。解决方法把自增NOP掉

然后OD调试,跟到密码处为byrr

Lab16-3

猜你喜欢

转载自blog.csdn.net/m0_37809075/article/details/82556473