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之间的转换的更多相关文章

  1. CString-int-string-char-BSTR之间的转换

    一.CString, int, string, char*之间的转换 string 转 CString CString.Format("%s", string.c_str());c ...

  2. (转)FFMPEG 实现 YUV,RGB各种图像原始数据之间的转换(swscale)

    雷霄骅分类专栏: FFMPEG FFmpeg 本文链接:https://blog.csdn.net/leixiaohua1020/article/details/14215391 FFMPEG中的sw ...

  3. JSON字符串和JS对象之间的转换

    JSON字符串和JS对象之间的转换 1 json字符串转换为js对象 1.1 标准json格式字符串转换为Js对象  JSON字符串 str JSON.parse(str) eval(str) eva ...

  4. C# Stream 和 byte[] 之间的转换

    一. 二进制转换成图片 MemoryStream ms = new MemoryStream(bytes); ms.Position = ; Image img = Image.FromStream( ...

  5. Java基础——基本类型和包装类、基本类型和字符串之间的转换

    基本类型和包装类之间的转换 基本类型和包装类之间经常需要互相转换,以 Integer 为例(其他几个包装类的操作雷同哦): 在 JDK1.5 引入自动装箱和拆箱的机制后,包装类和基本类型之间的转换就更 ...

  6. String类型和基本数据类型之间的转换

    Java 中基本类型和字符串之间的转换 在程序开发中,我们经常需要在基本数据类型和字符串之间进行转换. 其中,基本类型转换为字符串有三种方法: 1. 使用包装类的 toString() 方法 2. 使 ...

  7. Json与javaBean之间的转换工具类

    /**  * Json与javaBean之间的转换工具类  *  * {@code 现使用json-lib组件实现  *    需要  *     json-lib-2.4-jdk15.jar  * ...

  8. Stream 和 byte[] 之间的转换

    Stream 和 byte[] 之间的转换 一. 二进制转换成图片 ? 1 2 3 4 5 MemoryStream ms = new MemoryStream(bytes); ms.Position ...

  9. 百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换(JS版代码)

    /** * Created by Wandergis on 2015/7/8. * 提供了百度坐标(BD09).国测局坐标(火星坐标,GCJ02).和WGS84坐标系之间的转换 */ //定义一些常量 ...

随机推荐

  1. 爬虫必知必会(7)_scrapy框架高级

    一.请求传参 实现深度爬取:爬取多个层级对应的页面数据 使用场景:爬取的数据没有在同一张页面中 在手动请求的时候传递item:yield scrapy.Request(url,callback,met ...

  2. 选择 FreeBSD 而不是 Linux 的技术性原因1

    Ports FreeBSD Ports 是一个惊人的工程壮举.NetBSD 的 pkgsrc (package source) 和 OpenBSD 的 ports collection 都源于 Fre ...

  3. iOS 面试秘籍全套

    栏目将持续更新--请iOS的小伙伴关注!   (答案不唯一,仅供参考,文章最后有福利) iOS面试题大全(上) iOS面试题大全(下) 目录: iOS面试题:Run Loop iOS面试题:性能优化 ...

  4. Java中的四种权限修饰符及六种非访问修饰符(简识)

    一.是哪四种访问权限修饰符呢? public > protected > [default] > private (公共的 ) (受保护的) (默认的) (私有的) 二.简单认识四种 ...

  5. CRC校验原理和verilog实现方法(一)

    1.CRC简介 CRC全称循环冗余校验(Cyclic Redundancy Check, CRC),是通信领域数据传输技术中常用的检错方法,用于保证数据传输的可靠性.网上有关这方面的博客和资料很多,本 ...

  6. django 自带的用户系统

    首先,我要说明一下,下面内容不是必须品,如果各位大神喜欢手写也是可以的,你也可以选择自带的功能来缩减你的代码量,提高效率! 第一步 系统配置用户表 首先,在models中创建用户表,导包 from d ...

  7. [set]JZOJ 5821 手机信号

    Description

  8. sqli-labs系列——第二关

    less2 and 1=1有回显,and 1=2无回显,为数值型注入 order by 4–+报错,有3行 查询数据库名 ?id=0' union select 1,(select group_con ...

  9. Java之常用API

    API概述 什么是API API (Application Programming Interface) :应用程序编程接口 java中的API 指的就是 JDK 中提供的各种功能的 Java类,这些 ...

  10. Software

    Software is a bridge, acorss people, the links, and knowledge. 并非单一的产品,而是整个行业.