当前位置:主页 > 网络编程 > Visual C++ > vc技术文章 >

vc++编程实现绕过卡巴2010虚拟机启发式查毒

时间:2011-05-28 07:23 来源:未知 作者:中国计算机网 点击:

据我了解在卡巴7中就有虚拟启发式查毒的功能。国内就有人在BLOG上发表了一篇如何突破卡巴7的虚拟机启发式查毒的文章[1]。卡巴8和最新的卡巴2010中仍然具有该功能。卡巴斯基不用我多说了,大家都知道。我最近在网上查到有人说卡巴斯基是俄罗斯国家科学院合作开发的,军方和克里姆林宫专用。这个我还真的不清楚了,请原谅我的无知。我先来说下什么是虚拟机启发式杀毒。

我认为在这里的虚拟机启发式杀毒应该可以理解为在虚拟机中执行和启发式杀毒。虚拟机即构造一个虚拟执行环境或者说一个仿真的环境,将病毒等恶意代码在该仿真的环境中运行实现自己脱壳等等。该仿真的环境和用户计算机的真实环境是隔离的。

举个例子:现在的恶意代码都采用加壳为自己提供保护,尤其是一些已知病毒的变种。当采用虚拟机执行技术加壳保护的恶意代码仍能被杀毒软件检测到,有能力的读者可以自己实验一下。

启发式指的是自我发现并推断或判定事物的方式。启发式杀毒通过分析程序指令的序列或者API函数的调用顺序以及其他恶意代码与正常程序的不同等经验和知识的组合来判定是否是恶意代码。这样的启发式杀毒具备某种人工智能特点。它的优点不用我多说废话,举个例子:Downloader相信大家都知道,最重要的两个API是URLDownloadToFile和ShellExecute(也可以是其他执行一个程序的API)。例如,在使用虚拟机启发式杀毒时,当被查毒程序的API调用序列中出现URLDownloadToFile或者ShellExecute,又或者不是按照先URLDownloadToFile后ShellExecute的调用顺序是不会被报Downloader的。

可以说由于主动防御技术的种种缺点,现在各杀毒软件厂商已经将虚拟机杀毒和启发式杀毒作为杀毒业界的追求和探索的目标。可以预见到在未来几年内杀毒软件将不再会出现当正常使用系统和软件时频繁弹出主动防御窗口的尴尬。接下来将通过上面提到的Downloader例子分析下卡巴的虚拟机启发式查毒的特点,并在最后给出一种可能的绕过方法和演示代码,供各位看官赏玩。

我假设您已经知道什么是Downloader,一个最简单的Downloader是:
#include "stdafx.h"
#include
#include
#pragma comment (lib,"Urlmon.lib")

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
        TCHAR szFileName[MAX_PATH] = {0};
        URLDownloadToCacheFile(NULL,L"file://c:\\windows\\notepad.exe",szFileName,MAX_PATH,0,NULL);
        ShellExecute(0,L"open",szFileName,NULL,NULL,SW_SHOW);
        return 0;
}

这个程序是使用Visual Studio 2008创建的Win32窗口工程。编译后卡巴2010直接报Downloader。首先使用了之前提到的xyzreg提到的方法,现在在卡巴2010下已经不适用,简单的测试了一下卡巴2010会把自己模拟成explorer.exe。所以检查父进程是否是explorer.exe的方法不行了,但是如果检查自己的父进程是否是cmd.exe就可以了。当然这个实用性并不强,因为要求Downloader必须由cmd.exe启动。

我觉得应该有其他的方法可以逃过虚拟查毒,但是这里只从虚拟查毒本身入手。首先想到的是这个虚拟机和真实环境是否有区别?这个回答当然是肯定的。但是这些区别在哪里,这些区别是否会影响到。是否存在一种情况虚拟机无法虚拟而导致虚拟环境下无法执行到URLDownloadToCacheFile和ShellExecute那就不会检查到是Downloader了。这个思想很简单,然后要怎么实现呢。

首先想到虚拟机是否虚拟了异常处理,如果没有虚拟异常处理,那我们认为的制造一个异常,将具有Downloader特性的API调要放到异常处理程序中不就绕过了吗。于是有了下面的代码:

BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
    __try
    {
                *pResult = dividend / divisor;
    }
    __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?

分享按钮
评论区
正在载入评论数据中...