虚拟机安全 02 检测 01

杀戮 (乌云安全实验室的杂役) | 2014-12-17 14:05

大家好,我又来挖坑了,虚拟机的检测技术解决的问题是”你如何知道你是不是在虚拟机里”。

这篇起名叫2,我打算留着1讲讲虚拟机的实现方面的东西。

检测这块这篇的3种技术这篇先说两种,最后一种量比较多等下一篇。

先介绍几个早期的技术,最新的一些技术我改天心情好在写,其实早期的检测技术虽然可能利用点都大不相同,但是共性都是利用虚拟机与物理机对底层的交互的差异进行判断。

过去检测是否存在于虚拟机的思路一般是三种。

1. 比较CPU指令的结果

虚拟机虽然虚拟了大量底层细节,但是有些指令是虚拟化的技术难度很高,所以操作系统会重新部署一些数据结构。这样系统中就会同时出现两个相同的指令,但是其基地址是不同的,通过对比两种的差异可以得出是否在虚拟机中。

2. 虚拟机的API接口

虚拟机与物理机之间提供了API进行交互,只要验证是否可以进行API调用就行了。

3. 无效指令引发的异常

这是一个只有适用于Virtual PC的手法,当一个无效指令被触发,就好比你linux 下输入fuckyou,Virtual PC虚拟机会有自己的一套处理异常的方式,通过检测这种差异可以判断是否存在于虚拟机中。

2 虚拟机的API接口

虚拟机与物理机必须存在交互,不然怎么样,产品会砍死你,其他自己想。

虚拟机通过 I/O (就是操作系统操作设备使用的接口) 向Vmware(软件本身)发送一些指令获取一些需要的信息,我这次分析的POC是Vmware only的,不过虚拟机API本身却不是,其他虚拟机本身也会提供一些API进行交互,不过具体不清楚,可以自己测。

在x86下,这个交互通过汇编指令 IN/OUT 来进行。假设你在物理机上执行IN/OUT,因为IN/OUT本身是需要很高的权限才能使用的,一般我们操作计算机时只在ring3的用户权限下,一旦用户权限下的程序执行了IN/OUT ,就会产生一个异常,但是虚拟机本身并不存在这个限制,执行IN/OUT会正常返回值。

我们先来看看老外的POC。

bool IsInsideVMWare()
{
  bool rc = true;

  __try
  {
    __asm
    {
      push   edx
      push   ecx
      push   ebx

      mov    eax, 'VMXh'
      mov    ebx, 0 // any value but not the MAGIC VALUE
      mov    ecx, 10 // get VMWare version
      mov    edx, 'VX' // port number

      in     eax, dx // read port
                     // on return EAX returns the VERSION
      cmp    ebx, 'VMXh' // is it a reply from VMWare?
      setz   [rc] // set return value

      pop    ebx
      pop    ecx
      pop    edx
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    rc = false;
  }

  return rc;
}

我们只看重要的汇编指令,不懂汇编的同学可以看注释。

// 加载三个寄存器
push   edx
push   ecx
push   ebx
// 单纯的看做一个函数就好了 像这样的: def vmxh(0,10,’vx’)
mov    eax, 'VMXh'
mov    ebx, 0
mov    ecx, 10
mov    edx, 'VX'
// 执行函数....  Ebx = eval(vmxh())
in     eax, dx // read port
// ebx的值是不是 VMXh
cmp    ebx, 'VMXh'
// 是的话返回TRUE 然后存进一个叫RC的变量
setz[rc]
pop    ebx
pop    ecx
pop    edx

我们现在见到的比对一下物理机和虚拟机执行的结果,ollydbg会把程序执行的过程以汇编形式展现出来,我们看看。

物理机:

物理机:汇编代码

看不懂汇编没关系,先看再说,可以看到我们POC中的汇编代码,现在我们执行到IN看看会发生什么。

物理机:汇编代码

我们最终会来到这种地方,就是已经触发了异常。

这是我的判断代码

int _tmain(int argc, _TCHAR* argv[])
{
  bool vm = IsInsideVMWare();
  while(vm){
    printf(" 111 111 111 \n");
  }
  return 0;
}

就是说只要在虚拟机里头就输入一大串111,那些1没什么用,只是我的恶趣味。

我们来看看虚拟机中的执行结果。

虚拟机中的执行结果

就是这么任性。

现在虚拟机里用Ollydbg加载程序,先定位IN在哪

在虚拟机里用Ollydbg加载程序,先定位IN在哪

继续执行,我们会发现这次没有曝出任何异常,同时我们可以看到EBX的值变成了一个叫564D5868的东西,翻译成中文,不对翻译成字符串就是VMXh,然后cmp一对比 ,OK没问题,你在虚拟世界。

继续执行,我们会发现这次没有曝出任何异常,

3. 无效的指令引发的异常

这个我不多讲,只大概说下poc,为什么呢,首先这个机制是Virtual PC Only的,其次呢在我努力了两小时后我决定,等我哪天成功装上了它再讲…………..

这个检测的手法其实是利用了虚拟机与物理机处理异常指令时的不同,当VPC虚拟机中收到一个不正常的指令时会让操作系统不爽,但是VPC本身定义了一套异常处理机制用于应对这种情况,所以操作系统只能把异常交给VPC处理,但是操作系统本身不会引发异常。

POC长这鸟样

DWORD __forceinline IsInsideVPC_exceptionFilter(LPEXCEPTION_POINTERS ep)
{
  PCONTEXT ctx = ep->ContextRecord;

  ctx->Ebx = -1; // Not running VPC
  ctx->Eip += 4; // skip past the "call VPC" opcodes
  return EXCEPTION_CONTINUE_EXECUTION;
}

bool IsInsideVPC()
{
  bool rc = false;

  __try
  {
    _asm push ebx
    _asm mov  ebx, 0 // It will stay ZERO if VPC is running
    _asm mov  eax, 1 // VPC function number

    // 这是一个无效指令,会触发VPC处理
    _asm __emit 0Fh
    _asm __emit 3Fh
    _asm __emit 07h
    _asm __emit 0Bh

    _asm test ebx, ebx
    _asm setz [rc]
    _asm pop ebx
  }
  // 如果在虚拟机里头就不会触发异常
  __except(IsInsideVPC_exceptionFilter(GetExceptionInformation()))
  {
  }

  return rc;
}

重点还是 0FH 3FH 07H 0BH 是 一个无效的指令,会触发异常,同时触发虚拟机特殊机制。

_asm __emit 0Fh
_asm __emit 3Fh
_asm __emit 07h
_asm __emit 0Bh

[原文地址]

留言评论(旧系统):

一民 @ 2014-12-22 02:17:17

核大 现在有穿破VM VBOX的病毒吗,多吗?

本站回复:

有,极少,某些特定渗透环境下才会使用。