創(chuàng)新互聯(lián)自2013年起,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站設(shè)計、成都做網(wǎng)站網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元三穗做網(wǎng)站,已為上家服務(wù),為三穗各地企業(yè)和個人服務(wù),聯(lián)系電話:18982081108
接上一篇的win32下PE文件分析之DOS頭
(一)win32中PE的NT:
NT頭是PE文件中標(biāo)準(zhǔn)PE頭和可選PE頭的總體稱謂,還包含一個PE標(biāo)識.下面是它在Visual C++ 6.0中WINNT.h中的定義:
typedef struct _IMAGE_NT_HEADERS64 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; typedef struct _IMAGE_NT_HEADERS { DWORD Signature; //PE標(biāo)識 IMAGE_FILE_HEADER FileHeader; //標(biāo)準(zhǔn)PE頭(也稱文件頭) IMAGE_OPTIONAL_HEADER32 OptionalHeader; //可選PE頭 } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
第一個是64bit的NT頭定義,第二個是32bit的.這里只探討32bit的.標(biāo)準(zhǔn)PE頭也叫文件頭,這不重要,知道是那么個東西就行了,個人不太喜歡動不動就用高端名詞,高端名詞主要是為了嚴(yán)謹(jǐn)而取出來的,但是很多時候很晦澀,通俗易懂更易讓人接受.
(二).NT頭中的Signature:
這就是一個PE標(biāo)識,說明這是PE的開始位置.它在PE文件中的偏移由DOS頭中的最后一個成員e_lfanew決定,上一節(jié)解析了它的值為:0xE0,如圖:
(三).NT頭中的標(biāo)準(zhǔn)PE頭:
(1).NT頭中的標(biāo)準(zhǔn)PE頭數(shù)據(jù)寬度是0x14個字節(jié),在Visual C++ 6.0中的結(jié)構(gòu)定義如下:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
(2).代碼的文件結(jié)構(gòu)如下圖:每個解析頭函數(shù)定義分別放在不同的頭文件中,方便逐個頭結(jié)構(gòu)的觀察,為了可以多熟悉即便各個頭的數(shù)據(jù)結(jié)構(gòu),每個函數(shù)中都重新從頭開始解析了一遍,這樣效率會降低.后面如果有空,會提供優(yōu)化了的代碼.(優(yōu)化思路:在解析一開始,就將各個頭的地址放進一個unsigned long*的全局?jǐn)?shù)組里面,這樣在后面是用的時候就直接調(diào)用數(shù)組里的地址,而不用每次都重新定義DOS頭結(jié)構(gòu)再依計算出各個結(jié)構(gòu)的偏移.)
(3).解析文件頭的代碼如下(代碼中都只是輸出部分重要的數(shù)據(jù),博客中代碼列數(shù)的限制,注釋一行放不下,不美觀):
file.h
void Output_File(void* buffer) { void* buf = buffer; //計算偏移時有用 IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf; //pnt存放NT頭的地址. IMAGE_NT_HEADERS32* pnt = (IMAGE_NT_HEADERS32*)((unsigned char*)buf + pdos->e_lfanew); //pfile存放NT頭中標(biāo)準(zhǔn)PE頭結(jié)構(gòu)所在地址. IMAGE_FILE_HEADER* pfile = (IMAGE_FILE_HEADER*)&pnt->FileHeader; printf("\nNT Header:\n"); //PE標(biāo)識,值與PE的ascii碼一一對應(yīng) printf("PE: %#X\n", pnt->Signature); printf("File Header:\n"); //輸出程序能在哪種CPU平臺上運行. printf("Machine: %#X\n", pfile->Machine); //輸出PE文件中節(jié)的數(shù)量 printf("NumberOfSec: %#X\n", pfile->NumberOfSections); //時間戳,文件的創(chuàng)建時間,一般有編譯器填充,修改后不會影響程序運行 printf("TimeStamp: %#X\n", pfile->TimeDateStamp); //可選PE頭的大小(32bit默認(rèn)是0xE0,64bit默認(rèn)是0xF0) printf("SizeOfOpHdr: %#X\n", pfile->SizeOfOptionalHeader); //該文件的屬性(標(biāo)識給文件的類型,如是exe還是dll或其他) printf("Characteristics: %#X\n", pfile->Characteristics); }
注釋掉其他頭的解析:運行結(jié)果如下:
(四).NT頭中的可選PE頭:
可選PE頭結(jié)構(gòu)挺復(fù)雜,也最重要,32bit的和64bit的有點不同.在Visual C++ 6.0中winnt.h中定義如下:
typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
解析文件頭的代碼如下:
void Output_Optional(void* buffer) { void* buf = buffer; //計算偏移時使用 IMAGE_DOS_HEADER* pdos = (IMAGE_DOS_HEADER*)buf; //pop中存放可選PE頭的起始位置, 0x4是NT頭中PE表示,0x14是NT頭中的標(biāo)準(zhǔn)PE頭,根據(jù)結(jié)構(gòu)計算出可選PE頭的偏移 IMAGE_OPTIONAL_HEADER32* pop = (IMAGE_OPTIONAL_HEADER32*)((unsigned char*)buf + pdos->e_lfanew + 0x4 + 0x14); printf("Optional PE Header:\n"); //說明文件的類型,010B為32bit的PE文件,020B為64bit的PE文件 printf("Magic: %#X\n", pop->Magic); //所有代碼節(jié)的和,大小必須是FileAlignment的整數(shù)倍,有編譯器填充,修改無影響. printf("SizeOfCode: %#X\n",pop->SizeOfCode); //已經(jīng)初始化數(shù)據(jù)大小的和. printf("SizeOfinitializedData: %#X\n",pop->SizeOfInitializedData); //未初始化數(shù)據(jù)大小的和. printf("SizeOfuninitializedData: %#X\n",pop->SizeOfUninitializedData); //程序入口OEP printf("AddressOfEntryPoint: %#X\n",pop->AddressOfEntryPoint); //內(nèi)存鏡像基址 printf("ImageBase: %#X\n", pop->ImageBase); //內(nèi)存對齊 printf("SectionAlignment: %#X\n", pop->SectionAlignment); //文件對齊 printf("FileAlignment: %#X\n", pop->FileAlignment); //內(nèi)存中整個PE文件的映射大小,可比實際的大,必須為內(nèi)存對齊的整數(shù)倍 printf("SizeOfImage: %#X\n", pop->SizeOfImage); //所有頭+節(jié)表文件對齊后的大小,嚴(yán)格按照文件對齊. printf("SizeOfHeaders: %#X\n", pop->SizeOfHeaders); //校驗和,用來判斷文件是否被篡改.比如系統(tǒng)的一些dll加載時會用到. printf("CheckSum: %#X\n", pop->CheckSum); }
注釋掉其他解析部分,運行結(jié)果如下圖:
(五).說明:
解析過程中最為麻煩的是計算偏移,多算幾次,多看下結(jié)構(gòu)圖就好了.都是那么過來的.
網(wǎng)頁名稱:win32下PE文件分析之NT頭
瀏覽路徑:http://jinyejixie.com/article28/ppphjp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、關(guān)鍵詞優(yōu)化、品牌網(wǎng)站設(shè)計、標(biāo)簽優(yōu)化、網(wǎng)頁設(shè)計公司、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)