大神论坛

找回密码
快速注册
查看: 780 | 回复: 0

[原创] PE学习笔记一 PE介绍

主题

帖子

6

积分

初入江湖

UID
31
积分
6
精华
威望
12 点
违规
大神币
68 枚
注册时间
2021-04-10 16:01
发表于 2021-04-18 22:30
本帖最后由 ttegame 于 2021-04-18 22:30 编辑

PE学习笔记系列

PE学习笔记一 PE介绍

PE学习笔记二 PE文件的两种状态

PE学习笔记三 DOS部分
PE学习笔记四 PE文件头之标准PE头
PE学习笔记五 PE文件头之扩展PE头
PE学习笔记六 节表和节
PE学习笔记七 RVA与FOA转换
PE学习笔记八 实战之HOOK程序添加弹窗
PE学习笔记九 实战之HOOK程序添加弹窗续
PE学习笔记十 扩大节
PE学习笔记十一 新增节
PE学习笔记十二 修正内存对齐
PE学习笔记十三 合并节
PE学习笔记十四 导出表
PE学习笔记十五 导入表
PE学习笔记十六 代码重定位
PE学习笔记十七 重定位表


PE

需要用到的工具

十六进制文本编辑工具:WinHex和UltraEdit

工具论坛随便一搜或者百度就有,这里就不提供了

工具的作用

首先要明确任何文件在计算机的存储都是0或1(二进制)

上面的两个工具就是用于查看文件在计算机存储的内容

由于0和1比较冗长,所以使用十六进制来显示数据


准备好工具后正式开始学习PE

学习PE前需要先了解一下可执行文件

可执行文件

什么是可执行文件

可执行文件 (executable file) 指的是可以由操作系统进行加载执行的文件

可执行文件的格式

Windows平台

PE(Portable Executable)文件结构

翻译为:可移植(这里的可移植局限于Windows平台,不同版本的Win10 Win7 WinXp等)         可执行

Linux平台

ELF(Executable and Linking Format)文件结构

翻译为:执行 和 连接 格式


常见可执行文件

.exe        .sys .dll等都是windows下的可执行文件(它们都遵循PE文件结构的格式


常见非可执行文件

  • .txt .png .mp4等等都是非可执行文件,它们都需要使用其它可执行文件的软件进行加载
  • .txt可以使用Notepad、UltraEdit等 文本 工具查看
  • .png可以使用PhotoShop等 图片 工具查看
  • .mp4可以使用PotPlayer等 播放器 工具查看

为什么要学习PE

  • PE文件是Windows可执行程序必须满足的规范
  • 对软件的加壳和脱壳都基于PE
  • EXE文件如何加载到内存中也涉及PE的知识
  • 一个合格的逆向人员,必须熟悉PE

如何识别PE文件

PE文件特征(PE指纹)

前2个字节

分别用UltraEdit打开.exe .dll .sys 文件,观察特征前2个字节

本人使用的三个文件分别为:

.exe:EverEdit.exe(文本编辑工具)

.dll:dbghelp.dll(调试跟踪相关的一个dll,在C:\Windows\System32\dbghelp.dll里拷贝的)

.sys:passTp.sys(自己写的一个驱动程序,作用嘛大家懂的( ̄︶ ̄)↗ )


.exe

image-20210315131655743


.dll

image-20210315131945543


.sys

image-20210315132009119


可以看到这三个文件的头2个字节都是4D 5A(ASCII码为MZ)


3Ch位置数据

再看这三个文件各自位于3Ch位置的数据

.exe

image-20210315132930095

数据为:F0


.dll

image-20210315133001665

数据为F8


.sys

image-20210315133223414

数据为D8


对应数据的位置

.exe

先前的数据为F0,查看对应F0位置的2字节数据

image-20210315133439402


.dll

先前的数据为F8,查看对应F8位置的2字节数据

image-20210315133615072


.sys

先前的数据为D8,查看对应D8位置的2字节数据

image-20210315133744785


可以看到无论是exe、dll还是sys,通过上述方式找到的数据都为:50 45(对应ACSII码为PE)

小总结

如果一个文件,它的头两个字节为4D 5A(ASCII码为MZ),并且通过3Ch位置的数据再找到的位置里的数据为PE则基本可以断定这个文件是Windows下的可执行文件(满足PE结构)


反例

随便拉一个图片png文件进来看看

image-20210315134549954

很显然,开头的两个字节就已经表明它不是一个PE文件了

PS:识别可执行文件不能通过文件的后缀名来判断,而应该采用上述的方式进行判断,因为后缀名是可以改的ˋ( ° ▽、° )


PE文件总体结构

通过前面可以得知如何识别一个文件是否是PE文件

但是前面在前面为什么是查看一个文件的前2个字节和3Ch的位置,以及其它位置数据作用呢

这便是PE结构所规定

下面是PE文件的总体结构


image-20210315144634951


可以看到先前判断PE文件特征里的头两个字节对应这里的文件头:DOS ‘MZ’ HEADER

后面根据3Ch得到的50 45(对应ACSII码为PE)对应这里的PE文件头中的"PE"


PE在C中的定义

PE文件结构自然是一种数据结构,不过这种数据结构比较复杂

在C语言的winnt.h这个头文件中定义了PE文件结构相关的结构体

可以通过C语言中PE的定义来更好地学习PE


随便创建一个空的控制台项目,然后引入winnt.h这个头文件

#include<winnt.h>
int main(int argc, char* argv[])
{
        return 0;
}

然后在头文件这里右键→打开文档<winnt.h>即可

image-20210315141418626


接下来结合winnt.h这个头文件学习PE文件的总体结构:

DOS部首

该部分结构对应winnt.h中的_IMAGE_DOS_HEADER结构体

可以在先前打开的winnt.h中Ctrl+F搜索_IMAGE_DOS_HEADER

image-20210315141855795


查找后得到:

image-20210315141946400


对应代码为:

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

关于DOS头里的成员的具体说明这里暂且不表,留作的笔记再详细说明

这里主要说明一下各部分的大体作用

首先的这个DOS部首,可以说是Windows的历史遗留问题了,因为Windows程序最早是在DOS系统(16位系统)上运行的

所以该部分主要是给DOS用的(向下兼容)


PE文件头(NT头)

该部分结构对应winnt.h中的_IMAGE_NT_HEADERS结构体

使用同样的方法得到对应的代码:

 复制代码 隐藏代码
typedef struct _IMAGE_NT_HEADERS {     DWORD Signature;     IMAGE_FILE_HEADER FileHeader;     IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

可以看到PE文件头对应的结构体中还包含了其它结构体,这里依旧只介绍大体作用,细节留作之后的笔记

这里的PE文件头相对于先前的DOS部首则是给Windows使用的


块表(节表)

该部分结构对应winnt.h中的_IMAGE_SECTION_HEADER结构体

使用同样的方法得到对应的代码:

 复制代码 隐藏代码
typedef struct _IMAGE_SECTION_HEADER {     BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];     union {             DWORD   PhysicalAddress;             DWORD   VirtualSize;     } Misc;     DWORD   VirtualAddress;     DWORD   SizeOfRawData;     DWORD   PointerToRawData;     DWORD   PointerToRelocations;     DWORD   PointerToLinenumbers;     WORD    NumberOfRelocations;     WORD    NumberOfLinenumbers;     DWORD   Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

块表主要用来表示当前文件一共分为几个部分,和后面的块相对应

块表决定了后面的块,每一块从哪里开始,里面存储的数据是什么等等


块部分是由前面的块表决定的,是具体的存储数据的部分

image-20210315144652675


总结

image-20210315195059766

PE

返回顶部