入口點為0的程式
前幾天群裡有人給了個病毒樣本
拿來一看很奇怪,是個exe檔案,但入口點顯示卻是0
用OD載入後會提示出錯:
之後問了一下同事,大概瞭解了一下原理:
Windows系統載入PE檔案後,會通過PE檔案的特定結構讀取各種資訊。
而該PE檔案的各種資訊都是完整的,可以正常被讀取。
相關的PE結構撿主要的在這裡大概說一下: 檔案開始是一個IMAGE_DOS_HEADER的結構,以資料0x4D5A(ASCII字元為"MZ")開頭的e_magic元素。從該結構體開頭開始計算偏移量0x3c處為一個DWORD值——被稱為e_lfanew,該值為IMAGE_NT_HEADER結構體(即俗稱的PE頭)的偏移量。PE頭分三部分:第一部分是一個名為Signature的欄位,固定為0x4550(ASCII字元為"PE");第二部分從PE頭開始偏移0x4,名為FileHeader的結構;第三部分從PE頭開始偏移0x18,名為OptionalHeader。這個OptionalHeader中的AddressOfEntryPoint與ImageBase兩元素之和即是PE檔案被載入到記憶體中執行時,正式開始執行功能的程式碼起始點。 |
該檔案的AddressOfEntryPoint為0,而ImageBase為400000.
那麼嘗試在OD下用Ctrl+G查詢該地址:
可見固定的e_magic元素被識別為了彙編指令dec ebp和pop edx
而後面的8個位元組則是被人為修改的。
push edx是為了恢復前面"字元Z"被誤認為是指令所造成的出棧操作
而後jmp到自己的修改過的一段程式碼處:
在執行到這個retn指令後,棧中出現的才是原本的程式入口點:
執行retn之後,程式會自動執行到這個入口點(本身還有一層UPX加殼):
總結一下:
其實就是將程式原本的入口點(AddressOfEntryPoint)修改為0,這樣在載入PE檔案的時候就會從檔案的DOS頭開始作為二進位制指令開始執行。只要固定的e_magic不動就不會影響整體的PE結構識別,這樣修改之後的幾個位元組,來實現向程式原本入口點的直接或間接跳轉。
用以下程式碼可以輕鬆實現任意一個PE檔案的修改(跳轉方法沒有用jmp,比較麻煩。採用了push+retn的方法,很直接):
- VOID ChangeExeOEP( PVOID pBuffer)
- {
- /*將檔案對映到記憶體,通過記憶體中的控制代碼獲取檔案DOS頭*/
- PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
- /*通過DOS頭獲取PE頭*/
-
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (DWORD
- /*通過PE頭中OptionalHeader結構中的AddressOfEntryPoint和ImageBase相加獲取程式入口點*/
- DWORD dwOEP = pNtHeader->OptionalHeader.AddressOfEntryPoint + pNtHeader->OptionalHeader.ImageBase;
- /*初始化跳轉陣列,其中0x52和0x45分別為push edx指令和inc ebp,作用前面解釋過。
- 0x68為push指令,後面四個0x00為預留的原始入口點地址,0xC3為retn指令*/
- BYTE JmpArray[] = {0x4D,0x5A,0x52,0x45,0x68,0x00,0x00,0x00,0x00,0xC3};
- /*陣列的第五位起填入之前預留的原始入口點地址*/
- *(DWORD*)(JmpArray + 5) = dwOEP;
- memcpy( pBuffer,JmpArray,10 );
- /*將AddressOfEntryPoint元素置零*/
- pNtHeader->OptionalHeader.AddressOfEntryPoint = 0;
- }
用該方法修改notepad.exe,以下是修改前和修改後的notepad.exe的對比。僅此兩處修改,其餘均未變:
修改之後notepad照常執行,而入口點卻是0了:
就先寫到這了,權當學習記錄了。