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验证代码:
如何才能校验指定文件是否为一有效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; }
相关文章推荐
- PE文件-导出表[EXPORT TABLE]--转自iczelion,附vc示范和图例
- PE文件-节表--转自iczelion,附vc示范
- PE教程2: 检验PE文件的有效性
- PE文件-分析vc示范所有代码[不包含EXPORT TABLE]
- PE文件-分析vc示范所有代码[包含EXPORT TABLE]
- PE教程2: 检验PE文件的有效性
- PE教程2: 检验PE文件的有效性
- VC编译出来的PE文件大小优化
- VC++中的DUMPBIN 工具用来查看PE(可移植执行体)文件(EXE、dll。。。)
- 《Windows核心编程》---检测PE文件有效性
- VC读取PE文件的OEP(程序入口)
- vc编写自己的壳之一:对pe文件OEP的修改
- VC实现简单的PE文件感染(增加的是downloader功能)
- VC中改变PE文件中Dos Stub程序(显示This program cannot be run in DOS mode)那一段程序.
- PE文件基础补注(VC + 纯API版)
- VC修改PE文件字符串(类似木马生成器)
- 验证PE文件有效性
- VC PE导出/输入表演示(文件影射版本)
- 为pe文件添加CRC32自效验的小程序(vc)
- (高手勿进)为pe文件添加CRC32自效验的小程序(vc)