设为首页收藏本站
查看: 867|回复: 0

[翻译]规避技术: CPU

[复制链接]
  • TA的每日心情
    开心
    2022-1-9 18:41
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2021-9-12 16:52:02 | 显示全部楼层 |阅读模式
    备注
    原文地址:https://evasions.checkpoint.com/techniques/cpu.html
    原文标题:Evasions: CPU
    更新日期:2021年5月28日
    此文后期:根据自身所学进行内容扩充
    因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。




    目录
    • 使用的CPU检测方法
    • 1.通过CPUID指令检查供应商ID字符串
    • 2.通过CPUID指令检查是否在Hypervisor中运行
    • 3.检查全局表位置:IDT/GDT/LDT
    • 4.使用异域指令愚弄虚拟模拟器
    • 5.通过执行非法指令检测环境(仅VirtualPC)
    • 6.通过指令内-后门端口(仅适用于VMware)检测环境
    • 识别标志
    • 反制措施
    • 归功于

    使用的CPU检测方法
    这组技术使用特定的处理器指令来获取CPU的特定信息,或者执行预定义的指令序列,这些指令在常规的主机操作系统和虚拟环境中表现不同。
    1.通过CPUID指令检查供应商ID字符串
    CPUID指令是一条向EBX、ECX、EDX返回处理器识别和特征信息的指令。接收到这些寄存器的信息可以用来识别一个供应商。
    代码样本:
    1. __declspec(naked) void get_cpuid_vendor(char *vendor_id) {
    2.   __asm {        
    3.     ; save non-volatile register
    4.     push ebx
    5.    
    6.     ; nullify output registers
    7.     xor ebx, ebx
    8.     xor ecx, ecx
    9.     xor edx, edx
    10.    
    11.     ; call cpuid with argument in EAX
    12.     mov eax, 0x40000000
    13.     cpuid
    14.    
    15.     ; store vendor_id ptr to destination
    16.     mov edi, vendor_id
    17.    
    18.     ; move string parts to destination
    19.     mov eax, ebx  ; part 1 of 3 from EBX
    20.     stosd
    21.     mov eax, ecx  ; part 2 of 3 from ECX
    22.     stosd
    23.     mov eax, edx  ; part 3 of 3 from EDX
    24.     stosd
    25.    
    26.     ; restore saved non-volatile register
    27.     pop ebx
    28.    
    29.     ; return from function
    30.     retn
    31.   }
    32. }
    复制代码

    检测表:
    通过CPUID指令检查供应商ID字符串-分别以EBX、ECX、EDX的形式返回信息:
    检测
    EAX作为CPUID的参数
    字符串
    FreeBSD HV
    0x40000000
    bhyve bhyve
    Hyper-V
    0x40000000
    Microsoft Hv
    KVM
    0x40000000
    KVMKVMKVM
    Parallels
    0x40000000
    prl hyperv
    VirtualBox
    0x40000000
    VBoxVBoxVBox
    VirtualPC
    0x40000000
    Microsoft Hv
    VMware
    0x40000000
    VMwareVMware
    Xen
    0x40000000
    XenVMMXenVMM
    2.通过CPUID指令检查是否在Hypervisor中运行
    另一种检测程序是否在管理程序中运行的方法是以其他方式使用CPUID指
    不把EAX(CPUID的参数)设置为0x40000000,而是将EAX设置为1。
    当EAX被设置为1时,ECX(CPUID的返回值)中的第31位被设置,它表明程序正在Hypervisor中运行。
    代码样本 (函数GetAdaptersAddresses):
    1. __declspec(naked) bool is_run_in_hypervisor() {
    2.   __asm {
    3.     ; nullify output register
    4.     xor ecx, ecx
    5.    
    6.     ; call cpuid with argument in EAX
    7.     mov eax, 1
    8.     cpuid
    9.    
    10.     ; set CF equal to 31st bit in ECX
    11.     bt ecx, 31
    12.    
    13.     ; set AL to the value of CF
    14.     setc al
    15.    
    16.     ; return from function
    17.     retn
    18.   }
    19. }
    复制代码

    检测表:
    检查是否正在虚拟机管理程序中运行(通过CPUID)
    检测
    EAX作为CPUID的参数
    检查返回值
    Hypervisor
    1
    31st bit in ECX - set if run in Hypervisor

    3.检查全局表位置:IDT/GDT/LDT
    此技术不适用于最新的VMware版本(所有受影响的Windows版本)。然而,为了完整起见,这里对其进行了描述。
    这个技巧包括查看指向关键操作系统表的指针,这些表通常在虚拟机上重新定位。这就是所谓的“Red Pill”,由Joanna Rutkowska首次提出
    每个CPU有一个本地描述符表寄存器(LDTR)、一个全局描述符表寄存器(GDTR)和一个中断描述符表寄存器(IDTR)。当虚拟机操作系统运行时,必须将它们移动到其他位置,以避免与主机发生冲突。
    例如,在实际机器上,IDT位于内存中的位置低于在客户机(即虚拟机)上的位置。
    代码样本:
    1. idt_vm_detect = ((get_idt_base() >> 24) == 0xff);
    2. ldt_vm_detect = (get_ldt_base() == 0xdead0000);
    3. gdt_vm_detect = ((get_gdt_base >> 24) == 0xff);

    4. // sidt instruction stores the contents of the IDT Register
    5. // (the IDTR which points to the IDT) in a processor register.
    6. ULONG get_idt_base() {   
    7.     UCHAR idtr[6];
    8. #if defined (ENV32BIT)
    9.     _asm sidt idtr
    10. #endif
    11.     return *((unsigned long *)&idtr[2]);
    12. }

    13. // sldt instruction stores the contents of the LDT Register
    14. // (the LDTR which points to the LDT) in a processor register.
    15. ULONG get_ldt_base() {
    16.     UCHAR ldtr[5] = "\xef\xbe\xad\xde";
    17. #if defined (ENV32BIT)
    18.     _asm sldt ldtr
    19. #endif
    20.     return *((unsigned long *)&ldtr[0]);
    21. }

    22. // sgdt instruction stores the contents of the GDT Register
    23. // (the GDTR which points to the GDT) in a processor register.
    24. ULONG get_gdt_base() {
    25.     UCHAR gdtr[6];
    26. #if defined (ENV32BIT)
    27.     _asm sgdt gdtr
    28. #endif
    29.     return gdt = *((unsigned long *)&gdtr[2]);
    30. }
    复制代码

    该代码样本的作者:al-khaser项目
    4.使用异域指令愚弄虚拟模拟器
    这个链接对这一技术进行了描述(slide #37)。
    MMX指令可能被恶意软件用作随机指令。有时虚拟机不支持CPU指令的这种指令子集,因此会引起异常,而不是进行分析。
    例子:

    5.通过执行非法指令检测环境(仅VirtualPC)
    恶意软件执行非法指令,这些指令在真实的CPU上应该产生异常,但在虚拟环境中却正常执行--或以某种不同的方式执行。

    关于CPU异常的信息由这个链接提供。
    代码样本(variant 1, generating #ud exception):
    1. push ebx
    2. xor ebx, ebx
    3. mov eax, 1
    4. ; the following 4 bytes below generate #ud exception
    5. db 0x0F
    6. db 0x3F
    7. db 0x0D
    8. db 0x00
    9. test ebx, ebx
    10. setz al
    11. pop ebx
    复制代码

    应该强调的是,有超过1,000种的组合
    1. 0x0F
    2. 0x3F
    3. 0xXX
    4. 0xYY
    复制代码

    恶意软件可能使用的字节,以检测VirtualPC环境。
    代码样本: (variant 2, executing illegal STI instruction)
    1. // Taken here: https://pastebin.com/Nsv5B1yk
    2. // http://waleedassar.blogspot.com
    3. // http://www.twitter.com/waleedassar
    4. // Use this code to detect if Windows XP is running inside Virtual PC 2007
    5. #include "stdafx.h"
    6. #include "windows.h"
    7. #include "stdio.h"

    8. #define CONTEXT_ALL 0x1003F

    9. int dummy(int);
    10. unsigned long gf=0;

    11. int __cdecl Handler(EXCEPTION_RECORD* pRec,void* est,unsigned char* pContext,void* disp)
    12. {
    13.     if(pRec->ExceptionCode==0xC0000096)  //Privileged instruction
    14.     {
    15.         //---------------------Installing the trick--------------------------------------
    16.         *(unsigned long*)(pContext)=CONTEXT_ALL;/*CONTEXT_DEBUG_REGISTERS|CONTEXT_FULL*/
    17.         *(unsigned long*)(pContext+0x4)=(unsigned long)(&dummy);
    18.         *(unsigned long*)(pContext+0x8)=(unsigned long)(&dummy);
    19.         *(unsigned long*)(pContext+0xC)=(unsigned long)(&dummy);
    20.         *(unsigned long*)(pContext+0x10)=(unsigned long)(&dummy);
    21.         *(unsigned long*)(pContext+0x14)=0;
    22.         *(unsigned long*)(pContext+0x18)=0x155; //Enable the four DRx On-Execute
    23.         //---------------------------------------------------------------------------------
    24.         (*(unsigned long*)(pContext+0xB8))++;
    25.         return ExceptionContinueExecution;
    26.     }
    27.     else if(pRec->ExceptionCode==EXCEPTION_SINGLE_STEP)
    28.     {
    29.         if(gf==1)
    30.         {
    31.             MessageBox(0,"Expected behavior (XP)","waliedassar",0);
    32.             ExitProcess(0);
    33.         }
    34.         gf++;
    35.         (*(unsigned long*)(pContext+0xC0))|=0x00010000; //Set the RF (Resume Flag)
    36.         return ExceptionContinueExecution;
    37.     }
    38.     return ExceptionContinueSearch;
    39. }

    40. int dummy(int x)
    41. {
    42.     x+=0x100;
    43.     return x;
    44. }

    45. int main(int shitArg)
    46. {
    47.     unsigned long ver_=GetVersion();
    48.     unsigned long major=ver_&0xFF;
    49.     unsigned long minor=(ver_>>0x8)&0xFF;
    50.     if(major==0x05 & minor==0x01) //Windows XP
    51.     {
    52.         unsigned long x=0;
    53.         __asm
    54.         {
    55.             push offset Handler
    56.             push dword ptr fs:[0x0]
    57.             mov dword ptr fs:[0x0],esp
    58.             STI; Triggers an exception(privileged instruction)
    59.         }
    60.         dummy(0xFF);
    61.         __asm
    62.         {
    63.             pop dword ptr fs:[0x0]
    64.             pop ebx
    65.         }
    66.         MessageBox(0,"Virtual PC 2007 detected (XP)","waliedassar",0);
    67.     }
    68.     return 0;
    69. }
    复制代码

    代码样本(variant 3, resetting VirtualPC):
    1. // Taken here: https://pastebin.com/exAK5XQx
    2. // http://waleedassar.blogspot.com (@waleedassar)
    3. // Executing "\x0F\xC7\xC8\x05\x00" in VirtualPC 2007 triggers a reset error.
    4. #include "stdafx.h"
    5. #include "windows.h"
    6. #include "stdio.h"

    7. bool flag=false;

    8. int __cdecl Handler(EXCEPTION_RECORD* pRec,void* est,unsigned char* pContext,void* disp)
    9. {
    10.     if(pRec->ExceptionCode==0xC000001D  || pRec->ExceptionCode==0xC000001E || pRec->ExceptionCode==0xC0000005)
    11.     {
    12.         flag=true;
    13.         (*(unsigned long*)(pContext+0xB8))+=5;
    14.         return ExceptionContinueExecution;
    15.     }
    16.     return ExceptionContinueSearch;
    17. }

    18. int main(int argc, char* argv[])
    19. {
    20.     __asm
    21.     {
    22.         push offset Handler
    23.         push dword ptr fs:[0x0]
    24.         mov dword ptr fs:[0x0],esp
    25.     }
    26.     flag=false;
    27.     __asm
    28.     {
    29.         __emit 0x0F
    30.         __emit 0xC7
    31.         __emit 0xC8
    32.         __emit 0x05
    33.         __emit 0x00
    34.     }
    35.     if(flag==false)
    36.     {
    37.         MessageBox(0,"VirtualPC detected","waliedassar",0);
    38.     }
    39.     __asm
    40.     {
    41.         pop dword ptr fs:[0x0]
    42.         pop eax
    43.     }
    44.     return 0;
    45. }
    复制代码

    6.通过指令内-后门端口(仅适用于VMware)检测环境
    这篇文章首先解释了为什么在VMware中使用后门端口通信。
    代码样本(variant 1):
    1. bool VMWare::CheckHypervisorPort() const {
    2.     bool is_vm = false;
    3.     __try {
    4.         __asm {
    5.             push edx
    6.             push ecx
    7.             push ebx
    8.             mov eax, 'VMXh'
    9.             mov ebx, 0
    10.             mov ecx, 10
    11.             mov edx, 'VX'
    12.             in eax, dx      // <- key point is here
    13.             cmp ebx, 'VMXh'
    14.             setz[is_vm]
    15.             pop ebx
    16.             pop ecx
    17.             pop edx
    18.         }
    19.     }
    20.     __except (EXCEPTION_EXECUTE_HANDLER) {
    21.         is_vm = false;
    22.     }
    23.     return is_vm;
    24. }
    复制代码

    代码样本 (variant 2):
    1. bool VMWare::CheckHypervisorPortEnum() const {
    2.     bool is_vm = false;
    3.     short ioports[] = { 'VX' , 'VY' };
    4.     short ioport;
    5.     for (short i = 0; i < _countof(ioports); ++i) {
    6.         ioport = ioports[i];
    7.         for (unsigned char cmd = 0; cmd < 0x2c; ++cmd) {
    8.             __try {
    9.                 __asm {
    10.                     push eax
    11.                     push ebx
    12.                     push ecx
    13.                     push edx
    14.                     mov eax, 'VMXh'
    15.                     movzx ecx, cmd
    16.                     mov dx, ioport
    17.                     in eax, dx      // <- key point is here
    18.                     pop edx
    19.                     pop ecx
    20.                     pop ebx
    21.                     pop eax
    22.                 }
    23.                 is_vm = true;
    24.                 break;
    25.             }
    26.             __except (EXCEPTION_EXECUTE_HANDLER) {}
    27.         }
    28.         if (is_vm)
    29.             break;
    30.     }
    31.     return is_vm;
    32. }
    复制代码

    识别标志
    对于这个规避技术,没有提供识别标志,因为很难跟踪正在执行的代码。
    反制措施
    修补虚拟机监控程序(hypervisor)。如果证明不可能--由于许可证问题或其他原因--修补虚拟机配置。通常没有记录的选项会有帮助。
    • vs CPUID指令:请参考这篇文章,了解这种补丁的例子。
    • vs IN指令(VMware后门):看看这些配置变化

    归功于
    归功于开源项目,代码样本来自该项目,并归功于分享其发现的独立研究人员。:

    尽管Check Point工具InviZzzible已经实现了所有这些功能,但由于代码的模块化结构,需要更多的空间来展示这个工具的代码样本,以达到同样的目的。这就是为什么我们决定在整个百科全书中使用其他伟大的开源项目作为例子。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    红盟社区--红客联盟 

    Processed in 0.057345 second(s), 22 queries.

    站点统计| 举报| Archiver| 手机版| 黑屋 |   

    备案号:冀ICP备20006029号-1 Powered by HUC © 2001-2021 Comsenz Inc.

    手机扫我进入移动触屏客户端

    关注我们可获取更多热点资讯

    Honor accompaniments. theme macfee

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