體驗更改PE文件的樂趣
發(fā)表時間:2023-05-31 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]體驗修改PE文件的樂趣 適合讀者:程序員、破解愛好者前置知識:匯編語法體驗修改PE文件的樂趣 文/圖 牛淵 我們大家都知道, 在Windows 9x、NT、...
體驗修改PE文件的樂趣
適合讀者:程序員、破解愛好者
前置知識:匯編語法
體驗修改PE文件的樂趣
文/圖 牛淵
我們大家都知道, 在Windows 9x、NT、2000下, 所有的可執(zhí)行文件都是基于Microsoft設(shè)計的一種新的文件格式Portable Executable File Format(可移植的執(zhí)行體), 即PE格式。 有一些時候, 我們需要對這些可執(zhí)行文件進(jìn)行修改, 下面文字試圖詳細(xì)的描述PE文件的格式及對PE格式文件的修改。
PE文件框架構(gòu)成
dos MZ header
dos Stub
PE header
Section table
Section 1
Section 2
Section...
Section n
上表是PE文件結(jié)構(gòu)的總體層次分布。 所有 PE文件(甚至32位的 DLLs) 必須以一個簡單的 dos MZ header開始, 在偏移0處有dos下可執(zhí)行文件的“MZ標(biāo)志”, 有了它, 一旦程序在dos下執(zhí)行, dos就能識別出這是有效的執(zhí)行體, 然后運(yùn)行緊隨MZ header之后的dos Stub。 緊接著dos Stub的是PE header。 PE header是PE相關(guān)結(jié)構(gòu)IMAGE_NT_HEADERS的簡稱, 其中包含了許多PE裝載器用到的重要域。 可執(zhí)行文件在支持PE文件結(jié)構(gòu)的操作系統(tǒng)中執(zhí)行時, PE裝載器將從dos MZ header的偏移3CH處找到PE header的起始偏移量。 因而跳過了dos Stub直接定位到真正的文件頭PE header。
小知識:dos Stub實際上是個有效的EXE, 在不支持PE文件格式的操作系統(tǒng)中, 它將簡單顯示一個錯誤提示, 類似于字符串“This program cannot run in dos mode”或者程序員可根據(jù)自己的意圖實現(xiàn)完整的dos代碼。 通常dos Stub由匯編器/編譯器自動生成, 對我們的用處不是很大, 它簡單調(diào)用中斷21h服務(wù)9來顯示字符串“This program cannot run in dos mode”。
PE文件的真正內(nèi)容劃分成塊, 稱之為Sections(節(jié))。 每節(jié)是一塊擁有共同屬性的數(shù)據(jù), 比如“.text”節(jié)等, 那么, 每一節(jié)的內(nèi)容都是什么呢?實際上PE格式的文件把具有相同屬性的內(nèi)容放入同一個節(jié)中, 而不必關(guān)心類似“.text”、“.data”的命名, 其命名只是為了便于識別, 所有, 我們?nèi)绻麑E格式的文件進(jìn)行修改, 理論上講可以寫入任何一個節(jié)內(nèi), 并調(diào)整此節(jié)的屬性就可以了。
PE header 接下來的數(shù)組結(jié)構(gòu)Section table(節(jié)表)。 每個結(jié)構(gòu)包含對應(yīng)節(jié)的屬性、文件偏移量、虛擬偏移量等。 如果PE文件里有5個節(jié), 那么此結(jié)構(gòu)數(shù)組內(nèi)就有5個成員。
以上就是PE文件格式的物理分布, 下面將總結(jié)一下裝載一PE文件的主要步驟:
1.PE文件被執(zhí)行, PE裝載器檢查dos MZ header里的PE header偏移量。 如果找到, 則跳轉(zhuǎn)到PE header。
2.PE裝載器檢查PE header的有效性。 如果有效, 就跳轉(zhuǎn)到PE header的尾部。
3.緊跟 PE header的是節(jié)表。 PE裝載器讀取其中的節(jié)信息, 并采用文件映射方法將這些節(jié)映射到內(nèi)存, 同時附上節(jié)表里指定的節(jié)屬性。
4.PE文件映射入內(nèi)存后, PE裝載器將處理PE文件中類似Import table(引入表)邏輯部分。
PE文件頭定義
我們可以在Winnt.h這個文件中找到關(guān)于PE文件頭的定義:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
//PE文件頭標(biāo)志 :“PE\0\0”。 在開始dos header的偏移3CH處所指向的地址開始
IMAGE_FILE_HEADER FileHeader; //PE文件物理分布的信息
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //PE文件邏輯分布的信息
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //該文件運(yùn)行所需要的CPU, 對于Intel平臺是14Ch
WORD NumberOfSections; //文件的節(jié)數(shù)目
DWORD TimeDateStamp; //文件創(chuàng)建日期和時間
DWORD PointerToSymbolTable; //用于調(diào)試
DWORD NumberOfSymbols; //符號表中符號個數(shù)
WORD SizeOfOptionalHeader; //OptionalHeader 結(jié)構(gòu)大小
WORD Characteristics; //文件信息標(biāo)記, 區(qū)分文件是exe還是dll
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; //標(biāo)志字(總是010bh)
BYTE MajorLinkerVersion; //連接器版本號
BYTE MinorLinkerVersion; //
DWORD SizeOfCode; //代碼段大小
DWORD SizeOfInitializedData; //已初始化數(shù)據(jù)塊大小
DWORD SizeOfUninitializedData; //未初始化數(shù)據(jù)塊大小
DWORD AddressOfEntryPoint;
PE裝載器準(zhǔn)備運(yùn)行的PE文件的第一個指令的RVA, 若要改變整個執(zhí)行的流程, 可以將該值指定到新的RVA, 這樣新RVA處的指令首先被執(zhí)行(以往許多文章都有介紹RVA, 請大家先了解)。
DWORD BaseOfCode; //代碼段起始RVA
DWORD BaseOfData; //數(shù)據(jù)段起始RVA
DWORD ImageBase; //PE文件的裝載地址
DWORD SectionAlignment; //塊對齊
DWORD FileAlignment; //文件塊對齊
WORD MajorOperatingSystemVersion;//所需操作系統(tǒng)版本號
WORD MinorOperatingSystemVersion;//
WORD MajorImageVersion; //用戶自定義版本號
WORD MinorImageVersion; //
WORD MajorSubsystemVersion; //win32子系統(tǒng)版本。 若PE文件是專門為Win32設(shè)計的
WORD MinorSubsystemVersion; //該子系統(tǒng)版本必定是4.0否則對話框不會有3維立體感
DWORD Win32VersionValue; //保留
DWORD SizeOfImage; //內(nèi)存中整個PE映像體的尺寸
DWORD SizeOfHeaders; //所有頭+節(jié)表的大小
DWORD CheckSum; //校驗和
WORD Subsystem; //NT用來識別PE文件屬于哪個子系統(tǒng)
WORD DllCharacteristics; //
DWORD SizeOfStackReserve; //
DWORD SizeOfStackCommit; //
DWORD SizeOfHeapReserve; //
DWORD SizeOfHeapCommit; //
DWORD LoaderFlags; //
DWORD NumberOfRvaAndSizes; //
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
//IMAGE_DATA_DIRECTORY 結(jié)構(gòu)數(shù)組。 每個結(jié)構(gòu)給出一個重要數(shù)據(jù)結(jié)構(gòu)的RVA, 比如引入地址表等
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //表的RVA地址
DWORD Size; //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
PE文件頭后是節(jié)表, 在winnt.h下如下定義
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//節(jié)表名稱,如“.text”
union {
DWORD PhysicalAddress; //物理地址
DWORD VirtualSize; //真實長度
} Misc;
DWORD VirtualAddress; //RVA
DWORD SizeOfRawData; //物理長度
DWORD PointerToRawData; //節(jié)基于文件的偏移量
DWORD PointerToRelocations; //重定位的偏移
DWORD PointerToLinenumbers; //行號表的偏移
WORD NumberOfRelocations; //重定位項數(shù)目
WORD NumberOfLinenumbers; //行號表的數(shù)目
DWORD Characteristics; //節(jié)屬性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;以上結(jié)構(gòu)就是在Winnt.h中關(guān)于PE文件頭的定義, 如何我們用C/C++來進(jìn)行PE可執(zhí)行文件操作, 就要用到上面的所有結(jié)構(gòu), 它詳細(xì)的描述了PE文件頭的結(jié)構(gòu)。 修改PE可執(zhí)行文件
現(xiàn)在讓我們把一段代碼寫入任何一個PE格式的可執(zhí)行文件, 代碼如下:
-- test.asm --
.386p
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
.code
start:
INVOKE MessageBoxA,0,0,0,MB_ICONINFORMATION or MB_OK
ret
end start以上代碼只顯示一個MessageBox框, 編譯后得到二進(jìn)制代碼如下:
unsigned char writeline[18]={
0x6a,0x40,0x6a,0x0,0x6a,0x0,0x6a,0x0,0xe8,0x01,0x0,0x0,0x0,0xe9,0x0,0x0,0x0,0x0
};好, 現(xiàn)在讓我們看看該把這些代碼寫到那。 現(xiàn)在用Tdump.exe顯示一個PE格式得可執(zhí)行文件信息, 可以發(fā)現(xiàn)如下描述:
Object table:
# Name VirtSize RVA PhysSize Phys off Flags
-- -------- -------- -------- -------- -------- --------
01 .text 0000CCC0 00001000 0000CE00 00000600 60000020 [CER]
02 .data 00004628 0000E000 00002C00 0000D400 C0000040 [IRW]
03 .rsrc 000003C8 00013000 00000400 00010000 40000040 [IR]
Key to section flags:
C - contains code
E - executable
I - contains initialized data
R - readable
W - writeable上面描述此文件中存在3個段及每個段的信息, 實際上我們的代碼可以寫入任何一個段, 這里我選擇“.text”段。 用光盤中提供的代碼可以得到一個PE格式可執(zhí)行文件的頭信息。
由于在PE格式的文件中, 所有的地址都使用RVA地址, 所以一些函數(shù)調(diào)用和返回地址都要經(jīng)過計算才可以得到。 以上都是我在實踐中的心得, 希望大家能夠得到受益, 另外如果大家有更好的思路和方法, 希望大家能告訴我, 多多交流。
(文中涉及到的源代碼已收錄到雜志配套光盤“雜志相關(guān)”欄目, 按文章名查找即可)
上面是電腦上網(wǎng)安全的一些基礎(chǔ)常識,學(xué)習(xí)了安全知識,幾乎可以讓你免費(fèi)電腦中毒的煩擾。