快速查询PE文件知识点和PE文件解析

本文详细介绍了PE(Portable Executable)文件的结构,包括PE节、基础知识点如基地址、虚拟地址和相对虚拟地址的关系,以及DOS头、NT头、数据目录项、区段头、导入表、导出表、重定位表的解析。同时指出代码中关于导入表、导出表和重定位表的部分存在一些问题,建议参考其他资源进行修正。
摘要由CSDN通过智能技术生成

PE(Portable Executable)

PE文件的全称是Portable Executable ,意为可移植的可执行文件,常见的有EXE,DLL,SYS,COM,OCX,PE文件是微软Windows操作系统上的程序文件

PE节

节名 说明
.text .text 节是供机器指令使用的默认节。一般情况下,在最终生成的可执行文件中,链接器将把每个.OBJ文件的.text节合并成一个巨大的、统一的.text节。
.data 全局和静态变量存储(在编译时初始化)
.bss 全局和静态变量存储(在编译时不初始化)
.textbss 启用增量链接
.rsrc .rsrc节用于储存模块资源,这些资源是可以嵌入到可执行文件中的二进制对象。例如,定制的鼠标光标、字体、程序图标、字符串表及版本信息都是标准的资源。资源还可以是应用程序需要的任意数据块(例如另一个可执行文件)。
.idata 存储有关导入库例程信息
.edata 存储有关导出库例程信息
.reloc 重定位
.rdata 数据段(只读)
.crt c++ 运行时库 runtime
.tls 线程局部存储

基础知识

  • 基地址(ImageBase):当PE文件通过Windows加载器载入内存后,内存中的版本称为模块,映射文件的起始地址称为模块句柄,可通过模块句柄访问内存中其他数据结构,这个内存起始地址就称为基地址。

  • 虚拟地址(VA,Virtual Address):在Windows系统中,PE文件被系统加载到内存后,每个程序都有自己的虚拟空间,这个虚拟空间的内存地址称为虚拟地址。

  • 相对虚拟地址(RVA,Relative Virtual Address):可执行文件中,有许多地方需要指定内存中的地址。例如,应用全局变量时需要指定它的地址。为了避免在PE文件中出现绝对内存地址引入了相对虚拟地址,它就是在内存中相对于PE文件载入地址的偏移量。

它们之间的关系:虚拟地址(VA) = 基地址(Image Base)+相对虚拟地址(RVA)

  • 文件偏移地址(Offset):当PE文件存储在磁盘中时,某个数据的位置相对于文件头的偏移量称为文件偏移地址(File Offset)。文件偏移地址从PE文件的第一个字节开始计数,起始值为0

PE 头解析

DOS头

DOS头和DOS存根,它们的存在主要是用来兼容DOS系统。当我们的程序运行在DOS系统的时候,就会运行DOS存根中的代码,代码内容就是输出一段字符串告诉用户,这个程序不能在16位系统运行。

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // DOS头签名,4D5A
    WORD   e_cblp;                      // 最后(部分)页中的字节数
    WORD   e_cp;                        // 文件中的全部和部分页数
    WORD   e_crlc;                      // 重定位表中的指针数
    WORD   e_cparhdr;                   // 头部尺寸,以段落为单位
    WORD   e_minalloc;                  // 所需的最小附加段
    WORD   e_maxalloc;                  // 所需的最大附加段
    WORD   e_ss;                        // 初始化的SS值(相对偏移量)
    WORD   e_sp;                        // 初始化的SP值
    WORD   e_csum;                      // 补码检验值
    WORD   e_ip;                        // 初始化的IP值
    WORD   e_cs;                        // 初始化的CS值(相对偏移量)
    WORD   e_lfarlc;                    // 重定位表的字节偏移量
    WORD   e_ovno;                      // 覆盖号
    WORD   e_res[4];                    // 保留字
    WORD   e_oemid;                     // OEM 标识符(相对 e_oeminfo)
    WORD   e_oeminfo;                   // OEM 信息; e_oemid specific
    WORD   e_res2[10];                  // 保留字
    LONG   e_lfanew;                    // PE头的偏移位置
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

DOS存根

在DOS头下方,是个可选项,大小不固定,由代码与数据混合而成,一般从0x40开始

标识头

#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_OS2_SIGNATURE                 0x454E      // NE
#define IMAGE_OS2_SIGNATURE_LE              0x454C      // LE
#define IMAGE_VXD_SIGNATURE                 0x454C      // LE
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

解析DOS头

