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坐标系之间的转换 */ //定义一些常量 ...
随机推荐
- 001 说说Python中的深拷贝和浅拷贝
在Python编程中忽略深拷贝和浅拷贝可能会造成未知的风险. 比如我们打算保存一份原始对象的副本作为上一状态的记录,此后修改原始对象数据时,若是副本对象的数据也发生改变,那么这就是一个严重的错误. 注 ...
- 一文了解Python的迭代器的实现
本文对迭代器的解释参考自:https://www.programiz.com/python-programming/iterator 最后自己使用迭代器实现一个公平洗牌类. 博主认为,理论来自实践,假 ...
- JVM之类加载器子系统
类加载器子系统 作用 负责从文件系统或网络系统中加载class文件,class文件在开头有特殊的标记(魔术开头CA FE BA BE) ClassLoader只负责加载class文件,至于能否运行,由 ...
- 全局解决Vue跳转相同路由导致报错的问题
大家使用Vue做开发的时候应该都遇到过这个问题,就是某个页面下调用this.$router.push(path),而path指向的页面和当前页面是同一页面时,就会发生报错,vue-router会提示你 ...
- 解决springboot项目打成jar包部署到linux服务器后上传图片无法访问的问题
前言:目前大三,自己也在学习和摸索的阶段.在和学校的同学一起做前后端分离项目的时候,我们发现将后端打包成jar,然后部署到服务器中通过java -jar xxx.jar运行项目以后,项目中存在文件上传 ...
- 剑指 Offer 34. 二叉树中和为某一值的路径 + 记录所有路径
剑指 Offer 34. 二叉树中和为某一值的路径 Offer_34 题目详情 题解分析 本题是二叉树相关的题目,但是又和路径记录相关. 在记录路径时,可以使用一个栈来存储一条符合的路径,在回溯时将进 ...
- PAT-1140(Look-and-say Sequence)字符串处理
Look-and-say Sequence PAT-1140 #include<iostream> #include<cstring> #include<string&g ...
- LeetCode-[list-of-depth-lcci]
特定深度节点链表-求解每一层二叉树从左到右遍历形成的链表 list-of-depth-lcci 这是关于二叉树的问题,遍历每一层的结点并且存在链表中. 可以采取队列类似于广度优先搜索的方法进行搜索.每 ...
- 1.2 Python3基础-规范
>>返回主目录 总的来说,如果安装的不是安装的Anaconda,pip命令还是经常会用到的(cmd模式使用),当然也可以在PyCharm中直接安装 PEP8规范,我另有一篇博客已经写好,可 ...
- SpringCloud-服务与注册
SpringCloud- Eureka服务注册与发现 1.概述 springcloud是一个非常优秀的微服务框架,要管理众多的服务,就需要对这些服务进行治理,管理每个服务与每个服务之间的依赖关系,可以 ...