Page 1 of 1

How to calculate the RVA of .idata ?

Posted: Tue Jul 29, 2014 5:35 am
by Bencz
Hi :)

I'm making a simple, very very simple code to generate a simple EXE file... but, I'm with some problens... I don't know how to compute the values of .idata....

For example, I have this IMAGE_SECTION_HEADER struct:

Code: Select all

scth[1].Name = ".idata";
scth[1].Misc.VirtualSize = 0x54;
scth[1].VirtualAddress = 0x2000;
scth[1].SizeOfRawData = 0x200;
scth[1].PointerToRawData = 0x400;
scth[1].Characteristics = 0xc0300040;
And, my ImageBase is: 0x400000
And the size of IMAGE_SECTION_HEADER is: 0x28

I want to call the printf function of msvcrt.dll, how I can build the informations in IMAGE_IMPORT_DESCRIPTOR ( with correct informations... and positions) ?

Re: How to calculate the RVA of .idata ?

Posted: Tue Jul 29, 2014 7:44 am
by alexfru
Here's one example (how to assemble my compiler with NASM into a Windows .exe) of doing that.

My linker does that as well.

The following is a sample app for my compiler (Smaller C) and linker that uses a few Win32 functions:

Code: Select all

// file: main2.c
//
// How to compile:
//   smlrc -seg32 main2.c main2.asm
//   nasm -f elf main2.asm -o main2.o
//   smlrl -verbose -win -o main2.exe main2.o -map main2.map >main2.txt

typedef unsigned uint32;

typedef struct
{
  union
  {
    uint32 Characteristics;
    uint32 OrdinalFirstThunk;
  } u;
  uint32 TimeDateStamp;
  uint32 ForwarderChain;
  uint32 Name;
  uint32 FirstThunk;
} tPeImageImportDescriptor;

static char hint_ExitProcess[] = "\0\0ExitProcess";
static char hint_GetStdHandle[] = "\0\0GetStdHandle";
static char hint_WriteFile[] = "\0\0WriteFile";

static void* hints[] =
{
  hint_ExitProcess,
  hint_GetStdHandle,
  hint_WriteFile,
  0
};

static void* iat[] =
{
  hint_ExitProcess,
  hint_GetStdHandle,
  hint_WriteFile,
  0
};

tPeImageImportDescriptor _dll_imports[] =
{
  {
    { hints },
    0,
    0,
    "kernel32.dll",
    iat
  },
  {
    { 0 }
  }
};

void ExitProcess(unsigned ExitCode)
{
  asm("push dword [ebp+8]\n"
      "call [_iat + 4*0]");
}

unsigned GetStdHandle(unsigned nStdHandle)
{
  asm("push dword [ebp+8]\n"
      "call [_iat + 4*1]");
}

int WriteFile(unsigned Handle,
              void* Buffer,
              unsigned NumberOfBytesToWrite,
              unsigned* NumberOfBytesWritten,
              void* Overlapped)
{
  asm("push dword [ebp+24]\n"
      "push dword [ebp+20]\n"
      "push dword [ebp+16]\n"
      "push dword [ebp+12]\n"
      "push dword [ebp+8]\n"
      "call [_iat + 4*2]");
}

void _start(void)
{
  char hwmsg[] = "Hello, World!\r\n";
  int h = GetStdHandle(-11);
  WriteFile(h, hwmsg, sizeof hwmsg - 1, 0, 0);
  ExitProcess(0);
}
My linker does little to nothing unusual w.r.t. dll import information, it simply looks up the symbol __dll_imports (the _dll_imports[] array in the above code), writes its relative (to image base) address into the PE optional header and converts a few pointers in the relevant tables/arrays to relative as well.

The relevant parts in RelocateAndWriteAllSections() are these:

Code: Select all

          peImportsStart = FindSymbolAddress("__dll_imports");
          if (peImportsStart)
            PeOptionalHeader.DataDirectory[1].VirtualAddress = peImportsStart - imageBase;
and

Code: Select all

  // In PE, some importing-related addresses must be relative to the image base, so make them relative
  if (OutputFormat == FormatWinPe32 && peImportsStart)
  {
    uint32 iofs;
    for (iofs = peImportsStart; ; iofs += sizeof(tPeImageImportDescriptor))
    {
      tPeImageImportDescriptor id;
      uint32 ofs, v;

      Fseek(fout, iofs - imageBase, SEEK_SET);
      Fread(&id, sizeof id, fout);
      if (!id.u.OrdinalFirstThunk || !id.Name || !id.FirstThunk)
        break;
      id.u.OrdinalFirstThunk -= imageBase;
      id.Name -= imageBase;
      id.FirstThunk -= imageBase;
      Fseek(fout, iofs - imageBase, SEEK_SET);
      Fwrite(&id, sizeof id, fout);

      for (ofs = id.u.OrdinalFirstThunk; ; ofs += sizeof v)
      {
        Fseek(fout, ofs, SEEK_SET);
        Fread(&v, sizeof v, fout);
        if (!v)
          break;
        v -= imageBase;
        Fseek(fout, ofs, SEEK_SET);
        Fwrite(&v, sizeof v, fout);
      }

      for (ofs = id.FirstThunk; ; ofs += sizeof v)
      {
        Fseek(fout, ofs, SEEK_SET);
        Fread(&v, sizeof v, fout);
        if (!v)
          break;
        v -= imageBase;
        Fseek(fout, ofs, SEEK_SET);
        Fwrite(&v, sizeof v, fout);
      }
    }
  }
Also, there are articles about the format, e.g. Peering Inside the PE: A Tour of the Win32 Portable Executable File Format.

Re: How to calculate the RVA of .idata ?

Posted: Wed Jul 30, 2014 5:27 am
by Bencz
Thanks ;)