• Welcome to Valhalla Legends Archive.
 

Portable Executable (PE) RVA's

Started by shadypalm88, August 17, 2005, 11:42 AM

Previous topic - Next topic

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 from: MicrosoftRelative 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).

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?

Arta

There's a base address in the header.

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



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);

Arta

#2
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:


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;
}


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

MyndFyre

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.  :)
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

shadypalm88

Thanks Arta, the following formula worked:
Quoteresource_offset = resource_section->raw_data_offset + (resource_rva - resource_section->virtual_address)