规避检测(共五章):第一章

2023-11-20 12:42:32 浏览数 (1)

一、文件系统检测方法

所有文件系统检测方法的原理如下:

1.1 检查特定文件

通常的主机中没有这样的文件和目录;但是,它们存在于特定的虚拟环境和沙箱中。如果存在此类项目,则可以检测到虚拟环境。

简述:找特定文件是否在虚拟机内。

代码语言:javascript复制
BOOL is_FileExists(TCHAR* szPath)
{
    DWORD dwAttrib = GetFileAttributes(szPath);
    return (dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

/*
Check against some of VMware blacklisted files
*/
VOID vmware_files()
{
    /* 指定虚拟机特殊文件 */
    TCHAR* szPaths[] = {
    _T("system32\drivers\vmmouse.sys"),
    _T("system32\drivers\vmhgfs.sys"),
    };

    /* 获取目录 */
    WORD dwlength = sizeof(szPaths) / sizeof(szPaths[0]);
    TCHAR szWinDir[MAX_PATH] = _T("");
    TCHAR szPath[MAX_PATH] = _T("");
    GetWindowsDirectory(szWinDir, MAX_PATH);

    /* 逐个检查 */
    for (int i = 0; i < dwlength; i  )
    {
        PathCombine(szPath, szWinDir, szPaths[i]);
        TCHAR msg[256] = _T("");
        _stprintf_s(msg, sizeof(msg) / sizeof(TCHAR), _T("Checking file %s: "), szPath);
        if (is_FileExists(szPath))
            print_results(TRUE, msg);
        else
            print_results(FALSE, msg);
    }
}

1.2 检查是否存在特定目录

此方法使用通常主机系统和虚拟环境中存在的目录差异。虚拟环境中存在相当多的目录路径,这些路径特定于此类系统。这些目录不存在于未安装虚拟环境的常规主机系统上。

简述:通过路径判断是否在虚拟机内

代码语言:javascript复制
BOOL is_DirectoryExists(TCHAR* szPath)
{
    DWORD dwAttrib = GetFileAttributes(szPath);
    return (dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
}

/*
检查特定虚拟机目录
*/
BOOL vmware_dir()
{
    TCHAR szProgramFile[MAX_PATH];
    TCHAR szPath[MAX_PATH] = _T("");
    TCHAR szTarget[MAX_PATH] = _T("VMware\");
    if (IsWoW64())
        ExpandEnvironmentStrings(_T("%ProgramW6432%"), szProgramFile, ARRAYSIZE(szProgramFile));
    else
        SHGetSpecialFolderPath(NULL, szProgramFile, CSIDL_PROGRAM_FILES, FALSE);
    PathCombine(szPath, szProgramFile, szTarget);
    return is_DirectoryExists(szPath);
}

1.3 检查可执行文件的完整路径是否包含特定字符串之一

此方法依赖于在虚拟环境中启动可执行文件的特殊性。某些环境从特定路径启动可执行文件 - 恶意软件示例会检查这些路径。

简述:通过检查路径是否已被投放沙箱

代码语言:javascript复制
int gensandbox_path() {
    char path[500];
    size_t i;
    DWORD pathsize = sizeof(path);

    GetModuleFileName(NULL, path, pathsize);

    for (i = 0; i < strlen(path); i  ) {
        path[i] = toupper(path[i]);
    }

    // 一些常见路径
    if (strstr(path, "\SAMPLE") != NULL) {
        return TRUE;
    }
    if (strstr(path, "\VIRUS") != NULL) {
        return TRUE;
    }
    if (strstr(path, "SANDBOX") != NULL) {
        return TRUE;
    }

    return FALSE;
}

1.4 检查物理磁盘驱动器的根目录中是否存在具有特定名称的可执行文件

此方法依赖于虚拟环境的特殊性,在这种情况下,它是磁盘根根目录中存在特定文件。

代码语言:javascript复制
int pafish_exists_file(char* filename) {
    DWORD res = INVALID_FILE_ATTRIBUTES;
    if (pafish_iswow64() == TRUE) {
        void* old = NULL;
        // 在调用 GetFileAttributes 之前立即禁用重定向。
        if (pafish_disable_wow64_fs_redirection(&old)) {
            res = GetFileAttributes(filename);
            // 忽略 MSDN 在此调用失败时退出的建议.
            pafish_revert_wow64_fs_redirection(old);
        }
    }
    else {
        res = GetFileAttributes(filename);
    }
    return (res != INVALID_FILE_ATTRIBUTES) ? TRUE : FALSE;
}

int gensandbox_common_names() {
    DWORD dwSize = MAX_PATH;
    char szLogicalDrives[MAX_PATH] = { 0 };
    DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
    BOOL exists;

    if (dwResult > 0 && dwResult <= MAX_PATH)
    {
        char* szSingleDrive = szLogicalDrives;
        char filename[MAX_PATH] = { 0 };
        while (*szSingleDrive)
        {
            if (GetDriveType(szSingleDrive) != DRIVE_REMOVABLE) {
                snprintf(filename, MAX_PATH, "%ssample.exe", szSingleDrive);
                exists = pafish_exists_file(filename);
                if (exists) return TRUE;

                snprintf(filename, MAX_PATH, "%smalware.exe", szSingleDrive);
                exists = pafish_exists_file(filename);
                if (exists) return TRUE;
            }

            szSingleDrive  = strlen(szSingleDrive)   1;
        }
    }

    return FALSE;
}

二、注册表检测

所有注册表检测方法的原理如下:在通常的主机中没有这样的注册表项和值。但是,它们存在于特定的虚拟环境中。

有时,通常的系统在应用这些检查时可能会导致误报,因为它安装了某些虚拟机,因此系统中存在一些虚拟机项目。尽管在所有其他方面,与虚拟环境相比,这样的系统都被视为干净。

2.1 检查是否存在特定的注册表路径

代码语言:javascript复制
/* VirtualBox 检测以检查注册表路径*/
int vbox_reg_key7() {
    return pafish_exists_regkey(HKEY_LOCAL_MACHINE, "HARDWARE\ACPI\FADT\VBOX__");
}

/* code is taken from "pafish" project, see references on the parent page */
int pafish_exists_regkey(HKEY hKey, char* regkey_s) {
    HKEY regkey;
    LONG ret;

    /* regkey_s == "HARDWARE\ACPI\FADT\VBOX__"; */
    if (pafish_iswow64()) {
        ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ | KEY_WOW64_64KEY, ®key);
    }
    else {
        ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ, ®key);
    }

    if (ret == ERROR_SUCCESS) {
        RegCloseKey(regkey);
        return TRUE;
    }
    else
        return FALSE;
}

2.2 检查特定注册表项是否包含指定的字符串

代码语言:javascript复制
int vbox_reg_key2() {
    return pafish_exists_regkey_value_str(HKEY_LOCAL_MACHINE, "HARDWARE\Description\System", "SystemBiosVersion", "VBOX");
}

/* code is taken from "pafish" project, see references on the parent page */
int pafish_exists_regkey_value_str(HKEY hKey, char* regkey_s, char* value_s, char* lookup) {
    /*
        regkey_s == "HARDWARE\Description\System";
        value_s == "SystemBiosVersion";
        lookup == "VBOX";
    */

    HKEY regkey;
    LONG ret;
    DWORD size;
    char value[1024], * lookup_str;
    size_t lookup_size;

    lookup_size = strlen(lookup);
    lookup_str = malloc(lookup_size   sizeof(char));
    strncpy(lookup_str, lookup, lookup_size   sizeof(char));
    size = sizeof(value);

    /* regkey_s == "HARDWARE\Description\System"; */
    if (pafish_iswow64()) {
        ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ | KEY_WOW64_64KEY, ®key);
    }
    else {
        ret = RegOpenKeyEx(hKey, regkey_s, 0, KEY_READ, ®key);
    }

    if (ret == ERROR_SUCCESS) {
        /* value_s == "SystemBiosVersion"; */
        ret = RegQueryValueEx(regkey, value_s, NULL, NULL, (BYTE*)value, &size);
        RegCloseKey(regkey);

        if (ret == ERROR_SUCCESS) {
            size_t i;
            for (i = 0; i < strlen(value); i  ) {
                value[i] = toupper(value[i]);
            }
            for (i = 0; i < lookup_size; i  ) {
                lookup_str[i] = toupper(lookup_str[i]);
            }
            if (strstr(value, lookup_str) != NULL) {
                free(lookup_str);
                return TRUE;
            }
        }
    }

    free(lookup_str);
    return FALSE;
}

三、通用操作系统查询规避

通常的主机具有有意义的和非标准的用户名/计算机名称。特定的虚拟环境为默认用户分配一些预定义的名称以及计算机名称。主机操作系统和虚拟机之间的其他差异包括 RAM 大小、HDD 大小、显示器数量等。虽然这些可能不是检测虚拟环境的最可靠方法,但它们仍然常用于恶意软件样本中

3.1 检查用户名是否特定

代码语言:javascript复制
bool is_user_name_match(const std::string& s) {
    auto out_length = MAX_PATH;
    std::vector<uint8_t> user_name(out_length, 0);
    ::GetUserNameA((LPSTR)user_name.data(), (LPDWORD)&out_length);

    return (!lstrcmpiA((LPCSTR)user_name.data(), s.c_str()));
}

3.2 检查计算机名称是否特定

代码语言:javascript复制
bool is_user_name_match(const std::string& s) {
    auto out_length = MAX_PATH;
    std::vector<uint8_t> user_name(out_length, 0);
    ::GetUserNameA((LPSTR)user_name.data(), (LPDWORD)&out_length);

    return (!lstrcmpiA((LPCSTR)user_name.data(), s.c_str()));
}

3.3 检查主机名是否特定

代码语言:javascript复制
bool is_host_name_match(const std::string& s) {
    auto out_length = MAX_PATH;
    std::vector<uint8_t> dns_host_name(out_length, 0);
    ::GetComputerNameExA(ComputerNameDnsHostname, (LPSTR)dns_host_name.data(), (LPDWORD)&out_length);

    return (!lstrcmpiA((LPCSTR)dns_host_name.data(), s.c_str()));
}

3.4 检查总RAM是否低

代码语言:javascript复制
BOOL memory_space()
{
    DWORDLONG ullMinRam = (1024LL * (1024LL * (1024LL * 1LL))); // 1GB

    MEMORYSTATUSEX statex = { 0 };
    statex.dwLength = sizeof(statex);
    GlobalMemoryStatusEx(&statex); // 调用 NtQuerySystemInformation

    return (statex.ullTotalPhys < ullMinRam) ? TRUE : FALSE;
}

3.5 检查处理器数量是否少

代码语言:javascript复制
BOOL NumberOfProcessors()
{
#if defined (ENV64BIT)
    PULONG ulNumberProcessors = (PULONG)(__readgsqword(0x30)   0xB8);
#elif defined(ENV32BIT)
    PULONG ulNumberProcessors = (PULONG)(__readfsdword(0x30)   0x64);
#endif

    if (*ulNumberProcessors < 2)
        return TRUE;
    else
        return FALSE;
}
代码语言:javascript复制
__declspec(naked)
DWORD get_number_of_processors() {
    __asm {
        ; get pointer to Process Environment Block(PEB)
        mov eax, fs:0x30

        ; read the field containing target number
        mov eax, [eax   0x64]

        ; return from function
        retn
    }
}
代码语言:javascript复制
int gensandbox_one_cpu_GetSystemInfo() {
    SYSTEM_INFO si;
    GetSystemInfo(&si);
    return si.dwNumberOfProcessors < 2 ? TRUE : FALSE;
}

3.6 检查显示器数量是否少

代码语言:javascript复制
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    int* Count = (int*)dwData;
    (*Count)  ;
    return TRUE;
}

int MonitorCount()
{
    int Count = 0;
    if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&Count))
        return Count;
    return -1; // signals an error
}

3.7 检查硬盘驱动器大小和可用空间是否较小

代码语言:javascript复制
int gensandbox_drive_size() {
    GET_LENGTH_INFORMATION size;
    DWORD lpBytesReturned;

    HANDLE drive = CreateFile("\\.\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (drive == INVALID_HANDLE_VALUE) {
        // Someone is playing tricks. Or not enough privileges.
        CloseHandle(drive);
        return FALSE;
    }
    BOOL result = DeviceIoControl(drive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &size, sizeof(GET_LENGTH_INFORMATION), &lpBytesReturned, NULL);
    CloseHandle(drive);

    if (result != 0) {
        if (size.Length.QuadPart / 1073741824 <= 60) /* <= 60 GB */
            return TRUE;
    }

    return FALSE;
}

锦鲤安全

一个安全技术学习与工具分享平台

点分享

点收藏

点点赞

点在看

0 人点赞