您的位置:首页 > 其它

PE文件-检验PE文件的有效性--转自iczelion,附vc示范

2011-07-16 22:49 656 查看
同样我首先附上Iczelion的PE文档:
如何才能校验指定文件是否为一有效PE文件呢? 这个问题很难回答,完全取决于想要的精准程度。您可以检验PE文件格式里的各个数据结构,或者仅校验一些关键数据结构。大多数情况下,没有必要校验文件里的每一个数据结构,只要一些关键数据结构有效,我们就认为是有效的PE文件了。下面我们就来实现前面的假设。
我们要验证的重要数据结构就是 PE header。从编程角度看,PE header 实际就是一个 IMAGE_NT_HEADERS 结构。定义如下:
IMAGE_NT_HEADERS STRUCT
Signature dd ?
FileHeader IMAGE_FILE_HEADER <>
OptionalHeader IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS

Signature 一dword类型,值为50h, 45h, 00h, 00h(PE\0\0)。 本域为PE标记,我们可以此识别给定文件是否为有效PE文件。
FileHeader 该结构域包含了关于PE文件物理分布的信息, 比如节数目、文件执行机器等。
OptionalHeader 该结构域包含了关于PE文件逻辑分布的信息,虽然域名有"可选"字样,但实际上本结构总是存在的。
我们目的很明确。如果IMAGE_NT_HEADERS的signature域值等于"PE\0\0",那么就是有效的PE文件。实际上,为了比较方便,Microsoft已定义了常量IMAGE_NT_SIGNATURE供我们使用。
IMAGE_DOS_SIGNATURE equ 5A4Dh
IMAGE_OS2_SIGNATURE equ 454Eh
IMAGE_OS2_SIGNATURE_LE equ 454Ch
IMAGE_VXD_SIGNATURE equ 454Ch
IMAGE_NT_SIGNATURE equ 4550h
接下来的问题是: 如何定位 PE header? 答案很简单: DOS MZ header 已经包含了指向 PE header 的文件偏移量。DOS MZ header 又定义成结构IMAGE_DOS_HEADER 。查询windows.inc,我们知道 IMAGE_DOS_HEADER 结构的e_lfanew成员就是指向 PE header 的文件偏移量。
现在将所有步骤总结如下:
首先检验文件头部第一个字的值是否等于 IMAGE_DOS_SIGNATURE是则 DOS MZ header 有效。
一旦证明文件的 DOS header 有效后,就可用e_lfanew来定位 PE header 了。
比较 PE header 的第一个字的值是否等于IMAGE_NT_HEADER。如果前后两个值都匹配,那我们就认为该文件是一个有效的PE文件。
以下vc验证代码:
#include <windows.h>

#include <iostream>

#define PE_FILE_NAME TEXT("C:\\WINDOWS\\system32\\notepad.exe")
#define CREATE_FILE_FAILURE "创建文件失败"
#define CREATE_MAPPING_FILE "创建文件映射对象失败"
#define MAP_VIEW_FAILURE "映射文件到调用进程的地址空间失败"
#define VALID_DOS_SIGNATURE "这个文件的DOS签名是有效的"
#define VALID_PE_SIGNATURE "这个文件的PE签名是有效的"
#define VALID_PE_FILE "这是一个有效的PE文件"
#define INVALID_PE_FILE "这是一个无效的PE文件"

#define WRITE_LINE(msg) std::cout << TEXT(msg) << std::endl;
#define WRITE_LINE_EX(msg1,msg2) std::cout << TEXT(msg1) << TEXT(msg2) << std::endl;
#define WRITE(msg) std::cout << TEXT(msg);
#define PROCESS_FAILURE(msg) WRITE_LINE(msg)\
return FALSE;

#define PE_PARSE_NT_HEADER_CALLBACK void (*PARSE_NT_HEADER_CALLBACK)(IMAGE_NT_HEADERS*)=NULL
#define PE_PARSE_SECTION_HEADER_CALLBACK void (*PARSE_SECTION_HEADER_CALLBACK)(IMAGE_SECTION_HEADER*,INT)=NULL
#define PE_PARSE_IMPORT_TABLE_CALLBACK void (*PARSE_IMPORT_TABLE_CALLBACK)(IMAGE_DATA_DIRECTORY*,PVOID)

