IsDebuggerPresent查询进程环境块(PEB)中的IsDebugged标志。如果进程没有运行在调试器环境中,函数返回0;如果调试附加了进程,函数返回一个非零值。
CheckRemoteDebuggerPresent不仅可以查询系统其他进程是否被调试,而且还可以通过传递自己的进程句柄来判断自己是否被调试。
我们在编写程序的时候,经常会涉及到错误处理问题。我们用的最多的应该就是GetLastError()这个函数了。恶意代码可以使用异常来检查调试器。调试器捕获异常后,并不会立即将处理权返回被调试进程处理,大多数利用异常的反调试技术往往据此来检测调试器。
同样还可以使用CloseHandle、CloseWindow产生异常,使得错误码改变
下面是调试器在注册表中的一个常用位置。
32位系统:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
64位系统:HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
如果该这册表的键值被修改为OllyDbg,则恶意代码就可能确定它正在被调试。
比较简单的FindWindow函数会搜索顶级窗口的类名和窗口名称然后匹配指定的字符串。
EnumWindows函数枚举所有屏幕上的顶层窗口,并将窗口句柄传送给应用程序定义的回调函数。
GetForegroundWindow获取一个前台窗口的句柄。
查找进程信息和枚举进程的思路大致是一样的,遍历进程比较字符串。
调试器设置软件断点的基本机制利用INT 3临时替换运行程序中的一条指令,然后当程序运行到这条指令时,调用调试异常处理例程。INT 3指令的机器码是0xCC,因此无论何时,使用调试器设置一个断点,它都会插入一个0xCC来修改代码。恶意代码常用的一种反调试技术是在它的代码中查找机器码0xCC,来扫描调试器对它代码的INT 3修改。repne scasb指令用于在一段数据缓冲区中搜索一个字节。EDI需指向缓冲区地址,AL则包含要找的字节,ECX设为缓冲区的长度。当ECX=0或找到该字节时,比较停止。
在OllyDbg的寄存器窗口我们可以看到DR0、DR1、DR2、DR3、DR6和DR7这几个寄存器。
DR0、Dr1、Dr2、Dr3用于设置硬件断点,DR4、DR5由系统保留。 DR6、DR7用于记录Dr0-Dr3中断点的相关属性。如果没有硬件断点,那么DR0、DR1、DR2、DR3这4个寄存器的值都为0。
我们知道机器运行的速度,远远比我们分析代码的速度快得多,利用这个差异性我们找到了用时钟检测来探测调试器存在的方法。记录一段操作前后的时间戳,然后比较这两个时间戳,如果存在滞后,则可以认为存在调试器。
较常用的时钟检测方法是利用rdtsc指令(操作码0x0F31),它返回至系统重新启动以来的时钟数,并且将其作为一个64位的值存入EDX:EAX中。恶意代码运行两次rdtsc指令,然后比较两次读取之间的差值。
explorer.exe创建进程的时候会把STARTUPINFO结构中的值设为0,然而不是explorer.exe创建进程的时候会忽略这个结构中的值,也就是结构中的值不为0。所以可以利用STARTUPINFO来判断程序是否在被调试。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2019-7-18 20:35
被一谷米粒编辑
,原因: