学习PE

PE结构和定义

pe大体结构,主要包含DOS Header和NT Header结构体.


DOS Header结构


DOS HEADER结构体定义

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number "MZ"
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

NT Header下FileHeader结构


FileHeader结构体定义

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;

NT Header下OPTIONAL HEADER结构

NT Head而下OPTIONAL HEADER结构体定义(分32位和64位,这里以32位为主)

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;

读取PE结构

1. 读取dos header的e_magic魔数

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>


//读取pe头
int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		printf("argc <2!\n");
		exit(EXIT_FAILURE);
	}

	FILE *pf = fopen(argv[1], "rb");    //以二进制方式读取pe程序
	if (!pf)
	{
		printf("%s is open failed!\n");
		exit(EXIT_FAILURE);
	}
	char magic[3] = { 0 };		    //只读取前两位
	fread(magic, 1, 2, pf);             //读取前两个字节
	fclose(pf);
	printf("magic[0]=%02X\n", magic[0]);
	printf("magic[1]=%02X\n", magic[1]);
	printf("magic=%s\n", magic);

	return 0;
}

输出结果:

PE结构中,魔数为'MZ'

读取File Header和Optional Header,并输出各个字段的值

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		printf("argc <2!\n");
		exit(EXIT_FAILURE);
	}



	//1.打开文件
	HANDLE hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

	DWORD file_size = GetFileSize(hFile, NULL);
	printf("file size:%d\n", file_size);
	printf("--------------dos_header---------------\n");

	IMAGE_DOS_HEADER dos_header = { 0 };

	//
	SetFilePointer(hFile, 0, NULL, FILE_BEGIN);

	DWORD num = 0;
	if (ReadFile(hFile, &dos_header, sizeof(IMAGE_DOS_HEADER), &num, NULL))
	{
		//dos header主要为了兼容pe文件在dos系统,能够运行并给出提示
		//dos header结构中的e_lfanew字段,是nt_header的起止位置
		long e_lfanew = dos_header.e_lfanew;
		printf("dos_header.e_lfanew:%08X\n", e_lfanew);
	}

	IMAGE_NT_HEADERS nt_hreader = { 0 };
	SetFilePointer(hFile, dos_header.e_lfanew, NULL, FILE_BEGIN);            //从e_lfanew开始读取
	if (ReadFile(hFile, &nt_hreader, sizeof(IMAGE_NT_HEADERS), &num, NULL))
	{
		printf("--------------nt_header---------------\n");
		printf("nt_hreader.Signature:%08X\n", nt_hreader.Signature);     //判断是不是pe文件
		if (nt_hreader.Signature == IMAGE_NT_SIGNATURE)
		{
			printf("nt_hreader.Signature=%s\n", "PE00");
		}


		printf("--------------file_header---------------\n");
		IMAGE_FILE_HEADER* file_header = &nt_hreader.FileHeader;
		printf("file_header.Machine:%04X\n", file_header->Machine);     //运行平台 i386->x86 
		printf("file_header.NumberOfSections:%04X\n", file_header->NumberOfSections);      //节数(重要)
		printf("file_header.TimeDateStamp:%08X\n", file_header->TimeDateStamp);		   //pe创建时间
		printf("file_header.PointerToSymbolTable:%08X\n", file_header->PointerToSymbolTable);   //符号表偏移
		printf("file_header.NumberOfSymbols:%08X\n", file_header->NumberOfSymbols);		//符号表数量
		printf("file_header.SizeOfOptionalHeader:%04X\n", file_header->SizeOfOptionalHeader);   //可选头大小
		printf("file_header.Characteristics:%04X\n", file_header->Characteristics);

		printf("---------------optional_header----------------\n");
		IMAGE_OPTIONAL_HEADER32* optional_header = &nt_hreader.OptionalHeader;
		printf("optional_header.Magic:%04X\n", optional_header->Magic);            //0X010B(32位程序) 0X020B(64位程序)
		printf("optional_header.MajorLinkerVersion:%02x\n", optional_header->MajorLinkerVersion);
		printf("optional_header.MinorLinkerVersion:%04X\n", optional_header->MinorLinkerVersion);
		printf("optional_header.SizeOfCode:%08X\n", optional_header->SizeOfCode);
		printf("optional_header.SizeOfInitializedData:%08X\n", optional_header->SizeOfInitializedData);
		printf("optional_header.SizeOfUninitializedData:%08X\n", optional_header->SizeOfUninitializedData);
		printf("optional_header.AddressOfEntryPoint:%08X\n", optional_header->AddressOfEntryPoint);
		printf("optional_header.BaseOfCode:%08X\n", optional_header->BaseOfCode);
		printf("optional_header.BaseOfData:%08X\n", optional_header->BaseOfData);

		printf("optional_header.ImageBase:%08X\n", optional_header->ImageBase);		       //基地址
		printf("optional_header.SectionAlignment:%08X\n", optional_header->SectionAlignment);  //段对齐大小
		printf("optional_header.FileAlignment:%08X\n", optional_header->FileAlignment);	       //文件对齐
		printf("optional_header.Subsystem:%04X",optional_header->Subsystem);	//
	}

	//关闭文件
	CloseHandle(hFile);

	return 0;
}

pe中的IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER32结构解析

解析PE文件算是完成一部分,后面主要是对节的学习,这篇拖了好长时间,代码早就写好了,只是不知道怎么写本篇博文.

秋风 2018-09-08