虛擬機檢測技術簡單實踐

虛擬機檢測技術簡單實踐

概述

惡意軟件

  • 惡意軟件是指在計算機系統上執行惡意任務的病毒、蠕蟲和特洛伊木馬的程序,經過破壞軟件進程來實施控制。惡意軟件其自己多是一種病毒,蠕蟲,後門或漏洞攻擊腳本,它經過動態地改變攻擊代碼能夠逃避入侵檢測系統的特徵檢測(Signature-based detection ,也可稱爲模式匹配)。攻擊者經常利用這種多變代碼進入互聯網上的一些帶有入侵偵測的系統或IDSes入侵者警告系統。

虛擬機

  • 所謂的虛擬機(Virtual Machine)是指經過軟件模擬的具備完整硬件系統功能的、運行在一個徹底隔離環境中的完整計算機系統。經過虛擬機軟件(好比VMware,Virtual PC ,VirtualBox),你能夠在一臺物理計算機上模擬出一臺或多臺虛擬的計算機,這些虛擬機徹底就像真正的計算機那樣進行工做,例如你能夠安裝操做系統、安裝應用程序、訪問網絡資源等等。

虛擬機檢測技術

  • 在信息安全的研究範疇中,對惡意軟件的分析一直是研究的熱點。爲了提升病毒分析過程的安全性以及硬件資源的節約性,分析惡意軟件每每須要用到虛擬機技術,須要在一個虛擬的相對安全封閉的環境下測試惡意軟件的工做特色。考慮到虛擬機能夠徹底像真正的計算機那樣工做,而又不會影響到主機的使用,因此對病毒的行爲分析每每在虛擬機中進行。
  • 基於此,病毒開發者確定不肯意本身的病毒行爲特徵被分析出來,因此攻擊者爲了提升惡意程序的隱蔽性以及破壞真實主機的成功率,他們都在惡意程序中加入檢測虛擬機的代碼,以判斷程序所處的運行環境。當發現程序處於虛擬機(特別是蜜罐系統)中時,它就會改變操做行爲或者中斷執行,掩蓋其病毒的行爲特徵,以此提升反病毒人員分析惡意軟件行爲的難度。

原理介紹

基於CPU運算時間的檢測

  • 在虛擬機中,代碼的運行速度一般不如真實主機。因此惡意代碼經過運行一段特定的代碼來比較這段代碼在虛擬機和真實主機之中的相對運行時間,以此來判斷是否處於虛擬機之中。
bool CheckVMware1()
{
    __asm
    {
        rdtsc
        xchg ebx, eax
        rdtsc
        sub eax, ebx
        cmp eax, 0xFF
        jg detected
    }
    return FALSE;
detected:
    return TRUE;
}

基於註冊表的檢測

  • 經過讀取主機具備虛擬機特性的註冊表位置來判斷是否處於虛擬機環境中。針對VMware能夠判斷註冊表項HKEY_CLASSES_ROOT\\Applications\\VMwareHostOpen.exe
bool CheckVMware2()
{
    HKEY hkey;
    if (RegOpenKey(HKEY_CLASSES_ROOT, "\\Applications\\VMwareHostOpen.exe", &hkey) == ERROR_SUCCESS)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

基於當前進程信息的檢測

  • 經過進程快照讀取當前進程信息,查找是否存在虛擬機中特有的進程,如VMware中的vmtoolsd.exe
bbool CheckVMware3()
{
    PROCESSENTRY32 pe32;        //存放快照進程信息的一個結構體
    pe32.dwSize = sizeof(pe32);     //在使用這個結構以前,先設置它的大小
    HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);      //給系統內的全部進程拍一個快照
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }
    bool bMore = Process32First(hProcessSnap, &pe32);
    while (bMore)
    {
        if (strcmp((const char *)pe32.szExeFile, "vmtoolsd.exe") == 0)
        {
            return TRUE;
        }
        bMore = Process32Next(hProcessSnap, &pe32);
    }
    CloseHandle(hProcessSnap);
    return FALSE;
}

基於特定文件的檢測

  • 經過查找磁盤中是否存在特定的文件夾或文件,判斷當前是否在虛擬機中。VMware虛擬機中一般會有路徑C:\Program Files\VMware\VMware Tools\
