新书推荐:3.2.4节表二

B站影视 2024-11-27 16:20 5

摘要:intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,

实验十六:C语言实现将RVA地址转换为VA地址。

RVA地址转换为VA地址的方法:

sectionStartVa =sectionHeader->VirtualAddress + ntHeaders->OptionalHeader.ImageBase;

va = sectionStartVa + (rva - sectionStartRva)。

源代码

/*

FileName:RvaToVa.c

实验16:Rva地址转换为VA地址

(c) bcdaren, 2024

*/

#include

#include

#defineMAXSIZE 1024

#pragmacomment (lib,"dbghelp")

/*

函数使用64位PE的NT头结构体

*/

PVOIDRvaToVa64(PIMAGE_NT_HEADERS64ntHeaders, DWORDrva) {

PIMAGE_SECTION_HEADERsectionHeader = IMAGE_FIRST_SECTION(ntHeaders);

WORDnumberOfSections = ntHeaders->FileHeader.NumberOfSections;

for (WORDi = 0; i

DWORDsectionStartRva = sectionHeader->VirtualAddress;

DWORDsectionEndRva = sectionStartRva +sectionHeader->Misc.VirtualSize;

if (rva >= sectionStartRva && rva

//节区起始地址=节区虚拟内存起始地址+PE模块基址

DWORDsectionStartVa = (DWORD)sectionHeader->VirtualAddress +

(DWORD)ntHeaders->OptionalHeader.ImageBase;

unsignedlongva = sectionStartVa + (rva - sectionStartRva);

return (PVOID)va;

}

sectionHeader++;

}

returnNULL; // RVA not found

}

intWINAPIWinMain(HINSTANCEhInstance, HINSTANCEhPrevInstance,

PSTRszCmdLine, intiCmdShow)

{

constTCHARszCaption[MAXSIZE] = TEXT("RvaToVa");

staticTCHARszText[MAXSIZE] = { 0 };

// 获取当前模块的句柄

HMODULEhModule = GetModuleHandle(NULL);

// 获取模块的 IMAGE_NT_HEADERS 结构

PIMAGE_NT_HEADERSntHeaders = ImageNtHeader(hModule);

if (ntHeaders) {

// 假设要转换的 RVA 是 0x1000

ULONGrva = 0x1000;

//32位系统

//PVOID va = ImageRvaToVa(ntHeaders, hModule, rva, NULL);

//64位系统

PVOIDva = RvaToVa64((PIMAGE_NT_HEADERS64)ntHeaders, rva);

if (va) {

wsprintf(szText,TEXT("RVA 0x%08X converted to virtual address: %p\n"),rva, va);

}

else {

wsprintf(szText,TEXT("Failed to convert RVA to virtual address.\n"));

}

}

else {

wsprintf(szText, TEXT("Failed to retrieve IMAGE_NT_HEADERS.\n"));

}

MessageBox(NULL,szText,szCaption, MB_OK);

return 0;

图3-15 RVA 地址转VA地址

注意

1.注意观察多次在Windows 64位和32位系统下运行时,转换后的VA地址的变化。

2.XP系统使用VC6.0编译时,需要在编译目录C:\Program Files\Microsoft Visual Studio\VC98\Lib和Include中添加dbghelp.lib和dbghelp.h(注意选用i386处理器版本)。如果dbghelp.h头文件出现错误提示,请将其错误行去掉就可以了。

3.ImageRvaToVa函数在64位系统中会得到一个错误的VA地址,ImageRvaToVa函数只能在32位Windows系统中使用。为了兼容64位Windows系统,我们自定义了一个RvaToVa64函数,通过遍历节表的方法,确定RVA地址属于哪个节区,然后通过“节区起始地址=节区虚拟内存起始地址+PE模块基址”的方法获取VA地址。

4.PE文件内获取的基址是静态的基址,64位Windows系统将映像文件加载内存后动态获取的基址为重定位后的基址。

练习

使用汇编代码实现上述功能。可以考虑两种不同的方法实现:

方法1:调用ImageRvaToVa函数(64位系统中错误);

方法2:自己实现ImageRvaToVa函数的功能,兼容32位和64位操作系统;

实验十七:C语言实现将RVA地址转换为FOA地址。

RVA地址转换为FOA地址的方法:

sectionStartVa =sectionHeader->VirtualAddress + ntHeaders->OptionalHeader.ImageBase;

foa = sectionHeader->PointerToRawData(文件中的起始地址) + (rva - sectionStartRva)。

源代码

/*

FileName:RvaToFoa.c

实验17:Rva地址转换为FOA地址

(c) bcdaren, 2024

*/

DWORDRvaToFoa(PIMAGE_NT_HEADERSntHeaders, DWORDrva) {

// ntHeaders+4+sizeof(IMAGE_FILE_HEADER)+FileHeader.SizeOfOptionalHeader(32或64位PE)

DWORDsectionEndRva = sectionStartRva + sectionHeader->SizeOfRawData;

DWORDfoa = sectionHeader->PointerToRawData +(rva - sectionStartRva);

returnfoa;

}

}

return 0; // RVA not found

}

{

HMODULEhModule = GetModuleHandle(NULL); // 获取当前模块的句柄

if (ntHeaders) {

DWORDfoa = RvaToFoa(ntHeaders, rva);

if (foa) {

wsprintf(szText,TEXT("RVA 0x%08X converted to FOA: 0x%08X\n"), rva, foa);

}

else {

wsprintf(szText, TEXT("Failed to convert RVA to FOA.\n"));

}

}

else {

}

return 0;

}

运行:

图3-16 RVA地址转FOA地址

练习

使用汇编代码实现上述功能。

来源:墨先生文化艺术

相关推荐