Valhalla Legends Forums Archive | General Programming | Portable Executable (PE) RVA's

AuthorMessageTime
shadypalm88
For BNCSutil, I've been working on some code to read a portable executable (PE) file in order to locate the resource section, and in that section, the version information, and in that, the VS_FIXEDFILEINFO structure that contains the file version information needed to get the EXE version on non-Windows systems.  (Code: pe.h pe.c)  It's able to locate the resource section and parse its directory tree, and get each resource's information (i.e. size) just fine.

But then there's a problem.  Entries in the directory tree point to a small information stub that gives (most importantly) a file's size and its relative virtual address, or RVA.  An RVA is defined by the Microsoft documentation as:
[quote author=Microsoft]Relative Virtual Address. In an image file, an RVA is always the address of an item once loaded into memory, with the base address of the image file subtracted from it. The RVA of an item will almost always differ from its position within the file on disk (File Pointer).[/quote]

The gotcha is in the last sentence: I can't figure out how to resolve an RVA to an actual position in the file.  I tried subtracting the difference between the resource section's file pointer and its RVA from the structure's RVA, and although it came reasonably close, it undershot the start of the structure significantly.

The way it works right now is to just start at the resource information stub and move forward through the file to find the structure signature, but that's a crude hack.  Anyone have a better idea of how to get this working?
August 17, 2005, 4:42 PM
Arta
There's a base address in the header.

There's an easier way to get the version from resource information though:

[code]

char Filename[MAX_PATH];
GetModuleFileName(NULL, Filename, MAX_PATH);

DWORD Temp, Size = GetFileVersionInfoSize(Filename, &Temp);
if(!Size)
{
// Uhoh...
}

LPVOID VersionInfo  = new BYTE[Size];
GetFileVersionInfo(Filename, 0, Size, VersionInfo);

VS_FIXEDFILEINFO *Info;
UINT Len;
VerQueryValue(VersionInfo, "\\", (LPVOID*)&Info, &Len);

printf("\nProgram Version %u.%u\n", Info->dwProductVersionMS >> 16, Info->dwProductVersionLS);
[/code]
August 17, 2005, 5:01 PM
Arta
Oh, sorry - didn't see this was for non-windows.

The base address is somewhere in the NT header. I wrote this to patch the Import Address Table, it might help:

[code]
bool PatchIAT(DWORD ImageBase, DWORD Find, DWORD Replace)
{
// Get ImageBase address
if(!ImageBase)
{
return false;
}

IMAGE_DOS_HEADER *DosHeaders = (IMAGE_DOS_HEADER*)(__int64)ImageBase;
IMAGE_NT_HEADERS *Header = (IMAGE_NT_HEADERS*)(__int64)(ImageBase+DosHeaders->e_lfanew);

// Get an address for the IAT
DWORD IATSize = Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;

DWORD *IAT = (DWORD*)(ImageBase+Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress);

// Search for Find and overwrite it with Replace
for(DWORD *i=IAT; i<=IAT+IATSize; i+=4)
{
if(*i == Find)
{
DWORD Old;

if(!VirtualProtect((LPVOID)i, 4, PAGE_READWRITE, &Old))
{
return false;
}

*i = Replace;
return true;
}
}

return false;
}
[/code]

The resource table is in one of the data directories: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/image_data_directory_str.asp
August 17, 2005, 5:03 PM
Myndfyr
Rofl, I have been looking up info on PE because I'm trying to find out how to emit a DLL because I want my skin engine to support the .msstyles file format, which is just a resource DLL.  :)

Anyway:
http://www.windowsitlibrary.com/Content/356/11/1.html

There's a function there called ImageRvaToVa.  It might be able to help you out.  :)
August 17, 2005, 5:22 PM
shadypalm88
Thanks Arta, the following formula worked:
[quote]resource_offset = resource_section->raw_data_offset + (resource_rva - resource_section->virtual_address)[/quote]
August 17, 2005, 5:28 PM

Search