C/C++ 实现VA与FOA之间的转换
PE结构中的地址互转,这次再来系统的复习一下关于PE结构中各种地址的转换方式,最终通过编程来实现自动解析计算,最后将这个功能集成到我的迷你解析器中,本章中使用的工具是上次讲解PE结构文章中制作的CMD迷你结构解析器,如果不知道参数的基本使用请看前一篇。
PE工具的使用与下载:https://www.cnblogs.com/LyShark/p/12960816.html
将VA地址转换为FOA文件偏移: VA就是虚拟地址,转换为FOA文件偏移,其手工计算过程如下所示。
首先需要得到 ImageBase(镜像基址)
其次得到入口点地址,将两个地址相加即可得到VA,也就是实际装入地址。
通过上方的已知条件我们就可以计算出程序实际装入内存后的入口地址了.
VA(实际装入地址) = ImageBase(基址) + RVA(偏移) => 00400000 + 0000158b = 0040158b
如果不放心,可以将源程序拖入X64DBG中观察是否一致,如下OEP为 0040158b
与我们的计算结果完全一致。
接着我们需要得到 .text节
基地址以及 .text节
RVA,如下命令即可获取到。
虚拟地址开始位置:节区基地址 + 节区RVA => 00400000 + 00001000 = 00401000
虚拟地址结束位置:text节地址 + 节区尺寸 => 00401000 + 0x00000B44 = 00401B44
计算得出,虚拟地址text节开始位置 00401000
结束位置是 00401B44
打开X64dbg验证没错 确实落在了 text节上。
判断是否落在了.text节的依据是 开始位置 >= 401000 结束位置 <= 402000 很明显:00401B44小于402000。
接着我们就来计算一下,当前的VA地址0040158B
其对应到文件中的偏移FOA位置是多少,计算公式如下。
RVA(相对偏移) = VA - (.text节首地址) => 0040158B - 00401000 = 58B
FOA(文件偏移) = RVA + .text节对应到文件中的偏移 => 58B + 400 = 98B
计算出结果了,我们使用WinHEX定位到98B
处看看是否符合要求,机器码完全一致,符合要求。
接着就是使用C语言来实现这一计算过程了,有了计算流程之后使用C语言实现就变得简单许多。
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; // 获取节的结束地址
if (dwVA >= Section_Start && dwVA <= Section_Ends)
{
DWORD RVA = dwVA - pNtHead->OptionalHeader.ImageBase; // 计算RVA
DWORD FOA = pSection[each].PointerToRawData + (RVA - pSection[each].VirtualAddress); // 计算FOA
return FOA;
}
}
return -1;
}
将FOA文件偏移转换为VA地址: 将十六进制的文件偏移地址,反转为VA地址。
如下,通过公式计算一下文件偏移为0xF43的位置,其对应到VA虚拟地址是多少。
VPK(实际大小) = (text节首地址 - ImageBase) - 实际偏移 => 401000-400000-400 = C00
VA(虚拟地址) = FOA(.text节) + ImageBase + VPK => F43 + 400000 + C00 = 401B43
计算后的结果F43
对应到VA地址是401B43
验证一下,没错。
通过C语言实现也很简单,只需要把这个计算过程流程化即可。
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); // 得到FOA
return FOA;
}
}
return -1;
}
将RVA相对地址转换为FOA文件偏移: RVA就是相对地址,将相对地址转换为FOA文件内偏移,例如将158b
转换为FOA。
FOA = 实际偏移 + (RVA - 虚拟偏移) => 0x00000400 + (158b - 0x00001000) = 400 + 58b = 98B
计算出结果158b
虚拟地址对应到文件偏移为98B
,验证一下看看。
使用C语言实现此过程。
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); // 得到FOA
return FOA;
}
}
return -1;
}
将FOA文件偏移转换为VA地址: 将FOA文件偏移转换为VA内存装载地址,老样子,我们计算一下 FOA 98B
转为VA是多少?
首先计算RVA:RVA = pSection[each].VirtualAddress + (dwFOA - pSection[each].PointerToRawData);
RVA = 虚拟偏移 + (98B - 实际偏移) = 0x00001000 + (98B - 400) = 58B
DWORD VA = RVA + pNtHead->OptionalHeader.ImageBase;
VA = 00400000 + 00001000 + 58B = 40158b
结果就是40158b
没错,接着看看如何使用C语言实现计算过程吧。
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); // 计算出RVA
DWORD VA = RVA + pNtHead->OptionalHeader.ImageBase; // 计算出VA
return VA;
}
}
return -1;
}
实现无脑转换器(闭着眼转换): 为了节约大家的转换时间,以及让大家少动一些脑细胞,我决定将转换功能一并集成到解析器中,下面我给大家整体演示一遍使用方法。
先来演示一下VA转换为RVA的过程,将VA地址40158B
转换为FOA地址是多少?
输入命令 GetPE.exe c://lyshark.exe --VaToFoa 0040158b
完成计算,对应FOA 是 0000098B
计算结果完全一致。
在反转回去将FOA0000098B
转为VA地址,完全一致,没问题了,无脑乱搞。
C/C++ 实现VA与FOA之间的转换的更多相关文章
- CString-int-string-char-BSTR之间的转换
一.CString, int, string, char*之间的转换 string 转 CString CString.Format("%s", string.c_str());c ...
- (转)FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)
雷霄骅分类专栏: FFMPEG FFmpeg 本文链接:https://blog.csdn.net/leixiaohua1020/article/details/14215391 FFMPEG中的sw ...
- JSON字符串和JS对象之间的转换
JSON字符串和JS对象之间的转换 1 json字符串转换为js对象 1.1 标准json格式字符串转换为Js对象 JSON字符串 str JSON.parse(str) eval(str) eva ...
- C# Stream 和 byte[] 之间的转换
一. 二进制转换成图片 MemoryStream ms = new MemoryStream(bytes); ms.Position = ; Image img = Image.FromStream( ...
- Java基础——基本类型和包装类、基本类型和字符串之间的转换
基本类型和包装类之间的转换 基本类型和包装类之间经常需要互相转换,以 Integer 为例(其他几个包装类的操作雷同哦): 在 JDK1.5 引入自动装箱和拆箱的机制后,包装类和基本类型之间的转换就更 ...
- String类型和基本数据类型之间的转换
Java 中基本类型和字符串之间的转换 在程序开发中,我们经常需要在基本数据类型和字符串之间进行转换. 其中,基本类型转换为字符串有三种方法: 1. 使用包装类的 toString() 方法 2. 使 ...
- Json与javaBean之间的转换工具类
/** * Json与javaBean之间的转换工具类 * * {@code 现使用json-lib组件实现 * 需要 * json-lib-2.4-jdk15.jar * ...
- Stream 和 byte[] 之间的转换
Stream 和 byte[] 之间的转换 一. 二进制转换成图片 ? 1 2 3 4 5 MemoryStream ms = new MemoryStream(bytes); ms.Position ...
- 百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换(JS版代码)
/** * Created by Wandergis on 2015/7/8. * 提供了百度坐标(BD09).国测局坐标(火星坐标,GCJ02).和WGS84坐标系之间的转换 */ //定义一些常量 ...
随机推荐
- Leaflet 带箭头轨迹以及沿轨迹带方向的动态marker
前面写了篇文章,mapboxgl实现带箭头轨迹线,介绍了如何基于mapboxgl实现类似高德地图导航轨迹效果. 下图是我基于leaflet实现的效果. 接下来分享一下在我基于leaflet实现该效果时 ...
- Kafka集群消息积压问题及处理策略
通常情况下,企业中会采取轮询或者随机的方式,通过Kafka的producer向Kafka集群生产数据,来尽可能保证Kafka分区之间的数据是均匀分布的. 在分区数据均匀分布的前提下,如果我们针对要处理 ...
- SpringBoot启动流程原理解析(二)
在上一章我们分析了SpingBoot启动流程中实例化SpingApplication的过程. return new SpringApplication(primarySources).run(args ...
- AtCoder Beginner Contest 187
A Large Digits int n; int main() { IOS; int a, b, resa = 0, resb = 0; cin >> a >> b; whi ...
- Raft共识算法详解
Raft共识算法 一.背景 拜占庭将军问题是分布式领域最复杂.最严格的容错模型.但在日常工作中使用的分布式系统面对的问题不会那么复杂,更多的是计算机故障挂掉了,或者网络通信问题而没法传递信息,这种情况 ...
- python模块的打包和安装
假设需要打包的模块文件名是mm.py,代码如下: a = 2 在mm.py文件的同目录下新建一个setup.py文件,代码如下: from distutils.core import setup se ...
- C++11多线程编程(常见面试题)
[题目1] 子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码 [题解] 首先我们来分析一下这道题...( ...
- 亲测有效JS中9种数组去重方法
码文不易,转载请带上本文链接,感谢~ https://www.cnblogs.com/echoyya/p/14555831.html 目录 码文不易,转载请带上本文链接,感谢~ https://www ...
- Netflix业务运维分析和总结
目录 Netflix工作环境的分析和思考 为什么Netflix会做得如此极致? 海量业务规模下的技术架构和挑战 更加合理的组织架构和先进的工具体系及理念 自由与责任并存的企业文化 当前问题: 精选提问 ...
- noip初赛复习总纲
初赛复习总纲 目录 初赛复习总纲 计算机发展史 计算机的分类 计算机的应用 操作系统盘点 计算机的基本结构 中央处理器(**CPU**--**Central Processing Unit**) 存储 ...