Gau*_*gal 6 c++ windows portable-executable
在此文章中,定义
DWORD VirtualAddress
在 EXE 中,此字段保存 RVA 到加载程序应将部分映射到的位置。要计算内存中给定节的实际起始地址,请将图像的基地址添加到存储在此字段中的节的 VirtualAddress。
DWORD PointerToRawData
这是可以找到编译器或汇编器发出的原始数据的基于文件的偏移量。如果您的程序内存映射 PE 或 COFF 文件本身(而不是让操作系统加载它),则该字段比 VirtualAddress 字段更重要。在这种情况下,您将拥有一个完全线性的文件映射,因此您将在此偏移量处找到节的数据,而不是在 VirtualAddress 字段中指定的 RVA
也RVA被定义为
PE 文件中的许多字段都是根据 RVA 指定的。RVA 只是某个项目的偏移量,相对于文件的内存映射位置
和
要将 RVA 转换为可用指针,只需将 RVA 添加到模块的基地址即可。基地址是内存映射的 EXE 或 DLL 的起始地址
手头的问题是到达import sectionPE 文件。
hFile = CreateFile(..);
hFileMapping = CreateFileMapping(..);
lpFileBase = MapViewOfFile(..);
ImageBase = (PIMAGE_DOS_HEADER)lpFileBase;
PEHeader = (ImageBase + ImageBase->e_lfanew);
Run Code Online (Sandbox Code Playgroud)
现在要掌握 import table
PIMAGE_OPTIONAL_HEADER PEImageOptionalHeader = &(PEHeader->OptionalHeader);
IMAGE_DATA_DIRECTORY importTable = PEImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
Run Code Online (Sandbox Code Playgroud)
由于importTable.VirtualAddress是 RVA,为了获得可用的指针,我可以添加图像文件的基础。
所以ImageBase + importTable.virtualAddress应该让我导入部分。但它没有。为什么?
然后,如果我到达正确的部分标题(通常.idata)并执行此操作。
ImageBase + pointerToSection->PointerToRawData;
Run Code Online (Sandbox Code Playgroud)
以上正确地将我带到了IMAGE_IMPORT_DESCRIPTORS. 我知道使用pointerToSection->virtualAddress而不是PointerToRawData上面的数组是行不通的,因为我自己正在映射 PE 文件。
现在要获取name项目的 ,加载的模块依赖于,我可以使用指针来IMAGE_IMPORT_DESCRIPTORS使用该字段name,该字段又是一个RVA. 要转换一个RVA,我只需要添加ImageBase..
LPSTR libname = (PCHAR)((DWORD)ImageBase+ImageimportDescriptor->Name);
Run Code Online (Sandbox Code Playgroud)
但它不起作用。为什么?要转换一个RVA,我们只需添加图像的基地址。下面的工作
ImageBase+ImageimportDescriptor->Name + pointerToSection->PointerToRawData - pointerToSection->virtualAddress
Run Code Online (Sandbox Code Playgroud)
每次我需要某个部分中的一些信息时,我都需要进行此调整
pointerToSection->PointerToRawData - pointerToSection->virtualAddress
Run Code Online (Sandbox Code Playgroud)
为什么需要这种调整?
首先,这一行:
PEHeader = (ImageBase + ImageBase->e_lfanew);
Run Code Online (Sandbox Code Playgroud)
是不正确的。ImageBase是这样的类型,PIMAGE_DOS_HEADERS所以当你添加它时ImageBase->e_lfanew,这是DWORD你在做指针算术,也就是说,你添加的ImageBase字节(ImageBase->e_lfanew)*sizeof(IMAGE_DOS_HEADERS)数不是你想要的。您想要的是ImageBase->e_lfanew从位置ImageBase指向的位置推进字节。您可以通过执行以下操作来实现此目的:
PIMAGE_NT_HEADERS PEheader = (PIMAGE_NT_HEADERS) ((PBYTE)(ImageBase) + dosHeader->e_lfanew);
注意强制转换为PBYTE,这使操作逐字节推进。
这在处理 PE 文件时很常见,因为很多时候您希望从指针前进 n 个字节而不是指针指向的 n 个数据结构。在您提到的文章中,甚至在评论中说:
// Ignoring typecasts and pointer conversion issues for clarity...
pNTHeader = dosHeader + dosHeader->e_lfanew;
Run Code Online (Sandbox Code Playgroud)
现在回答你关于VirtualAddressand的问题PointerToRawData:
由于ImageBase + importTable.virtualAddress以下原因,该行也不正确:
PE 加载器不会像您在文件映射中那样连续映射内存中的所有可执行文件,而是将每个部分映射到相应的VirtualAddress. 在后一种情况下,从你刚才添加的RVA得到VAImageBase的RVA和它的作品,因为磁盘上的文件,就是要什么样的PE装载在内存映射的表示。但是,由于您没有将每个部分映射到 PE 加载器将映射它们的位置,因此将 加入ImageBase到RVA您所做的工作中是行不通的。
您需要一个给定 RVA 的函数,为您提供与磁盘文件中该 RVA 对应的文件偏移量。要获得 VA,您只需将此文件偏移量添加到指向映射文件的字节指针。
每当您有 RVA(如导入部分的 RVA,或名称字符串或其他内容)时,为了访问它,您必须执行以下操作。
PBYTE actualAddress = (PBYTE) (lpFileBase + RVAtoFileOffset(pNTHeader, RVA))
这是功能:我将它发布在 pastebin 上,因为我无法在此处正确格式化它。
它的工作原理如下:当您有 RVA 时,该 RVA 必须位于一个节内,因此您遍历所有节标题(位于可选标题之后),并且当您找到 RVA 所在的节时,您计算该 RVA 在该部分中的偏移量RVA - VirtualAddress并将其添加到该PointerToRawData部分的 ,现在您拥有 RVA 的文件偏移量。如果 RVA 无效(它不属于任何部分),则函数返回 0。
您需要这样做才能访问导入目录或每个导入描述符的名称,因为您拥有的是 RVA。
我希望我有所帮助。
| 归档时间: |
|
| 查看次数: |
3065 次 |
| 最近记录: |