selph
selph
发布于 2021-11-20 / 635 阅读
0
0

恶意代码分析实战Lab16-反调试技术

探测Windows调试器

使用Windows API

这是最简单的方法:

  • IsDebuggerPresent
  • CheckRemoteDebuggerPresent

通过修改API检测的地方,或者直接hook API即可绕过

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main() {
	int ret = 0;
	// 1. IsDebuggerPresent,检查PEB的IsDebugged标志
	ret = IsDebuggerPresent();
	if (ret)printf("当前处于被调试环境\n"); else printf("当前未处于被调试环境\n");
	
	// 2. CheckRemoteDebuggerPresent,原理同上,可检查其他进程
	CheckRemoteDebuggerPresent(GetCurrentProcess(), &ret);
	if (ret)printf("当前处于被调试环境\n"); else printf("当前未处于被调试环境\n");

	return 0;
}

手动检测数据结构

书上说这种比较常用,可以避免hook WindowsAPI所带来的检测失效

检测BeingDebugged属性:

该属性在PEB结构的第二个字节处,

手动修改该标志位即可绕过,调试器的插件会自动绕过这种反调试

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main() {
	int ret = 0;
	__asm {
		mov eax, dword ptr fs : [030h] ;
		movsx ebx, byte ptr[eax + 2];
		test ebx, ebx;
		jnz ISDEBUG;
	}

	if (ret) {
ISDEBUG:
		printf("当前处于被调试环境\n");
	}
	else {
NOTDEBUG:
		printf("当前未处于被调试环境\n");
	}
	system("pause");
	return 0;
}

书上还提到了其他两个位置(Process Heap和NtGlobalFlag),但经过实验,在windows10上似乎并没有效果,也可能是我操作有问题

系统痕迹检测

通过搜索窗口名称是不是调试器,或者搜索其他调试器正在运行的痕迹来进行判断

识别调试器行为

INT扫描:遍历内存中的0xCC来进行判断,如果存在0xCC表示这里有被下断点,说明有调试器存在

代码校验:CRC校验或md5校验,确保机器码没被改过

时钟检测

[不好使]rdtsc命令读取从开机到现在的时钟数,两次获取检测差值判断是否被调试

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main() {
	int ret = 0;
	__asm {
		rdtsc;
		xor ecx, ecx;
		add ecx, eax;
		rdtsc;
		sub eax, ecx;
		cmp eax, 0xFFF;
		jnb ISDEBUG;
	}

	if (ret) {
ISDEBUG:
		printf("当前处于被调试环境\n");
	}
	else {
NOTDEBUG:
		printf("当前未处于被调试环境\n");
	}
	system("pause");
	return 0;
}

使用WindowsAPI:QueryPerformanceCounter或GetTickCount也可以获取到时钟数

干扰调试器功能

TLS回调、使用异常、插入中断

作业

Lab 16-1

分析Lab16-01.exe

  1. 使用了哪些反调试?

    答:在main函数开头使用了三种反调试:

    image-20211120153406033

  2. 当每种反调试成功执行会发生什么?

    答:反调试会执行sub_401000函数,该函数会获取当前文件路径,并拼接命令进行执行cmd.exe /c del filename >> nul,然后退出程序

  3. 如何应对这些反调试?

    答:手动修改或使用插件修改进程这些结构的值

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

    答:单步执行到那里,然后手动修改内存

Lab 16-2

分析Lab16-02.exe

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

    答:

    image-20211120154227991

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

    答:见上题

  3. 命令行密码是什么?

    答:该PE文件存在TLS回调,IDA通过ctrl+e可查看:

    image-20211120155948551

    在调试之前需要把这里给处理了,OD里设置起始断点为系统断点,然后在tls这里,断下来给这里进行修改:把返回结果修改了,这样就判断不出来调试器的存在了

    image-20211120160243334

    接下来进入主函数:

    image-20211120160654544

    密码应该是bzrr,经过输入发现不对,还有反调试存在!!

    后来发现0x401020还有个函数在检测调试:

    image-20211120162632897

    这里判断如果被调试,则给byte_40A968++,不然就直接返回,那就od里修改跳过这里++操作:

    image-20211120164121510

    然后拿到密码:byrr

    image-20211120164216437

    image-20211120164234900

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

    答:见上题分析

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

    答:会直接退出进程

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

    答:包含TLS节

  7. 回调(callback)发生在那些位置?(提示:IDA PRO使用ctrl+e组合键)

    答:发生在0x401060位置:

    image-20211120164335541

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

    答:检查调试器窗口标题,通过对该部分程序打补丁或修改调试器窗口标题都行

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

    答:见题3分析

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

    答:见题3分析

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

    答:修改程序,让反调试技术不生效

Lab 16-3

分析Lab16-03.exe

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

    答:删除命令和获取当前时钟

    image-20211120164852325

    image-20211120164915646

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

    答:什么也没发生

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

    答:

    image-20211120181214799

    这里使用strcmp来判断文件名,预期文件名被这个函数作为参数调用过:这个函数里出现了反调试,和异常处理

    image-20211120181326479

    OD里把反调试的这个jle跳转给换成jmp跳转即可绕过本反调试,拿到真正的文件名:

    image-20211120182154043

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

    答:除了上题遇到的反调试,在之后的运行中还出现了下一个基于时钟的反调试:只需要修改跳转条件即可绕过

    image-20211120182450460

    在这之后紧接着调用了函数sub_401300:和之前的反调试一个路子,不过如果发现在调试了会触发自我删除,一样可以修改跳转条件来绕过

    image-20211120182748471

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

    答:对于QueryPerformanceCounter反调试,会修改判断的字符串

    对于GetTickCount反调试,会产生导致程序奔溃的异常

    对于rdtsc反调试,会触发自我删除程序

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

    答:通过使用SEH异常,使得程序在调试器中运行比实际中慢得多,从而确保这种反调试能够成

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

    答:

    image-20211120183530327


评论