Reversing
21 February 2011 2 Comments

Portable Executable: Converting RVA to File Offset and Back

Introduction

Most fields in a Portable Executable (.exe) file that refer to a location in memory use a so-called Relative Virtual Address (RVA). This is useful because it allows the Windows loader to load the executable in any virtual memory location, without having to change every pointer in the executable. The RVA is relative to the Load Base Address, which is the location where the first byte of the executable is loaded into memory. A virtual address refers to a location in memory, whereas a file offset refers to a location in an executable file on physical storage.

The goal is to convert between these values:

  • (Relative) Virtual Address: a location in virtual memory
  • File offset: a location in a file on physical storage

How it Works

When an executable is loaded into memory it is not copied byte for byte from disk. What happens is a process called aligning: the sections in a PE file are spaced so they all start on the first byte of a memory page (usually 4096 bytes on x86 systems). This can introduce padding at the end of sections. Because of this effect, among other things, we cannot translate directly between RVA and file offset.

An overview of information contained in the IMAGE_SECTION_HEADER.

Luckily, the PE file header contains a structure called IMAGE_SECTION_HEADER that allows us to make the translation. Since we can deduce the virtual memory layout from the this header, we can trace back the RVA to the PE section that resides at that address. Once we know the name of the PE section–and the offset into that section– we can find the file offset.

Of course, we can also reverse the process to find the a file offset’s corresponding RVA.

Example: RVA to File Offset

Let’s assume we have a RVA 0x11B4 for this example.

1. Find out which section the RVA belongs to.

  • The section .text starts at virtual offset 0x1000. Virtual offset is a synonym for RVA.
  • A virtual size of 0x24C, meaning the in-memory size in bytes, means the section ends at 0x1000+0x24C = 0x124C.
  • Our example RVA 0x11B4 is between 0x1000 and 0x124C, so it belongs to the .text section.

2. Subtract the virtual offset of the section from the RVA. This gives an offset relative to the .text section, instead of relative to the Load Base Address.

0x11B4 - 0x1000 = 0x1B4

3. Add the location of the .text section in the file to the offset for our final answer. The section offsets in the file are in the Raw Offset field.

0x1B4 + 0x400 = 0x5B4

So: the RVA 0x11B4  is equivalent to file offset 0x5B4. This formula summarizes the calculation.

File Offset = RVA - Section Virtual Offset + Section Raw Offset

Useful Programs

I suggest using a program like dumpbin or LordPE to help you analyze PE files. Most of these programs have a feature for translating between the offsets.

The location calculator of LordPE.

 

Credits for some parts of this text go to Sunshine2k for his tutorial.

2 Responses to “Portable Executable: Converting RVA to File Offset and Back”

  1. Mr.unknow 8 September 2011 at 5:37 pm #

    hello and thank you so much for this tutorial but i have a note on this subject first of all the method that you explained i think is true but in real life only this equitation can do the job
    Virtual Address – Image Base
    Yes i know that everyone agree with you but if we use for example ollydbg we can see in the command bar when we select an instruction something like this

    0040B967–>0040B968 : … | OFFEST:0000B967->0000B968

    so to double check this if we open the program with a hex editor and press ctrl+G and type B967 we will notice the same opecode at it is in the RVA so i hope that you have an answer for this and again thank you so much

    • tboerman 22 September 2011 at 10:38 pm #

      While that might be true for the first section of a PE executable, it is an oversimplification. The spacing between subsequent sections is changed (usually increased) when the PE file is loaded into memory, so you will see that your formula does not hold true for locations in subsequent sections.