目录
-
所使用的网络检测方法
-
1. 具体的网络属性
-
1.1. 检查MAC地址是否是特定的
-
1.2. 检查适配器名称是否是特定的
-
1.3. 检查网络共享的提供者的名称是否是特定的
-
2. 检查网络是否属于安全范围
-
3. 基于NetValidateName结果的反伪装技术
-
4. 基于Cuckoo ResultServer连接的反伪装技术
-
识别标志:
-
反制措施
-
归功于
网络检测方法
这一组的规避技术与网络有着某种联系。要么使用与网络有关的功能,要么检查网络参数–如果它们与通常的主机操作系统不同,那么虚拟环境很可能被检测到。
1. 具体的网络属性
不同虚拟环境的供应商为他们的产品硬编码了一些值(MAC地址)和名称(网络适配器)–由于这一事实,这种环境可以通过检查适当对象的属性来检测。
1.1. 检查MAC地址是否是特定的
使用的函数:
-
GetAdaptersAddresses(AF_UNSPEC, …)
-
GetAdaptersInfo
代码样本(函数GetAdaptersAddresses):
|
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
|
int pafish_check_mac_vendor(char * mac_vendor) { unsigned long alist_size = 0, ret; ret = GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &alist_size); if (ret == ERROR_BUFFER_OVERFLOW) { IP_ADAPTER_ADDRESSES* palist = (IP_ADAPTER_ADDRESSES*)LocalAlloc(LMEM_ZEROINIT,alist_size); void * palist_free = palist; if (palist) { GetAdaptersAddresses(AF_UNSPEC, 0, 0, palist, &alist_size); char mac[6]={0}; while (palist){ if (palist->PhysicalAddressLength == 0x6) { memcpy(mac, palist->PhysicalAddress, 0x6); if (!memcmp(mac_vendor, mac, 3)) { /* First 3 bytes are the same */ LocalFree(palist_free); return TRUE; } } palist = palist->Next; } LocalFree(palist_free); } } return FALSE;} |
代码样本(函数etAdaptersInfo):
|
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
|
BOOL check_mac_addr(TCHAR* szMac){ BOOL bResult = FALSE; PIP_ADAPTER_INFO pAdapterInfo; ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO); pAdapterInfo = (PIP_ADAPTER_INFO) MALLOC(sizeof(IP_ADAPTER_INFO)); if (pAdapterInfo == NULL) { _tprintf(_T("Error allocating memory needed to call GetAdaptersinfo.\n")); return -1; } // Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { FREE(pAdapterInfo); pAdapterInfo = (PIP_ADAPTER_INFO) MALLOC(ulOutBufLen); if (pAdapterInfo == NULL) { printf("Error allocating memory needed to call GetAdaptersinfo\n"); return 1; } } // Now, we can call GetAdaptersInfo if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_SUCCESS) { // Convert the given mac address to an array of multibyte chars so we can compare. CHAR szMacMultiBytes [4]; for (int i = 0; i < 4; i++) { szMacMultiBytes[i] = (CHAR)szMac[i]; } while(pAdapterInfo) { if (pAdapterInfo->AddressLength == 6 && !memcmp(szMacMultiBytes, pAdapterInfo->Address, 3)) { bResult = TRUE; break; } pAdapterInfo = pAdapterInfo->Next; } } return bResult;} |
检测表:
|
检查MAC地址是否从以下值开始: |
||
|
检测 |
MAC地址的开头是 |
字节数 |
|
Parallels |
00:1C:42 |
\x00\x1C\x42 |
|
VirtualBox |
08:00:27 |
\x08\x00\x27 |
|
VMware |
00:05:69 |
\x00\x05\x69 |
|
00:0C:29 |
\x00\x0C\x29 |
|
|
00:1C:14 |
\x00\x1C\x14 |
|
|
00:50:56 |
\x00\x50\x56 |
|
|
Xen |
00:16:E3 |
\x00\x16\xE3 |
1.2. 检查适配器名称是否是特定的
使用的函数:
-
GetAdaptersAddresses(AF_UNSPEC, …)
-
GetAdaptersInfo
代码样本(函数GetAdaptersAddresses):
|
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
|
int pafish_check_adapter_name(char * name) { unsigned long alist_size = 0, ret; wchar_t aux[1024]; mbstowcs(aux, name, sizeof(aux)-sizeof(aux[0])); ret = GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &alist_size); if (ret == ERROR_BUFFER_OVERFLOW) { IP_ADAPTER_ADDRESSES *palist = (IP_ADAPTER_ADDRESSES *)LocalAlloc(LMEM_ZEROINIT, alist_size); void * palist_free = palist; if (palist) { if (GetAdaptersAddresses(AF_UNSPEC, 0, 0, palist, &alist_size) == ERROR_SUCCESS) { while (palist) { if (wcsstr(palist->Description, aux)) { LocalFree(palist_free); return TRUE; } palist = palist->Next; } } LocalFree(palist_free); } } return FALSE;} |
代码样本(函数GetAdaptersInfo):
|
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
|
BOOL check_adapter_name(TCHAR* szName){ BOOL bResult = FALSE; PIP_ADAPTER_INFO pAdapterInfo; ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); pAdapterInfo = (PIP_ADAPTER_INFO)MALLOC(sizeof(IP_ADAPTER_INFO)); if (pAdapterInfo == NULL) { _tprintf(_T("Error allocating memory needed to call GetAdaptersinfo.\n")); return -1; } // Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { FREE(pAdapterInfo); pAdapterInfo = (PIP_ADAPTER_INFO)MALLOC(ulOutBufLen); if (pAdapterInfo == NULL) { printf("Error allocating memory needed to call GetAdaptersinfo\n"); return 1; } } if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_SUCCESS) { while (pAdapterInfo) { if (StrCmpI(ascii_to_wide_str(pAdapterInfo->Description), szName) == 0) { bResult = TRUE; break; } pAdapterInfo = pAdapterInfo->Next; } } return bResult;} |
检测表:
|
检查适配器的名称为: |
|
|
检测 |
名称 |
|
VMware |
Vmware |
1.3. 检查网络共享的提供者的名称是否是特定的
使用的函数(见关于本地函数的注释):
-
WNetGetProviderName(WNNC_NET_RDR2SAMPLE, …)
代码样本:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
int vbox_network_share() { unsigned long pnsize = 0x1000; char provider[pnsize]; int retv = WNetGetProviderName(WNNC_NET_RDR2SAMPLE, provider, &pnsize); if (retv == NO_ERROR) { if (lstrcmpi(provider, "VirtualBox Shared Folders") == 0) return TRUE; else return FALSE; } return FALSE;} |
检测表:
| 检查网络共享的提供者名称如下: | |
|
检测 |
名称 |
|
VirtualBox |
VirtualBox Shared Folders |
2. 检查网络是否属于安全范围
恶意软件向https[:]//http://www.maxmind.com/geoip/v2.1/city/me 发出请求,这通常需要某种认证或API密钥。为了绕过这一要求,恶意软件通过将HTTP Referrer设置为https[:]//http://www.maxmind.com/en/locate-my-ip-address,将User-Agent设置为Mozilla/5.0(兼容;MSIE 10.0;Windows NT 6.1;Trident/6.0),使请求看起来像是来自该网站本身。这个技巧允许样本检索它所运行的机器的IP地址信息。
响应以JSON格式返回,包含国家、城市的信息,最重要的是,与IP地址相关的组织。如果在响应中发现一些 “坏 “字符串,恶意软件就知道它是在某种安全边界/组织内启动的。
实例
-
反虚拟机的技巧
-
恶意宏添加沙盒规避技术以进行分发 new Dridex
-
恶意的带有宏的文件 规避自动分析系统
恶意软件样本中的“包含恶意的字符串”(固定大小写):
|
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
|
AmazonanonymousBitDefenderBlackOakComputersBlue CoatBlueCoatCiscocloudData CenterDataCenterDataCentrededicatedESET, SpolFireEyeForcePointFortinetHetznerhispeed.chhostedHostingIron PortIronPortLeaseWebMessageLabsMicrosoftMimeCastNForceOvh SasPalo AltoProofPointRackspacesecurityServerStrong TechnologiesTrend MicroTrendMicroTrustWaveVMVaultZscaler |
3. 基于NetValidateName结果的反伪装技术
最初,这种技术是为绕过AV检测而设计的。它本身并不是一种规避技术–相反,而是在调用函数后滥用有趣的副作用。
主要的想法是使用NetValidateName API函数调用的确定结果,将无效的参数作为服务器名称(例如 “123”)来动态地计算跳转地址。这个跳转通常指向某些指令的中间,以绕过AV软件的启发式分析。但这种技术也有(至少)一个副作用。
如果在操作系统中设置了默认的NetBIOS设置(NetBIOS over TCP/IP被启用),返回代码总是等于ERROR_BAD_NETPATH(0x35)。
如果关闭了TCP/IP上的NetBIOS,那么返回代码是ERROR_NETWORK_UNREACHABLE(0x4CF)。
因此,跳转地址将被错误地计算,这将导致样本崩溃。因此,这个技术可以用来破解沙盒中的伪装,在沙盒中,TCP/IP上的NetBIOS被关闭,以防止操作系统产生垃圾流量。
注意:关闭TCP/IP上的NetBIOS是为了在通过DNS解析服务器IP时不产生额外的网络请求。关掉这个选项会取消本地网络的查询请求。
代码样本 (函数GetAdaptersAddresses):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
void EntryPoint(void){ HANDLE NetApi32 = LoadLibraryW(L"netapi32.dll"); TD_NetValidateName NetValidateName = (TD_NetValidateName)GetProcAddress(NetApi32, "NetValidateName"); DWORD Result = NetValidateName(L"123", L"", L"", L"", 1); __asm { call dword ptr ds:[GetLastError] add eax, offset TrueEntryPoint sub eax, 0xCB // ERROR_ENVVAR_NOT_FOUND call eax }} |
4. 基于Cuckoo ResultServer连接的反伪装技术
这项技术可用于检测Cuckoo沙盒虚拟环境。恶意软件列举了所有已建立的出站TCP连接,并检查是否有连接到Cuckoo ResultServer使用的特定TCP端口(2042)。
识别标志
别标志对每种技术都是通用的:钩住使用的函数并跟踪它是否被调用。例如,很难说出应用程序为什么要获取适配器名称。这并不一定意味着应用规避技术。所以在这种情况下,最好的办法是拦截目标函数并跟踪其调用。
反制措施
-
与检查网络参数的对比:为虚拟环境更改;
-
与检查安全周长相比:以适当的方式模拟网络响应;
-
与NetValidateName基于结果的技术相比:通过TCP/IP打开NetBIOS;
-
与基于Cuckoo ResultServer连接的技术相比:在Cuckoo配置中改变ResultServer端口。













暂无评论内容