type
status
date
slug
summary
tags
category
icon
password
😀
PE格式是进行逆向分析的基础
学习中使用的工具及文档
密码:4bo5

📝 PE文件

PE文件的概念

PE(Protable Executable File Format)可移植的执行体文件格式

可执行文件

  • 可执行文件(executable file)指的是可以由操作系统进行加载的文件
  • 可执行文件格式
Windows PE(Portable Executable)文件结构(.EXE,.DLL,.SYS)

PE文件的识别

这里我使用的是WinHex拖到WinHex里面
notion image
首先我们要注意到的是,在WinHex/010editor当中,数据是小端排序的
👉
小端排序:例如0x11223344,小端排序就是 44 33 22 11
PE文件的标志
开头的0x4D5A,其实就是我们的MZ头,而我们PE文件的标志就是
(base+0x3C处去四个字节),例如上图就是0x00000060,它指向的就是PE头,我们在地址0x00000060处得到的四个字节 0x00004550就是我们的PE头,这就是我们PE文件的标志

PE文件结构

notion image
但是这个图一开始看,我们肯定脑子就非常的混乱,因此笔者选择一个比较简单的图进行学习
notion image
其实我们把这些看成一个一个的文件夹
例如在上图中有三个大的文件夹:PE文件头,Section,Debug Information
而PE文件头里面也包含Dos头部,IMAGE_NT_HEADERS ,Section Table…
notion image
我们可以用PEtools查看petools
notion image
我们可以选择”O”选项,然后会看到IMAGE_OPTIONAL_HEADER部分,这里我先了解到
👉
程序的入口点: ImageBase+EntryPoint
我们可以用x96dbg看一下,是不是一样
notion image
如果初始的话就是系统断点,我们需设置入口断点
notion image
notion image
设置完以后再运行就是断到入口点
notion image

HEADER-IMAGE_DOS_HEADER

  • IMAGE_DOS_HEADER结构是面对16位程序的,现在大部分程序都是32或者64位的。
  • 32或64位的程序仅使用其中两个成员。
e_magic: 该成员为MZ标记(DOS系统开发人员中一个人的名字),用于判断是否为可执行文件,如果此值不是0x5a4d程序将不会正常启动。
e_lfanew: 该成员中存储的值为IMAGE_NT_HEADERS结构的偏移,加上文件头来定位IMAGE_NT_HEADERS结构。
IMAGE_DOS_HEADER结构之后的IMAGE_NT_HEADERS 结构之前的数据为垃圾值编译器填充称为DOS_SUB,可随意修改,不会影响程序正常运行。
修改后的DOS_SUB
notion image
还是可以正常运行
notion image

读取IMAGE_DOS_HEADER

Main.c
Tools.c
Tools.h
notion image
notion image

IMAGE_NT_HEADER

通过IMAGE_DOS_HEADER中成员 e_lfanew+文件起始地址可以定位IMAGE_NT_HEADER结构
IMAGE_NT_HEADER结构定义如下:
notion image
Signature:成员为PE文件标识,该值必须为0x00004550(’P’’E’’0’’0’)否则程序无法正常启动
 
FileHeader:成员指向了标准PE头IMAGE_FILE_HEADER
 
OptionalHeader:成员指向了扩展PE头IMAGE_OPTIONAL_HEADER

IMAGE_FILE_HEADER

标准PE头位于IMAGE_NT_HEADER中,紧挨着PE标记。(IMAGE_NT_HEADER+4)
  • IMAGE_FILE_HEADER大小为20字节。(0x14)
IMAGE_FILE_HEADER结构如下:
notion image
Machine:该成员用来指定PE文件运行的平台.定义如下:
NumberOfSections:该成员表示了PE文件中节的总数(虽然是2字节,但是节最大值不能超过96)
 
TimeDateStamp:该成员为时间戳,编译器创建此文件时的时间戳.32位存放的值是自1970年1月1日00:00时开始到创建时间为止的总秒数.该数值可以随意修改而不会影响程序运行。
 
SizeOfOptionalHeader:该成员制定了IMAGE_OPTIONAL_HEADER结构的大小即拓展PE头大小,32位PE文件扩展PE头大小默认为0xE0,64位PE文件扩展PE头大小默认为0xF0。
 
Characteristics:该成员为PE文件属性标志字段(是否可执行,是否为DLL等等)此值每一位都代表不同含义,如下图所示:

读取IMAGE_FILE_HEADER

notion image
notion image

IMAGE_OPTIONAL_HEADER

IMAGE_OPTIONAL_HEADER结构定义:
notion image
notion image
Magic:魔术字,表示了PE文件类型
常量符号
常量值
含义
IMAGE_NT_OPTIONAL_HDR32_MAGIC
0x10b
PE32
IMAGE_NT_OPTIONAL_HDR64_MAGIC
0x20b
PE64
AddressOfEntryPoint:表示了程序入口地址,该值是一个RVA,加上Imagebase为程序在内存中的入口地址(OEP)。如果在一个可执行文件中附加了一段自己的代码,并且想让这段代码首先被执行,需要修改这里的值指向自己的代码位置。 对于普通程序来说它就是启动地址;对于设备驱动程序来说它是初始化函数的地址入口点对于DLL来说是可选的,如果不存在入口点,这个字段必须设置为0
 
ImageBase:指出PE文件的优先载入内存中的起始地址,如果这个地址已经被占用,操作系统会重新分配(DLL会出现这种情况),这时就需要重定位表提供的数据来修复,EXE首先加载不会出现这种情况,大部分EXEimagebase默认为0x400000。 此值可随便修改,不能超出虚拟地址空间以及必须是64KB的整数倍,并修复重定位数据即可正常运行。
 
