2.14 PE结构:地址之间的转换

在可执行文件PE文件结构中,通常我们需要用到地址转换相关知识,PE文件针对地址的规范有三种,其中就包括了VARVAFOA三种,这三种该地址之间的灵活转换也是非常有用的,本节将介绍这些地址范围如何通过编程的方式实现转换。

如下是三种格式的异同点:

  • VA(Virtual Address,虚拟地址):它是在进程的虚拟地址空间中的地址,用于在运行时访问内存中的数据和代码。VA是相对于进程基址的偏移量。在不同的进程中,相同的VA可能映射到不同的物理地址。
  • RVA(Relative Virtual Address,相对虚拟地址):它是相对于模块基址(Module Base Address)的偏移量,用于定位模块内部的数据和代码。RVA是相对于模块基址的偏移量,通过将模块基址和RVA相加,可以计算出相应的VA。
  • FOA(File Offset Address,文件偏移地址):它是相对于文件起始位置的偏移量,用于定位可执行文件中的数据和代码在文件中的位置。通过将文件偏移地址和节表中的指定节的起始位置相加,可以计算出相应的FOA。

VA虚拟地址转换为FOA文件偏移

VA地址代指的是程序加载到内存后的内存地址,而FOA地址则代表文件内的物理地址,通过编写VA_To_FOA则可实现将一个虚拟地址转换为文件偏移地址,该函数的实现方式,首先得到ImageBase镜像基地址,并得到NumberOfSections节数量,有了该数量以后直接循环,通过判断语句将节限定在一个区间内该区间dwVA >= Section_Start && dwVA <= Section_Ends,当找到后,首先通过VA-ImageBase得到当前的RVA地址,接着通过该地址减去VirtualAddress并加上PointerToRawData文件指针,即可获取到文件内的偏移。

#include <iostream>
#include <Windows.h>
#include <ImageHlp.h>#pragma comment(lib,"Imagehlp.lib")// 读取NT头
PIMAGE_NT_HEADERS GetNtHeader(PVOID ImageBase)
{PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){return NULL;}PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + pDosHeader->e_lfanew);if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE){return NULL;}return pNtHeaders;
}// 读取PE结构的封装
HANDLE OpenPeFile(LPTSTR FileName)
{HANDLE hFile, hMapFile, lpMapAddress = NULL;DWORD dwFileSize = 0;// CreateFile 既可以创建文件,也可以打开文件,这里则是打开文件的含义hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){return 0;}// 获取到文件大小dwFileSize = GetFileSize(hFile, NULL);// 创建文件的内存映像hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);if (hMapFile == NULL){return 0;}// 读取映射中的内存并返回一个句柄lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);if (lpMapAddress != NULL){return lpMapAddress;}return 0;
}// 将 VA(虚拟地址) --> 转换为 FOA(文件偏移)
DWORD VA_To_FOA(HANDLE ImageBase, DWORD dwVA)
{PIMAGE_NT_HEADERS pNtHead = NULL;PIMAGE_FILE_HEADER pFileHead = NULL;PIMAGE_SECTION_HEADER pSection = NULL;DWORD NumberOfSectinsCount = 0;DWORD dwImageBase = 0;pNtHead = GetNtHeader(ImageBase);pSection = IMAGE_FIRST_SECTION(pNtHead);dwImageBase = pNtHead->OptionalHeader.ImageBase;NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;for (int each = 0; each < NumberOfSectinsCount; each++){// 获取节的开始地址与结束地址DWORD Section_Start = dwImageBase + pSection[each].VirtualAddress;DWORD Section_Ends = dwImageBase + pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize;// 判断当前的VA地址落在了那个节上if (dwVA >= Section_Start && dwVA <= Section_Ends){DWORD RVA = dwVA - pNtHead->OptionalHeader.ImageBase;                                    // 计算RVADWORD FOA = pSection[each].PointerToRawData + (RVA - pSection[each].VirtualAddress);     // 计算FOAreturn FOA;}}return -1;
}int main(int argc, char * argv[])
{HANDLE lpMapAddress = NULL;// 打开PE文件lpMapAddress = OpenPeFile(L"d://lyshark.exe");// 转换DWORD FOA = VA_To_FOA(lpMapAddress, 0x401000);printf("VA --> FOA 结果为: %x \n", FOA);system("pause");return 0;
}

上述代码运行后即可获取到内存地址0x401000对应的文件地址为0x1000,读者可自行打开WinHex验证是否相等,如下图所示;

RVA相对地址转换为FOA文件偏移

所谓的相对地址则是内存地址减去基址所获得的地址,该地址的计算同样可以使用代码实现,如下RVA_To_FOA函数可用于将一个相对地址转换为文件偏移,如果内存VA地址是0x401000而基址是0x400000那么相对地址就是0x1000,将相对地址转换为FOA文件偏移,首相要将相对地址加上基址,我们通过相对地址减去PointerToRawData数据指针即可获取到文件偏移。

#include <iostream>
#include <Windows.h>
#include <ImageHlp.h>#pragma comment(lib,"Imagehlp.lib")// 读取NT头
PIMAGE_NT_HEADERS GetNtHeader(PVOID ImageBase)
{PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){return NULL;}PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + pDosHeader->e_lfanew);if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE){return NULL;}return pNtHeaders;
}// 读取PE结构的封装
HANDLE OpenPeFile(LPTSTR FileName)
{HANDLE hFile, hMapFile, lpMapAddress = NULL;DWORD dwFileSize = 0;// CreateFile 既可以创建文件,也可以打开文件,这里则是打开文件的含义hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){return 0;}// 获取到文件大小dwFileSize = GetFileSize(hFile, NULL);// 创建文件的内存映像hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);if (hMapFile == NULL){return 0;}// 读取映射中的内存并返回一个句柄lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);if (lpMapAddress != NULL){return lpMapAddress;}return 0;
}// 将 RVA(虚拟地址) --> 转换为 FOA(文件偏移)
DWORD RVA_To_FOA(HANDLE ImageBase, DWORD dwRVA)
{PIMAGE_NT_HEADERS pNtHead = NULL;PIMAGE_FILE_HEADER pFileHead = NULL;PIMAGE_SECTION_HEADER pSection = NULL;DWORD NumberOfSectinsCount = 0;DWORD dwImageBase = 0;pNtHead = GetNtHeader(ImageBase);pSection = IMAGE_FIRST_SECTION(pNtHead);dwImageBase = pNtHead->OptionalHeader.ImageBase;NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;for (int each = 0; each < NumberOfSectinsCount; each++){DWORD Section_Start = pSection[each].VirtualAddress;                                  // 计算RVA开始位置DWORD Section_Ends = pSection[each].VirtualAddress + pSection[each].Misc.VirtualSize; // 计算RVA结束位置if (dwRVA >= Section_Start && dwRVA <= Section_Ends){DWORD VA = pNtHead->OptionalHeader.ImageBase + dwRVA;                                  // 得到VA地址DWORD FOA = pSection[each].PointerToRawData + (dwRVA - pSection[each].VirtualAddress); // 得到FOAreturn FOA;}}return -1;
}int main(int argc, char * argv[])
{// 打开文件HANDLE lpMapAddress = NULL;lpMapAddress = OpenPeFile(L"d://lyshark.exe");// 计算地址DWORD FOA = RVA_To_FOA(lpMapAddress, 0x1000);printf("RVA --> FOA 结果为: %x \n", FOA);system("pause");return 0;
}

我们还是以上述功能为例,计算相对地址0x1000的文件偏移,则可以得到0x1000的文件偏移值,如下图所示;

FOA文件偏移转换为VA虚拟地址

将文件内的偏移地址FOA转换为内存虚拟地址,在转换时首先通过VirtualAddress节虚拟地址加上,文件偏移地址减去PointerToRawData数据域指针,得到相对地址,再次加上ImageBase基地址即可获取到实际虚拟地址。

#include <iostream>
#include <Windows.h>
#include <ImageHlp.h>#pragma comment(lib,"Imagehlp.lib")// 读取NT头
PIMAGE_NT_HEADERS GetNtHeader(PVOID ImageBase)
{PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)ImageBase;if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE){return NULL;}PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + pDosHeader->e_lfanew);if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE){return NULL;}return pNtHeaders;
}// 读取PE结构的封装
HANDLE OpenPeFile(LPTSTR FileName)
{HANDLE hFile, hMapFile, lpMapAddress = NULL;DWORD dwFileSize = 0;// CreateFile 既可以创建文件,也可以打开文件,这里则是打开文件的含义hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){return 0;}// 获取到文件大小dwFileSize = GetFileSize(hFile, NULL);// 创建文件的内存映像hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);if (hMapFile == NULL){return 0;}// 读取映射中的内存并返回一个句柄lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);if (lpMapAddress != NULL){return lpMapAddress;}return 0;
}// 将 FOA(文件偏移) --> 转换为 VA(虚拟地址)
DWORD FOA_To_VA(HANDLE ImageBase, DWORD dwFOA)
{PIMAGE_NT_HEADERS pNtHead = NULL;PIMAGE_FILE_HEADER pFileHead = NULL;PIMAGE_SECTION_HEADER pSection = NULL;DWORD NumberOfSectinsCount = 0;DWORD dwImageBase = 0;pNtHead = GetNtHeader(ImageBase);pSection = IMAGE_FIRST_SECTION(pNtHead);dwImageBase = pNtHead->OptionalHeader.ImageBase;NumberOfSectinsCount = pNtHead->FileHeader.NumberOfSections;for (int each = 0; each < NumberOfSectinsCount; each++){DWORD PointerRawStart = pSection[each].PointerToRawData;                                // 文件偏移开始位置DWORD PointerRawEnds = pSection[each].PointerToRawData + pSection[each].SizeOfRawData;  // 文件偏移结束位置if (dwFOA >= PointerRawStart && dwFOA <= PointerRawEnds){DWORD RVA = pSection[each].VirtualAddress + (dwFOA - pSection[each].PointerToRawData);  // 计算出RVADWORD VA = RVA + pNtHead->OptionalHeader.ImageBase;                                     // 计算出VAreturn VA;}}return -1;
}int main(int argc, char * argv[])
{// 打开文件HANDLE lpMapAddress = NULL;lpMapAddress = OpenPeFile(L"d://lyshark.exe");// 转换DWORD VA = FOA_To_VA(lpMapAddress, 0x1000);printf("FOA --> VA 结果为: 0x%X \n", VA);system("pause");return 0;
}

运行后即可将文件偏移0x1000转换为内存虚拟地址0x401000如下图所示;

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/ccb722fb.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/76893.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac端交互式原型设计 Axure RP 8 for Mac汉化

Axure RP 8是一款专业的交互原型设计工具&#xff0c;它被广泛应用于用户体验设计、界面设计和产品原型制作等领域。该软件提供了丰富的功能和工具&#xff0c;使用户能够创建出具有高度交互性和可视化效果的原型。 Axure RP 8的主要特点和功能包括&#xff1a; 1. 快速原型&a…

产教融合 | 力软联合重庆科技学院开展低代码应用开发培训

近日&#xff0c;力软与重庆科技学院联合推出了为期两周的低代码应用开发培训课程&#xff0c;来自重庆科技学院相关专业的近百名师生参加了此次培训。 融合研学与实践&#xff0c;方能成为当代数字英才。本次培训全程采用线下模式&#xff0c;以“力软低代码平台”为软件开发…

光谱通用款积分球

随着惯性约束聚变&#xff08;ICF&#xff09;物理理论的不断发展以及精密物理实验要求的不断提高&#xff0c;激光驱动器的光束路数急剧增多&#xff0c;光路长度和元器件数目成倍增长。模块化是新一代激光驱动器的发展趋势。对于高功率激光多参数测量系统&#xff0c;模块化设…

《DevOps实践指南》- 读书笔记(五)

DevOps实践指南 Part 4 第二步 &#xff1a;反馈的技术实践14. 建立能发现并解决问题的遥测系统14.1 建设集中式监控架构14.2 建立生产环境的应用程序日志遥测14.3 使用遥测指导问题的解决14.4 将建立生产遥测融入日常工作14.5 建立自助访问的遥测和信息辐射器14.6 发现和填补遥…

【视觉SLAM入门】7.4.后端优化 --- 基于位姿图和基于因子图

"议论平恕&#xff0c;无所向背” 1. 位姿图1.1 具体做法1.2 小结 2. 因子图2.1 具体做法2.1.1 贝叶斯网络2.1.2 因子图2.1.3 更具体的因子图2.1.4 增量的求解方法 引入&#xff1a; 上节BA将位姿和路标都作为优化的节点&#xff0c;H矩阵也告诉我们路标远大于位姿&#…

Python绘图系统16:动态更新tkinter组件

文章目录 前情提要源代码模式输入序列源码 Python绘图系统&#xff1a; &#x1f4c8;从0开始的3D绘图系统&#x1f4c9;一套3D坐标&#xff0c;多个函数&#x1f4ca;散点图、极坐标和子图自定义控件&#xff1a;极坐标&#x1f4c9;绘图风格&#x1f4c9;风格控件图表类型和…

rsync远程同步+inotify监控

目录 一、Rsync 简介 1、rsync是什么 2、备份的方式 3、rsync同步方式 4、常用rsync命令 5、配置源的两种表达方法 二、rsync实验 1、本地复制 ​编辑​编辑 2、异地复制 2.1 rsync服务器配置 2.2 rsync客户端配置 2.2.1 普通同步 2.2.2 免密同步 2.2.3 --delet…

EmguCV-C#版本Opencv图像识别和处理

目录 0、简介 1、图像处理 &#xff08;1&#xff09;颜色处理 &#xff08;2&#xff09;图像差 &#xff08;3&#xff09;图像拼接 &#xff08;4&#xff09;直方图 &#xff08;5&#xff09;颜色空间/通道提取 2、预处理 &#xff08;1&#xff09;均衡化 &…

idea2021.1.3版本双击启动,没反应

今天打开电脑&#xff0c;点开idea&#xff0c;界面悬在这里&#xff0c;几秒然后就是没了。然后就一直打不开idea了。 然后又是卸载重装&#xff0c;又是删除缓存文件。我把电脑关于idea的文件全都删除了 。重新安装后&#xff08;首次运行倒是可以打开&#xff0c;但是关掉id…

Python爬虫-IP隐藏技术与代理爬取

前言 在进行爬虫程序开发和运行时&#xff0c;常常会遇到目标网站的反爬虫机制&#xff0c;最常见的就是IP封禁&#xff0c;这时需要使用IP隐藏技术和代理爬取。 一、IP隐藏技术 IP隐藏技术&#xff0c;即伪装IP地址&#xff0c;使得爬虫请求的IP地址不被目标网站识别为爬虫。…

spring boot 使用AOP+自定义注解+反射实现操作日志记录修改前数据和修改后对比数据,并保存至日志表

一、添加aop starter依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>二&#xff1a;自定义字段翻译注解。&#xff08;修改功能时&#xff0c;需要显示如…

【mysql】—— 函数的基本介绍

前言&#xff1a; MySQL是一种常用的关系型数据库管理系统&#xff0c;它提供了许多内置的函数来进行数据操作和处理。本期&#xff0c;我将给大家介绍的就是关于 “函数” 的相关知识&#xff01;&#xff01;&#xff01; 目录 &#xff08;一&#xff09;日期函数 &#…

Linux基础命令(示例代码 + 解释)

查看目录下文件 ls [-a -l -h] [路径] -a&#xff08;全部&#xff09; -l&#xff08;细节&#xff09; -h&#xff08;大小&#xff09; ls ls / ls -a ls -l ls -h ls -alh ls -l -h -a ls -lah /切换目录 cd [路径] change di…

webrtc-m79-测试peerconnectionserver的webclient-p2p-demo

1 背景 webrtc的代码中有peerconnectionclient和peerconnectionserver的例子&#xff0c;但是没有对应的web端的例子&#xff0c;这里简单的写了一个测试例子&#xff0c;具体如下&#xff1a; 2 具体操作 2.1 操作流程 2.2 测试效果 使用webclient与peerconnectionclient的…

算法 数据结构 双向环形链表 手撸环形链表 环形链表实现容器 环形链表添加修改删除获取大小 环形链表实现自定义容器 手撸容器 双向环形哨兵链表 数据结构(六)

1. 环形链表&#xff1a; 2. 建议先不要看我写得自己先实现下&#xff0c;只将Node内部类复制自己命名得容器内&#xff0c; 实现方法&#xff1a; a. add方法&#xff08;添加到头部&#xff0c;尾部添加&#xff0c;指定位置添加&#xff09; b. get方法&#xff08;获取首部…

HBASE知识点

HBASE是什么&#xff1f; 高可靠、高性能、面向列、可伸缩、实时读写的分布式数据库。利用HDFS作为其文件存储系统&#xff0c;利用MapReduce来处理HBase中的海量数据。利用Zookeeper作为其分布式协同服务。用于存储非结构化和半结构化的松散数据。 HBase数据模型 RowKey: 唯…

Java“牵手”拼多多商品详情数据,拼多多商品详情接口,拼多多API接口申请指南

拼多多商品详情API接口的作用是获取拼多多平台上某个商品的详细信息&#xff0c;包括商品标题、价格、图片、规格、参数、店铺信息等。 开发者可以通过该接口获取到商品的原始数据&#xff0c;方便进行数据分析、价格比较、爬取等操作。通过该接口获取到的商品详情数据可以结合…

flink命令行提交jar包任务

1. 环境准备 1.1 flink环境准备 关于如何安装flink&#xff0c;这个写的非常详细&#xff0c;https://blog.csdn.net/qq_43699958/article/details/132826440 在flink的bin目录启动flink cluster [rootlocalhost bin]# ./start-cluster.sh1.2 Linux环境准备 1.2.1 关闭linu…

43.MQ—RabbitMQ

目录 一、MQ—RabbitMQ。 &#xff08;1&#xff09;同步调用与异步调用。 &#xff08;1.1&#xff09;同步调用。 &#xff08;1.2&#xff09;异步调用。 &#xff08;2&#xff09;MQ之间的区别。 &#xff08;3&#xff09;RabbitMQ学习。 &#xff08;3.1&#xf…

一文读懂:苹果手机怎么录屏?

“刚买的苹果14&#xff0c;最近需要用来录屏&#xff0c;找了很久都没找到&#xff0c;朋友说苹果手机没有录屏功能&#xff0c;可是我半信半疑&#xff0c;花了这么多钱买的&#xff0c;怎么可能没有录屏功能呢&#xff0c;有人知道苹果手机怎么录屏吗&#xff1f;” 苹果手…