WindowsPE文件格式入门02.选项头其它和节表
https://www.bpsend.net/thread-444-1-1.html
选项头 IMAGE_OPTIONAL_HEADER:以供操作系统加载PE文件使用,32位必选。
重要字段:
DWORD AddressOfEntryPoint; 入口点
DWORD ImageBase 建议模块地址
DWORD SectionAlignment; 内存对齐值
DWORD FileAlignment; 文件对齐值,
DWORD SizeOfImage; 模块在内存中总大小,与 SectionAlignment 对齐
DWORD SizeOfHeaders; PE头总大小,与 FileAlignment 对齐
IMAGE_OPTIONAL_HEADER 结构体
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic; // 32位PE: IMAGE_NT_OPTIONAL_HDR32_MAGIC , 0x10b.
// 以 _IMAGE_OPTIONAL_HEADER 结构体解析
// 64位PE: IMAGE_NT_OPTIONAL_HDR64_MAGIC , 0x20b.
// 以 _IMAGE_OPTIONAL_HEADER64 结构体解析
BYTE MajorLinkerVersion; // 主链接器版本号 (无用)
BYTE MinorLinkerVersion; // 副链接器版本号 (无用) //系统分配内存不看着3个值,但是对于调试器有影响(影响反汇编所用内存大小,OD是机器码个数*2,字节数是通过SizeOfCode 得到)
DWORD SizeOfCode; // 代码所占空间大小 (没啥用)
DWORD SizeOfInitializedData; // 已初始化数据所占空间大小 (没啥用)
DWORD SizeOfUninitializedData;// 未初始化数据所占空间大小 (没啥用) DWORD AddressOfEntryPoint; // *oep:原本的程序入口点(实际为偏移,+模块基址=实际入口点)
// ep: 被加工后的入口点
//这个值可以修改,但是修改过后必须跳转到在该偏移处跳转到真正入口 DWORD BaseOfCode; // 代码基址 (无用)
DWORD BaseOfData; // 数据基址 (无用) DWORD ImageBase; // *建议模块地址:exe映射加载到内存中的首地址= PE 0处,即实例句柄hInstance
// 一般而言,exe文件可遵从装载地址建议,但dll文件无法满足 (开了随机基址可能也不是这个值,是通过重定位表得到)
//这个值最好不要改,改的话要改动大量地方,因为函数和全局变量的地址也需要跟着改变 DWORD SectionAlignment; //内存对齐值,数据在内存的对齐值,很多内存地址,大小都要依赖他来计算
//默认1000h 一个分页大小,系统管理内存是以分页为单位
DWORD FileAlignment; //文件对齐值, 200h,磁盘的一个扇区大小 (vc6是1000h)
//文件的起始位置和大小都是跟文件对齐值对齐的
// 对齐值都是2的倍数 如果把所有节合并了 就可以设为1,否则不可以随便修改因为要配合节检查 //主副系统相关版本号 除了 MajorSubsystemVersion 不可修改,其他5个可以
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion; //主子系统版本号 不可以修改 这里改成4可以再xp运行
WORD MinorSubsystemVersion; DWORD Win32VersionValue; // win32版本值 xp上不可以改 ,win7和win10可以修改 //改值是通过节表计算得到的
DWORD SizeOfImage; //模块在内存中总大小,与 SectionAlignment 对齐,改的话不可以改变分页数量(但最好对齐)
DWORD SizeOfHeaders; // PE头总大小,与 FileAlignment 对齐 DWORD CheckSum; //校验值 3环程序随便改,0环程序会检查,不允许改 可以用 MapFileAndCheckSum 计算值 WORD Subsystem; //子系统 不允许修改 /subsystem WORD DllCharacteristics; //描述应用程序的一些相关信息(例如是否开了随机基址等),可以改,但不能随便改 //这四个值可以改,但是不能改得太离谱
DWORD SizeOfStackReserve; //栈保留
DWORD SizeOfStackCommit; //栈提交
DWORD SizeOfHeapReserve; //堆保留
DWORD SizeOfHeapCommit; //堆保留 DWORD LoaderFlags; //跟调试相关,目前用不到,值可以随便改
DWORD NumberOfRvaAndSizes; //下面数组个数(最小可以改为2,最大为16,前2个表是导入,导出表,必须要有)
//数据目录表(成员2个 dword 第一个是内存偏移,第二个大小 )
//描述PE中各种个样的表的位置和大小,每个下标对应一个固定的表(前2个不能改,导入,导出表,改了无法调API)
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //柔性数组 个数由上面值决定,但是总大小为16个
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
AddressOfEntryPoint EP
OEP 程序入口点 - Old Entry Point
如果 EP 没有被修改的话 OEP = EP ,但是很多时候为了隐藏程序入口点 通常会修改 EP 的值
例如 原本 AddressOfEntryPoint 的值为1000 可以改成 1100 ,那么模块基址 + 1100 的地方就成了程序入口点 再到 该地址 执行跳转指令 ,可以挑战转到 偏移 为 1000 处或者 跳转到其他地方在跳回 偏移 1000处
ImageBase 建议模块基址
命令行编译的时候可以通过 /base修改
link /subsystem:windows /base:0x01000000 pe.obj
名称
开了随机基址,PE里面就会有一个重定位表,记录了所有需要修改的地方,没开没有
节表 IMAGE_SECTION_HEADER
●描述PE文件与内存之间的映射关系,说明PE文件的指定内容拷贝至内存的哪个位置、拷贝大小及内存属性的设置。
●一个结构体总大小为 0x 28 (40) 字节
如何定位节表
●节表置于选项头之后,位置 = 选项头( IMAGE_OPTIONAL_HEADER) 的地址
+ 选项头( IMAGE_OPTIONAL_HEADER)的大小。
节表字段的意义
// IMAGE_SECTION_HEADER 节表结构体,大小40B
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // 节表名称:描述性字段 2个字节 // 下方4个字段:从文件S1处开始,拷贝S2大小的数据,到内存S3处,有效数据占用内存S4大小
union {
DWORD PhysicalAddress;
DWORD VirtualSize; // S4:内存大小
} Misc;
DWORD VirtualAddress; // S3:内存地址:基于模块基址,与SectionAlignment对齐(0x1000)
DWORD SizeOfRawData; // S2:文件大小,与FileAlignment对齐(0x200)
DWORD PointerToRawData; // S1:文件偏移,与FileAlignment对齐(0x200) //跟调试相关
DWORD PointerToRelocations; // 无用
DWORD PointerToLinenumbers; // 无用
WORD NumberOfRelocations; // 无用
WORD NumberOfLinenumbers; // 无用 DWORD Characteristics; // 节内存属性,取值IMAGE_SCN_...系列宏 分低位和高位
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
空节
文件大小和偏移都为0
编译器一般用来存放未初始化的数据
节表与OD复制到文件功能的关系
- 由于内存是基于分页管理,所以要注意区块与页的关系。
节表字段的关系
- 关系:各个节之间是连续不间断的(除特殊节.textbss)。但是系统检查没那么严格改成不对齐也没事(修改 VirtualSize 的值或 SizeOfRawData ),但是不能改变分页情况,最好连续
- 下一个节的PointerToRawData = 上一个节的PointerToRawData+SizeOfRawData。
- 下一个节的VirtualAddress= 上一个节的VirtualAddress+VirtualSize对齐后的值(+0x1000)。
- SizeofImage PE文件在进程内存中的总大小=
- 算法1:最后一个节的virtualAddress + VirtualSize对齐后的值(+0x1000)
- 算法2:各个节占内存大小的总和+PE头大小(对齐后0x1000)。
最后一个节点数据不能随便改,再便宜为 0c处的 存的是资源信息表
地址转换 FA,VA和RVA的转换
FA --- file Address 文件地址(文件偏移)
VA --- virtual Address 虚拟内存(内存中的绝对地址)
RVA --- relative virtual Address 相对虚拟地址(基于模块基质的偏移,内存偏移)
注意:
通过FA 一定可以找到对应的 VA地址 因为文件对齐位200h,比内存偏移1000h小
VA地址不一定可以找到对应的 FA 地址 内存偏移 大于 当前节 200h是 , 文件中没办法找到对应偏移
VA 转 RVA
- 相对虚拟地址 = 绝对虚拟地址 - 基地址
RVA = VA - ImageBase
RVA 转 FA
VA -> FA
- 计算相对虚拟地址:RVA = VA - ImageBase
- 定位RVA所在的节,查节表,定位所在节
- 计算节内偏移:= RVA - 所定位节表virtualAddress字段的值
- 计算FA = 节内偏移 + PointToRawData
特殊的节:文件大小和偏移都为空,这叫空节,虽然不映射文件,但是会申请空间。
FA - > VA
- 定位节
- 计算节内偏移 = FA - PointRawData
- 计算相对虚拟地址:RVA = 节内偏移 + VirtualAddress
- 计算绝对虚拟地址:VA = RVA + ImageBase
WindowsPE文件格式入门02.选项头其它和节表的更多相关文章
- 【网络爬虫入门02】HTTP客户端库Requests的基本原理与基础应用
[网络爬虫入门02]HTTP客户端库Requests的基本原理与基础应用 广东职业技术学院 欧浩源 1.引言 实现网络爬虫的第一步就是要建立网络连接并向服务器或网页等网络资源发起请求.urllib是 ...
- CSS3基础入门02
CSS3 基础入门02 边框相关属性 border-radius 通过这个属性我们可以设置边框圆角,即可以将四个角设置为统一的圆角,也可以单独的设置具体的某一个角的圆角. grammer: borde ...
- PE文件格式详解,第三讲,可选头文件格式,以及节表
PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...
- JavaScript基本入门02
目录 JavaScript基础入门 02 条件语句 if 语句 if .. else 语句 switch 结构 循环语句 while 循环 continue 关键字 do...while语句 for ...
- Shell入门02
Shell入门-02 1.重定向 标准输入(<) 标准输出 标准错误重回定向 程序 = 指令 + 数据 命令 变量 在程序中,数据如何输入?又如何输出? 数据输入:键盘 – 标准输入,但是并 ...
- # 095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 03 封装总结 01 封装知识点总结
095 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 04 static关键字(续)
094 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 03 static关键字(下)
093 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 02 static关键字(中)
092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
- 091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 01 static关键字(上)
091 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...
随机推荐
- 值得推荐的IT公司名单(成都篇)
成都,作为新一线城市中的科技强市,拥有众多优秀的 IT 公司,为广大 IT 从业者提供了丰富的就业机会和良好的职业发展环境.以下是一些值得推荐的 IT 公司(排名不分先后): 一.互联网巨头在成都 1 ...
- VNCTF2025_Crypto
VNCTF2025_Crypto Simple prediction task.py from random import shuffle from Crypto.Util.number import ...
- 【ABAQUS后处理】打印视口到文件
abaqus cae 允许您在画布上打印一个或多个视口的快照,并将图像直接发送到打印机或文件以供以后使用,例如包含在嵌入打印报告的演示文稿中或以 html 格式显示document 打印的图像将在画布 ...
- vue2 配置 mock.js 模拟后端数据
安装 mockj 首先确保你有一个 vue 2 项目,如果没有,可以用 Vue CLI 创建一个: vue create vue-mock-demo 开始安装 Mock.js npm install ...
- C#实现自己的Json解析器(LALR(1)+miniDFA)
C#实现自己的Json解析器(LALR(1)+miniDFA) Json是一个用处广泛.文法简单的数据格式.本文介绍如何用bitParser(拥有自己的解析器(C#实现LALR(1)语法解析器和min ...
- Linux系统查看CPU使用率、内存使用率、磁盘使用率
一.查看CPU使用率1. top 命令[root@sss ~]# toptop - 16:54:38 up 7 days, 5:13, 3 users, load average: 0.00, ...
- 【SpringCloud】SpringCloud Bus消息总线
SpringCloud Bus消息总线 概述 上一讲解的加深和扩充,一言以蔽之 分布式自动刷新配置功能 Spring Cloud Bus配合Spring Cloud Config使用可以实现配置的动态 ...
- 第10章面向对象编程(高级部分)-cnblog
类变量与类方法 static修饰的成员变量(类变量,静态变量)的特性? 同一个类所有对象共享 类变量是随着类的加载而创建, 所以即使没有创建对象实例也可以访问 ,但是类变量的访问, 必须遵守 相关的访 ...
- 学习EXTJS6(9)面向对象的基础框架-1
Ext创造一套精细的对象模型与API,用这套API,可以快速实现对象的定义.创建.继承和扩展:1. 1.创建新类 Ext.define('demo.Demo',{ name: 'usegear', h ...
- Golang高性能引擎:ZKmall开源商城支撑百万级日活交易流畅运行
在电商业务高并发.低延迟的严苛场景下,技术栈的选择直接决定系统上限.ZKmall开源商城基于Golang技术生态,以协程级并发.毫秒级响应为核心优势,为百万级日活电商平台提供高性能解决方案.本文从架构 ...