PE文件的修改和感染

【轉】PE文件的修改和感染算法

2008-04-29 08:20數組

既然已經可以搜索磁盤及網絡共享文件中的全部文件,要實現寄生,那麼天然下一步就是對搜索到的PE文件進行感染了。感染PE的很重要的一個考慮就是將病毒代碼寫入到PE 文件的哪一個位置。讀寫文件通常利用Win32 API CreateFile、CreateFileMapping、MapViewOfFile等API之內存映射文件的方式進行,這樣能夠避免本身管理緩衝的麻煩,於是爲較多病毒所採用。爲了可以讀寫具備只讀屬性的文
件,病毒在操做前首先利用GetFileAttributes 獲取其屬性並保存,而後用SetFileAttributes將文件的屬性修改成可寫,在
感染完畢後再恢復其屬性值。
  
  通常說來,有以下幾種感染PE文件的方案供選擇:

  a)添加一個新的節。將病毒代碼寫入到新的節中,相應修改節表,文件頭中文件大小等屬性值。因爲在PE尾部增長了一個節,所以較容易被用戶察覺。在某些狀況下,因爲原PE頭部沒有足夠的空間存放新增節的節表信息,所以還要對其它數據進行搬移等操做。鑑於上述問
題,PE 病毒使用該方法的並很少。

  b)附加在最後一個節上。修改最後一個節節表的大小和屬性以及文件頭中文件大小等屬性值。因爲愈來愈多的殺毒軟件採用了一種尾部掃描的方式,所以不少病毒還要在病毒代碼以後附加隨機數據以逃避該種掃描。現代PE 病毒大量使用該種方式。

  c)寫入到PE文件頭部未用空間各個節所保留的空隙之中。PE 頭部大小通常爲1024 字節,有5-6 個節的普通PE文件實際被佔用部分通常僅爲600 字節左右,尚有400 多個字節的剩餘空間能夠利用。PE文件各個節之間通常都是按照512 字節對齊的,但節中的實際數據經常未徹底使用所有的512字節,PE文件的對齊設計原本是出於效率的考慮,但其留下的空隙卻給病毒留下了棲身之地。這種感染方式感染後原PE 文的總長度可能並不會增長,所以自CIH 病毒首次使用該技術以來,備受病毒做者的青睞。

  d)覆蓋某些很是用數據。如通常exe文件的重定位表,因爲exe通常不須要重定位,所以能夠覆蓋重定位數據而不會形成問題,爲保險起見可將文件頭中指示重定位項的DataDirectory 數組中的相應項清空,這種方式通常也不會形成被感染文件長度的增長。所以不少病毒也普遍使用該種方法。

  e)壓縮某些數據或代碼以節約出存放病毒代碼的空間,而後將病毒代碼寫入這些空間,在程序代碼運行前病毒首先解壓縮相應的數據或代碼,而後再將控制權交給原程序。該種方式通常不會增長被感染文件的大小,但需考慮的因素較多,實現起來難度也比較大。用的還很少。
  
  不論何種方式,都涉及到對PE頭部相關信息以及節表的相關操做,咱們首先研究一下PE的修改,即如何在添加了病毒代碼後使得PE文件仍然是合法的PE文件,仍然可以被系統加載器加載執行。

  PE文件的每一個節的屬性都是由節表中的一個表項描述的,節表緊跟在IMAGE_NT_HEADERS後面,所以從文件偏移0x3C 處的雙字找到IMAGE_NT_HEADERS 的起始偏移,再加上IMAGE_NT_HEADERS的大小(248字節)就定位了節表的起始位置,每一個表項是一個IMAGE_SECTION_HEADER結構:
網絡

typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
//
節的名字
  union {
  DWORD PhysicalAddress;
  DWORD VirtualSize;
// 字節計算的實際大小
   } Misc;
   DWORD VirtualAddress;
// 節的起始虛擬地址
   DWORD SizeOfRawData;
// 按照文件頭FileAlignment
  
// 對齊後的大小
   DWORD PointerToRawData;
