飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2279|回复: 2

[病毒分析] [翻译]规避技术:常规操作系统查询

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2021-5-18 16:35:00 | 显示全部楼层 |阅读模式
    本帖最后由 梦幻的彼岸 于 2021-5-18 17:49 编辑

    备注
    原文地址:https://evasions.checkpoint.com/techniques/generic-os-queries.html
    原文标题:Evasions: Generic OS queries
    更新日期:2021年5月18日
    此文后期:根据自身所学进行内容扩充
    因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。


    目录
    • 常规操作系统查询
    • 1. 检查用户名是否是特定的
    • 2. 检查计算机名称是否是特定的
    • 3. 检查主机名称是否是特定的
    • 4. 检查总内存是否过低
    • 5.检查主机操作系统的屏幕分辨率是否不正常
    • 6.检查处理器数量是否过少
    • 7. 检查显示器的数量是否很少
    • 8.检查硬盘大小和可用空间是否较小
    • 9. 检查系统的正常运行时间是否很小
    • 10. 检查操作系统是否从虚拟硬盘启动(Win8+)
    • 反制措施
    • 归功于

    识别标志是通用的
    识别标志对每种技术都是通用的:钩住使用的函数,并跟踪它是否被调用。例如,很难说出应用程序为什么要获取用户名。这并不一定意味着应用规避技术。所以在这种情况下,最好的办法就是拦截目标函数并跟踪其调用。
    通过常规的操作系统检查进行检测
    通常的主机具有有意义的非标准用户名/计算机名。特定的虚拟环境将一些预定义的名称分配给默认用户以及计算机名称。主机操作系统和虚拟机之间的其他区别包括RAM大小、HDD大小、监视器数量等等。虽然这些可能不是检测虚拟环境最可靠的方法,但它们仍然常用于恶意软件样本。
    1. 检查用户名是否是特定的
    请注意,检查是不区分大小写的。
    使用的函数:
    • GetUserNameA/W

    代码样本
    1. bool is_user_name_match(const std::string &s) {
    2.     auto out_length = MAX_PATH;
    3.     std::vector<uint8_t> user_name(out_length, 0);
    4.     ::GetUserNameA((LPSTR)user_name.data(), (LPDWORD)&out_length);

    5.     return (!lstrcmpiA((LPCSTR)user_name.data(), s.c_str()));
    6. }
    复制代码

    代码样本取自InviZzzible tool
    反制措施
    将用户名改为不可疑的用户名。
    检测表
    检查用户名是否为以下其中之一:
    检测
    字符串
    [general]
    admin
    andy
    honey
    john
    john doe
    malnetvm
    maltest
    malware
    roo
    sandbox
    snort
    tequilaboomboom
    test
    virus
    virusclone
    wilbert
    Nepenthes
    nepenthes
    Norman
    currentuser
    ThreatExpert
    username
    Sandboxie
    user
    VMware
    vmware

    2. 检查计算机名称是否是特定的
    请注意,检查是不区分大小写的。
    使用的函数:
    • GetComputerNameA/W

    代码样本
    1. bool is_computer_name_match(const std::string &s) {
    2.     auto out_length = MAX_PATH;
    3.     std::vector<uint8_t> comp_name(out_length, 0);
    4.     ::GetComputerNameA((LPSTR)comp_name.data(), (LPDWORD)&out_length);

    5.     return (!lstrcmpiA((LPCSTR)comp_name.data(), s.c_str()));
    6. }
    复制代码

    代码样本取自InviZzzible tool
    反制措施
    将计算机名称改为不可疑的名称。
    检测表
    检查计算机名是否为以下其中之一:
    检测
    字符串
    [generic]
    klone_x64-pc
    tequilaboomboom
    Anubis
    TU-4NH09SMCG1HC
    InsideTm

    3. 检查主机名称是否是特定的
    请注意,检查是不区分大小写的。
    使用的函数:
    • GetComputerNameExA/W

    代码样本
    1. bool is_host_name_match(const std::string &s) {
    2.     auto out_length = MAX_PATH;
    3.     std::vector<uint8_t> dns_host_name(out_length, 0);
    4.     ::GetComputerNameExA(ComputerNameDnsHostname, (LPSTR)dns_host_name.data(), (LPDWORD)&out_length);

    5.     return (!lstrcmpiA((LPCSTR)dns_host_name.data(), s.c_str()));
    6. }
    复制代码

    代码样本取自InviZzzible tool
    反制措施
    将主机名称改为不可疑的名称。
    检测表
    检查主机名是否为以下其中之一:
    Detect
    String
    [generic]
    SystemIT

    4. 检查总内存是否过低
    用来获取可执行路径的函数:
    • GetMemoryStatusEx

    代码样本
    1. BOOL memory_space()
    2. {
    3.     DWORDLONG ullMinRam = (1024LL * (1024LL * (1024LL * 1LL))); // 1GB
    4.    
    5.     MEMORYSTATUSEX statex = {0};
    6.     statex.dwLength = sizeof(statex);
    7.     GlobalMemoryStatusEx(&statex); // calls NtQuerySystemInformation
    8.    
    9.     return (statex.ullTotalPhys < ullMinRam) ? TRUE : FALSE;
    10. }
    复制代码

    该代码样本的作者:al-khaser project
    反制措施
    修补/拦截NtQuerySystemInformation以在SystemBasicInformation中返回新数量的PhysicalPages。
    提示:在本例中,它的第一个参数等于2-SystemPerformanceInformation枚举值。
    或者,修补KUSER_SHARED_DATA中的NumberOfPhysicalPages。
    5.检查主机操作系统的屏幕分辨率是否不正常
    • 使用以下一组函数:
    • GetDesktopWindow
    • GetWindowRect

    或者:
    • GetSystemMetrics
    • SystemParametersInfo
    • GetMonitorInfo

    代码样本
    看看这个StackOverflow主题
    反制措施
    改变屏幕分辨率,使之与常规主机的分辨率相匹配(例如1600x900)。
    6.检查处理器数量是否过少
    使用的函数:
    • GetSystemInfo

    除此之外,处理器的数量可以通过asm内联函数或内在函数从PEB获得,请参见下面的代码示例。
    代码样本(variant 1, al-khaser project)
    1. BOOL NumberOfProcessors()
    2. {
    3. #if defined (ENV64BIT)
    4.         PULONG ulNumberProcessors = (PULONG)(__readgsqword(0x30) + 0xB8);
    5. #elif defined(ENV32BIT)
    6.         PULONG ulNumberProcessors = (PULONG)(__readfsdword(0x30) + 0x64);
    7. #endif

    8.     if (*ulNumberProcessors < 2)
    9.         return TRUE;
    10.     else
    11.         return FALSE;
    12. }
    复制代码

    该代码样本的作者:al-khaser project
    代码样本(variant 2, al-khaser project, asm inline)
    1. __declspec(naked)
    2. DWORD get_number_of_processors() {
    3.     __asm {
    4.         ; get pointer to Process Environment Block (PEB)
    5.         mov eax, fs:0x30

    6.         ; read the field containing target number
    7.         mov eax, [eax + 0x64]

    8.         ; return from function
    9.         retn
    10.     }
    11. }
    复制代码

    该代码样本的作者:al-khaser project
    代码样本(variant 3, pafish project)
    1. int gensandbox_one_cpu_GetSystemInfo() {
    2.     SYSTEM_INFO si;
    3.     GetSystemInfo(&si);
    4.     return si.dwNumberOfProcessors < 2 ? TRUE : FALSE;
    5. }
    复制代码

    该代码样本的作者:pafish project
    反制措施
    为虚拟机分配两个或多个内核。
    作为一个替代方案,打补丁/拦截NtCreateThread,为每个新线程分配特定的内核。
    7. 检查显示器的数量是否很少
    使用的函数:
    • EnumDisplayMonitors
    • GetSystemMetrics (SM_MONITOR)

    代码样本
    1. BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
    2. {
    3.     int *Count = (int*)dwData;
    4.     (*Count)++;
    5.     return TRUE;
    6. }

    7. int MonitorCount()
    8. {
    9.     int Count = 0;
    10.     if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&Count))
    11.         return Count;
    12.     return -1; // signals an error
    13. }
    复制代码

    该代码样本归功于:StackOverflow forum
    反制措施
    在虚拟环境中至少添加一个显示器。
    8.检查硬盘大小和可用空间是否较小
    使用的函数:
    • DeviceIoControl(..., IOCTL_DISK_GET_LENGTH_INFO, ...)
    • GetDiskFreeSpaceExA/W

    代码样本(checking drive total size)
    1. int gensandbox_drive_size() {
    2.     GET_LENGTH_INFORMATION size;
    3.     DWORD lpBytesReturned;

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

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

    16.     return FALSE;
    17. }
    复制代码

    该代码样本的作者:al-khaser project
    代码样本(checking drive free space)
    1. int gensandbox_drive_size2() {
    2.     ULARGE_INTEGER total_bytes;

    3.     if (GetDiskFreeSpaceExA("C:\", NULL, &total_bytes, NULL))
    4.     {
    5.         if (total_bytes.QuadPart / 1073741824 <= 60) /* <= 60 GB */
    6.         return TRUE;
    7.     }

    8.     return FALSE;
    9. }
    复制代码

    该代码样本的作者:al-khaser project
    反制措施
    针对检查磁盘大小:使用特定CTL代码筛选到\\device\\HarddiskN的IRP设备控制请求:
    • DRIVE_GEOMETRY_EX
    • DRIVE_LAYOUT_EX
    • PARTITION_INFO_EX

    禁止检查可用空间:修补/挂接NtQueryVolumeInformationFile以处理这些类:
    • FileFsSizeInformation
    • FileFsFullSizeInformation

    如果句柄指向\\Device\\HarddiskVolumeN。
    9. 检查系统的正常运行时间是否很小
    使用的函数:
    • GetTickCount
    • GetTickCount64
    • NtQuerySystemInformation

    代码样本
    1. bool Generic::CheckSystemUptime() const {
    2.     const DWORD uptime = 1000 * 60 * 12; // 12 minutes
    3.     return GetTickCount() < uptime;
    4. }
    复制代码

    代码样本取自InviZzzible tool
    代码样本
    1. #define MIN_UPTIME_MINUTES 12
    2. BOOL uptime_check()
    3. {
    4.     ULONGLONG uptime_minutes = GetTickCount64() / (60 * 1000);
    5.     return uptime_minutes < MIN_UPTIME_MINUTES;
    6. }
    复制代码

    代码样本
    1. BOOL uptime_check2()
    2. {
    3.     SYSTEM_TIME_OF_DAY_INFORMATION  SysTimeInfo;
    4.     ULONGLONG uptime_minutes;
    5.     NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
    6.     uptime_minutes = (SysTimeInfo.CurrentTime.QuadPart - SysTimeInfo.BootTime.QuadPart) / (60 * 1000 * 10000);
    7.     return uptime_minutes < MIN_UPTIME_MINUTES;
    8. }
    复制代码

    反制措施
    • 调整KeBootTime值
    • 调整SharedUserData->TickCount, SharedUserData->TickCoundLowDeprecated值

    10. 检查操作系统是否从虚拟硬盘启动(Win8+)
    • 使用的函数:
    • IsNativeVhdBoot // 在主机操作系统上为false,在虚拟机内为true

    代码样本(excerpt from malware)
    在这里看一下恶意软件的节选
    代码样本(pafish project)
    1. int gensandbox_IsNativeVhdBoot() {
    2.     BOOL isnative = FALSE;

    3.     IsNativeVhdBoot fnnative = (IsNativeVhdBoot) GetProcAddress(
    4.         GetModuleHandleA("kernel32"), "IsNativeVhdBoot");

    5.     /* IsNativeVhdBoot always returns 1 on query success */
    6.     if (fnnative)
    7.         fnnative(&isnative);
    8.                
    9.     return (isnative) ? TRUE : FALSE;
    10. }
    复制代码

    该代码样本的作者:pafish project
    反制措施
    拦截IsNativeVhdBoot并将其结果改为所需的结果。
    反制措施
    反措施存在于适当的分节中,见上文。
    归功于
    归功于开放源码项目,代码样本来自这些项目。
    尽管Check Point工具InviZzzible已经实现了所有这些功能,但由于代码的模块化结构,需要更多的空间来展示这个工具的代码样本,以达到相同的目的。这就是为什么我们决定在整个百科全书中使用其他伟大的开源项目作为例子。
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    12 小时前
  • 签到天数: 1394 天

    [LV.10]以坛为家III

    发表于 2021-5-18 22:23:14 | 显示全部楼层
    感谢大婶分享翻译文件
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-5-13 23:22
  • 签到天数: 853 天

    [LV.10]以坛为家III

    发表于 2021-5-18 22:28:35 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表