病毒木马查杀实战第017篇:U盘病毒之专杀工具的编写
前言
? ? ? ?經過前幾次的討論,我們對于這次的U盤病毒已經有了一定的了解,那么這次我們就依據病毒的行為特征,來編寫針對于這次U盤病毒的專殺工具。
專殺工具功能說明
? ? ? ?因為這次是一個U盤病毒,所以我打算把這次的專殺工具換一種形式實現。不再像前幾次那樣需要被動運行,而是當我們的專殺工具執行后,一旦有U盤插入,就能主動檢測U盤內容,如果發現病毒,就將其刪除掉,之后檢查系統中是否也存在病毒,如果有,也一并清理干凈。我們這次的專殺工具需要實現以下幾個功能:
? ? ? ?1、專殺工具開啟后,需要時刻監測是否有U盤插入,如果有,則啟動檢測機制。
? ? ? ?這里可以使用OnDeviceChange()這個消息響應函數,從而對當前系統中新添加的設備進行實時監控,并且通過對這個函數的參數具體內容的判斷,就可以實現U盤的監控。
? ? ? ?2、查找U盤中是否存在autorun.inf文件,如果有,則解析該文件中的“open”語句后的內容,獲取自啟動病毒程序的名稱。
? ? ? ?解析autorun.inf文件的內容,可以使用GetPrivateProfileString()這個函數,通過它,先找到“AutoRun”區段,之后找到該區段下“open”后面的內容,就能夠獲取自啟動的病毒程序的名稱。
? ? ? ?3、刪除autorun.inf文件以及它所要打開的程序(Recycle.exe)。
? ? ? ?首先應當計算Recycle.exe的CRC32指紋特征碼,保存為全局變量,用于之后病毒程序的匹配。由于病毒創建出來的程序具有系統以及隱藏屬性,因此在刪除之前,應當先將病毒程序的文件屬性設置為NORMAL(普通),這可以通過SetFileAttributes()函數實現。之后再利用DeleteFile()將病毒程序刪除。
? ? ? ?4、全盤搜索U盤中的exe程序,進行CRC32指紋匹配,刪除所有病毒程序,并恢復被隱藏的文件夾。
? ? ? ?依據上面計算出的病毒程序的CRC32值,就可以對U盤根目錄盤中的所有exe文件進行匹配。畢竟病毒程序本體是沒有變化的,只不過是換了一個名稱而已。另外,病毒還會將與病毒同名文件夾進行隱藏,由于我們并沒有分析過病毒是如何選取這些文件夾的(其實也沒必要分析),因此我們只能通過病毒名稱來查找被隱藏的文件夾,之后將其屬性設置為NORMAL,那么文件夾也就恢復了。
? ? ? ?5、解析本地系統的注冊表啟動項,找到病毒程序的名稱以及隱藏位置。
? ? ? ?在刪除本地系統中的病毒程序之前,我們需要先結束掉病毒進程。由于病毒的名稱是依據計算機的特征計算出來的,而我們并沒有逆向分析它的算法(其實也沒有必要),所以我們并不知道病毒程序在不同的計算機中的進程名稱是什么,也就不能直接結束病毒進程。但是這里可以使用一種取巧的方法,那就是病毒會將自身加入到注冊表啟動項中,因此我們只要解析注冊表啟動項,就能夠獲取病毒名稱以及隱藏位置。經過我在不同的計算機中的測試,可以知道病毒名稱是由六個字符組成的,那么我們只要查找啟動項中的名稱為六個字符,并且它所啟動的程序能夠匹配之前計算的CRC32指紋特征,那么我們也就找到了病毒的名稱以及隱藏位置。
? ? ? ?6、依據上面所找到的病毒名稱,結束掉當前正在運行的病毒進程,并刪除病毒啟動項以及病毒本體。
? ? ? ?有了病毒名稱,就可以在當前進程中搜索,找到之后,就可以結束掉病毒進程,之后再刪除病毒本體。
? ? ? ?7、將病毒創建的九個動態鏈接庫文件刪除,它們位于臨時文件夾中的“E_N4”中。
? ? ? ?其實這里即便是不刪除這幾個動態連庫文件,也是可以的,但是為了進行徹底的查殺,我在這里還是需要將它們刪除,但是這里需要說明的是,一般來說,文件夾是不能夠直接刪除的,需要先將文件夾中的內容清空,才能移除文件夾。
? ? ? ?縱觀以上七項內容可以發現,前四項主要是針對于U盤的修復,而后面三項則是針對于本地系統的修復。接下來我會利用MFC來實現這些功能。
界面設計
? ? ? ?這里新建一個“MFC AppWizard(exe)”工程,工程名稱設定為“UVirusKiller”,然后創建一個“基本對話框”,再單擊“完成”,接下來使用一個“編輯框”以及兩個“按鈕”控件完成界面設計:
圖1 界面設計
? ? ? ?接下來對“編輯框”進行如下設定:
圖2
? ? ? ?并將其ID改為IDC_LIST。之后為“安全打開U盤”按鈕控件創建一個類型為“Control”,名為“m_SafeOpen”的變量:
圖3
? ? ? ?至此,界面設計結束。其實大家完全可以依據自己的喜好來設計自己的程序界面。
編寫用于檢測U盤盤符的代碼
? ? ? ?由于程序是在MFC下進行開發的,因此可以使用OnDeviceChange()這個消息響應函數。那么我們的第一步就是先在文件UVirusKillerDlg.cpp中添加消息映射:
圖4 添加消息映射代碼
? ? ? ?接下來在頭文件UVirusKillerDlg.h中的protected下,添加消息響應函數的定義:
圖5 添加消息響應函數定義
之后在文件UVirusKillerDlg.cpp中添加獲取盤符的代碼:void CUVirusKillerDlg::GetDriverName(DWORD dwData) {PDEV_BROADCAST_HDR pDevHdr = (PDEV_BROADCAST_HDR)dwData;//如果設備類型為DBT_DEVTYP_VOLUME,則把當前結構體轉換為//DBT_DEVTYP_VOLUME類型的結構體if ( pDevHdr->dbch_devicetype == DBT_DEVTYP_VOLUME ){//結構體轉換PDEV_BROADCAST_VOLUME pDevVolume = (PDEV_BROADCAST_VOLUME)pDevHdr; //如果pDevVolume->dbcv_flags為0表示為可移動磁盤if ( pDevVolume->dbcv_flags == 0 ){ //通過將pDevVolume->dbcv_unitmask移位來判斷邏輯盤符,//第0位表示A盤,第1位表示B盤,依此類推。DWORD dwUnitmask = pDevVolume->dbcv_unitmask;//最多循環移動26位,因為至多有26位for (i = 0; i < 26; ++i){//因為新插入的可移動設備一定會是最后一個盤符的后一個,//所以這里尋找dwUnitmask中的最低位數值為0x1的位。if ( dwUnitmask & 0x1){//找到則跳出循環break;}//沒找到則繼續移位尋找dwUnitmask = dwUnitmask >> 1;}//如果循環完26位依舊沒找到,則返回if ( i >= 26 ){return ;}//格式操作轉化為字符串DriverName.Format("%c:", i + 'A');}} }? ? ? ?最后在頭文件UVirusKillerDlg.h中的public下添加:
圖6
? ? ? ?需要說明的是,由于程序中使用了DBT_DEVTYP_VOLUME這樣以DBT_開頭的宏,所以一定要在UVirusKillerDlg.cpp中包含頭文件“Dbt.h”。再定義一個字符型全局變量i用于保存可移動磁盤的盤符。并且定義一個CString類型的csTxt用于保存提示內容。至此,判斷盤符的程序已經完成。編寫完以上程序后,接下來我們還需完善OnDeviceChange()函數。
檢測U盤中的可疑文件
這里不再進行講解,我已經在代碼中添加了足夠的注釋:BOOL CUVirusKillerDlg::OnDeviceChange( UINT nEventType, // An event type. DWORD dwData // The address of a structure that // contains event-specific data. ) {// The system broadcasts the DBT_DEVICEARRIVAL device event when // a device or piece of media has been inserted and becomes available.if ( nEventType == DBT_DEVICEARRIVAL ){// 在未對U盤進行查殺之前,令“安全打開U盤”不可用m_SafeOpen.EnableWindow(FALSE);SetDlgItemText(IDC_LIST, csTxt);//獲取盤符名稱GetDriverName(dwData);//顯示可移動磁盤的盤符CString TmpFile;TmpFile.Format("檢測到可移動磁盤為:%c\r\n", i + 'A');csTxt += TmpFile;SetDlgItemText(IDC_LIST, csTxt);// 如果成功獲取盤符,則繼續執行if ( DriverName != "" ){// 創建CString類型的File,令其保存autorun.inf的完整路徑CString File = DriverName;File += "\\autorun.inf";// 用于保存由autorun.inf所啟動的程序名char szBuff[MAX_PATH] = { 0 };// 判斷可移動磁盤中的autorun.inf文件是否存在if ( GetFileAttributes(File.GetBuffer(0)) == -1 ){csTxt += "在可移動磁盤中沒有檢測到autorun.inf\r\n";SetDlgItemText(IDC_LIST, csTxt);// 如果當前U盤中不存在autorun.inf,則令“安全打開U盤”按鈕可用m_SafeOpen.EnableWindow(TRUE);return FALSE;}csTxt += "在可移動磁盤中檢測到autorun.inf\r\n";csTxt += "正在解析autorun.inf的啟動內容\r\n";SetDlgItemText(IDC_LIST, csTxt);// 獲取AutoRun.inf文件中open后面的內容,即所要自動打開的可疑文件GetPrivateProfileString("AutoRun", //The name of the section containing the key name."open", //The name of the key whose associated string is to be retrieved.NULL, //A default string. szBuff, //A pointer to the buffer that receives the retrieved string.MAX_PATH, //The size of the buffer pointed to by the lpReturnedString //parameter, in characters.File.GetBuffer(0) //The name of the initialization file.);// DelFile保存由autorun.inf啟動的程序的路徑CString DelFile = DriverName;DelFile += '\\';DelFile += szBuff;csTxt += "由autorun.inf啟動的程序為:";csTxt += DelFile;csTxt += "\r\n正在計算病毒程序的哈希值...\r\n";SetDlgItemText(IDC_LIST, csTxt);// 獲取病毒程序的CRC32值VirusCRC32 = CalcCRC32(DelFile); // 刪除可移動磁盤中的autorun.inf以及由之啟動的文件,需要首先將病毒程序的屬性調整為NORMALcsTxt += "正在刪除可移動磁盤中的autorun.inf以及由之啟動的程序...\r\n"; SetFileAttributes(File, FILE_ATTRIBUTE_NORMAL); // 刪除autorun.infBOOL bRet = DeleteFile(File); csTxt += File;if (bRet){csTxt += _T("病毒程序被刪除!\r\n");} else{csTxt += _T("病毒程序無法刪除!\r\n");} SetFileAttributes(DelFile, FILE_ATTRIBUTE_NORMAL);// 刪除由autorun.inf啟動的病毒程序bRet = DeleteFile(DelFile); csTxt += DelFile;if (bRet){csTxt += _T("病毒程序被刪除!\r\n");} else{csTxt += _T("病毒程序無法刪除!\r\n");}SearchAndDeleteVirus(DriverName);csTxt += _T("U盤修復完畢,您現在可以安全地打開U盤或修復本地系統!\r\n");SetDlgItemText(IDC_LIST, csTxt);//令"安全打開U盤"按鈕可用 m_SafeOpen.EnableWindow(TRUE);}}//The system broadcasts the DBT_DEVICEREMOVECOMPLETE device event //when a device or piece of media has been physically removed.else if ( nEventType == DBT_DEVICEREMOVECOMPLETE ){//當U盤被拔出時,令"安全打開U盤"按鈕不可用m_SafeOpen.EnableWindow(FALSE);}return TRUE; }編寫“修復本地系統”按鈕事件代碼
void CUVirusKillerDlg::OnBtnRepair() {// TODO: Add your control notification handler code herecsTxt += _T("開始檢測本地系統...\r\n正在檢查注冊表啟動項...\r\n");char RegName[]="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\";DWORD dwType = 0;DWORD dwBufferSize = MAXBYTE;DWORD dwKeySize = MAXBYTE;char szValueName[MAXBYTE] = { 0 };char szValueKey[MAXBYTE] = { 0 };//打開注冊表啟動項HKEY hKey = NULL;LONG lRetRun = RegOpenKey(HKEY_LOCAL_MACHINE, RegName, &hKey);if ( lRetRun != ERROR_SUCCESS ){AfxMessageBox("注冊表啟動項打開失敗!");return ;}int i = 0; while ( TRUE ){// 枚舉鍵項lRetRun = RegEnumValue(hKey, i, szValueName, &dwBufferSize, NULL, &dwType, (unsigned char *)szValueKey, &dwKeySize);if ( lRetRun == ERROR_NO_MORE_ITEMS ){break;}// 如果鍵項為6個字符,并且鍵值指向的程序的CRC32指紋與病毒指紋匹配,則關閉病毒進程以及刪除鍵項與病毒本體if ( lstrlen(szValueName) == 6 && CalcCRC32(szValueKey) == VirusCRC32 ){BOOL bRet = FALSE;DWORD dwPid = 0; // 刪除病毒的注冊表啟動項RegDeleteValue(hKey, szValueName);csTxt += _T("注冊表啟動項清理完畢!\r\n");strcat(szValueName, ".EXE");bRet = FindTargetProcess(szValueName, &dwPid);if(TRUE){csTxt += _T("檢查系統內存...\r\n");csTxt += _T("系統中存在病毒進程:");csTxt += szValueName;csTxt += _T("準備進行查殺...\r\n");SetDlgItemText(IDC_LIST,csTxt);// 提升權限bRet = EnableDebugPrivilege(SE_DEBUG_NAME);if (bRet == FALSE){csTxt += _T("提升權限失敗\r\n");}else{csTxt += _T("提升權限成功!\r\n");}SetDlgItemText(IDC_LIST,csTxt);// 打開并嘗試結束病毒進程HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPid);if (hProcess == INVALID_HANDLE_VALUE){csTxt += _T("無法結束病毒進程\r\n");return ;}bRet = TerminateProcess(hProcess,0);if (bRet == FALSE){csTxt += _T("無法結束病毒進程\r\n");return ;}csTxt += _T("病毒進程已經結束\r\n");SetDlgItemText(IDC_LIST,csTxt);CloseHandle(hProcess);}break;} //清空緩沖區ZeroMemory(szValueName,MAXBYTE);ZeroMemory(szValueKey, MAXBYTE);i++;}RegCloseKey(hKey);// 刪除自啟動的病毒程序csTxt += szValueKey;// 獲取病毒程序所在文件夾的路徑szValueKey[lstrlen(szValueKey)-11] = '\0';SetFileAttributes(szValueKey, FILE_ATTRIBUTE_NORMAL); BOOL bRet = DeleteDirectory(szValueKey); if (bRet){csTxt += _T("病毒程序被刪除!\r\n");} else{csTxt += _T("病毒程序無法刪除!\r\n");}// 獲取保存有病毒DLL文件的文件夾路徑 char tempPath[100];DWORD dwSize = 100;GetTempPath(dwSize, tempPath);lstrcat(tempPath, "\E_N4");SetFileAttributes(tempPath, FILE_ATTRIBUTE_NORMAL); // 刪除病毒文件夾bRet = DeleteDirectory(tempPath); csTxt += tempPath;if (bRet){csTxt += _T("病毒文件夾被刪除!\r\n");} else{csTxt += _T("病毒文件夾無法刪除!\r\n");}SetDlgItemText(IDC_LIST,csTxt); }? ? ? ?至此,所有主要的程序編寫完畢,接下來就可以進行專殺工具的測試了。
專殺工具的測試
? ? ? ?這里我們需要讓本地系統還有U盤保持中毒的狀態,先拔出U盤,然后啟動專殺工具,使其開始進行監控,之后插入U盤,專殺工具就會自動開始查殺:
圖7
? ? ? ?此時如果點擊“安全打開U盤”,就會打開U盤,可以發現此時U盤中已經沒有了病毒程序,并且被隱藏的文件夾也都顯示出來了。如果點擊“修復本地系統”,那么專殺工具會首先結束掉病毒進程,之后再刪除系統中的病毒程序,從而對系統進行徹底的清理。
小結
這次的專殺工具的代碼稍長,但其實也并不難,都是一些基礎的API函數的調用,這其中還使用了很多之前“熊貓燒香專殺工具”的函數代碼,說明我們應當善于利用之前所編寫過的程序。并且應當善于分析病毒特征,比如如何判斷病毒名稱以及被隱藏的文件夾等,如果要逆向分析這些算法,那么過程無疑是艱辛的。至此,針對于這次的U盤病毒的講解就到這里,希望大家能夠舉一反三,有所收獲。總結
以上是生活随笔為你收集整理的病毒木马查杀实战第017篇:U盘病毒之专杀工具的编写的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ue4多人联网的实例
- 下一篇: 非985/211面试大厂校招经历经验总结