bool CheckVMware4()
{
    if (PathIsDirectory("C:\\Program Files\\VMware\\VMware Tools\\") == 0)
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

基於註冊服務的檢測

  • 經過獲取主機當前具備VMware特性的服務信息,判斷當前主機是否爲虛擬機,在VMware中一般會存在VMware物理磁盤助手服務和VMware Tools服務等。
bool CheckVMware5()
{
    //打開系統服務控制器    
    SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
    if (SCMan == NULL)
    {
        printf("%ld", GetLastError());
        printf("OpenSCManager Eorror/n");
        return -1;
    }
    //保存系統服務的結構  
    LPENUM_SERVICE_STATUSA service_status;
    DWORD cbBytesNeeded = NULL;
    DWORD ServicesReturned = NULL;
    DWORD ResumeHandle = NULL;
    service_status = (LPENUM_SERVICE_STATUSA)LocalAlloc(LPTR, 1024 * 64);
    //獲取系統服務的簡單信息    
    bool ESS = EnumServicesStatusA(SCMan, //系統服務句柄    
        SERVICE_WIN32, //服務的類型    
        SERVICE_STATE_ALL,  //服務的狀態    
        (LPENUM_SERVICE_STATUSA)service_status,  //輸出參數,系統服務的結構    
        1024 * 64,  //結構的大小    
        &cbBytesNeeded, //輸出參數,接收返回所需的服務    
        &ServicesReturned, //輸出參數,接收返回服務的數量    
        &ResumeHandle); //輸入輸出參數,第一次調用必須爲0,返回爲0表明成功    
    if (ESS == NULL)
    {
        printf("EnumServicesStatus Eorror/n");
        return -1;
    }
    for (int i = 0; i < ServicesReturned; i++)
    {
        if (strstr(service_status[i].lpDisplayName, "VMware Tools") != NULL || strstr(service_status[i].lpDisplayName, "VMware 物理磁盤助手服務") != NULL)
        {
            return TRUE;
        }
    }
    //關閉服務管理器的句柄   
    CloseServiceHandle(SCMan);
    return FALSE;
}

運行實現

通常實現

  • 根據原理介紹中提到的5個虛擬機檢測原理,將其整合到一個CPP文件下,main函數以下所示:
int main()
{
    int n;
    bool result;
    while (1)
    {
        printf("虛擬機檢測技術:\n");
        printf("1. 基於CPU運算時間的檢測\n");
        printf("2. 基於註冊表的檢測\n");
        printf("3. 基於當前進程信息的檢測\n");
        printf("4. 基於特定文件的檢測\n");
        printf("5. 基於註冊服務的檢測\n");
        printf("0. 退出\n");
        printf("請選擇:");
        scanf("%d", &n);
        flushall();
        printf("檢測結果:");
        switch (n)
        {
        case 0: return 0;
        case 1: result = CheckVMware1(); break;
        case 2: result = CheckVMware2(); break;
        case 3: result = CheckVMware3(); break;
        case 4: result = CheckVMware4(); break;
        case 5: result = CheckVMware5(); break;
        default:printf("輸入錯誤,請從新輸入!\n"); Sleep(2000); system("cls"); continue;
        }
        if (result)
            printf("yes!\n");
        else
            printf("no!\n");
        printf("按任意鍵返回主菜單\n");
        getch();
        flushall();
        system("cls");
    }
    return 0;
}

運行效果:

  • 主機效果圖(win7):
  • 虛擬機效果圖(win7):

DLL文件實現

  • 主要編寫2個文件:checkvm.dlltestvm.exe,下面分2部分詳細介紹。安全

    checkvm.dll

  • 該文件主要做爲能夠檢測虛擬機的關鍵代碼,包含4個主要文件:checkvm.hcheckvm.cppdllmain.cppSource.def
  • checkvm.h:checkvm.dll的頭文件,給出dll包含的函數方法
bool chekvm();
  • checkvm.cpp:該部分代碼主體功能部分類與通常實現方法一致,只是不須要Main函數,提供接口便可,不一樣部分以下:
bool checkvm()
{
    int num = 0;
    if (CheckVMware1())
        num++;
    if (CheckVMware2())
        num++;
    if (CheckVMware3())
        num++;
    if (CheckVMware4())
        num++;
    if (CheckVMware5())
        num++;
    if (num >= 4)
    {
        printf("This is a virtual machine!\n");
        return FALSE;
    }
    else
    {
        printf("This is not a virtual machine!\n");
        return TRUE;
    }
}
  • dllmain.cpp:定義 DLL 應用程序的入口點(固定寫法)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    break;
    }
    return TRUE;
}
  • Source.def:給出可調用的函數方法
LIBRARY "checkvm"
EXPORTS
checkvm @1

testvm.exe

  • 該部分代碼爲測試checkvm.dll所編寫,調用checkvm.dll中的checkvm()函數便可,詳細代碼以下:
int main()
{
    HMODULE hmod = LoadLibrary("checkvm.dll");      //用於加載dll
    typedef int(*LoadProc)();
    LoadProc Load_proc = (LoadProc)GetProcAddress(hmod, "checkvm");     //GetProcAddress()用於得到函數地址
    int iRet = Load_proc();
    getchar();
    return 0;
}

運行效果(將testvm.exe與checkvm.dll放在同一個文件夾下)

  • 主機效果圖(win7):
  • 虛擬機效果圖(win7):

總結

  • 選擇這個項目的緣由是本身對惡意軟件的檢測很感興趣,惡意軟件與檢測就是一種博弈的關係,對於檢測者來講最安全的方式就是採用虛擬機檢測,而一些惡意軟件的製做者顯然也不傻,則會在其病毒代碼執行前加載一段虛擬機檢測代碼,若是檢測爲虛擬機環境,則不會暴露其行爲特徵,沒法對其運行行爲進行分析,當檢測到脫離了虛擬機環境,就能夠大展拳腳實現其目的了。
  • 經過此次的實踐,初步體會到了一些惡意軟件在繞過虛擬機檢測所採起的策略,經過代碼編寫,更加熟悉了虛擬機檢測的機制,最後運用到了本學期在另外一門課程中學到的DLL開發,將關鍵代碼寫入一個dll文件中,在從此須要檢測的過程當中,只須要調用checkvm.dll便可。
  • 總之,此次的實踐不只豐富了個人理論知識,並且也增長了我動手操做的能力,特別是將課上所學運用到實際項目中的時候,造成了一個可在現實中使用的小工具,特別有成就感。
相關文章
相關標籤/搜索