反调试
反调试的意义
反调试技术,恶意代码用它识别是否被调试,或者让调试器失效。恶意代码编写者意识到分析人员经常使用调试器来观察恶意代码的操作,因此他们使用反调试技术尽可能地延长恶意代码的分析时间。为了阻止调试器的分析,当恶意代码意识到自己被调试时,它们可能改变正常的执行路径或者修改自身程序让自己崩溃,从而增加调试时间和复杂度。很多种反调试技术可以达到反调试效果。
反调试相关函数
IsDebuggerPresent()
这是恶意代码中使用最高的反调试函数,是在win32API里面的应用层函数。
1 | BOOL IsDebuggerPresent(); |
1 |
|
正如以上描述,如果存在调试的环境,就输出A,如果不是调试的环境,就会输出B。
该函数原理:
我们知道OD和其他动态调试器的原理都是通过附加到另一个进程上使用windows的debug机制去进行调试,而IsDebuggerpresent
函数本来就是该debug机制的一个函数,它负责查看这个环节中函数返回的值是否为0用来判断是否是调试环境。
效果展示:如果在vs中直接使用本地windows调试器方法去运行,便会出现a。
而直接在命令行中去执行
CheckRemoteDebuggerPresent()
1 | BOOL CheckRemoteDebuggerPresent( |
该函数不仅可以检测自己是否正在被debug,还可以检测其他任意句柄是否被debug。
1 | BOOL CheckDebug1() |
它会把结果传输给一个布尔变量的指针,往这个地址里面直接写true或者false,用来判断是否是调试环境。
效果展示:
NtQueryInformationProcess
NtQueryInformationProcess
是ntdll.dll里面的函数,所以要想调用这个函数,是比较麻烦的,需要loadlibrary
加getprocaddress
1 | __kernel_entry NTSTATUS NtQueryInformationProcess( |
https://learn.microsoft.com/zh-cn/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
最关键的是参数中
用来检测是否是调试器环境。(如果是非0的值,就表示有一个调试器。)
1 | bool NtQueryInformationProcessApproach() |
大致的意义就是将这个函数里面的值取出来放在定义的debugPort
变量中。用来检测是否是调试器环境。
效果展示:
运用调试器的异常接管来判断
当没有调试器的时候,我们关闭一个不存在的进程,错误会自动交给windows操作系统,但是如果在有调试器的情况下,当系统报错时,会将报错交给调试器。同时这个就是调试器的原理,OD的普通断点就是使用int3报错的方式来下的断点。
1 |
|
内核级调试的反调试
不同于OD等,windbg是内核级调试器。这种内核级调试器同样有内核级的反调试手段。
1 |
|
原理:
在32位下,KUSER_SHARED_VA 0x7FFE0000这段内存是一个内核层和用户层都能访问的内存段。而在偏移量2d4这个位置,也就是0x7FFE02d4这个位置,会有一个关于是否是内核级调试器的标志位,这就是问题的关键,通过这个标志位置,可以知道是否是在调试环境中。
因为没有用windbg,所以可以检测出来是disabled的。
进程名称查看是否在调试环境
1 |
|
这个很明显,就是比对一下任务管理器中有不有进程名字与这几个调试器的名字相同。
GetTickCount
这个也是逻辑上的检测方式,执行三条指令,看程序的执行时间来看是不是调试环境。
1 |
|
TLS加载器
TLS就是在运行主函数之前,就运行一段程序的机制。
1 |
|
即在程序运行main前就会报异常
自动下断点
1 |
|
它使用汇编语言自动写一个int3断点,如果你在调试器环境,那么就会被调试器接管,如果说你用od去调试他,就会发现他会退出,如果是正常环境就不管。
补充项目
https://github.com/MrH1TM4N86/Al-Khaser-Master
这个项目里面包含了各种各样的反调试手段和代码,可以用于借鉴。