// 文件中指向該節起始的偏移
   DWORD PointerToRelocations;
   DWORD PointerToLinenumbers;
   WORD NumberOfRelocations;
   WORD NumberOfLinenumbers;
   DWORD Characteristics;
// 節的屬性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
app


  節表項的數目由IMAGE_NT_HEADERS的NumberOfSections成員肯定。由節表中的起始虛擬地址以及該節在文件中的位置就能夠換算加載後內存虛擬地址和文件中地址之間的映射關係。添加一個節則須要修改該節表數組, 在其中增長一個表項, 而後相應修改
NumberOfSections 的數目。值得注意的是,某些PE文件現存節表後面可能緊跟着其它數據,如bound import 數據,這時就不能簡單地增長一個節表項,須要先移動這些數據並修改相應的結構後才能增長節,不然PE文件將不能正常執行。因爲不少病毒是自我修改的,所以節屬性一般設置爲E000XXXX,表示該節可讀寫執行,不然就須要在病毒的開始處調用VirtualProtect之類的API動態修改內存頁的屬性了。

  由上述節表的定義還能夠看到每一個節的實際數據都是按照文件頭中FileAlignment 對齊的,這個大小通常是512,所以每一個節可能有不超過512字節的未用空間(SizeOfRawData-VirtualSize),這剛好給病毒以可乘之機,著名的CIH病毒首先採用了這種技術,不過問題是每一個節的空隙大小是不定的,所以就須要將病毒代碼分紅若干部分存放,運行時再經過一段代碼組合起來,優勢是若是病毒代碼較小則無需增長PE的大小,隱蔽性較強。若是全部節的未用空間仍不足以容納病毒代碼,則可新增節或附加到最後一個節上。

  附加到最後一個節上是比較簡單的,只要修改節表中最後一個節的VirtualSize 以及按FileAlignment 對齊後的SizeOfRawData成員便可。固然在上述全部修改節的狀況中,若是改變了文件的大小,都要修正文件頭中SizeOfImage這個值的大小,該值是全部節和頭按照SectionAlignment 對齊後的大小。

  這裏有兩個問題值得注意,第一問題就是對WFP(Windows File Protection)文件的處理,WFP機制是從Windows 2000 開始新增的保護系統文件的機制,若系統發現重要的系統文件被改變,則彈出一個對話框警告用戶該文件已被替換。固然有多種方法繞過WFP 保護,但對病毒而言,更簡單的方法就是不感染在WFP 列表中的系統文件。

  可以使用sfc.dll的導出函數SfcIsFileProtected判斷一個文件是否在該列表中,該API 的第一個問 匭胛?,第二個參數是要判斷的文件名,若在列表中返回非0值,不然返回0。

  另一個問題就是關於PE文件的校驗。大部分PE文件都不使用文件頭中的CheckSum域的校驗和值,不過有些PE文件,如關鍵的系統服務程序文件以及驅動程序文件則該值必須正確,不然系統加載器將拒絕加載。PE 頭部的CheckSum 可使用Imagehlp.dll的導出函數 CheckSumMappedFile計算,也能夠在將該域清0後按照以下簡單的等價算法計算:

  若是PE文件大小是奇數字節,則以0補足,使之按偶數字節。將PE文件頭的CheckSum 域清0,而後以兩個字節爲單位進行adc運算,最後和將該累加和同文件實際大小進行adc運算即獲得校驗和的值。下面的cal_checksum過程假設esi 已經指向PE文件頭,文件頭部CheckSum域已經被清0,CF 標誌位已經被複位:
函數

;調用示例:
;clc
;push pe_fileseize
;call cal_checksum cal_checksum:
adc bp,word [esi] ;初始esi指向文件頭,ebx 中保
存的是文件大小
inc esi
inc esi
loop cal_checksum
mov ebx,[esp+4]
adc ebp,ebx ;ebp 中存放的就是PE 的校驗和
ret 4
oop


  除了PE頭部的校驗和以外,不少程序自身也有校驗模塊,如Winzip 和Winrar 的自解壓文件,若是被感染,將形成沒法正常解壓縮。所以對於相似的PE文件,病毒應儘可能不予感染。spa

相關文章
相關標籤/搜索