SectionAlignment:内存中节的对齐粒度,该字段指定了节被装入内存后的对齐单位.Win32的页面大小是4KB,所以Win32PE文件中节的内存对齐粒度般都为4KB大小,十六进制表示为10ooh.SectionAlignment必须大于或等于FileAlignment.当它小于系统页面大小时,必须保证SectionAlignment与FileAlignment相等
 
FileAlignment:文件中节的对齐粒度,Win32PE文件中节的文件对齐粒度一般都为200h,Windows会选择使用512字节的大小(一个物理扇区的大小).
 
SizeOfImage:表示内存中整个PE文件的映射尺寸,必须是SectionAlignment的整数倍.(该值可以比实际的值大,但不能比它小).
 
基地址(Imagebase)
虚拟内存地址(VA - Virtual Address) = 基地址(Imagebase) + 相对虚拟基址(RVA)
相对虚拟地址(RVA - Relative Virtual Address) = VA - 基地址(Imagebase)
文件偏移地址(FOA - File offset Address)

读取IMAGE_OPTIONAL_HEADER

notion image

IMAGE_SECTION_HEADER

IMAGE_SECTION_HEADER
  • 每个节表项记录了PE中与某个特定的节有关的信息,如节的属性,节的大小,节在文件和内存中的起始位置等.节表中节的数量由IMAGE_FILE_HEADER.NumberOfSection来定义
通过WinHex定位第一个节表:
notion image
Name:节表名称.大小8字节.一般情况下是以”\0”结尾的ASCII码字符串.如果不是以“\0”结尾,系统会截取8个字节的长度进行处理.内容可自定义.
  • 常见样式
.data
初始化的数据
.idata
导入表
.rsrc
资源数据
.reloc
基地址重定位表
.edata
导出表
.tls
thread local storage,线程局部存储器
.rdata
存放调试目录和说明字符串
Misc.VirtualSize:节在内存中实际的大小(单位为字节)。默认为编译器填充。
 
VirtualAddress:该值为RVA(Relative Virtual Address)相对虚拟地址,必须是SectionAlignment的整数倍.节在内存中的偏移地址.加上ImageBase才是在内存的地址.
 
SizeOfRawData:节在文件中按照文件对齐后的大小(单位为字节).必须是FileAlignment的整数倍.
notion image
节的属性很多,这里只记几个常见的
👉
这里的属性在在文件中的体现是多个属性进行异或的

读取IMAGE_SECTION_HEADER

notion image

BUFFER-FileBufferToImageBuffer

👉
用到的样例:bgview.exe
Header在内存中的体现
notion image
在内存中我们以文件大小对齐为标准
notion image
我们可以看到SectionAlignment为0x1000,FileAlignment为0x200,在前面学习中我们提到SizeOfImage的大小为FileAlignment的整数倍.
notion image
这里我们复习一下IMAGE_SECTION_HEADER的结构
首先前8个字节为节的名称,接下来的4个字节0x05dc68为它的内存大小,后面的4个字节0x1000为在内存的偏移,后面4个字节0x05DE00为它的文件大小,再后面的4个字节0x400为文件的偏移
notion image
👉
在内存中都按文件大小对齐,不足的补0
notion image

实现缓存转换

我们要实现从FileBuffer——>ImageBuffer的转变
notion image

RVA-FOA的转换

notion image
我们是为了实现RVA(虚拟内存地址)到FOA(文件偏移地址)的转变.
Main.c
Tool.c

EXPORT

LIB

我们为啥导入头文件之后可以直接调用strlen
notion image
原因是在我们导入头文件之后在生成工程的时候会调用静态链接库
notion image

DLL

所谓DLL就是动态链接库(Dynamic-link library)
声明导出
notion image
notion image
但其实这个时候程序默认的是_cdecl,你命名的是什么导出表里面就显示的是什么
notion image
我们把它改成_stdcall
notion image
我们发现这个名字变成了_Add@8,后面这个@8其实就是指的是参数的大小
我们如果想调用dll文件可以这样
notion image
我们也可以自己定义模块
notion image
notion image

IMAGE_EXPORT_DIRECTORY

PE中的导出表通常存在于动态链接库文件里.有些EXE也会存在导出表.导出表的的主要作用是将PE中存在的函数引出到外部,以便其他人可以使用这些函数,实现代码的重用.导出表的存在可以让程序的开发者很容易清楚PE中到底有多少可以使用的函数.
IMAGE_EXPORT_DIRECTORY
我们定位到 IMAGE_DATA_DIRECTORY DataDirectory的位置,在这个数组里面第一个值就是导出表
notion image
但是这是RVA,我们需要转变成FOA
notion image
定位到文件中
notion image
解析每个部分
notion image
这里面有好多RVA,因此我们在后面进行读取的时候需要进行转换

读取IMAGE_EXPORT_DIRECTORY

Import

IMAGE_IMPORT_DESCRIPTOR

读取IMAGE_IMPORT_DESCRIPTOR

RELOCATION

IMAGE_BASE_RELOCATION

RepairRelocation

读取IMAGE_BASE_RELOCATION

 
 
 
 
 
 
 
 
 
 
 

🤗总结归纳

总结文章的内容

📎 参考文章

  • 一些引用
  • 引用文章
 
💡
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
周报(三)关于NotionNext评论系统的搭建(Twikoo)
Loading...
5m10v3
5m10v3
目前主攻方向为Re
Announcement
🎉5m10v3のBlog已经上线啦🎉
-- 感谢各位师傅的支持 ---
👏欢迎师傅们前来交流👏