首页
社区
课程
招聘
[原创]分析实战读书笔记12_常见反调试
发表于: 2021-3-11 14:21 9241

[原创]分析实战读书笔记12_常见反调试

2021-3-11 14:21
9241

在分析恶意代码的过程中,免不了需要动态分析,所以掌握常见反调试技术是必要的,否则就要出师未捷身先死了。

IsDebuggerPresent

CheckRemoteDebuggerPresent

NtQueryInformationProcess

OutputDebugString

在PEB结构中存储很多信息可以用来检测调试器。

BeingDebugged属性

ProcessHeap属性

NTGlobalFlag属性

注册表

文件遍历

进程遍历

窗口遍历

断点扫描

CRC校验

时钟检测

TLS回调会在程序执行OEP之前执行,因此若一个样本使用TLS回调,在OD分析断在OEP处时,实际上TLS回调函数已经执行完毕。

一个样本具备TLS回调的特征是区段中包含一个.tls节。正常程序很少使用该技术,因此当样本中出现.tls区段则很可能具备反调试手段。

若想分析TLS函数,在OD中将调试选项中的入口断点改为系统断点即可

image-20210304150851982

在IDA中按下Ctrl+E可以查看所有入口函数,若包含TLS回调,则会显示

image-20210304151100368

image-20210304152024216

使用OD的忽略异常可以让调试器不接收异常从而将异常处理权限还给进程自身。

image-20210304152127188

由于调试器使用int3(0xCC)或int 3(0xCD 03)指令产生异常从而接管异常处理来达到“断下来”的效果。因此若在程序中人为的添加中断指令就会被调试器认为是自己下的断点从而接管程序的执行。(现在的调试器都具备了区分断点归属性的能力,很少被这种技术欺骗)

而这种技术在一些调试器上会恰巧更改程序的执行流程,如下图:

image-20210304153101066

这段代码在面对WinDbg调试器时,会展现它的反调试功能。当程序执行到int 3指令时,会触发3号中断,从而被WinDbg捕获,在捕获后,WinDbg会将中断指令的地址+1存入EIP,这就导致了原本利用SEH技术将要执行的continue代码被WinDbg强行更改为int 3后面的指令。从而错过了真正的代码流。

指令icebp(0xF1)会产生一个单步异常,调试器会误认为是自身单步导致的异常,从而接管异常处理。这时如果恶意作者使用icebp+SEH技术的话,调试器就会由于接管了异常处理而越过恶意代码作者的SEH函数。因此当代码中出现icebp,不要使用单步执行走过去。而是要在SEH处理函数下断进行监测。

该漏洞是由于调试器在读取PE数据时过于规则化,从而导致当恶意代码作者在不损坏文件的前提下修改PE头数据时,会被调试器视为一个损坏的PE文件从而无法加载。对于这种情况,我们只需观察PE数据对其进行手动修正即可。

此漏洞在目前版本的调试器已不存在,只针对OD1.0版本。漏洞内容如下:

通过本章的知识,可以发现反调试没有一个固定的规则,任何能对分析师对调试器造成欺骗的技术都可以作为反调试。小到一个API大到一个调试器的漏洞都可以被用来检测调试器。因此需要分析师与时俱进。

另外大多数反调试行为会涉及PEB结构(fs:[30]),因此需要对这种指令十分敏感。

这个恶意代码使用了哪些反调试技术?

image-20210304160202997

image-20210304160503369

当每种反调试技术成功执行时,有什么现象?

image-20210304160939360

如何应对这些反调试技术

如何在调试过程中手动修改检测的数据结构?

哪一种 OllyDbg 插件可以帮你逃避恶意代码的反调试技术?

在命令行中运行Lab16-02.exe时,会发生什么?

image-20210304165747263

当使用猜测的命令参数运行Lab16-02.exe时,会发生什么?

image-20210304165856958

命令行密码是什么?

image-20210304170136475

image-20210304171547144

使用IDA Pro加载Lab16-02.exe。在main函数的何处可以找到strncmp函数?

image-20210304170225408

在默认设置下,将这个恶意代码加载到OllyDbg中会发生什么?

image-20210304170309733

image-20210304170324157

Lab16-02.exe中PE结构的独特之处是什么?

image-20210304170554226

回调(callback)发生在哪些位置?(提示:在 IDA Pro中使用Ctrl+E组合键。)

恶意代码使用哪一种反调试技术使它在调试器中立即终止运行?如何避免这种检查?

当你禁用反调试技术后,你在调试器中看到的命令行密码是什么?

