今天是端午节,祝大家节日快乐!准备利用三天的时间来介绍检测沙盒的一些技巧方法,很实用!
看到了这些asm,又钩起了我的回忆,真是老了,又重温历史了,
下面几幅图,是我当年逆向病毒和程序(如UCDOS)中总结出来的那些个反跟踪技巧,里面也有用到了CPU的方法,最后用到了我的加密程序中Gal,可惜源码掉了。
言归正传吧,都是过去式了。
一、利用CPU特性:
使用特定的处理器指令来获取有关CPU的特定信息 - 或执行在通常的主机操作系统和虚拟环境中行为不同的预定义指令序列。
1.通过CPUID指令查看厂商ID字符串
CPUID指令是将处理器标识和特征信息返回给EBX、ECX、EDX的指令。接收到这些寄存器的信息可用于识别供应商。
代码示例
__declspec(naked) void get_cpuid_vendor(char *vendor_id) {
__asm {
; save non-volatile register
push ebx
; nullify output registers
xor ebx, ebx
xor ecx, ecx
xor edx, edx
; call cpuid with argument in EAX
mov eax, 0x40000000
cpuid
; store vendor_id ptr to destination
mov edi, vendor_id
; move string parts to destination
mov eax, ebx ; part 1 of 3 from EBX
stosd
mov eax, ecx ; part 2 of 3 from ECX
stosd
mov eax, edx ; part 3 of 3 from EDX
stosd
; restore saved non-volatile register
pop ebx
; return from function
retn
}}
检测表
Check vendor ID string via CPUID instruction - returned in parts in EBX, ECX, EDX: | ||
Detect |
EAX as argument to CPUID |
String |
---|---|---|
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中的第31位(CPUID的返回值),表示程序正在运行在管理程序中。
代码示例(函数GetAdaptersAddresses)
__declspec(naked) bool is_run_in_hypervisor() {
__asm {
; nullify output register
xor ecx, ecx
; call cpuid with argument in EAX
mov eax, 1
cpuid
; set CF equal to 31st bit in ECX
bt ecx, 31
; set AL to the value of CF
setc al
; return from function
retn
}}
检测表
Check if being run in Hypervisor (via CPUID) | ||
Detect |
EAX as argument to CPUID |
Check of return value |
---|---|---|
Hypervisor | 1 | 31st bit in ECX - set if run in Hypervisor |
3.检查全局表位置:IDT/GDT/LDT
此技术不适用于最新的VMware版本(受影响的所有 Windows版本)。但是,为了完整起见,这里对其进行描述。
这个技巧涉及查看指向通常在虚拟机上重定位的关键操作系统表的指针。这就是所谓的“Red Pill”。
每个CPU有一个本地描述符表寄存器(LDTR)、一个全局描述符表寄存器(GDTR)和一个中断描述符表寄存器(IDTR)。当客户操作系统运行时,必须将它们移动到不同的位置,以避免与主机发生冲突。
例如,在真实机器上,IDT在内存中的位置低于它在来宾(即虚拟)机器上的位置。
代码示例
idt_vm_detect = ((get_idt_base() >> 24) == 0xff);
ldt_vm_detect = (get_ldt_base() == 0xdead0000);
gdt_vm_detect = ((get_gdt_base >> 24) == 0xff);
// sidt instruction stores the contents of the IDT Register
// (the IDTR which points to the IDT) in a processor register.
ULONG get_idt_base() {
UCHAR idtr[6];
#if defined (ENV32BIT)
_asm sidt idtr
#endif
return *((unsigned long *)&idtr[2]);
}
// sldt instruction stores the contents of the LDT Register
// (the LDTR which points to the LDT) in a processor register.
ULONG get_ldt_base() {
UCHAR ldtr[5] = "xefxbexadxde";
#if defined (ENV32BIT)
_asm sldt ldtr
#endif
return *((unsigned long *)&ldtr[0]);
}// sgdt instruction stores the contents of the GDT Register
// (the GDTR which points to the GDT) in a processor register.
ULONG get_gdt_base() {
UCHAR gdtr[6];
#if defined (ENV32BIT)
_asm sgdt gdtr
#endif
return gdt = *((unsigned long *)&gdtr[2]);
}
4. 使用奇异指令欺骗虚拟模拟器
MMX指令可能被恶意软件用作随机指令。有时仿真器不支持此类CPU指令子集,因此会引发异常而不是执行分析。
例子:
5. 通过执行非法指令检测环境(仅限VirtualPC)
恶意软件执行非法指令,这些指令应该在真实CPU上产生异常,但在虚拟环境中正常执行 - 或以某种不同的方式执行。
代码示例(变体 1,生成#ud 异常)
push ebx
xor ebx, ebx
mov eax, 1
; the following 4 bytes below generate #ud exception
db 0x0F
db 0x3F
db 0x0D
db 0x00
test ebx, ebx
setz al
pop ebx
需要强调的是,有1000多种组合
0
0x0F
0x3F
0xXX
0xYY
恶意软件可能会使用这些字节来检测 VirtualPC 环境。
代码示例(变体 2,执行非法 STI 指令)
// Taken here: https://pastebin.com/Nsv5B1yk// http://waleedassar.blogspot.com// http://www.twitter.com/waleedassar// Use this code to detect if Windows XP is running inside Virtual PC 2007
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"#include "windows.h"
#include "stdio.h"
#define CONTEXT_ALL 0x1003F
int dummy(int);unsigned long gf=0;
int __cdecl Handler(EXCEPTION_RECORD* pRec,void* est,unsigned char* pContext,void* disp){
if(pRec->ExceptionCode==0xC0000096) //Privileged instruction
{
//---------------------Installing the trick--------------------------------------
*(unsigned long*)(pContext)=CONTEXT_ALL;/*CONTEXT_DEBUG_REGISTERS|CONTEXT_FULL*/
*(unsigned long*)(pContext+0x4)=(unsigned long)(&dummy);
*(unsigned long*)(pContext+0x8)=(unsigned long)(&dummy);
*(unsigned long*)(pContext+0xC)=(unsigned long)(&dummy);
*(unsigned long*)(pContext+0x10)=(unsigned long)(&dummy);
*(unsigned long*)(pContext+0x14)=0;
*(unsigned long*)(pContext+0x18)=0x155; //Enable the four DRx On-Execute
//---------------------------------------------------------------------------------
(*(unsigned long*)(pContext+0xB8))++;
return ExceptionContinueExecution;
}
else if(pRec->ExceptionCode==EXCEPTION_SINGLE_STEP)
{
if(gf==1)
{
MessageBox(0,"Expected behavior (XP)","waliedassar",0);
ExitProcess(0);
}
gf++;
(*(unsigned long*)(pContext+0xC0))|=0x00010000; //Set the RF (Resume Flag)
return ExceptionContinueExecution;
}
return ExceptionContinueSearch;}
int dummy(int x){
x+=0x100;
return x;}
int main(int shitArg){
unsigned long ver_=GetVersion();
unsigned long major=ver_&0xFF;
unsigned long minor=(ver_>>0x8)&0xFF;
if(major==0x05 & minor==0x01) //Windows XP
{
unsigned long x=0;
__asm
{
push offset Handler
push dword ptr fs:[0x0]
mov dword ptr fs:[0x0],esp
STI; Triggers an exception(privileged instruction)
}
dummy(0xFF);
__asm
{
pop dword ptr fs:[0x0]
pop ebx
}
MessageBox(0,"Virtual PC 2007 detected (XP)","waliedassar",0);
}
return 0;}
代码示例(变体 3,重置 VirtualPC)
// Taken here: https://pastebin.com/exAK5XQx// http://waleedassar.blogspot.com (@waleedassar)// Executing "x0FxC7xC8x05x00" in VirtualPC 2007 triggers a reset error.#include "stdafx.h"
#include "windows.h"
#include "stdio.h" bool flag=false;
int __cdecl Handler(EXCEPTION_RECORD* pRec,void* est,unsigned char* pContext,void* disp){
if(pRec->ExceptionCode==0xC000001D || pRec->ExceptionCode==0xC000001E || pRec->ExceptionCode==0xC0000005)
{
flag=true;
(*(unsigned long*)(pContext+0xB8))+=5;
return ExceptionContinueExecution;
}
return ExceptionContinueSearch;}
int main(int argc, char* argv[]){
__asm
{
push offset Handler
push dword ptr fs:[0x0]
mov dword ptr fs:[0x0],esp
}
flag=false;
__asm
{
__emit 0x0F
__emit 0xC7
__emit 0xC8
__emit 0x05
__emit 0x00
}
if(flag==false)
{
MessageBox(0,"VirtualPC detected","waliedassar",0);
}
__asm
{
pop dword ptr fs:[0x0]
pop eax
}
return 0;}
6.通过IN指令检测环境-后门端口(仅限VMware)
首先解释了为什么在 VMware 中使用后门端口通信。
代码示例(变体 1)
bool VMWare::CheckHypervisorPort() const {
bool is_vm = false;
__try {
__asm {
push edx
push ecx
push ebx
mov eax, 'VMXh'
mov ebx, 0
mov ecx, 10
mov edx, 'VX'
in eax, dx // <- key point is here
cmp ebx, 'VMXh'
setz[is_vm]
pop ebx
pop ecx
pop edx
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
is_vm = false;
}
return is_vm;}
代码示例(变体 2)
bool VMWare::CheckHypervisorPortEnum() const {
bool is_vm = false;
short ioports[] = { 'VX' , 'VY' };
short ioport;
for (short i = 0; i < _countof(ioports); ++i) {
ioport = ioports[i];
for (unsigned char cmd = 0; cmd < 0x2c; ++cmd) {
__try {
__asm {
push eax
push ebx
push ecx
push edx
mov eax, 'VMXh'
movzx ecx, cmd
mov dx, ioport
in eax, dx // <- key point is here
pop edx
pop ecx
pop ebx
pop eax
}
is_vm = true;
break;
}
__except (EXCEPTION_EXECUTE_HANDLER) {}
}
if (is_vm)
break;
}
return is_vm;}
原文始发于微信公众号(MicroPest):检测沙盒技巧(一)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论