前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PE格式:实现VA与FOA之间的转换

PE格式:实现VA与FOA之间的转换

原创
作者头像
王 瑞
发布于 2022-12-24 11:23:17
发布于 2022-12-24 11:23:17
4520
举报

PE结构中的地址互转,这次再来系统的复习一下关于PE结构中各种地址的转换方式,最终通过编程来实现自动解析计算,最后将这个功能集成到我的迷你解析器中,本章中使用的工具是上次讲解PE结构文章中制作的CMD迷你结构解析器,如果不知道参数的基本使用请看前一篇。

将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语言实现就变得简单许多。

代码语言:C
AI代码解释
复制
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语言实现也很简单,只需要把这个计算过程流程化即可。

代码语言:C
AI代码解释
复制
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语言实现此过程。

代码语言:C
AI代码解释
复制
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 = pSectioneach.VirtualAddress + (dwFOA - pSectioneach.PointerToRawData);

RVA = 虚拟偏移 + (98B - 实际偏移) = 0x00001000 + (98B - 400) = 58B

DWORD VA = RVA + pNtHead->OptionalHeader.ImageBase;

VA = 00400000 + 00001000 + 58B = 40158b

结果就是40158b没错,接着看看如何使用C语言实现计算过程吧。

代码语言:C
AI代码解释
复制
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地址,完全一致,没问题了,无脑乱搞。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
最小生成树(Kruskal算法和Prim算法)
上一篇文章,我们讲了图的创建和遍历,其中遍历的算法主要有BFS(广度优先算法)和DFS(深度优先算法)两种,并且DFS算法对很多问题都有很好的启示!而今天我们要说一个非常实用的算法——最小生成树的建立!这是图论中一个经典问题,可以使用Kruskal和Prim两种算法来进行实现!
算法工程师之路
2019/08/05
8K0
文心一言 VS 讯飞星火 VS chatgpt (349)-- 算法导论23.2 8题
八、Borden教授提出了一个新的分治算法来计算最小生成树。该算法的原理如下:给定图$G=(V,E)$,将$V$划分为两个集合$V_1$和$V_2$,使得$|V_1|$和$|V_2|$的差最多为1。设$E_1$为端点全部在$V_1$中的边的集合,$E_2$为端点全部在$V_2$中的边的集合。我们递归地解决两个子图$G_1=(V_1,E_1)$和$G_2=(V_2,E_2)$的最小生成树问题。最后,在边集合$E$中选择横跨切割$V_1$和$V_2$的最小权重的边来将求出的两棵最小生成树连接起来,从而形成一棵最后的最小生成树。请证明该算法能正确计算出一棵最小生成树,或者举出反例来明说该算法不正确。如果要写代码,请用go语言。
福大大架构师每日一题
2024/09/18
880
文心一言 VS 讯飞星火 VS chatgpt (349)-- 算法导论23.2 8题
文心一言 VS 讯飞星火 VS chatgpt (345)-- 算法导论23.2 4题
四、假定图中的边权重全部为整数,且在范围$1 \sim |V|$内。在此种情况下,Kruskal算法最快能多快?如果边的权重取值范围在1到某个常数$W$之间呢?如果要写代码,请用go语言。
福大大架构师每日一题
2024/09/13
1240
文心一言 VS 讯飞星火 VS chatgpt (345)-- 算法导论23.2 4题
文心一言 VS 讯飞星火 VS chatgpt (339)-- 算法导论23.1 8题
要证明对于图G的任何其他最小生成树T',列表L(作为树T的边权重有序列表)也是T'中一个边权重的有序列表,我们可以从最小生成树的定义和性质出发。
福大大架构师每日一题
2024/09/06
680
文心一言 VS 讯飞星火 VS chatgpt (339)-- 算法导论23.1 8题
加权无向图----Prim算法实现最小生成树
上一篇:加权无向图的实现 加权无向图----Kruskal算法实现最小生成树 图的生成树是它的一棵含有其所有顶点的无环连通子图,加权图的最小生成树(MST)是它的一棵权值最小的生成树。 切分:图的一种切分是将图的所有顶点分为两个非空且不重合的两个集合。横切边是一条连接两个属于不同集合的顶点的边。 切分定理:在一幅加权图中,给定任意的切分,它横切边中权重最小者必然属于图的最小生成树。 切分定理是解决最小生成树问题的所有算法的基础。  Prim算法能够得到任意加权连通无向图的最小生成树。 数据结构设计: 采用一
SuperHeroes
2018/05/30
1.7K0
使用贪心算法解决最小生成树
生成树的定义:对于一个图G,获取G的边使得所有的顶点都连接到。最小生成树(MST Minimun spanning tree):给定图G(V,E),以及对应的边的权重,获取一颗总权重最小的生成树。
爬蜥
2019/07/09
1.3K0
文心一言 VS 讯飞星火 VS chatgpt (347)-- 算法导论23.2 6题
在比较Prim算法和Kruskal算法在特定条件下的性能时,我们需要考虑几个因素,主要是图的表示方式、边的数量、顶点的数量以及边的权重分布。由于在这个问题中,所有的边权重都均匀分布在半开区间[0,1)内,且我们并没有明确图的密度(即边数与顶点数的关系),但我们可以基于算法的基本性质给出一些一般性的分析。
福大大架构师每日一题
2024/09/18
1190
文心一言 VS 讯飞星火 VS chatgpt (347)-- 算法导论23.2 6题
文心一言 VS 讯飞星火 VS chatgpt (338)-- 算法导论23.1 7题
连接所有结点的最小权重边集合是{AB, BC, CD, DA},总权重为-5(注意DA边的权重是负的)。然而,这个边集合形成了一个环(ABCDA),并不是一个树。
福大大架构师每日一题
2024/09/06
870
文心一言 VS 讯飞星火 VS chatgpt (338)-- 算法导论23.1 7题
图的应用——最小生成树
最小生成树 生成树(极小连通子图):含有图中全部n个顶点,但只有n-1条边。并且n-1条边不能构成回路。 [在这里插入图片描述] 生成森林:非连通图每个连通分量的生成树一起组成非连通图的生成森林。 [在这里插入图片描述] 求最小生成树 使用不同的遍历图的方法,可以得到不同的生成树 从不同的顶点出发,也可能得到不同的生成树。 按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。在网的多个生成树中,寻找一个各边权值之和最小的生成树 构造最小生成树的准则 必须只使用该网中的边来构造最小生成
ruochen
2021/06/29
8910
图的应用——最小生成树
文心一言 VS 讯飞星火 VS chatgpt (332)-- 算法导论23.1 1题
为了证明边(u,v)是图G的某棵最小生成树中的一条边,我们可以使用反证法结合最小生成树的性质来进行证明。
福大大架构师每日一题
2024/08/29
1130
文心一言 VS 讯飞星火 VS chatgpt (332)-- 算法导论23.1 1题
文心一言 VS 讯飞星火 VS chatgpt (336)-- 算法导论23.1 5题
要证明在连通图G=(V,E)中,如果e是某条环路上权重最大的边,则图G'=(V,E-{e})中存在一棵最小生成树,这棵生成树同时也是G的最小生成树,我们可以按照以下步骤进行:
福大大架构师每日一题
2024/09/06
1360
文心一言 VS 讯飞星火 VS chatgpt (336)-- 算法导论23.1 5题
文心一言 VS 讯飞星火 VS chatgpt (337)-- 算法导论23.1 6题
假设图 G 的每个切割都包含一条横跨该切割的唯一轻量级边(即最小权重的边)。我们需要证明 G 存在一棵唯一的最小生成树。
福大大架构师每日一题
2024/09/06
880
文心一言 VS 讯飞星火 VS chatgpt (337)-- 算法导论23.1 6题
克鲁斯卡尔(Kruskal )算法——求最小生成树贪心算法
克鲁斯卡尔算法是一种用于求解最小生成树问题的贪心算法。最小生成树是一个连通图的生成树,其边的权重之和最小。
一条晒干的咸鱼
2024/11/19
4530
克鲁斯卡尔(Kruskal )算法——求最小生成树贪心算法
软考高级架构师:最小生成树和克鲁斯卡尔算法、普利姆算法
图论是研究图的数学理论和方法,其中图是由顶点集合及连接这些顶点的边集合组成的数学结构。图论在计算机科学、网络规划、生物信息学等众多领域都有重要应用。最小生成树(Minimum Spanning Tree,MST)是图论中一个经典问题,指在一个加权连通图中寻找一棵权值最小的生成树。克鲁斯卡尔(Kruskal)算法和普利姆(Prim)算法是解决最小生成树问题的两种著名算法。
明明如月学长
2024/05/25
2330
软考高级架构师:最小生成树和克鲁斯卡尔算法、普利姆算法
文心一言 VS 讯飞星火 VS chatgpt (335)-- 算法导论23.1 4题
为了提供一个例子,其中边集合 {(u,v): 存在一个切割(S,V-S),使得(u,v)是横跨该切割的一条轻量级边} 不形成一棵最小生成树,我们可以考虑一个具有特殊结构的图。
福大大架构师每日一题
2024/08/30
1180
文心一言 VS 讯飞星火 VS chatgpt (335)-- 算法导论23.1 4题
最小生成树-Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算
用户1215536
2018/02/05
3.9K0
最小生成树-Prim算法和Kruskal算法
C++ Prim和 Kruskal 求最小生成树算法
生成树:在图中找一棵包含图中的所有节点的树,生成树是含有图中所有顶点的无环连通子图。所有可能的生成树中,权重和最小的那棵生成树就叫最小生成树。在无向加权图中计算最小生成树,使用最小生成树算法的现实场景中,图的边权重一般代表成本、距离这样的标量。
一枚大果壳
2023/11/07
3290
C++ Prim和 Kruskal 求最小生成树算法
Python 算法高级篇:最小生成树算法的优化与应用
最小生成树( Minimum Spanning Tree , MST )是图论中的一个重要问题,涉及到在一个加权连通图中找到一棵包含所有节点且边的权重之和最小的树。最小生成树问题在许多实际应用中都有重要作用,例如通信网络设计、电路板布线、城市规划等。在本篇博客中,我们将深入探讨最小生成树算法的优化和应用,主要关注两个著名的算法: Prim 算法和 Kruskal 算法。
小蓝枣
2023/11/02
9300
Python 算法基础篇之最小生成树算法: Prim 算法和 Kruskal 算法
在图论中,最小生成树是一个重要的概念,它是一个连通图的子图,包含图中的所有节点,并且边的权重之和最小。 Prim 算法和 Kruskal 算法是两种常用的最小生成树算法。本篇博客将重点介绍这两种算法的原理、应用场景以及使用 Python 实现,并通过实例演示每一行代码的运行过程。
小蓝枣
2023/07/25
1.4K0
【算法与图】通向高效解决方案的钥匙
BFS(广度优先搜索)是一种图的遍历算法,用于从一个起始节点出发,逐层访问图中的所有节点。其基本流程如下:
用户11305458
2024/10/09
9320
【算法与图】通向高效解决方案的钥匙
推荐阅读
相关推荐
最小生成树(Kruskal算法和Prim算法)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档