目录
什么是PE?
什么是PEView?
分析PE文件
什么是DOS头?
IMAGE_DOS_HEADER是干嘛的?
DOS块是干嘛的?
什么是NT头?
Signatrue?
IMAGE_FILE_HEADER?
IMAGE_OPTIONAL_HEADER?
section头?
1.找到 NT 头的起始偏移地址、结束地址?
参考博客:https://blog.csdn.net/hou09tian/article/details/100397525
PE文件是Portable Executable(可移植的可执行文件)的简写。EXE、DLL、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件。
PE的结构:
PEview.exe工具是一款可以进行PE文件解析的强大PE文件解析工具。通过PEview软件,我们一起来分析PE文件的详细格式。
参考博客:https://blog.csdn.net/hou09tian/article/details/100404142,(都是一个博主写的,很简练,跟着学习)。
在VS2015中,新建一个控制台程序,不输入任何代码,编译生成exe文件,该exe文件就是一个PE文件。
我没有安装VS2015,用codeblocks去试一下, 额,不知道对不对,新建了个helloworld初始的exe:
用PEView打开看:
左侧的树形控件显示了PE文件的格式,而右侧则显示的是PE文件的头部和数据的具体内容。
PE文件头部中的DOS头分为MZ文件头和DOS块,分别对应的是IMAGE_DOS_HEADER和MS-DOS Stub Program。
IMAGE_DOS_HEADER STRUCT
{
+0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
+2h WORD e_cblp // Bytes on last page of file
+4h WORD e_cp // Pages in file
+6h WORD e_crlc // Relocations
+8h WORD e_cparhdr // Size of header in paragraphs
+0ah WORD e_minalloc // Minimun extra paragraphs needs
+0ch WORD e_maxalloc // Maximun extra paragraphs needs
+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS
+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP
+12h WORD e_csum // Checksum
+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口
+18h WORD e_lfarlc // File Address of relocation table
+1ah WORD e_ovno // Overlay number
+1ch WORD e_res[4] // Reserved words
+24h WORD e_oemid // OEM identifier(for e_oeminfo)
+26h WORD e_oeminfo // OEM information;e_oemid specific
+29h WORD e_res2[10] // Reserved words
+3ch DWORD e_lfanew // Offset to start of PE header 指向PE文件头
} IMAGE_DOS_HEADER ENDS
e_magic:一个WORD类型,值是一个常数0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'MZ'开头。
e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。
有用的只有两个数据,一个是 e_magic 固定为 “MZ”,另外一个是最后的 e_lfanew ,指向pe头
整个开头占64byte(字节)
- 前两个字节0x4D和0x5A,是字母“M”和“Z”的ASCII码,是MS-DOS设计者Mark Zbikowski的姓名缩写。
- 最后四个字节,表示下一个头部,即NT头的偏移地址,,该值是0x00000080,即NT头的起始地址是0x00000080。
- (左边高地址高字节右边低地址低字节小端显示,关于地址大小端之类的问题我在栈溢出那个博客里有写。)
- 这两个标志之间的是PE文件在MS-DOS环境下运行时所需要的一些参数,点击左侧树形控件的“IMAGE_DOS_HEADER”,在右侧既可以看到这些参数的具体值。
- MS-DOS stub Program中包含了一个字符串,
- 当PE文件在DOS环境下运行时,就会显示该字符串,来提示用户PE程序必须在Windows下才能运行。
“MS-DOS stub Program”即为DOS块。
DOS块是一个在DOS环境下可以运行的程序,在图所示的界面中点击左侧的“MS-DOS stub Program”,则会在右侧显示该程序的数据
PE文件在DOS环境下运行时,会显示该字符串“This program cannot be run in DOS mode”。
先来看文件头的结构:
typedef struct IMAGE_NT_HEADERS
{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
如图:
点击PEview左侧树形控件中的“IMAGE_NT_HEADERS”左侧的“+”,展开NT头结构,看到NT头包括Signatrue、IMAGE_FILE_HEADER和IMAGE_OPTIONAL_HEADER三部分。
IMAGE_FILE_HEADER部分共20字节。
从上往下看,
①头两个字节表示机器类型,用于标识CPU的类型,后两个字节表示CPU为Intel 386或后继处理器及其兼容处理器;
②接下来的Number of Section表示节的数目,0x0010表示本应用程序有16个节(section),从图中可以看出,本应用程序确实有16个节(section);
③第三个Time date stamp表示时间,这里没有值,如果有值可以换算成十进制秒然后再换算成年月日之类的,看到这个博客https://www.cnblogs.com/bokernb/articles/6116512.html
讲的很细致,里面好像说这个值是程序已经存在的时间啥的。
④Size of optional header这两个字节是IMAGE_OPTIONAL_HEADER,即NT头的第三部分的大小,其值为0x00E0;
0x00E0就是十进制的224,也就是说OptionalHeader的大小是224字节。
⑤Characteristics这两个字节指定了文件特征值,其值为0x0107。
Characteristics表示文件属性,它的每一个bit都代表了某种含义。
Bit 0 :置1表示文件中没有重定向信息。每个段都有它们自己的重定向信息。
这个标志在可执行文件中没有使用,在可执行文件中是用一个叫做基址重定向目录表来表示重定向信息的,这将在下面介绍。
Bit 1 :置1表示该文件是可执行文件(也就是说不是一个目标文件或库文件)。
Bit 2 :置1表示没有行数信息;在可执行文件中没有使用。
Bit 3 :置1表示没有局部符号信息;在可执行文件中没有使用。
Bit 4 :
Bit 7
Bit 8 :表示希望机器为32位机。这个值永远为1。
Bit 9 :表示没有调试信息,在可执行文件中没有使用。
Bit 10:置1表示该程序不能运行于可移动介质中(如软驱或CD-ROM)。在这 种情况下,OS必须把文件拷贝到交换文件中执行。
Bit 11:置1表示程序不能在网上运行。在这种情况下,OS必须把文件拷贝到交换文件中执行。
Bit 12:置1表示文件是一个系统文件例如驱动程序。在可执行文件中没有使用。
Bit 13:置1表示文件是一个动态链接库(DLL)。
Bit 14:表示文件被设计成不能运行于多处理器系统中。
Bit 15:表示文件的字节顺序如果不是机器所期望的,那么在读出之前要进行
交换。在可执行文件中它们是不可信的(操作系统期望按正确的字节顺序执行程序)。或者 看这:https://www.cnblogs.com/findumars/p/5037657.html
IMAGE_OPTIONAL_HEADER头由两部分组成:参数部分和数据目录部分;OptionalHeader,占224个字节
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
值得注意的是:DataDirectory
DataDirectory,占用128个字节,为一个IMAGE_DATA_DIRECTORY structure结构体数组(16个)。
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
这个结构体有两个成员,一个成员占用4个字节,也就是8个字节。这个数组有16个数据,也就是16*8=128字节。
对应关系:
.bss 未初始化的数据
.data 代码节
.edata 导出表
.idata 导入表
.pdata 异常信息
.rdata 只读的已初始化数据(常量)
.reloc 重定位信息
.rsrc 资源目录
.sbss 与GP相关的未初始化数据
.sdata 与GP相关的已初始化数据
.text 默认代码节
.idlsym 包含已注册的SEH,以支持IDL
查看默认代码节的节头:
Characteristics各位含义
1-5 未使用 6 此节包含可执行代码
7 此节包含已初始化的数据 8 此节包含未初始化的数据
9-15 未使用 16 此节包含通过全局指针来引用的数据
17-24 未使用 25 此节包含扩展的重定位信息
26 此节可以在需要时被丢弃 27 此节不能被缓存
28 此节不能被交换到页面文件中 29 此节可以在内存中共享
30 此节可以作为代码执行 31 此节可读
32 此节可写
0x60500060转化成二进制:1 10000 00101 00000 00000 00011 00000(位数由低到高对照)
对照着表看到,第6,7,21,23,30,31是1:该PE文件的默认代码节包含可执行代码、已初始化数据、可以作为代码执行,可读。
如下图:
可以直接找到起始偏移地址和结束地址:
https://www.cnblogs.com/bokernb/articles/6116512.html
PE文件的结构在磁盘和内存中是基本一样的,但在装入内存中时又不是完全复制。
Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或访问某一页中的数据时,这个页才会被从磁盘提交到物理内存。
但因为装载可执行文件时,有些数据在装入前会被预先处理(如需要重定位的代码),装入以后,数据之间的相对位置也可能发生改变。因此,一个节的偏移和大小在装入内存前后可能是完全不同的。