PE文件是Windows系统中任何可执行模块或者DLL的文件格式。PE即Portable Executable,它是Win32环境自身所带的执行文件格式。PE文件是跨Win32平台的,也就是说即使是运行在非intel CPU上的Windows都能够被PE转载器识别和使用该文件格式。
PE文件以64字节的DOS文件头(IMAGE_DOS_HEADER结构)开始,之后是一小段DOS程序,然后是248字节的NT文件头(IMAGE_NT_HEADERS结构)。NT文件头的偏移地址由IMAGE_DOS_HEADER结构的e_lfanew成员给出。
所有常见的PE结构定义在winnt.h头文件中。我们谈论两个结构,即IMAGE_DOS_HEADER和IMAGE_NT_HEADERS。
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; //DOS可执行文件标记,为”MZ”。依此识别DOS头是否有效
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; //IMAGE_NT_HEADERS结构的地址
} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //PE文件标识,为”PE/0/0”。依此识别NT文件头是否有效
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
在IMAGE_DOS_HEADER中,e_magic为DOS可执行文件标记;e_lfanew是相对实际PE头标的相对偏移量,也就是IMAGE_NT_HEADERS结构的地址。在IMAGE_NT_HEADERS中,我们只使用Signature这个成员,它是PE文件的标识(PE/0/0)。
为了方便编程,在winnt.h中位DOS标识和PE标识定义宏:
#define IMAGE_DOS_SIGNATURE 0x5A4D //MZ
#define IMAGE_NT_SIGNATURE 0x00004550 //PE00
检测PE文件有效性程序的步骤:
1)使用CreateFile打开要检测的文件,判断是否是IMAGE_DOS_SIGNATURE来检测是否是有效的DOS头;
2)使用e_lfanew来定位PE头,接着通过判断是否是IMAGE_NT_SIGNATURE来检测文件的有效性;
3)最后使用closeHandle来关闭已打开的文件的句柄。
//定义PE文件中的DOS头和NT头
IMAGE_DOS_HEADER dosHeader;
IMAGE_NT_HEADERS ntHeaders;
BOOL bValid = FALSE;
//第一步,打开要检测的文件
hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARED_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//第二步,检测DOS头部的有效性
ReadFile(hFile, &dosHeader, sizeof(dosHeader), &dwRead, NULL);
if(dwRead == sizeof(dosHeader))
{
if(IMAGE_DOS_SIGNATURE == dosHeader.e_magic)
{
//第三步,定位image_nt_headers的位置
if(SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN))
{
ReadFile(hFile, &ntHeaders, sizeof(ntHeaders), &dwRead, NULL);
if(dwRead == sizeof(ntHeaders))
{
//最后一步,检测PE头部的有效性
if(IMAGE_NT_SIGNATURE == ntHeaders.Signature)
{
bValid = TRUE;
}
}
}
}
}
if(bValid)
MessageBox("该程序是有效PE文件");
else
MessageBox("该程序不是有效的PE文件");
closeHandle(hFile);