/* 根据文件头获得文件节表头 */
#define GET_IMAGE_SECTION_HEADER(lpNtHeader) ((IMAGE_SECTION_HEADER *)((byte*)lpNtHeader+sizeof(*lpNtHeader)))
/* 根据文件头获得文件节数量 */
#define GET_IMAGE_NUMBER_OF_SECTIONS(lpNtHeader) (lpNtHeader->FileHeader.NumberOfSections)
/* 虚拟地址到文件偏移量 */
#define RVA_TO_OFFSET(pImageBase,rva) ((PVOID)((byte*)pImageBase+rva))

/* 映射文件到内存映像 */
PVOID MapFileToView(LPCSTR filename);
/* 获得PE文件头 */
IMAGE_NT_HEADERS* GetPeHeader(LPVOID pMapping);
/* 验证PE合法性函数 */
BOOL Validate(LPVOID pMapping);
/* 分析PE头函数 */
void PARSE_NT_HEADER_CALLBACK(IMAGE_NT_HEADERS* lpNtHeader);
/* 分析PE节表函数 */
void PARSE_SECTION_HEADER_CALLBACK(IMAGE_SECTION_HEADER* lpSectionHeader,INT numberOfSections);
/* 分析引入表 */
void PARSE_IMPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase);
/* 将相对虚拟地址转换为文件偏移地址 */
DWORD RVAToFileOffset(PVOID,DWORD);
/* 显示DLL的所有引入函数 */
void PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(PVOID,IMAGE_THUNK_DATA*);

void main()
{
//将文件映射到内存
PVOID pMapping = MapFileToView(PE_FILE_NAME);
//获取文件头
IMAGE_NT_HEADERS* lpImageNtHeader = GetPeHeader(pMapping);

if (lpImageNtHeader)
{
//显示文件头信息
PARSE_NT_HEADER_CALLBACK(lpImageNtHeader);
//显示文件节头信息
PARSE_SECTION_HEADER_CALLBACK(GET_IMAGE_SECTION_HEADER(lpImageNtHeader),GET_IMAGE_NUMBER_OF_SECTIONS(lpImageNtHeader));
//分析导入表
PARSE_IMPORT_TABLE_CALLBACK(&(lpImageNtHeader->OptionalHeader.DataDirectory[1]),pMapping);
}

//取消映射
UnmapViewOfFile(pMapping);
pMapping = NULL;

}

/* 映射文件到内存映像 */
PVOID MapFileToView(LPCSTR filename)
{
HANDLE fHandle = ::CreateFile(filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (fHandle==INVALID_HANDLE_VALUE)
{
PROCESS_FAILURE(CREATE_FILE_FAILURE);
}

HANDLE hMapping = ::CreateFileMapping(
fHandle,
NULL,
PAGE_READONLY,
NULL,
NULL,
NULL
);
if (hMapping==NULL)
{
CloseHandle(fHandle);
PROCESS_FAILURE(CREATE_MAPPING_FILE);
}

LPVOID pMapping = ::MapViewOfFile(hMapping,FILE_MAP_READ,NULL,NULL,NULL);
if (pMapping==NULL)
{

PROCESS_FAILURE(MAP_VIEW_FAILURE);
}
CloseHandle(hMapping);
CloseHandle(fHandle);
hMapping = NULL;
fHandle = NULL;
return pMapping;
}

/* 验证PE入口函数 */
BOOL Validate(LPVOID pMapping)
{

//1.validate IMAGE_DOS_HEADER
IMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER*)pMapping;
// 	if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)
// 	{
// 		WRITE_LINE(VALID_DOS_SIGNATURE);
// 	}

IMAGE_NT_HEADERS * nt_header=(IMAGE_NT_HEADERS*)((byte*)pMapping+dosHeader->e_lfanew);
// 	if (nt_header->Signature == IMAGE_NT_SIGNATURE)
// 	{
// 		WRITE_LINE(VALID_PE_SIGNATURE);
// 	}

// 	WRITE_LINE(
// 		(
// 		dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE?
// 		TEXT(VALID_PE_FILE):
// 	TEXT(INVALID_PE_FILE)
// 		)
// 		);

return dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: