rgb565和rgb555的文件头区别_Windows可执行文件格式
前言
下文提及的相關(guān)數(shù)據(jù)結(jié)構(gòu),代碼片段均為64位環(huán)境,32位環(huán)境會(huì)加以標(biāo)注.
? PE文件
PE(即Portable?Executable)表示可移植的可執(zhí)行文件,是Windows平臺(tái)原生的可執(zhí)行代碼載體(此處要區(qū)別于NET的IL,?JAVA的字節(jié)碼等),Windows平臺(tái)所有可以被加載執(zhí)行的文件都遵從PE文件格式。
注:在linux平臺(tái)下的可執(zhí)行文件都遵從ELF文件格式,PE與ELF文件格式都繼承于Unix的COFF文件格式,由此可見,雖然不同平臺(tái)上的可執(zhí)行文件不能兼容,但是從設(shè)計(jì)思想上有很多共通之處。
PE文件格式詳解
文件數(shù)據(jù)結(jié)構(gòu)布局
(網(wǎng)上有很多查看PE文件格式的工具,我常用010editor配合其EXE模版)
注:010editor模版所顯示的在Section Data后還有其他內(nèi)容,這只是模版的顯示,相關(guān)內(nèi)容其實(shí)還是在某個(gè)Section Data內(nèi)部,但是由于其有特殊用途,故被模版單獨(dú)展示。
由上圖所示,一個(gè)PE文件有定長部分和不定長部分,這也體現(xiàn)了PE文件格式良好的可擴(kuò)展性和兼容性。
定長部分:
DOS?header?+?DOS?Stub?+?NT?header
不定長部分:
Section?header[n]?+?Section?data[n]
磁盤布局與內(nèi)存布局
一個(gè)PE文件,在加載運(yùn)行前后的布局這里我叫做磁盤布局和內(nèi)存布局,這兩種布局由于不同時(shí)期的對(duì)齊粒度不同導(dǎo)致有所差異:磁盤布局的對(duì)齊粒度是0x200,內(nèi)存布局的對(duì)齊粒度是0x1000。
所以這里就有一個(gè)偏移地址轉(zhuǎn)換的問題,PE文件中大體上有四類地址:
虛擬內(nèi)存地址(VA):RVA +?加載基地址
相對(duì)虛擬地址(RVA):內(nèi)存偏移
文件偏移地址(FOA):文件偏移
特殊地址:這中地址很少見,在資源節(jié)中有使用,其計(jì)算方式類似于匯編相對(duì)跳轉(zhuǎn)的計(jì)算
相關(guān)數(shù)據(jù)結(jié)構(gòu)(依次說明)
//DOS?Header結(jié)構(gòu)typedef?struct?_IMAGE_DOS_HEADER
{
?????WORD?e_magic;????????//DOS文件簽名?0x4d5a
?????WORD?e_cblp;
?????WORD?e_cp;
?????WORD?e_crlc;
?????WORD?e_cparhdr;
?????WORD?e_minalloc;
?????WORD?e_maxalloc;
?????WORD?e_ss;
?????WORD?e_sp;
?????WORD?e_csum;
?????WORD?e_ip;
?????WORD?e_cs;
?????WORD?e_lfarlc;
?????WORD?e_ovno;
?????WORD?e_res[4];
?????WORD?e_oemid;
?????WORD?e_oeminfo;
?????WORD?e_res2[10];
?????LONG?e_lfanew;????????//NT頭偏移
}?IMAGE_DOS_HEADER,?*PIMAGE_DOS_HEADER;
其中最重要的是e_magic和e_lfanew字段,e_magic字段是文件頭,固定值0x4D5A,e_lfanew:NT頭的文件偏移,通常是0xE8
//DOS?Stub這是一小段Dos程序,當(dāng)在Dos系統(tǒng)下運(yùn)行時(shí),會(huì)打印出"This?program?cannot?be?run?in?DOS?mode",現(xiàn)在基本不會(huì)用到。
//NT?header結(jié)構(gòu)
typedef?struct?_IMAGE_NT_HEADERS64?{
??DWORD???????????????????Signature;????????//PE簽名,0x4550
??IMAGE_FILE_HEADER???????FileHeader;????????//文件頭
??IMAGE_OPTIONAL_HEADER64?OptionalHeader;????//可選頭
}?IMAGE_NT_HEADERS64,?*PIMAGE_NT_HEADERS64;
//File?Header結(jié)構(gòu)
typedef?struct?_IMAGE_FILE_HEADER?{
??WORD??Machine;????????????????????????????//運(yùn)行平臺(tái)
??WORD??NumberOfSections;????????????????????//Section?Header的數(shù)目
??DWORD?TimeDateStamp;????????????????????????//編譯時(shí)間戳
??DWORD?PointerToSymbolTable;????????????????//COFF符號(hào)表指針
??DWORD?NumberOfSymbols;????????????????????//符號(hào)數(shù)目
??WORD??SizeOfOptionalHeader;????????????????//可選頭大小,32位與64位大小不同
??WORD??Characteristics;????????????????????//屬性,實(shí)際上是一個(gè)bitmap
}?IMAGE_FILE_HEADER,?*PIMAGE_FILE_HEADER;
運(yùn)行平臺(tái):
| IMAGE_FILE_MACHINE_I386(0x014c) | x86 |
| IMAGE_FILE_MACHINE_IA64(0x0200) | Intel Itanium |
| IMAGE_FILE_MACHINE_AMD64(0x8664) | x64 |
//IMAGE_FILE_HEADER.Characteristics字段
struct?FILE_CHARACTERISTICS?Characteristics?{
????WORD?IMAGE_FILE_RELOCS_STRIPPED?:?1????????????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_EXECUTABLE_IMAGE?:?1????????????//置1表示該文件為exe文件。
????WORD?IMAGE_FILE_LINE_NUMS_STRIPPED?:?1??????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_LOCAL_SYMS_STRIPPED?:?1?????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_AGGRESIVE_WS_TRIM?:?1???????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_LARGE_ADDRESS_AWARE?:?1?????????//該應(yīng)用程序可以處理大于2G的地址。
????WORD?IMAGE_FILE_BYTES_REVERSED_LO?:?1???????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_32BIT_MACHINE?:?1???????????????//置1表示希望是32位平臺(tái)
????WORD?IMAGE_FILE_DEBUG_STRIPPED?:?1??????????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP?:?1?????//置1表示該程序不能在可移動(dòng)介質(zhì)中運(yùn)行。
????WORD?IMAGE_FILE_NET_RUN_FROM_SWAP?:?1???????????//置1表示該程序不能在網(wǎng)絡(luò)中運(yùn)行。
????WORD?IMAGE_FILE_SYSTEM?:?1??????????????????????//在可執(zhí)行文件中沒有使用。
????WORD?IMAGE_FILE_DLL?:?1?????????????????????????//置1表示文件是一個(gè)動(dòng)態(tài)鏈接庫。
????WORD?IMAGE_FILE_UP_SYSTEM_ONLY?:?1??????????????//置1該文件應(yīng)僅在單處理器計(jì)算機(jī)上運(yùn)行。
????WORD?IMAGE_FILE_BYTES_REVERSED_HI?:?1???????????//在可執(zhí)行文件中沒有使用。
}
//IMAGE_OPTIONAL_HEADER64結(jié)構(gòu)
typedef?struct?_IMAGE_OPTIONAL_HEADER64?{
??WORD?????????????????Magic;????????????????????????//判斷是32還是64位可執(zhí)行映像
??BYTE?????????????????MajorLinkerVersion;????????????//鏈接器主版本號(hào)
??BYTE?????????????????MinorLinkerVersion;????????????//鏈接器此版本號(hào)
??DWORD????????????????SizeOfCode;????????????????????//多個(gè)代碼段大小
??DWORD????????????????SizeOfInitializedData;????????//多個(gè)初始化數(shù)據(jù)段大小
??DWORD????????????????SizeOfUninitializedData;????????//多個(gè)為初始化數(shù)據(jù)段大小
??DWORD????????????????AddressOfEntryPoint;????????????//代碼入口點(diǎn)的RVA
??DWORD????????????????BaseOfCode;????????????????????//代碼段基址
??ULONGLONG????????????ImageBase;????????????????????//加載基址
??DWORD????????????????SectionAlignment;????????????//內(nèi)存對(duì)齊粒度,默認(rèn)為頁面大小4k
??DWORD????????????????FileAlignment;????????????????//文件對(duì)齊粒度
??WORD?????????????????MajorOperatingSystemVersion;????//操作系統(tǒng)主版本號(hào)
??WORD?????????????????MinorOperatingSystemVersion;????//操作系統(tǒng)此次版本號(hào)
??WORD?????????????????MajorImageVersion;????????????//可執(zhí)行文件主版本號(hào)
??WORD?????????????????MinorImageVersion;????????????//可執(zhí)行文件次版本號(hào)
??WORD?????????????????MajorSubsystemVersion;????????//子系統(tǒng)主版本號(hào)
??WORD?????????????????MinorSubsystemVersion;????????//子系統(tǒng)此次版本號(hào)
??DWORD????????????????Win32VersionValue;????????????//保留,必須為0
??DWORD????????????????SizeOfImage;????????????????????//占用內(nèi)存的大小,需對(duì)齊
??DWORD????????????????SizeOfHeaders;????????????//定長部分+SectionHeader數(shù)組的大小,需對(duì)齊
??DWORD????????????????CheckSum;????????????????????//校驗(yàn)和
??WORD?????????????????Subsystem;????????????????????//所需子系統(tǒng)環(huán)境
??WORD?????????????????DllCharacteristics;????????????//映像屬性
??ULONGLONG????????????SizeOfStackReserve;????????????//棧保留大小
??ULONGLONG????????????SizeOfStackCommit;????????????//棧提交大小
??ULONGLONG????????????SizeOfHeapReserve;????????????//堆保留大小
??ULONGLONG????????????SizeOfHeapCommit;????????????//堆提交大小
??DWORD????????????????LoaderFlags;????????????????????//在可執(zhí)行文件中沒有使用。
??DWORD????????????????NumberOfRvaAndSizes;????????????//DataDirectory表表項(xiàng)的數(shù)目
??IMAGE_DATA_DIRECTORY?DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];????//DataDirectory表
}?IMAGE_OPTIONAL_HEADER64,?*PIMAGE_OPTIONAL_HEADER64;
可選頭雖說名字叫可選頭,但是確是PE?件中最不可缺少的部分,其中 DataDirectory 數(shù)組尤為重要,??是系統(tǒng)加映像時(shí),初始化資源的重要數(shù)據(jù)的索引,數(shù)組?共有16項(xiàng),?項(xiàng)保留,其余15項(xiàng)分別對(duì)應(yīng)15種資源索引,由于篇幅原因, DataDirectory 會(huì)在后?的?章中單獨(dú)詳細(xì)解讀。
以上就是PE?件中的定?結(jié)構(gòu)部分,下?是不定?的Section Header數(shù)組和各個(gè)Section Data。
//Section?Header數(shù)組就是由一項(xiàng)一項(xiàng)的IMAGE_SECTION_HEADER結(jié)構(gòu)構(gòu)成//IMAGE_SECTION_HEADER結(jié)構(gòu)
typedef?struct?_IMAGE_SECTION_HEADER?{
??BYTE??Name[IMAGE_SIZEOF_SHORT_NAME];????//char類型的八字節(jié)數(shù)組,保存section的名稱
??union?{
????DWORD?PhysicalAddress;
????DWORD?VirtualSize;
??}?Misc;????????????????????????????????//section加載到內(nèi)存的大小
??DWORD?VirtualAddress;????????????????????//section起始地址的RVA
??DWORD?SizeOfRawData;????????????????????//Misc.VirtualSize內(nèi)存對(duì)齊后的大小
??DWORD?PointerToRawData;????????????????//section起始地址的文件偏移
??DWORD?PointerToRelocations;????????????//指向該部分的重定位條目的文件偏移。為0則沒有重定位。
??DWORD?PointerToLinenumbers;????????????//未使用
??WORD??NumberOfRelocations;????????????//未使用
??WORD??NumberOfLinenumbers;????????????//未使用
??DWORD?Characteristics;????????????????//section屬性
}?IMAGE_SECTION_HEADER,?*PIMAGE_SECTION_HEADER;
section常?屬性:
| IMAGE_SCN_CNT_CODE(0x00000020) | 本節(jié)包含可執(zhí)行代碼。 |
| IMAGE_SCN_CNT_INITIALIZED_DATA(0x00000040) | Section 含初始化數(shù)據(jù)。 |
| IMAGE_SCN_CNT_UNINITIALIZED_DATA(0x00000080) | Section 含未初始化的數(shù)據(jù)。 |
| IMAGE_SCN_GPREL(0x00008000) | 本節(jié)包含通過全局指針引用的數(shù)據(jù)。 |
| IMAGE_SCN_LNK_NRELOC_OVFL(0x01000000) | 本節(jié)包含擴(kuò)展的重定位。 |
| IMAGE_SCN_MEM_SHARED(0x10000000) | 該部分可以在內(nèi)存中共享。 |
| IMAGE_SCN_MEM_EXECUTE(0x20000000) | 該部分可以作為代碼執(zhí)行。 |
| IMAGE_SCN_MEM_READ(0x40000000) | 可讀 |
| IMAGE_SCN_MEM_WRITE0x80000000 | 可寫 |
其他不常用標(biāo)志見后面 MSDN 鏈接。
最后說明一下文件偏移和內(nèi)存相對(duì)偏移的計(jì)算:FOA = RVA - VirtualAddress + PointerToRawData首先要判斷的的RVA地址所落在的section,條件是VirtualAddress <= RVA < VirtualAddress + SizeOfRawData附上我寫的轉(zhuǎn)換代碼,?個(gè)殼的代碼?段:
/*參數(shù):RVA:內(nèi)存相對(duì)偏移,pNT:指向NT頭的指針
返回:轉(zhuǎn)換后的文件偏移
*/
UINT32?RvaToOffset(UINT32?RVA,?PIMAGE_NT_HEADERS?pNT){
????UINT32?NumberOfSections?=?pNT->FileHeader.NumberOfSections;?//獲取Section數(shù)量
????UINT32?offset?=?0;
????PIMAGE_SECTION_HEADER?pSH?=?(PIMAGE_SECTION_HEADER)((UINT64)pNT?+?sizeof(IMAGE_NT_HEADERS));????//獲取Section?header數(shù)組
????for?(UINT32?i?=?0;?i?????{????????pSH->Characteristics?|=?IMAGE_SCN_MEM_WRITE;????//為每個(gè)section添加寫屬性????????if?(RVA?>=?pSH->VirtualAddress&&?RVA?VirtualAddress?+?pSH->SizeOfRawData)????????{????????????offset?=?RVA?-?pSH->VirtualAddress?+?pSH->PointerToRawData;????????}????}????return?offset;}
常?section?
這些都是VS編譯器?成的,??的數(shù)據(jù)帶有特定作?.
.bss:存放未初始化數(shù)據(jù)
.data:存放初始化數(shù)據(jù)
.edata:存放導(dǎo)出表
.idata:存放導(dǎo)?表
.pdata:存放異常信息
.rdata:存放初始化的只讀數(shù)據(jù)
.reloc:存放重定位信息
.rsrc:存放資源數(shù)據(jù)
.text:存放可執(zhí)?代碼
.xdata:存放異常信息
?定義section
//在vs中可以通過以下方式自定一個(gè)section,命名為syclover#pragma?data_seg("syclover")?
char?WhoAmI[]?=?"syclover!";?
#pragma?data_seg()
注:SectionHeadr和SectionData并不是一一對(duì)應(yīng)的關(guān)系,例如.bss段,占內(nèi)存但是并不占文件空間,在文件中可以找到.bss段對(duì)應(yīng)的SectionHeadr條目,但是并沒有對(duì)應(yīng)的SectionData存在,
參考
https://blog.csdn.net/liuyez123/article/details/51281905
https://docs.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-image_nt_headers64
https://docs.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-image_section_header
長
按
關(guān)
注
三葉草小組公眾號(hào)
微信號(hào) : 三葉草小組Syclover
新浪微博:@三葉草小組Syclover
在與你相遇的路上馬不停蹄~
總結(jié)
以上是生活随笔為你收集整理的rgb565和rgb555的文件头区别_Windows可执行文件格式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql两列数据去重_CiteSpac
- 下一篇: cad绘制椭圆的方法有几种_你还在头疼C