Drunkmars's Blog

反沙箱调试

字数统计: 1k阅读时长: 4 min
2021/10/04

很多杀软都有自己的后端云沙箱,这些沙箱能够模拟出软件执行所需的运行环境,通过进程hook技术来对软件执行过程中的行为进行分析,判断其是否有敏感的操作行为,或者更高级的检测手法是,将获取到的程序的API调用序列以及其他的一些行为特征输入到智能分析引擎中进行检测。所以,如果我们的木马没有做好反调试,很容易就被沙箱检测出来。

前言

最简单的反调试的措施就是检测父进程。一般来说,我们手动点击执行的程序的父进程都是explorer。如果一个程序的父进程不是explorer,那么我们就可以认为他是由沙箱启动的。那么我们就直接exit退出,这样,杀软就无法继续对我们进行行为分析了。

这里主要的思路是获取调用kernel32库中的CreateToolhelp32Snapshot函数获得一个进程快照信息,然后从快照中获取到explorer.exe的进程id信息,然后通过当前进程的pid信息在进程快照中找到其父进程的id信息,最后将两者进行比较,判断当前进程是否是有人工启动的。

反调试的措施不仅仅是检测父进程,还可以通过调用windows的API接口IsDebuggerPresent来检查当前进程是否正在被调试。

实现过程

首先通过调用CreateToolhelp32Snapshot拍摄快照

1
2
HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));
FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");

然后使用汇编语句进行传参

1
2
3
4
5
6
_asm{
push 0
push 2
call Address
mov hkz, eax
}

因为传参的话是从右往左传参,传入的第一个参数就是2,在createtoolhelp32snapshot里第一个参数为2的时候含义如下

image-20211003221740066

第二个参数传入0,代表的是默认进程

image-20211003221812310

遍历结构并返回父进程

1
2
3
4
5
6
7
8
9
10
if ( Process32First( hkz, &pe ) ){
do{
if ( pe.th32ProcessID == pid ){
ParentProcessID = pe.th32ParentProcessID;
break;
}
}
while ( Process32Next( hkz, &pe ) );
}
return ParentProcessID;

然后再编写一个函数获取explorer.exe的pid,思路的话都是差不多的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
DWORD get_explorer_processid() {
DWORD explorer_id = -1;
PROCESSENTRY32 pe;
HANDLE hkz;
HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));

if (hModule == NULL) {
OutputDebugString(_T("Loaddll error"));
return(-1);
}
FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");

if (Address == NULL) {
OutputDebugString(_T("GetProc error"));
return(-1);
}

_asm {
push0
push2
call Address
mov hkz, eax
}

pe.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(hkz, &pe)) {
do {
if (_wcsicmp(pe.szExeFile, L"explorer.exe") == 0)
{
explorer_id = pe.th32ProcessID;
break;
}
} while (Process32Next(hkz, &pe));
}
return explorer_id;
}

然后再对两个函数返回的ID进行比较,如果ID相同则不为沙箱,若不相同的话则直接退出

image-20211003222448120

完整代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// testvm.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>

DWORD get_parent_processid(DWORD pid)
{
DWORD ParentProcessID = -1;

PROCESSENTRY32 pe;

HANDLE hkz;

HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));

FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");

if (Address == NULL) {
OutputDebugString(_T("GetProc error"));
return(-1);
}

_asm {
push 0
push 2
call Address
mov hkz, eax
}

pe.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(hkz, &pe)) {
do {
if (pe.th32ProcessID == pid) {
ParentProcessID = pe.th32ParentProcessID;
break;
}
} while (Process32Next(hkz, &pe));
}
return ParentProcessID;
}


DWORD get_explorer_processid() {
DWORD explorer_id = -1;
PROCESSENTRY32 pe;
HANDLE hkz;
HMODULE hModule = LoadLibrary(_T("Kernel32.dll"));

if (hModule == NULL) {
OutputDebugString(_T("Loaddll error"));
return(-1);
}
FARPROC Address = GetProcAddress(hModule, "CreateToolhelp32Snapshot");

if (Address == NULL) {
OutputDebugString(_T("GetProc error"));
return(-1);
}

_asm {
push 0
push 2
call Address
mov hkz, eax
}

pe.dwSize = sizeof(PROCESSENTRY32);

if (Process32First(hkz, &pe)) {
do {
if (_wcsicmp(pe.szExeFile, L"explorer.exe") == 0)
{
explorer_id = pe.th32ProcessID;
break;
}
} while (Process32Next(hkz, &pe));
}
return explorer_id;
}


int main() {
DWORD explorer_id = get_explorer_processid();
DWORD parent_id = get_parent_processid(GetCurrentProcessId());
if (explorer_id == parent_id)
{ /* 判断父进程id是否和explorer进程id相同{ */
MessageBox(0, L"Not sandbox", L"Success", 0);
}
else
{
exit(1);
}
}

实现效果

在正常情况下运行的话pid是相同的那么弹窗不为沙箱

image-20211003224110914

如果是我直接在vs里面运行一下进行调试就报错直接退出

image-20211003224437259

这里再拿到od里面调试一下可以看到直接终止了

testvm

CATALOG
  1. 1. 前言
  2. 2. 实现过程
  3. 3. 实现效果