PE(Portable Executeable File Format)可移植的执行文体格式,我们平时常见的exe\dll\sys等都是PE文件的一种。PE文件的组成可以被分为PE Head和PE Body,我们先从PE文件头的Dos头部说起。
DOS头部分为两部分:第一部分是DOS MZ头第二部分是DOS Stub(指令字节码)。
以下为DOS MZ头部微软给出的定义,其中我学习中用到的最关键两个字段就是e_magic和e_lfanew,分别用来确定是否是PE文件和寻址NT Headers的首地址
typedef struct _IMAGE_DOS_HEADER // DOS .EXE header
{
WORD e_magic; //魔术字 0x4d5a 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; //DOS头部距离NT头部的偏移
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
Dos Stub大多数时候是由编译器自动生成,其长度是PE文件链接生成时确定的,其长度在不同的PE文件中不一定相同,其紧跟在DOS MZ头部的下面,整个时一个字节块,PE中没有与之相关的结构体。所以我们不可以直接用 Dos Heaher基地址+sizeof(IMAGE_DOS_HEADER)的方式定位到Nt头部。
接下来附上一点我的测试代码和定位到NT头的代码:
TCHAR* CPEHelper::GetFileMemPointer(TCHAR* FileFullPath,DWORD* m_FileSize)
{
//打开文件获取句柄
HANDLE FileHandle = CreateFile(
FileFullPath,
GENERIC_READ, //只读
FALSE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
MessageBox(0, _T("文件打开失败\r\n"), 0, 0);
return NULL;
}
//获取文件大小
DWORD FileSize = GetFileSize(FileHandle, NULL);
*m_FileSize = FileSize; //文件大小返出值
//申请内存 用来存放PE文件数据
TCHAR* BuferData = new TCHAR[FileSize] {};
//读文件
DWORD ReturnLength;
ReadFile(FileHandle, BuferData, FileSize, &ReturnLength, NULL);
//关闭文件句柄
if (FileHandle != NULL)
{
CloseHandle(FileHandle);
FileHandle = NULL;
}
//返回PE文件起始位置(基址)
return BuferData;
}
//.......判断PE文件的一部分代码
PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;//FileBuffer = 上面函数返回的BufferData
if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
//#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
return FALSE;
}
//定位到Nt头部
PIMAGE_NT_HEADERS ImageNtHeaders =
(PIMAGE_NT_HEADERS)(ImageDosHeader->e_lfanew + (ULONG)FileBuffer);
Next:IMAGE_NT_HEADERS
“梅须逊雪三分白,雪却输梅一段香。”
参考书籍:
《Windows PE权威指南》
联系客服