win32下PE文件分析之NT頭

win32下PE文件分析之NT頭

創(chuàng)新互聯(lián)自2013年起,是專業(yè)互聯(lián)網技術服務公司,擁有項目成都網站設計、成都做網站網站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元三穗做網站,已為上家服務,為三穗各地企業(yè)和個人服務,聯(lián)系電話:18982081108

接上一篇的win32下PE文件分析之DOS頭

(一)win32中PE的NT:

    NT頭是PE文件中標準PE頭和可選PE頭的總體稱謂,還包含一個PE標識.下面是它在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標識
    IMAGE_FILE_HEADER FileHeader;           //標準PE頭(也稱文件頭)
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; //可選PE頭
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

    第一個是64bit的NT頭定義,第二個是32bit的.這里只探討32bit的.標準PE頭也叫文件頭,這不重要,知道是那么個東西就行了,個人不太喜歡動不動就用高端名詞,高端名詞主要是為了嚴謹而取出來的,但是很多時候很晦澀,通俗易懂更易讓人接受.

(二).NT頭中的Signature:

    這就是一個PE標識,說明這是PE的開始位置.它在PE文件中的偏移由DOS頭中的最后一個成員e_lfanew決定,上一節(jié)解析了它的值為:0xE0,如圖:

win32下PE文件分析之NT頭

(三).NT頭中的標準PE頭:

    (1).NT頭中的標準PE頭數(shù)據(jù)寬度是0x14個字節(jié),在Visual C++ 6.0中的結構定義如下:

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).代碼的文件結構如下圖:每個解析頭函數(shù)定義分別放在不同的頭文件中,方便逐個頭結構的觀察,為了可以多熟悉即便各個頭的數(shù)據(jù)結構,每個函數(shù)中都重新從頭開始解析了一遍,這樣效率會降低.后面如果有空,會提供優(yōu)化了的代碼.(優(yōu)化思路:在解析一開始,就將各個頭的地址放進一個unsigned long*的全局數(shù)組里面,這樣在后面是用的時候就直接調用數(shù)組里的地址,而不用每次都重新定義DOS頭結構再依計算出各個結構的偏移.)

 win32下PE文件分析之NT頭


    (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頭中標準PE頭結構所在地址.
	IMAGE_FILE_HEADER* pfile = (IMAGE_FILE_HEADER*)&pnt->FileHeader;	
	printf("\nNT Header:\n");
	//PE標識,值與PE的ascii碼一一對應
	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默認是0xE0,64bit默認是0xF0)	
	printf("SizeOfOpHdr:	%#X\n", pfile->SizeOfOptionalHeader);
	//該文件的屬性(標識給文件的類型,如是exe還是dll或其他)	
	printf("Characteristics:	%#X\n", pfile->Characteristics);	
}

    注釋掉其他頭的解析:運行結果如下:

win32下PE文件分析之NT頭(四).NT頭中的可選PE頭:

    可選PE頭結構挺復雜,也最重要,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頭中的標準PE頭,根據(jù)結構計算出可選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);	
	//已經初始化數(shù)據(jù)大小的和.
	printf("SizeOfinitializedData:		%#X\n",pop->SizeOfInitializedData);
	//未初始化數(shù)據(jù)大小的和.
	printf("SizeOfuninitializedData:	%#X\n",pop->SizeOfUninitializedData);	
	//程序入口OEP
	printf("AddressOfEntryPoint:		%#X\n",pop->AddressOfEntryPoint);
	//內存鏡像基址
	printf("ImageBase:			%#X\n", pop->ImageBase);		
	//內存對齊			
	printf("SectionAlignment:		%#X\n", pop->SectionAlignment);	
	//文件對齊
	printf("FileAlignment:			%#X\n", pop->FileAlignment);
	//內存中整個PE文件的映射大小,可比實際的大,必須為內存對齊的整數(shù)倍			
	printf("SizeOfImage:			%#X\n", pop->SizeOfImage);
	//所有頭+節(jié)表文件對齊后的大小,嚴格按照文件對齊.
	printf("SizeOfHeaders:			%#X\n", pop->SizeOfHeaders);
	//校驗和,用來判斷文件是否被篡改.比如系統(tǒng)的一些dll加載時會用到.			
	printf("CheckSum:			%#X\n", pop->CheckSum);							
}

    注釋掉其他解析部分,運行結果如下圖:

win32下PE文件分析之NT頭

(五).說明:

    解析過程中最為麻煩的是計算偏移,多算幾次,多看下結構圖就好了.都是那么過來的.

網頁名稱:win32下PE文件分析之NT頭
瀏覽路徑:http://muchs.cn/article28/ppphjp.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站收錄關鍵詞優(yōu)化、品牌網站設計、標簽優(yōu)化、網頁設計公司定制開發(fā)

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都網頁設計公司