调试器中找到的密码在命令行中运行有效吗?

哪种反调试技术为调试器和命令行设置不同的密码?如何防御它们?

image-20210304171050524

image-20210304171118599

当使用静态分析法分析这个二进制文件时,你看到了哪些字符串?

image-20210304172347723

当运行这个二进制文件时会发生什么?

image-20210304172616319

如何重命名它,才能使这个二进制文件正常运行?

image-20210311132823322

这个恶意代码使用了哪些反调试技术?

image-20210311100410913

image-20210311133056746

对每一种反调试技术而言,如果恶意代码确定它运行在调试器中,它将做什么?

为什么反调试技术在这个恶意代码中能够成功?

恶意代码使用了什么域名?

image-20210311133858317

该API查询PEB结构中的IsDebugger标志位, 未调试返回0   调试状态返回1
该API查询PEB结构中的IsDebugger标志位, 未调试返回0   调试状态返回1
与IsDebuggerPresent原理一致,此API可以检测其他进程的调试状态,只需传入进程句柄。
通过传入自身进程句柄可检测自身调试状态   未调试返回0   调试状态返回1
与IsDebuggerPresent原理一致,此API可以检测其他进程的调试状态,只需传入进程句柄。
通过传入自身进程句柄可检测自身调试状态   未调试返回0   调试状态返回1
该API用于提取一个进程的状态信息,第一个参数为进程句柄,第二个参数为信息类型,当传入类型为0x7(ProcessBebugPort)时会获取调试端口。  未调试返回0   调试状态返回端调试口号
该API用于提取一个进程的状态信息,第一个参数为进程句柄,第二个参数为信息类型,当传入类型为0x7(ProcessBebugPort)时会获取调试端口。  未调试返回0   调试状态返回端调试口号
此API含义: 输出一个字符串,当未处于调试状态时调用该API会设置错误码,处于调试状态时会正常输出。通过对比手动设置的错误码可以检测是否处于调试状态。    报错未调试,未报错则处于调试状态。
此API含义: 输出一个字符串,当未处于调试状态时调用该API会设置错误码,处于调试状态时会正常输出。通过对比手动设置的错误码可以检测是否处于调试状态。    报错未调试,未报错则处于调试状态。
PEB结构偏移为2的位置为BeingDebugger属性,宽度1字节,   未调试0   调试状态为1
[fs:[0x30]+2] -> byte
PEB结构偏移为2的位置为BeingDebugger属性,宽度1字节,   未调试0   调试状态为1
[fs:[0x30]+2] -> byte
ProcessHeap是PEB结构中Reserved4数组中一个未公开的属性,偏移为0x18,第一个堆头部有一个属性指明了是否为调试器创建。(ForceFlags / Flags)
XP: Flags位于堆头部偏移0x10处   [[fs:[0x30]+0x18]+0x10] -> dword
WIN7:Flags位于堆头部偏移0x44处  [[fs:[0x30]+0x18]+0x44] -> dword
0未调试   不为0处于调试状态
ProcessHeap是PEB结构中Reserved4数组中一个未公开的属性,偏移为0x18,第一个堆头部有一个属性指明了是否为调试器创建。(ForceFlags / Flags)
XP: Flags位于堆头部偏移0x10处   [[fs:[0x30]+0x18]+0x10] -> dword
WIN7:Flags位于堆头部偏移0x44处  [[fs:[0x30]+0x18]+0x44] -> dword
0未调试   不为0处于调试状态
NTGlobalFlag是PEB结构中另一个未公开位置,偏移0x68,这个值指明了如何创建堆结构。如果此处值为0x70则处于调试状态
0x70含义:  FLG_HEAP_ENABLE_TAIL_CHECK|FLG_HEAP_ENABLE_FREE_CHECK|FLG_HEAP_VALIDATE_PARAMETERS
[fs:[30]+0x68-> dword   == 0x70?调试:非调试
NTGlobalFlag是PEB结构中另一个未公开位置,偏移0x68,这个值指明了如何创建堆结构。如果此处值为0x70则处于调试状态
0x70含义:  FLG_HEAP_ENABLE_TAIL_CHECK|FLG_HEAP_ENABLE_FREE_CHECK|FLG_HEAP_VALIDATE_PARAMETERS
[fs:[30]+0x68-> dword   == 0x70?调试:非调试
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
该注册表项指定当应用程序发生错误时,触发哪一个调试器。默认情况下它被设置为“Dr.Watson”,若是变成了“OllyDbg”,则恶意程序可以确定他处于被调试的状态。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
该注册表项指定当应用程序发生错误时,触发哪一个调试器。默认情况下它被设置为“Dr.Watson”,若是变成了“OllyDbg”,则恶意程序可以确定他处于被调试的状态。
恶意代码还可能通过遍历磁盘文件寻找调试器文件名。
恶意代码还可能通过遍历磁盘文件寻找调试器文件名。
通过遍历进程寻找是否有黑名单中的进程来监测调试器,如od ida x32dbg之类的进程名
通过遍历进程寻找是否有黑名单中的进程来监测调试器,如od ida x32dbg之类的进程名
通过FindWindow可以遍历窗口寻找是否有疑似调试器的程序在运行
通过FindWindow可以遍历窗口寻找是否有疑似调试器的程序在运行
调试器断点常使用int3指令(0xCC)触发3号中断,因此在下断时会临时修改指令字节,程序可以通过开启线程循环扫描自身代码段数据查找是否存在0xCC字节数据。
调试器断点常使用int3指令(0xCC)触发3号中断,因此在下断时会临时修改指令字节,程序可以通过开启线程循环扫描自身代码段数据查找是否存在0xCC字节数据。
原理同断点扫描类似,程序首先计算自身代码段的CRC校验值,当运行时开启新线程循环计算自身进程代码段的CRC校验值并与预先定义好的值进行比较,若不同则说明代码段某一处或多出字节被修改,这时程序可以停止执行,转而执行伪装代码。
原理同断点扫描类似,程序首先计算自身代码段的CRC校验值,当运行时开启新线程循环计算自身进程代码段的CRC校验值并与预先定义好的值进行比较,若不同则说明代码段某一处或多出字节被修改,这时程序可以停止执行,转而执行伪装代码。
在调试时程序执行速度会大幅降低,通过比对两处代码的执行间隔可以推断出是否处于调试状态。
所需指令: rdstc   从开机到此刻的时钟数,存到EDX:EAX中
所需API: QueryPerformanceCounter  与  GetTickCount
在调试时程序执行速度会大幅降低,通过比对两处代码的执行间隔可以推断出是否处于调试状态。
所需指令: rdstc   从开机到此刻的时钟数,存到EDX:EAX中
所需API: QueryPerformanceCounter  与  GetTickCount
 
 
 
 
 
 
 
 
 
 
OutputDebugString参数为“%s%s%s%s%s%s%s%s%s%s%s”使会使调试器崩溃。
OutputDebugString参数为“%s%s%s%s%s%s%s%s%s%s%s”使会使调试器崩溃。
 
使用了BeingDebugged  ProcessHeap NTGlobalFlag,  通过搜索fs:30可以发现有几十处代码,可见这个样本反调试很多
使用了BeingDebugged  ProcessHeap NTGlobalFlag,  通过搜索fs:30可以发现有几十处代码,可见这个样本反调试很多
当检测到调试器时会调用401000处代码进行自删除

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 264
活跃值: (1134)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
师傅这个系列真的
2021-3-16 11:19
0
雪    币: 70
活跃值: (2010)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
恶意代码分析实战
2021-3-22 11:32
0
雪    币: 8073
活跃值: (6364)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2021-3-25 13:51
0
雪    币: 1470
活跃值: (74)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
5
00D6DAFE    FFD0            call eax                    ; kernel32.GetCurrentProcess   获取当前程序句柄
00D6DAFE    FFD0            call eax                    ; kernel32.IsDebuggerPresent   eax=0 
00D6DAFE    FFD0            call eax                    ; kernel32.CheckRemoteDebuggerPresent  
00D6DAFE    FFD0            call eax                    ; ntdll_12.ZwQueryInformationProcess
00D6DAFE    FFD0            call eax                    ; kernel32.GetModuleFileNameW
00D6DAFE    FFD0            call eax                    ; advapi32.OpenSCManagerW
00D6DAFE    FFD0            call eax                    ; advapi32.EnumServicesStatusExW
00D6DAFE    FFD0            call eax                    ; kernel32.GetLastError
00D6DAFE    FFD0            call eax                    ; kernel32.LocalAlloc
00D6DAFE    FFD0            call eax                    ; advapi32.EnumServicesStatusExW
00D6DAFE    FFD0            call eax                    ; user32.MessageBoxW


到messagenoxw这里就弹出不要调试程序了。这几个哪个检测到了我调试他呢
2021-7-17 11:23
0
游客
登录 | 注册 方可回帖
返回
//