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

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

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

将VA地址转换为FOA文件偏移: VA就是虚拟地址,转换为FOA文件偏移,其手工计算过程如下所示。

首先需要得到 ImageBase(镜像基址) 其次得到入口点地址,将两个地址相加即可得到VA,也就是实际装入地址。

image.png

通过上方的已知条件我们就可以计算出程序实际装入内存后的入口地址了.

VA(实际装入地址) = ImageBase(基址) + RVA(偏移) => 00400000 + 0000158b = 0040158b

如果不放心,可以将源程序拖入X64DBG中观察是否一致,如下OEP为 0040158b 与我们的计算结果完全一致。

image.png

接着我们需要得到 .text节 基地址以及 .text节 RVA,如下命令即可获取到。

image.png

虚拟地址开始位置:节区基地址 + 节区RVA => 00400000 + 00001000 = 00401000

image.png

虚拟地址结束位置:text节地址 + 节区尺寸 => 00401000 + 0x00000B44 = 00401B44

image.png

计算得出,虚拟地址text节开始位置 00401000 结束位置是 00401B44 打开X64dbg验证没错 确实落在了 text节上。

判断是否落在了.text节的依据是 开始位置 >= 401000 结束位置 <= 402000 很明显:00401B44小于402000。

image.png

接着我们就来计算一下,当前的VA地址0040158B其对应到文件中的偏移FOA位置是多少,计算公式如下。

image.png

RVA(相对偏移) = VA - (.text节首地址) => 0040158B - 00401000 = 58B
FOA(文件偏移) = RVA + .text节对应到文件中的偏移 => 58B + 400 = 98B

image.png

计算出结果了,我们使用WinHEX定位到98B处看看是否符合要求,机器码完全一致,符合要求。

image.png

接着就是使用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

image.png

VA(虚拟地址) = FOA(.text节) + ImageBase + VPK => F43 + 400000 + C00 = 401B43

image.png

计算后的结果F43对应到VA地址是401B43 验证一下,没错。

image.png

通过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

image.png

计算出结果158b虚拟地址对应到文件偏移为98B,验证一下看看。

image.png

使用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

image.png

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

VA = 00400000 + 00001000 + 58B = 40158b

image.png

结果就是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地址是多少?

image.png

输入命令 GetPE.exe c://lyshark.exe --VaToFoa 0040158b 完成计算,对应FOA 是 0000098B

image.png

计算结果完全一致。

image.png

在反转回去将FOA0000098B 转为VA地址,完全一致,没问题了,无脑乱搞。

image.png

相关文章
|
算法 编译器 程序员
BIT-3-函数(6000字详解析)
BIT-3-函数(6000字详解析)
58 0
|
7月前
将图片(路径)转换为Base64 和 将base64转换为file类型
将图片(路径)转换为Base64 和 将base64转换为file类型
|
7月前
|
存储
TS 自定义结构Long与number类型相互转换
TS 自定义结构Long与number类型相互转换
269 0
|
7月前
|
编解码
ABB AO02 SD系列输入/输出控制器
ABB AO02 SD系列输入/输出控制器
|
Linux Windows
PE格式:实现ELF结构解析工具
ELF文件格式,是一个开放的可执行文件和链接文件格式,其主要工作在Linux系统上,是一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件,ELF文件格式类似于PE格式,但比起PE结构来ELF结构显得更加的简单,Linux文件结构相比于Windows结构来说简单一些.
249 0
|
存储 Windows
2.4 PE结构:节表详细解析
节表(Section Table)是Windows PE/COFF格式的可执行文件中一个非常重要的数据结构,它记录了各个代码段、数据段、资源段、重定向表等在文件中的位置和大小信息,是操作系统加载文件时根据节表来进行各个段的映射和初始化的重要依据。节表中的每个记录则被称为`IMAGE_SECTION_HEADER`,它记录了一个段的各种属性信息和在文件中的位置和大小等信息,一个文件可以由多个`IMAGE_SECTION_HEADER`构成。
192 0
2.4 PE结构:节表详细解析
|
JSON Go 数据格式
Go 结构体与 JSON 之间的转换
本文介绍了 Go 语言里,JSON 与结构体之间的转换。在结构体转 JSON 时,我们可以通过给字段打标签,指定转换后的 key 命名,需要注意的是,如果结构体的字段为非导出字段或字段的 JSON 标签值为 -,在转换 JSON 时,将会被忽略。反之 JSON 解析结构体时也是一样的。
412 1
Go 结构体与 JSON 之间的转换
|
编译器 C++
驱动开发:内核PE结构VA与FOA转换
本章将继续探索内核中解析PE文件的相关内容,PE文件中FOA与VA,RVA之间的转换也是很重要的,所谓的FOA是文件中的地址,VA则是内存装入后的虚拟地址,RVA是内存基址与当前地址的相对偏移,本章还是需要用到`《驱动开发:内核解析PE结构导出表》`中所封装的`KernelMapFile()`映射函数,在映射后对其PE格式进行相应的解析,并实现转换函数。
247 0
|
安全 编译器 数据安全/隐私保护
PE格式:VA地址与FOA地址
PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如文件加密与解密,病毒分析,外挂技术等。
241 0
PE格式:VA地址与FOA地址
|
存储 编译器 开发者
PE格式:分析IatHook并实现
Ring 3层的 IAT HOOK 和 EAT HOOK 其原理是通过替换IAT表中函数的原始地址从而实现Hook的,与普通的 InlineHook 不太一样 IAT Hook 需要充分理解PE文件的结构才能完成 Hook,接下来将具体分析 IAT Hook 的实现原理,并编写一个DLL注入文件,实现 IAT Hook 。
270 0
PE格式:分析IatHook并实现