脱壳学习(二)- 反“反调试”篇
2023-3-31 17:2:4 Author: 雷石安全实验室(查看原文) 阅读量:10 收藏

{
点击蓝色
 
关注我们
}

继上一篇《脱壳学习计划1——计算机底层基础》有人私信说想看后续之后,我们就冲冲把2给肝出来了。

今天这篇主要讲述常见的反调试技术和如何绕过反调试的实例。调试无论是在脱壳还是PWN及逆向中都有着很重要的意义,反调试被程序作者用来保护程序不被调试,以此来保护自己的秘密。不过逆行分析人员也有自己的破解反调试的方法,就是“反反调试”

以下是我们经常会遇到到的一些反调试技术,为了好记一点,总结分为以下三类:通过调试的痕迹去识别是否正在被调试、识别调试器行为、干扰调试器功能

1.调试痕迹识别

WindowsAPI

手动检测数据结构

系统痕迹检测

这里最常见得就是手动检测数据结构,也就是检测PEB(PEB表存放进程信息)表BeingDebugged,ProcessHeap,NTGlobalFlag属性,这里有个小知识,32位程序PEB得地址用的是fs:[30],64位程序的地址为gs:[60],位于用户地址空间,进程环境块的地址对于每个进程来说是固定的。如果发现程序中出现引用PEB的地址然后出现程序退出的地址比如sub_401000,那大概率是进行了反调试。

绕过:fs段寄存器偏移0x30h,用ctrl+G可以找到PEB。第一个fs:[30h]+2指向了PEB的BeingDubgged,这是检验反调试的一种技术。BeingDubgged=1的时候就是被调试,这里是第一处反调试。然后我们通常会在fs:[30h]+2把01修改为00或使用插件:PhantOM,勾选hide from PEB。

[fs:[30h]+18]+10,ProcessHeap也是用来测试反调试的的标志。fs:30h+68,NtGlobalFlag反调试。同样是BeingDubgged原理,通过修改调试标志来绕过。

 

2.识别调试器的行为

INT扫描

执行代码校验和检查

时钟监测

判断父进程是否是explorer.exe

这里常用就是时钟监测,计算时间差值,反调试。如果时间过长,判断文件当前正在被调试,就删除文件。我们在OD里找到这个时钟的地方,QueryPerformanceCounter,GetTickCount,

使用nop(汇编代码无操作空指令)就可以绕过,其实原理就是破坏他程序监测反调试的功能。其他几种也是同样的道理,检测都是又程序编写,代码控制,我们只要破坏掉就可以了。

 

3.干扰调试器的功能

使用TLS回调

使用异常

插入中断

这里最常用的也是TLS回调,因为现在OD的插件越来越牛,新版的OD看不出有什么区别,最简单的方法,扔到CFF去看一下目录结构,可以很明确的看到TLS目录(全保护)

然后我们打开IDA可以看到调用的函数

可以看到字符如果当前窗口类名为OLLYDBG“,就退出程序。这个是最简单的干扰,实际上现在常用的OD都已经会隐藏自己的窗口类名了,插件的功能越来越多,TLS回调对于反调试的干扰越来越弱。

以上就是比较常见的反调试。下面就是一个简单的小实例。这里VMProtect3.5进行全保护加壳。代码就很简单,c语言helloword!。

先点击运行,VMP3.5的全保护首先就是要过掉BeingDebugger和NTGLObalflags,我这里用的程序是64位,所以PEB地址为gs:[60],BeingDebugger和NTGLObalflags的地址PEB+2 -> BeingDebugger,PEB + BC ->NTGLObalflags。

删除所有断点:

然后给这两个函数下断点 设置条件断点

NtQueryInformationProcess:函数就可以获取调试端口。若处于调试状态 , 第三个参数会被置为0xFFFFFFFF(-1);若处于非调试状态,第三个参数值会被设置为0。

设定条件断点rdx == 0x07 || rdx ==0x1E

NtSetInformationThread:使用Windows的一个未公开函数的方法,你可以在当前线程里调用NtSetInformationThread,调用这个函数时,如果在第二个参数里指定0x11这个值(意思是ThreadHideFromDebugger),等于告诉操作系统,将所有附加的调试器统统取消掉。设定条件断点rdx == 0x11

然后运行 执行顺序可能不一样 但处理方法一样 我这里先断在了

NtQueryInformationProcess:rdx == 0x07 把r8 置为nullptr(0)

再运行,NtQueryInformationProcess:rdx ==0x1E 把r8 置为nullptr(0)执行到返回值

ret返回 并将RAX返回值C0000353

在运行,NtSetInformationThread:rdx == 0x11 将rdx置为3后,禁用这两个断点。

在这两个函数下硬件断点

ntclose 硬件断点:NtClose函数在释放无效句柄时。如果没有被调试,那么函数返回FALSE。如果处于调试状态则会抛出异常C0000008H 并设置条件 rcx == 0xDEADC0DE

NtQuerySystemInformation硬件断点:被 ntdll.dll 导出,当第一个参数传入 0x23 (SystemInterruptInformation) 时,会返回一个SYSTEM_KERNEL_DEBUGGER_INFORMATION 结构,里面的成员KdKdDebuggerEnable 和 KdDebuggerNotPresent 标志系统是否启用内核调试。并设置条件 rcx == 0x23

然后运行如果执行到NtQuerySystemInformation 且rcx==0x23 执行到返回 然后将RAX变为status_unsuccessful(0xC0000001)

然后运行到ntclose 并将RCX设置为0(flase)

然后清除(禁用)所有断点然后运行

也是成功的绕过了反调试,shift+F9运行在进行调试中就不会有任何报错。

以上就是此次关于反调试技术的一些想法分享,下一篇晚点见~

往期回顾

01
脱壳学习(一)- 计算机底层基础
02

威胁情报-telegram消息监控

03

记一次畅捷通任意文件读取漏洞复现发现的问题

雷石安全实验室

商务咨询:

0571-87031601

商务邮箱:

[email protected]

转发,点赞,在看,安排一下?

文章来源: http://mp.weixin.qq.com/s?__biz=MzI5MDE0MjQ1NQ==&mid=2247520155&idx=1&sn=ec86938d0d0a5d02ea00b12eb5a97722&chksm=ec26ae03db512715d86112e5919ba38f30f97a1efb37126c3866c0f0456c325339379928c1b5#rd
如有侵权请联系:admin#unsafe.sh