操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    惡意代碼編寫者經常使用反虛擬機技術逃避分析,這種技術可以檢測自己是否運行在虛擬機中。如果惡意代碼探測到自己在虛擬機中運行,它會執行與其本身行為不同的行為,其中最簡單的行為是停止自身運行。

    近年來,隨著虛擬化技術的使用不斷增加,采用反虛擬機技術的惡意代碼數量逐漸下降。惡意代碼編寫者已經開始意識到,目標主機是虛擬機,也并不意味著它就沒有攻擊價值。

    隨著虛擬化技術的不斷發展和普通應用,反虛擬機技術可能變得更加少見。這里研究最常見的反虛擬機技術(包括、和,重點是最常用的),并且介紹一些如何防御它們的辦法。

    一、檢測虛擬機痕跡

    1.根據MAC地址

    通常,MAC地址的前三個字節標識一個提供商。以00:05:69、00:0c:29和00:50:56開始的MAC地址與相對應;以00:03:ff開始的MAC地址與對應;以08:00:27開始的MAC地址與對應。

    BOOL CheckVMWare() ?
    { ?
    ? ?string mac; ?
    ? ?get_3part_mac(mac); ?
    ? ?if (mac=="00-05-69" || mac=="00-0c-29" || mac=="00-50-56") ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?string mac; ?
    ? ?get_3part_mac(mac); ?
    ? ?if (mac=="00-03-ff") ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?string mac; ?
    ? ?get_3part_mac(mac); ?
    ? ?if (mac=="08-00-27") ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    typedef struct _ASTAT_ ?
    {
    ?
    ? ?ADAPTER_STATUS adapt; ?
    ? ?NAME_BUFFER NameBuff[30]; ?
    } ASTAT, *PASTAT;

    void get_3part_mac(string &mac) ?
    { ?
    ? ?NCB Ncb; ?
    ? ?ASTAT Adapter; ?
    ? ?UCHAR uRetCode; ?
    ? ?LANA_ENUM lenum; ?
    ? ?memset(&Ncb, 0, sizeof(Ncb)); ?
    ? ?Ncb.ncb_command = NCBENUM; ?
    ? ?Ncb.ncb_buffer = (UCHAR *)&lenum; ?
    ? ?Ncb.ncb_length = sizeof(lenum); ?
    ? ?uRetCode = Netbios(&Ncb); ?
    ? ?for (int i = 0; i < lenum.length; i++) ?
    ? ?{ ?
    ? ? ? ?memset(&Ncb, 0, sizeof(Ncb)); ?
    ? ? ? ?Ncb.ncb_command = NCBRESET; ?
    ? ? ? ?Ncb.ncb_lana_num = lenum.lana[i]; ?
    ? ? ? ?uRetCode = Netbios(&Ncb); ?
    ? ? ? ?memset(&Ncb, 0, sizeof(Ncb)); ?
    ? ? ? ?Ncb.ncb_command = NCBASTAT; ?
    ? ? ? ?Ncb.ncb_lana_num = lenum.lana[i]; ?
    ? ? ? ?strcpy((char *)Ncb.ncb_callname, "*"); ?
    ? ? ? ?Ncb.ncb_buffer = (unsigned char *)&Adapter; ?
    ? ? ? ?Ncb.ncb_length = sizeof(Adapter); ?
    ? ? ? ?uRetCode = Netbios(&Ncb); ?
    ? ? ? ?if (uRetCode == 0) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?char tmp[128]; ?
    ? ? ? ? ? ?sprintf(tmp, "x-x-x", ?
    ? ? ? ? ? ? ? ?Adapter.adapt.adapter_address[0], ?
    ? ? ? ? ? ? ? ?Adapter.adapt.adapter_address[1], ?
    ? ? ? ? ? ? ? ?Adapter.adapt.adapter_address[2] ?
    ? ? ? ? ? ?); ?
    ? ? ? ? ? ?mac = tmp; ?
    ? ? ? ?} ?
    ? ?} ?
    }

    2.基于主板序列號、主機型號、系統盤所在磁盤名稱等其他硬件信息

    //通過WMI獲取主機信息 ?
    BOOL ManageWMIInfo(string &result, string table, wstring wcol) ?
    { ? ?
    ? ?HRESULT hres; ?
    ? ?char bord[1024]; ?
    ? ?//初始化COM ?
    ? ?hres = CoInitialize(0); ?
    ? ?//獲得WMI連接COM接口 ? ?
    ? ?IWbemLocator *pLoc = NULL; ?
    ? ?hres = CoCreateInstance( ?
    ? ? ? ?CLSID_WbemLocator, ?
    ? ? ? ?0, ?
    ? ? ? ?CLSCTX_INPROC_SERVER, ?
    ? ? ? ?IID_IWbemLocator, (LPVOID *) &pLoc); ?
    ? ?if (FAILED(hres)) ?
    ? ?{ ?
    ? ? ? ?cout << "Failed to create IWbemLocator object." ?
    ? ? ? ? ? ?<< "Err code = 0x" ?
    ? ? ? ? ? ?<< hex << hres << endl; ?
    ? ? ? ?CoUninitialize(); ?
    ? ? ? ?return false; ?
    ? ?} ?
    ? ?//通過連接接口連接WMI的內核對象名ROOT//CIMV2 ? ?
    ? ?IWbemServices *pSvc = NULL; ?
    ? ?hres = pLoc->ConnectServer( ?
    ? ? ? ?_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace ?
    ? ? ? ?NULL, // User name. NULL = current user ?
    ? ? ? ?NULL, // User password. NULL = current ?
    ? ? ? ?0, // Locale. NULL indicates current ?
    ? ? ? ?NULL, // Security flags. ?
    ? ? ? ?0, // Authority (e.g. Kerberos) ?
    ? ? ? ?0, // Context object ?
    ? ? ? ?&pSvc // pointer to IWbemServices proxy ?
    ? ? ? ?); ?
    ? ?if (FAILED(hres)) ?
    ? ?{ ?
    ? ? ? ?cout << "Could not connect. Error code = 0x" ?
    ? ? ? ? ? ?<< hex << hres << endl; ?
    ? ? ? ?pLoc->Release(); ?
    ? ? ? ?CoUninitialize(); ?
    ? ? ? ?return false; ?
    ? ?} ?
    ? ?//設置請求代理的安全級別 ? ?
    ? ?hres = CoSetProxyBlanket( ?
    ? ? ? ?pSvc, // Indicates the proxy to set ?
    ? ? ? ?RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx ?
    ? ? ? ?RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx ?
    ? ? ? ?NULL, // Server principal name ?
    ? ? ? ?RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx ?
    ? ? ? ?RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx ?
    ? ? ? ?NULL, // client identity ?
    ? ? ? ?EOAC_NONE // proxy capabilities ?
    ? ? ? ?); ?
    ? ?if (FAILED(hres)) ?
    ? ?{ ?
    ? ? ? ?cout << "Could not set proxy blanket. Error code = 0x" ?
    ? ? ? ? ? ?<< hex << hres << endl; ?
    ? ? ? ?pSvc->Release(); ?
    ? ? ? ?pLoc->Release(); ?
    ? ? ? ?CoUninitialize(); ?
    ? ? ? ?return false; ?
    ? ?} ?
    ? ?//通過請求代理來向WMI發送請求 ?
    ? ?IEnumWbemClassObject* pEnumerator = NULL; ?
    ? ?string select = "SELECT * FROM "+ table; ?
    ? ?hres = pSvc->ExecQuery( ?
    ? ? ? ?bstr_t("WQL"), ? ?
    ? ? ? ?bstr_t(select.c_str()), ?
    ? ? ? ?WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, ?
    ? ? ? ?NULL, ?
    ? ? ? ?&pEnumerator); ?
    ? ?if (FAILED(hres)) ?
    ? ?{ ?
    ? ? ? ?cout << "Query for Network Adapter Configuration failed." ?
    ? ? ? ? ? ?<< " Error code = 0x”" ?
    ? ? ? ? ? ?<< hex << hres << endl; ?
    ? ? ? ?pSvc->Release(); ?
    ? ? ? ?pLoc->Release(); ?
    ? ? ? ?CoUninitialize(); ?
    ? ? ? ?return false; ?
    ? ?} ?
    ? ?//循環枚舉所有的結果對象 ?
    ? ?ULONG uReturn = 0; ?
    ? ?IWbemClassObject *pclsObj; ?
    ? ?while (pEnumerator) ?
    ? ?{ ?
    ? ? ? ?HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, ?
    ? ? ? ? ? ?&pclsObj, &uReturn); ?
    ? ? ? ?if(0 == uReturn) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?break; ?
    ? ? ? ?} ?
    ? ? ? ?VARIANT vtProp; ?
    ? ? ? ?VariantInit(&vtProp); ?
    ? ? ? ?hr = pclsObj->Get(wcol.c_str(), 0, &vtProp, 0, 0); ?
    ? ? ? ?if(!FAILED(hr)) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?CW2A tmpstr1(vtProp.bstrVal); ?
    ? ? ? ? ? ?strcpy_s(bord,200,tmpstr1); ?
    ? ? ? ? ? ?result = bord; ?
    ? ? ? ?} ?
    ? ? ? ?VariantClear(&vtProp); ?
    ? ?} ?
    ? ?//釋放資源 ? ?
    ? ?pSvc->Release(); ?
    ? ?pLoc->Release(); ?
    ? ?pEnumerator->Release(); ?
    ? ?pclsObj->Release(); ?
    ? ?CoUninitialize(); ?
    ? ?return true; ?
    }

    BOOL CheckVMWare() ?
    { ?
    ? ?string table = "Win32_BaseBoard"; ?
    ? ?wstring wcol = L"SerialNumber"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret == "None") ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVMWare() ?
    { ?
    ? ?string table = "Win32_DiskDrive"; ?
    ? ?wstring wcol = L"Caption"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("VMware") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVMWare() ?
    { ?
    ? ?string table = "Win32_computersystem"; ?
    ? ?wstring wcol = L"Model"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("VMware") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualBox() ?
    { ? ?
    ? ?string table = "Win32_computersystem"; ?
    ? ?wstring wcol = L"Model"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("VirtualBox") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?string table = "Win32_DiskDrive"; ?
    ? ?wstring wcol = L"Caption"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("VBOX") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?string table = "Win32_DiskDrive"; ?
    ? ?wstring wcol = L"Caption"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("Virtual HD") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?string table = "Win32_computersystem"; ?
    ? ?wstring wcol = L"Model"; ?
    ? ?string ret; ?
    ? ?ManageWMIInfo(ret, table, wcol); ?
    ? ?if (ret.find("Virtual Machine") != string::npos) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    3.根據當前進程信息

    通過進程快照讀取當前進程信息,查找是否存在虛擬機中特有的進程,如中的.exe和中的.exe。

    BOOL CheckVMWare() ?
    { ?
    ? ?DWORD ret = 0; ?
    ? ?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(pe32.szExeFile, "vmware.exe")==0) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?return TRUE; ?
    ? ? ? ?} ?
    ? ? ? ?bMore = Process32Next(hProcessSnap, &pe32); ?
    ? ?} ?
    ? ?CloseHandle(hProcessSnap); ?
    ? ?return FALSE; ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?DWORD ret = 0; ?
    ? ?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(pe32.szExeFile, "VBoxService.exe")==0) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?return TRUE; ?
    ? ? ? ?} ?
    ? ? ? ?bMore = Process32Next(hProcessSnap, &pe32); ?
    ? ?} ?
    ? ?CloseHandle(hProcessSnap); ?
    ? ?return FALSE; ?
    }

    4.根據特定的文件夾或文件信息

    通過查找磁盤中是否存在特定的文件夾或文件,判斷當前是否在虛擬機中。虛擬機中通常會有路徑C:\ Files\\ Tools\;虛擬機中通常會有路徑 C:\ Files\\ Guest \。

    BOOL CheckVMware() ?
    { ?
    ? ?if (PathIsDirectory("C:\\Program Files\\VMware\\VMware Tools\\") == 0) ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?if (PathIsDirectory("C:\\Program Files\\Oracle\\VirtualBox Guest Additions\\") == 0) ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    }

    5.根據特定注冊表信息

    通過讀取主機具有虛擬機特性的注冊表位置來判斷是否處于虛擬機環境中。針對可以判斷注冊表項\\\\.exe;針對可以判斷注冊表項\\\\\\ Guest 。當然,注冊表中能被檢測出的位置很多,這里只是舉個例子。

    BOOL CheckVMWare() ?
    { ?
    ? ?HKEY hkey; ?
    ? ?if (RegOpenKey(HKEY_CLASSES_ROOT, "\\Applications\\VMwareHostOpen.exe", &hkey) == ERROR_SUCCESS) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?HKEY hkey; ?
    ? ?if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Oracle\\VirtualBox Guest Additions", &hkey) == ERROR_SUCCESS) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    6.根據特定服務名

    通過獲取主機當前具有特性的服務信息,判斷當前主機是否為虛擬機。在中通常會存在物理磁盤助手服務和 Tools服務等;在中通常會存在 Guest 服務等。

    BOOL CheckVMWare() ?
    { ?
    ? ?int menu = 0; ? ?
    ? ?//打開系統服務控制器 ? ?
    ? ?SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); ?
    ? ?if(SCMan == NULL) ? ?
    ? ?{ ?
    ? ? ? ?cout << GetLastError() << endl; ?
    ? ? ? ?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; ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?int menu = 0; ? ?
    ? ?//打開系統服務控制器 ? ?
    ? ?SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); ?
    ? ?if(SCMan == NULL) ? ?
    ? ?{ ?
    ? ? ? ?cout << GetLastError() << endl; ?
    ? ? ? ?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, "Virtual Machine")!=NULL) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?return TRUE; ?
    ? ? ? ?} ?
    ? ?} ? ?
    ? ?//關閉服務管理器的句柄 ?
    ? ?CloseServiceHandle(SCMan); ?
    ? ?return FALSE; ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?int menu = 0; ? ?
    ? ?//打開系統服務控制器 ? ?
    ? ?SC_HANDLE SCMan = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); ?
    ? ?if(SCMan == NULL) ? ?
    ? ?{ ?
    ? ? ? ?cout << GetLastError() << endl; ?
    ? ? ? ?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, "VirtualBox Guest")!=NULL) ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?return TRUE; ?
    ? ? ? ?} ?
    ? ?} ? ?
    ? ?//關閉服務管理器的句柄 ?
    ? ?CloseServiceHandle(SCMan); ?
    ? ?return FALSE; ?
    }

    7.根據時間差

    由于在虛擬機中,代碼的運行速度通常不如真實主機。所以惡意代碼通過運行一段特定的代碼來比較這段代碼在虛擬機和真實主機之中的相對運行時間,以此來判斷是否處于虛擬機之中。

    BOOL CheckVMWare() ?
    { ?
    ? ?__asm ?
    ? ?{ ?
    ? ? ? ?rdtsc ?
    ? ? ? ?xchg ebx,eax ?
    ? ? ? ?rdtsc ?
    ? ? ? ?sub eax,ebx ?
    ? ? ? ?cmp eax,0xFF ?
    ? ? ? ?jg detected ?
    ? ?} ?
    ? ?return FALSE; ?
    detected: ?
    ? ?return TRUE; ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?__asm ?
    ? ?{ ?
    ? ? ? ?rdtsc ?
    ? ? ? ?xchg ebx,eax ?
    ? ? ? ?rdtsc ?
    ? ? ? ?sub eax,ebx ?
    ? ? ? ?cmp eax,0xFF ?
    ? ? ? ?jg detected ?
    ? ?} ?
    ? ?return FALSE; ?
    detected: ?
    ? ?return TRUE; ?
    }

    BOOL CheckVirtualBox() ?
    { ?
    ? ?__asm ?
    ? ?{ ?
    ? ? ? ?rdtsc ?
    ? ? ? ?xchg ebx,eax ?
    ? ? ? ?rdtsc ?
    ? ? ? ?sub eax,ebx ?
    ? ? ? ?cmp eax,0xFF ?
    ? ? ? ?jg detected ?
    ? ?} ?
    ? ?return FALSE; ?
    detected: ?
    ? ?return TRUE; ?
    }

    二、查找漏洞指令

    虛擬機監視器監視虛擬機的運行,它運行在宿主操作系統,并為客戶機操作系統提供一個完整的虛擬平臺。與此同時,虛擬機監視器也存在一些可以被惡意代碼探測到虛擬化的安全缺陷。

    在內核模式下,使用二進制翻譯技術進行指令的模擬。運行于內核態的某些特權指令被解釋和模擬,所以它們不在物理處理器上運行。

    相反,在用戶模式下,代碼直接在處理器上運行,幾乎所有與硬件交互的指令,要么是特權指令,要么會產生內核態陷阱指令或中斷指令。

    截獲所有中斷并處理它們,以便虛擬機仍然認為這是一個正常機器。然而在x86體系結構中,一些指令在獲取硬件相關的信息時并不產生異常,如sidt、sgdt、sldt、cpuid等等。為了正確虛擬這些指令,需要在所有指令上進行二進制翻譯,因此造成巨大的性能損失。

    為了避免執行全指令模擬造成的巨大性能損失,允許一些特定指令在沒有正確虛擬化的前提下運行。最終,這意味著某些指令序列在虛擬機而不是在物理機中運行時返回不同的結果。處理器使用某些關鍵的結構與表,它們會被加載與真實系統不同的偏移量,而這正是未進行全虛擬化的副作用。

    中斷描述表(IDT)是CPU內部的一個數據結構,操作系統使用它來確保正確響應中斷和異常。在x86體系結構下,所有的內存獲取,或是通過全局描述表(GDT)獲得,或是通過本地描述表(LDT)獲得。這些表中包含段描述符,它們提供每一個段的詳細存取信息,其中包含段基地址類型、長度,以及存取權限等等。

    IDT、GDT和LDT是CPU內部的寄存器,它們分別存放著各自表的基地址和大小。有三條敏感指令(sidt、sgdt和sldt)可以讀取這些表的位置,并且將相應的寄存器存入內存地址。因為這些指令可以隨時被用戶態代碼調用,且不會產生陷阱,也未被正確虛擬化,所以這些異常都可能被用來探測的存在。

    1.使用Red Pill反虛擬機技術

    Red Pill通過運行sidt指令獲取IDTR寄存器的值。虛擬機監視器必須重新定位Guest系統的IDTR,來避免與Host系統的IDTR沖突。因為在虛擬機中運行sidt指令時,虛擬機監視器不會得到通知,所以會返回虛擬機的IDTR。

    Red Pill通過測試這種差異來探測的使用。這種方法存在一個缺陷,由于IDT的值只針對處于正在運行的處理器而言,在單CPU中它是個常量,但當它處于多CPU時就可能會受到影響了,因為每個CPU都有其自己的IDT,這樣問題就自然而然的產生了。

    針對此問題, 組織成員提出了兩種應對方法:

    其中一種方法就是利用Red Pill反復地在系統上循環執行任務,以此構造出一張當前系統的IDT值變化統計圖,但這會增加CPU負擔;

    另一種方法就是 API函數k()將線程限制在單處理器上執行,當執行此測試時只能準確地將線程執行環境限制在本地處理器,而對于將線程限制在VM處理器上就可能行不通了,因為VM是計劃在各處理器上運行的,VM線程在不同的處理器上執行時,IDT值將會發生變化,因此此方法也很少被使用。

    2.使用No Pill反虛擬機技術

    sgdt和sldt指令探測的技術通常被稱為No Pill。

    BOOL CheckVMWare() ?
    { ?
    ? ?ULONG xdt = 0 ; ?
    ? ?ULONG InVM = 0; ?
    ? ?__asm ?
    ? ?{ ?
    ? ? ? ?push edx ?
    ? ? ? ?sidt [esp-2] ?
    ? ? ? ?pop edx ?
    ? ? ? ?nop ?
    ? ? ? ?mov xdt , edx ?
    ? ?} ?
    ? ?if (xdt > 0xd0000000) ?
    ? ?{ ?
    ? ?
    ? ? ? ?InVM = 1; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?InVM = 0; ?
    ? ?} ?
    ? ?__asm ?
    ? ?{ ?
    ? ? ? ?push edx ?
    ? ? ? ?sgdt [esp-2] ?
    ? ? ? ?pop edx ?
    ? ? ? ?nop ?
    ? ? ? ?mov xdt , edx ?
    ? ?} ?
    ? ?if (xdt > 0xd0000000) ?
    ? ?{ ?
    ? ? ? ?InVM += 1; ?
    ? ?} ?
    ? ?if (InVM == 0) ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    }

    通過禁用加速可以防止No Pill技術的探測。

    3.查詢I/O端口

    使用虛擬化的I/O端口完成宿主系統與虛擬機之間的通信,以便支持諸如復制和粘貼功能。這個端口可以被查詢,然后與一個magic數比較,以確定的使用。

    這種技術成功的關鍵在于x86體系結構中的in指令,它從一個源操作數指定的端口復制數據到目的操作數指定的內存地址。會監視in指令的執行,并捕獲目的通信端口為(VX)的I/O。

    會檢查第二個操作數是否是VX,在這種情況發生時,EAX寄存器載入的值是(VMXh),ECX寄存器必須被載入你希望在端口上執行相應操作的值,值0xA表示 get type,0x14代表get the size。

    它們都可以被用來探測,但0xA更受歡迎,因為它能確定的版本。如代碼所示setz指令在magic數與VMXh匹配時設置返回值rc為1,如果在真實的機器上運行會觸發NDLER異常,在異常處理中設置返回值rc為0。

    BOOL CheckVMWare() ?
    { ?
    ? ?bool rc = true; ?
    ? ?__try ?
    ? ?{ ?
    ? ? ? ?__asm ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?push ? edx ?
    ? ? ? ? ? ?push ? ecx ?
    ? ? ? ? ? ?push ? ebx ? ?
    ? ? ? ? ? ?mov ? ?eax, 'VMXh' ?
    ? ? ? ? ? ?mov ? ?ebx, 0 ? ?
    ? ? ? ? ? ?mov ? ?ecx, 10 ?
    ? ? ? ? ? ?mov ? ?edx, 'VX' ?
    ? ? ? ? ? ?in ? ? eax, dx ?
    ? ? ? ? ? ?cmp ? ?ebx, 'VMXh' ?
    ? ? ? ? ? ?setz ? [rc] ?
    ? ? ? ? ? ?pop ? ?ebx ?
    ? ? ? ? ? ?pop ? ?ecx ?
    ? ? ? ? ? ?pop ? ?edx ?
    ? ? ? ?} ?
    ? ?} ?
    ? ?__except(EXCEPTION_EXECUTE_HANDLER) ? ?
    ? ?{ ?
    ? ? ? ?rc = false; ?
    ? ?} ?
    ? ?return rc; ?
    }

    對付這種反虛擬化技術的最簡單方法是使用NOP指令替換in指令,或修補條件跳轉,使得它不論比較結果如何,都執行到未探測到虛擬機的程序分支。

    4.使用str指令

    在保護模式下運行的所有程序在切換任務時,對于當前任務中指向TSS的段選擇器將會被存儲在任務寄存器中,TSS中包含有當前任務的可執行環境狀態,包括通用寄存器狀態、段寄存器狀態、標志寄存器狀態、EIP寄存器狀態等等,當此項任務再次被執行時,處理器就會其原先保存的任務狀態。

    每項任務均有其自己的TSS,而我們可以通過STR指令來獲取指向當前任務中TSS的段選擇器。這里STR指令是用于將任務寄存器(TR)中的段選擇器存儲到目標操作數,目標操作數可以是通用寄存器或內存位置,使用此指令存儲的段選擇器指向當前正在運行的任務的任務狀態段(TSS)。

    在虛擬機和真實主機之中,通過STR讀取的地址是不同的,當地址等于時,說明處于虛擬機中,否則為真實主機。

    BOOL CheckVMWare() ?
    { ?
    ? ?unsigned char mem[4] = {0}; ?
    ? ?__asm str mem; ?
    ? ?if ((mem[0] == 0x00) && (mem[1] == 0x40)) ?
    ? ?{ ?
    ? ? ? ?return TRUE; ?
    ? ?} ?
    ? ?else ?
    ? ?{ ?
    ? ? ? ?return FALSE; ?
    ? ?} ?
    }

    在IDA PRO中,可以使用下面的腳本查找我們前面提到的指令。

    from idautils import * ?
    from idc import * ?
    ?
    heads = Heads(SegStart(ScreenEA()), SegEnd(ScreenEA())) ?
    antiVM = [] ?
    for i in heads: ?
    ? ?if (GetMnem(i) == "sidt" or GetMnem(i) == "sgdt" or GetMnem(i) == "sldt" or GetMnem(i) == "smsw" or GetMnem(i) == "str" or GetMnem(i) == "in" or GetMnem(i) == "cpuid"): ?
    ? ? ? ?antiVM.append(i) ?
    ?
    print "Number of potential Anti-VM instructions: %d" % (len(antiVM)) ?
    ?
    for i in antiVM: ?
    ? ?SetColor(i, CIC_ITEM, 0x0000ff) ?
    ? ?Message("Anti-VM: x\n" % i)

    要在IDA PRO中運行腳本,選擇File-> File,可以看到下面的輸出。

    這個輸出表明腳本檢測到了三條漏洞指令類型。滾動到IDA PRO的反匯編窗口,我們看到三條紅色高亮顯示的指令sidt、str和sldt。

    5.使用無效的操作碼

    每臺機器都有一組定義的指令,通常稱為指令集架構( Set )。

    當遇到無效指令(不存在于ISA中)時,機器引發無效操作碼異常。軟件可以處理異常(使用通常的try/catch機制),也可以讓操作系統處理異常,或者在最壞的情況下崩潰機器。

    使用一堆無效指令來允許虛擬機和之間連接。當的虛擬機想要與通信時,程序設置異常處理程序(try/catch塊),在調用VM軟件之前設置所需的參數,發出特殊的無效操作碼指令。

    VM軟件將識別此無效操作碼并相應地操作,如果存在則不引起異常,并且如果不存在則產生異常。

    最后,程序的catch塊將處理異常并檢查返回的VM軟件的參數。總之,使用無效的操作碼機制作為后門。

    DWORD IslnsideVPC_exceptionFilter(LPEXCEPTION_POINTERS ep) ?
    { ?
    ? ?PCONTEXT ctx=ep->ContextRecord; ?
    ? ?ctx->Ebx = -1; //未運行在VPC中 ?
    ? ?ctx->Eip += 4; //跳過”call VPC”操作 ?
    ? ?return EXCEPTION_CONTINUE_EXECUTION; ?
    }

    BOOL CheckVirtualPC() ?
    { ?
    ? ?bool rc = TRUE; ?
    ? ?__try ?
    ? ?{ ?
    ? ? ? ?__asm ?
    ? ? ? ?{ ?
    ? ? ? ? ? ?push ebx ?
    ? ? ? ? ? ?mov ebx, 0 ?
    ? ? ? ? ? ?mov eax, 1 ?
    ? ? ? ? ? ?__emit 0fh ?
    ? ? ? ? ? ?__emit 3fh ?
    ? ? ? ? ? ?__emit 07h ?
    ? ? ? ? ? ?__emit 0bh ?
    ? ? ? ? ? ?test ebx, ebx ?
    ? ? ? ? ? ?setz[rc] ?
    ? ? ? ? ? ?pop ebx ?
    ? ? ? ?} ?
    ? ?} ?
    ? ?__except(IslnsideVPC_exceptionFilter(GetExceptionInformation())) ?
    ? ?{ ?
    ? ? ? ?rc = FALSE; ?
    ? ?} ?
    ? ?return rc; ?
    }

    三、基于社會工程學的技巧

    1.檢測電腦中常用軟件的使用情況

    名為 Inc.doc 的惡意軟件樣本文件使用了下面的反虛擬機技巧,值為7f8e。

    對象表示系統最近打開過的歷史文檔。

    通常,安裝了word程序的用戶可能會打開超過2個或更多數量的文檔。然而,當該惡意軟件植入到新創建的虛擬機和word環境中后,總是狀況不斷,不能正常運行。每次測試時手動打開一兩次,總是出現程序異常。即使是保存了虛擬機鏡像狀態,重啟調試分析后,惡意程序仍然不能正常執行。

    從函數功能可以看出,惡意軟件以數量來判斷是否身處VM環境中,如果在VM環境中,它將不會執行任何惡意行為。之后,隨意創建了3個不同名稱的word文檔,逐一打開并關閉,讓歷史文檔數量為3,最終成功運行并檢測到了惡意軟件。

    2. 探測殺毒軟件公司相關的IP地址

    同樣是上面的惡意軟件,它在另一個子程序中使用了下面的反虛擬機技巧。

    首先,它通過向遠程地址 發出某種認證請求,之后設置請求信息中的HTTP Refer屬性和User-Agent值,訪問鏈接 以此獲取宿主系統的地址信息。

    獲取信息封裝于JSON格式文件中,包含國家、城市、或者與IP相關的組織機構等信息。IP信息的字段顯示為美國寬帶網絡供應商。

    惡意軟件發出訪問請求后,獲取到宿主系統的相關信息將存儲于某個數組中。如果獲取到的組織機構名稱與JSON文件中的任何機構字符串匹配,惡意軟件將發生異常并停止運行。當然怎么把文件發到虛擬機上,列表中的機構名稱在代碼中是經過混淆的。

    四、虛擬機逃逸

    等軟件中或多或少都存在一些安全漏洞,可以利用這些漏洞使宿主操作系統崩潰或者是在宿主操作系統中運行代碼。當主機系統被感染后,一些公開可用的工具可以用來對等軟件進行攻擊。

    五、總結

    當遇到的惡意代碼似乎不能運行時,在使用調試或反匯編惡意代碼搜索其反虛擬機探測代碼之前,應該考慮使用一個卸載了 Tools的虛擬機。中有一些未文檔化的功能可以幫助減輕反虛擬機技術的探測。將下面的代碼放到的.vmx文件中,以減輕虛擬機被探測的可能。

    isolation.tools.getPtrLocation.disable = "TRUE" 
    isolation.tools.setPtrLocation.disable = "TRUE"
    isolation.tools.setVersion.disable = "TRUE"
    isolation.tools.getVersion.disable = "TRUE"
    monitor_control.disable_directexec = "TRUE"
    monitor_control.disable_chksimd = "TRUE"
    monitor_control.disable_ntreloc = "TRUE"
    monitor_control.disable_selfmod = "TRUE"
    monitor_control.disable_reloc = "TRUE"
    monitor_control.disable_btinout = "TRUE"
    monitor_control.disable_btmemspace = "TRUE"
    monitor_control.disable_btpriv = "TRUE"
    monitor_control.disable_btseg = "TRUE"

    參數可以使用戶模式下的代碼被模擬執行而不是直接在硬件上運行,因此它可以挫敗一些反虛擬機技術。

    前四條設置被后門命令使用怎么把文件發到虛擬機上,它們的作用是使得運行在Guest系統中的 Tools不能獲取宿主系統的信息。這些設置會禁用 Tools的一些有用功能,并可能對虛擬機性能有嚴重負面影響。所以,僅當其他技術無效時再添加這些選項。當然,也可以將惡意代碼在其他虛擬環境或者物理主機上運行。

    同反調試技術一樣,要想發現惡意代碼中的反虛擬機技術需要在長期調試過程中積累更多經驗。例如,看到一個代碼在一個條件跳轉處過早終止,這可能就是反虛擬機技術造成的結果。一如既往地警惕這種類型的問題,然后查看其之前的代碼,來確定它到底執行了什么操作。

    和反調試技術一樣,通過修改條件跳轉指令或者使用NOP指令覆蓋來繞過相關探測。

    最后讓我們總結一下提到的內容:

    騰訊2016游戲安全技術競賽有一道題,大概意思就是給一個exe,要求編寫一個.dll,并導出多個接口函數 、、。X為1-100之間的數字。函數功能是檢測自己是否處于相應的虛擬機中,是返回TRUE,否則返回FALSE。函數的原型都是 BOOL (* )();。

    編譯好dll之后,放在.exe的同目錄,運行.exe,點擊檢測按鈕,在物理機中運行時函數接口輸出為0,在虛擬機、虛擬機和虛擬機中運行時,相關的接口輸出1。我們把提到的知識綜合一下完成這道題目。

    解題的參考代碼和題目相關信息:

    參考資料

    1.《惡意代碼分析實戰》第17章反虛擬機技術(本文的主體框架)

    2.這個惡意軟件“奇葩”的反虛擬機技巧

    3.天樞戰隊官方博客(本文大部分代碼的來源)

    4.虛擬機檢測技術剖析

    5. if your is a

    本文由看雪論壇原創

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有