1. 程式人生 > WINDOWS開發 >WIN PE檔案插入MessageBox

WIN PE檔案插入MessageBox

1.準備工作

1.1獲取MessageBox地址

方法①:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include<stdio.h> #include<windows.h> typedefvoid(*FuncPointer)(LPTSTR);//函式指標 intmain() { HINSTANCELibHandle; FuncPointerGetAddr; //載入成功後返回庫模組的控制代碼 LibHandle=LoadLibrary("user32"); printf("user32LibHandle=0x%X\n"
,LibHandle);
//返回動態連結庫(DLL)中的輸出庫函式地址 GetAddr=(FuncPointer)GetProcAddress(LibHandle,"MessageBoxA"); printf("MessageBoxA=0x%X\n",GetAddr); return0; }

方法②: 用OllyDBG載入notepad,左下角command框中輸入bp MessageBoxA下斷點。檢視斷點即可得MessageBox地址為:0x77D507EA

1.2CALL和JMP的計算

1 2 3 4 5 6 7 8 9 10 11 #include<stdio.h>
#include<windows.h> voidfunc() { MessageBox(0,0); } intmain() { func(); return0; }

main函式反彙編:

1 2 3 4 11:func(); 0040D478E88D3BFFFFcall@ILT+5(func)(0040100a) 12:return0; 0040D47D33C0xoreax,eax

得到CALL的硬編碼是E8
call func繼續跟進去:

1 2 0040100AE901000000jmpfunc(00401010) 0040100FCCint3

得到JMP的硬編碼是E9


func函式反彙編:

1 2 3 4 5 6 7 6:MessageBox(0,0); 004010288BF4movesi,esp 0040102A6A00push0 0040102C6A00push0 0040102E6A00push0 004010306A00push0 00401032FF15ACA24200calldwordptr[[email protected](0042a2ac)]

觀察到:

1 2 3 地址機器指令彙編指令指令所佔位元組數 0040D478E88D3BFFFFcall@ILT+5(func)(0040100a)5 0040D47D

E8後邊的值並不是真正我們要呼叫的函式地址, 他們有以下關係:

1 2 3 4 5 E8這條指令的下一行地址E8當前指令的地址E8當前指令所佔大小 0x0040D47D=0x0040D478+0x5 真正要跳轉的地址E8後邊的值E8當前指令的下一行地址 0x0040100A=0xFFFF3B8D+0x0040D47D

總結出:

1 2 E8後邊的值=真正要跳轉的地址-(E8當前指令的地址+E8當前指令所佔大小) =真正要跳轉的地址-E8當前指令的下一行地址

1.3構造shellcode

通過之前的學習,可以構造出:

1 2 3 4 5 //18Bytes shellcode[]={0x6A,0x00,0x6A,/*MessageBox4個引數入棧*/ 0xE8,/*呼叫MessageBox*/ 0xE9,0x00/*跳到原程式的入口(AddressOfEntryPoint)*/ };

2.程式碼區新增shellcode

2.1分析PE結構

技術分享圖片

圖1

技術分享圖片

圖2

從圖2中可以得到以下資訊:

1 2 3 4 5 6 IMAGE_OPTIONAL_HEADER(可選頭)中部分成員資訊: DWORDAddressOfEntryPoint;//程式執行入口RVA(0x0000739D) DWORDImageBase;//程式的優先裝載地址(基址)(0x01000000) //程式執行時,PE裝載器先建立程序,再將檔案載入記憶體,然後把EIP暫存器的值設定為:ImageBase+AddressOfEntryPoint; DWORDSectionAlignment;//記憶體中節的對齊粒度(0x00001000) DWORDFileAlignment;//檔案中節的對齊粒度(0x00000200
1 2 3 4 5 IMAGE_SECTION_HEADER(節表第一項即程式碼區部分成員資訊): DWORDVirtualSize;//節區在記憶體中沒有對齊前的實際大小(0x00007748) DWORDVirtualAddress;//節區在記憶體中起始位置(RVA)(0x00001000) DWORDSizeOfRawData;//節區在檔案中對齊後的大小(0x00007800) DWORDPointerToRawData;//節區在在檔案中的偏移(0x00000400)

2.2判斷空閒區域是否能放下shellcode

計算檔案中程式碼區空閒空間

SizeOfRawData(0x7800) - VirtualSize(0x007748) > 0x12

空閒空間大於shellcode長度,可以放得下。

2.3將構造好的ShellCode寫入空閒區:

PointerToRawData(0x0400)+SizeOfRawData(0x7800)=0x7C00,

在0x7B48與0x7C00之間寫入shellcode:

技術分享圖片

圖3

2.4計算E8後邊的值

在計算相關值由檔案對映到記憶體時,需要考慮記憶體對齊和檔案對齊。

真正要跳轉的地址:MessageBox地址:0x77D507EA

1 2 3 4 5 檔案中,E8下一行地址相對PointerToRawData偏移量:0x7B5D-0x400=0x775D 對映到記憶體中,E8下一行地址:ImageBase+VirtualAddress+0x775D=0x0100875D E8後邊的值:MessageBox-0x0100875D=0x76D4808D

2.5計算E9後邊的值

要保證MessageBox關閉後,程式能夠正常執行,需要jmp到原來的OEP

1 2 3 4 5 6 7 原來OEP(真正要跳轉的地址):ImageBase+AddressOfEntryPoint=0x0100739D 檔案中,E9下一行地址相對PointerToRawData偏移量:0x7B62-0x400=7762 對映到記憶體中,E9下一行地址:ImageBase+VirtualAddress+0x7762=0x01008762 E9後邊的值:`0x0100739D-0x01008762=0xFFFFEC3B`

2.6修改OEP(AddressOfEntryPoint)

1 2 3 4 5 檔案中shellcode起始地址相對PointerToRawData偏移量:0x7B50-0x400=0x7750 對映到記憶體中,相對ImageBase偏移:VirtualAddress+0x7750=0x8750 將原來的OEP修改為,對映到記憶體後的shellcode起始地址(0x8750)。

另存檔案,雙擊,成功彈出MessageBox,如圖4: