通过关注系统环境来检测沙箱或虚拟机。导致不运行恶意代码,而是运行其他无害的代码。
一般来说虚拟的内存和CPU的数量都是有限的,但是这里不建议加虚拟机的反调试,因为有时候我们去打项目的时候难免会遇到Vcenter搭建的,但是话又说回来,一般来说使用Vcenter创建的虚拟机里面都跑一些正常的业务,内存这些也就不会很小。
比如说我们可以检测CPU处理器的数量是否低于或等于2,并且RAM是否低于4GB,如果低于的话那么我们直接运行正常的代码就可以了比如说可以MessageBoxA弹框之类的。
如下代码:
#include <stdio.h>#include <windows.h>int main() {SYSTEM_INFO info;MEMORYSTATUSEX status;GetSystemInfo(&info);printf("处理器: %u\n", info.dwNumberOfProcessors);status.dwLength = sizeof(status);GlobalMemoryStatusEx(&status);printf("内存: %I64u MB\n", status.ullTotalPhys / (1024 * 1024));return 0;}
这里的SYSTEM_INFO,它是一个结构类型,它里面包含了系统资源的相关信息,我们可以利用它来检索CPU的数量。MEMORYSTATUSEX也是一个结构,里面包含了内存的状态等等,然后通过调用GetSystemInfo函数来检索关硬件的信息,最后再调用GlobalMemoryStatusEx函数检索有关系统内存状态的信息。
我们来查看虚拟机的内存和CPU。
获取到之后就可以判断了,如果处理器小于4个,并且内存小于4GB的话,执行正常代码。
#include <stdio.h>#include <windows.h>int main() {SYSTEM_INFO info;MEMORYSTATUSEX status;GetSystemInfo(&info);printf("处理器: %u\n", info.dwNumberOfProcessors);status.dwLength = sizeof(status);GlobalMemoryStatusEx(&status);printf("内存: %I64u MB\n", status.ullTotalPhys / (1024 * 1024));if (info.dwNumberOfProcessors < 8 && (status.ullTotalPhys / (1024 * 1024)) < 4096) {MessageBoxA(NULL, "执行正常代码", "执行正常代码", NULL);}else {MessageBoxA(NULL, "执行shellcode", "执行shellcode", NULL);}return 0;}
虚拟机需要一些特定的文件才能跑起来,无论是Vmware还是VirtualBox都有自己的特定文件,我们可以查询这些文件的路径来判断是否被分析。
这里可以使用Windows API来实现。
如下代码:
首先通过LoadLibrary去加载NTDLL.DLL模块。
HMODULE ntdllTest = LoadLibrary(L"ntdll.dll");获取到DLL之后通过GetProcAddress去动态获取函数的地址。
#include <stdio.h>#include <windows.h>#include <winternl.h>typedef NTSTATUS(NTAPI* pNtOpenFile) (PHANDLE FileHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PIO_STATUS_BLOCK IoStatusBlock,ULONG ShareAccess,ULONG OpenOptions);typedef VOID(NTAPI* pRtlInitUnicodeString) (PUNICODE_STRING DestinationString,PCWSTR SourceString);int main() {//通过LoaderLibrary先去加载NTDLL.DLL模块HMODULE ntdllTest = LoadLibrary(L"ntdll.dll");pNtOpenFile NtOpenFile = (pNtOpenFile)GetProcAddress(ntdllTest, "NtOpenFile");pRtlInitUnicodeString RtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(ntdllTest, "RtlInitUnicodeString");getchar();}
紧接着指定要读取的文件。
UNICODE_STRING dirName; RtlInitUnicodeString(&dirName,L"C:\\Users\\Admin\\Desktop\\1.txt");然后去搜索文件,不区分大小写。
InitializeObjectAttributes(&objectAttributes, &dirName, OBJ_CASE_INSENSITIVE, nullptr, nullptr);最后打开文件,如果打开成功的话,那么就执行正常代码,如果打开失败的话,那么就执行shellcode。
完整代码:
#include <stdio.h>#include <windows.h>#include <winternl.h>typedef NTSTATUS(NTAPI* pNtOpenFile) (PHANDLE FileHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PIO_STATUS_BLOCK IoStatusBlock,ULONG ShareAccess,ULONG OpenOptions);typedef VOID(NTAPI* pRtlInitUnicodeString) (PUNICODE_STRING DestinationString,PCWSTR SourceString);int main() {//通过LoaderLibrary先去加载NTDLL.DLL模块HMODULE ntdllTest = LoadLibrary(L"ntdll.dll");pNtOpenFile NtOpenFile = (pNtOpenFile)GetProcAddress(ntdllTest, "NtOpenFile");pRtlInitUnicodeString RtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(ntdllTest, "RtlInitUnicodeString");HANDLE hFile = NULL;NTSTATUS status;UNICODE_STRING dirName;IO_STATUS_BLOCK ioStatusBlock;RtlInitUnicodeString(&dirName,L"C:\\Users\\Admin\\Desktop\\1.txt");OBJECT_ATTRIBUTES objectAttributes;InitializeObjectAttributes(&objectAttributes, &dirName, OBJ_CASE_INSENSITIVE, nullptr, nullptr);status = NtOpenFile(&hFile, FILE_READ_DATA, &objectAttributes, &ioStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE);if (!NT_SUCCESS(status)) {MessageBoxA(NULL, "执行shellcode", "shellcode", NULL);}else {MessageBoxA(NULL, "执行正常代码", "执行正常代码", NULL);}getchar();}
那么这里的话就可以将C:\Users\Admin\Desktop\1.txt 更改为特定的一些文件,比如VMware 3D 驱动程序,vm3dum64.dll,VMware 虚拟 SCSI 驱动程序 vmscsi.sys等等。
我们可以利用延时来规避沙箱。我们可以使用NtDelayExecution来进行延迟。
#include <iostream>#include <Windows.h>#include <string>#include <winternl.h>typedef NTSTATUS(NTAPI* pNtDelayExecution) (BOOL Alertable,PLARGE_INTEGER DelayInterval);int main(){//获取NTDLL的基地址HMODULE hmodule = GetModuleHandleA("NTDLL.DLL");pNtDelayExecution NtDelayExecution = (pNtDelayExecution)GetProcAddress(hmodule, "NtDelayExecution");LARGE_INTEGER delay;delay.QuadPart = -50000000;//睡眠5秒NTSTATUS status = NtDelayExecution(FALSE, &delay);printf("sucess");}
其实是和Sleep函数是差不多的,这里延迟了5秒,我们在写loader的时候延迟几分钟即可。