#include<Windows.h>
#include<iostream>
using namespace std;

void ImageDosHeader(_In_z_ const char* path)
{
	// 获取文件对象
	HANDLE hfile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	// 获取文件大小
	DWORD fSize = GetFileSize(hfile, NULL);
	char* pBuff = new char[fSize];
	DWORD dwReadSize = 0;
	
	// 读文件
	BOOL bSuccess = ReadFile(hfile, pBuff, fSize, &dwReadSize, NULL);
	if (bSuccess)
	{
		PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBuff;
		// DOS头签名
		cout << hex << pDosHeader->e_magic << endl;
		// PE头的偏移位置
		cout << hex << pDosHeader->e_lfanew << endl;
	}
	else (cout.write("打开文件失败", 20));
	CloseHandle(hfile);
	delete[] pBuff;
}

void main()
{
	ImageDosHeader(R"(C:\Users\11981\Desktop\Project1\1.exe)");
}

NT头

typedef struct _IMAGE_NT_HEADERS64 {
    DWORD Signature; // 标识,0x00004550
    IMAGE_FILE_HEADER FileHeader; // 文件头
    IMAGE_OPTIONAL_HEADER64 OptionalHeader; // 可选头
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

NT头:文件头

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine; // 运行平台
    WORD    NumberOfSections; // 文件存在的区段数量
    DWORD   TimeDateStamp; // PE文件的创建时间,一般有连接器填写
    DWORD   PointerToSymbolTable; // COFF文件符号表在文件中的偏移
    DWORD   NumberOfSymbols; // 符号表的数量
    WORD    SizeOfOptionalHeader; // 可选PE头的大小
    WORD    Characteristics; // 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

Machine:运行平台

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST       0x0001  // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2  // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define 
搜索任意目录中的所有文件,并按照PE文件和非PE文件分类,并把PE文件按照PE文件头16字节分类。 结果如下: NO. PE_Header_HEX Number PE_Header_ASCII 1 4D 5A 90 00 03 00 11 11 11 11 10 00 FF FF 00 00 1 MZ? 2 4D 5A 90 00 03 00 01 11 11 11 11 00 FF FF 00 00 1 MZ? 3 4D 5A 90 00 03 00 00 00 11 11 10 00 FF FF 00 00 1 MZ? 4 4D 5A 90 00 03 00 00 00 01 11 00 00 FF FF 00 00 1 MZ? 5 4D 5A 90 00 03 00 00 01 11 10 00 00 FF FF 00 00 1 MZ? 6 4D 5A 90 00 03 00 00 00 11 11 11 10 FF FF 00 00 1 MZ? 7 4D 5A 90 11 11 11 11 10 04 00 00 00 FF FF 00 00 1 MZ? 8 4D 5A 90 00 03 00 11 11 04 01 10 00 FF 11 00 00 1 MZ? 9 4D 5A 90 01 13 00 00 00 04 00 00 01 11 FF 00 00 1 MZ? 10 4D 5A 90 00 03 00 00 01 11 11 11 11 1F FF 00 00 1 MZ? 11 4D 5A 44 56 41 50 41 11 11 11 14 6C 6C 00 6F 6C 1 MZDVAPA 12 4D 5A 72 75 6E 20 71 11 11 11 12 20 57 69 6E 33 1 MZrun qWin3 13 4D 5A 90 00 11 11 00 00 04 00 00 00 FF FF 00 00 1 MZ? 14 4D 5A 90 00 03 00 00 00 04 00 00 01 11 11 11 10 1 MZ? 15 4D 5A 50 00 02 00 00 00 04 00 0F 00 FF FF 01 10 1 MZP 16 4D 5A 50 00 02 00 00 10 04 11 11 00 FF FF 00 00 1 MZP 17 4D 5A 72 75 6E 20 75 E1 11 11 12 20 57 69 6E 33 1 MZrun u?Win3 18 4D 5A 90 54 68 69 73 20 70 72 6F 67 72 61 6D 20 2 MZ怲hiprogram 19 4D 5A D2 00 19 00 02 00 20 00 00 00 FF FF AD 02 1 MZ? 20 4D 5A 47 44 49 33 32 2E 64 6C 6C 00 55 53 45 52 2 MZGDI32.dll 21 4D 5A 90 00 03 00 02 22 22 22 22 20 FF FF 00 00 1 MZ? 22 4D 5A 50 00 02 00 00 00 04 00 0F 00 FF FF 00 00 2 MZP 23 4D 5A 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 6F 7MZKERNEL32.dll
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值