10

I am currently writing a PE parser/loader. I have successfully loaded the PE file into memory using standard c file io, retrieved valid DOS and PE headers (the optional header) as well as gaining access to the PE's sections. My next target is to gain access to the Export table to retrieve exported symbols. To do this i have used the RVA stored in the optional headers data-dictionary array at index 0 (which i believe points to the export table) and added this address to the address of the PE file loaded into program memory, then casted this into a valid export table header. I am turning up NULL addresses and data when i do this. here is a small code snippet;

// RVA from optional headers data dictionaries array cast to Export directory type 
  IMAGE_EXPORT_DIRECTORY* ied(
  (IMAGE_EXPORT_DIRECTORY*)((void*)
  ((unsigned char*)buffer + ioh->DataDirectory[0].VirtualAddress)));

Do i have to use memory mapped IO to do this properly? Am i calculating the address wrong? Information on PE RVA's seems sparse. thanks in advance.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
jmgunn
  • 101
  • 1
  • 1
  • 3
  • The set of articles pointed to in this SO answer might be helpful: http://stackoverflow.com/questions/2307754/within-a-dll-how-is-the-function-table-structured/2307850#2307850 – Michael Burr Jun 04 '10 at 16:34

4 Answers4

16

I opened one my old project from the time as I like you examined the structure of import and export directories (IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT and IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). I can in short explain the part where you have a problem. I mean the part how to find out the pointer to for example IMAGE_EXPORT_DIRECTORY inside of PE.

First of all of cause it is possible to use Read/Write file operations to analyse a PE file, but it is much easier to use file mapping like following:

hSrcFile = CreateFile (pszSrcFilename, GENERIC_READ, FILE_SHARE_READ,
                       NULL, OPEN_EXISTING, 0, NULL);
hMapSrcFile = CreateFileMapping (hSrcFile, NULL, PAGE_READONLY, 0, 0, NULL);
pSrcFile = (PBYTE) MapViewOfFile (hMapSrcFile, FILE_MAP_READ, 0, 0, 0);

after we have the pointer pSrcFile which point to the PE file contain we can find another important places inside of PE:

pDosHeader = (IMAGE_DOS_HEADER *)pSrcFile;
IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32 *)
    ((PBYTE)pDosHeader + pDosHeader->e_lfanew);
IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *)
    ((PBYTE)&pNtHdr->OptionalHeader +
     pNtHdr->FileHeader.SizeOfOptionalHeader);

Now we have all needed virtual address of any directory. For example,

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

is a virtual address of export directory. After that to convert the virtual address to the memory pointer, we should find out the section of PE which has this virtual address inside. To do this we can enumerate sections of PE and find an i greater or equal to 0 and less then pNtHdr->FileHeader.NumberOfSections where

pFirstSectionHeader[i].VirtualAddress <= 
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

and at the same time

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
< pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize

then you should search for export data in the section pFirstSectionHeader[i]:

IMAGE_SECTION_HEADER *pSectionHeader = &pFirstSectionHeader[i];
IMAGE_EXPORT_DIRECTORY *pExportDirectory =
   (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
    pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress -
    pSectionHeader->VirtualAddress);

The same procedure you should repeat to find (IMAGE_IMPORT_DESCRIPTOR *) which corresponds to IMAGE_DIRECTORY_ENTRY_IMPORT and (IMAGE_BOUND_IMPORT_DESCRIPTOR *) which corresponds to IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT to dump import information inclusive a binding information (if exist).

To dump information from IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT (corresponds to (ImgDelayDescr *) defined in delayimp.h) you should use also information from the IMAGE_DIRECTORY_ENTRY_IAT (corresponds to (IMAGE_THUNK_DATA32 *)).

For more information about PE I recommend you http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

Jason Shirk
  • 7,734
  • 2
  • 24
  • 29
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Just for clarification, can you say where `pbyFile` comes from? – Ray Mar 01 '15 at 16:28
  • @DebugErr: It's the same as `pSrcFile` used before. One don't need to read the whole EXE/DLL file in memory. One can just use memory mapping methods to access it. – Oleg Mar 01 '15 at 16:39
  • I see, I'm writing this in C#, so I'm a bit lazy right now and just needed the address in the file (pSrcFile would just be 0 then for the calculation). I implemented your function, but except for the TimeDateStamp field, all my other ExportDataDirectory fields look horribly wrong :( – Ray Mar 01 '15 at 16:45
  • @DebugErr: Sorry, but I can't debug your code. I can only guess that you can have problems with 64-bit/32-bit. See my [another old answer](http://stackoverflow.com/a/3430822/315935). – Oleg Mar 01 '15 at 16:49
  • I didn't want you to :) I'll read over the MSDN article again, if I found a solution, I'll post what I did wrong. – Ray Mar 01 '15 at 17:04
  • @DebugErr: Do you tried [the code](http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c) which I referenced in [the answer](http://stackoverflow.com/a/3430822/315935)? Does it produce the correct results for your test DLL/EXE? If it's so that you will need just to rewrite it using managed code. – Oleg Mar 01 '15 at 18:07
  • Compared you code with mine, looks like the data I parsed out wasn't so wrong. However, your code also has problems with many exports, it prints several lines going like `29 [NONAME] (forwarded to ï Uï∞ §...)` (tried to parse `C:\Windows\SysWOW64\shell32.dll` of Win 8.1.1) – Ray Mar 01 '15 at 20:50
  • @DebugErr. I'm sure thet in 10 year the code will displays even more errors for the files compiled 10 years later. :-) I can you suggest to debug the code only. I personally do nothing in the direction since years... – Oleg Mar 01 '15 at 21:01
  • I solved it in C#, it works flawlessy from the first tries. In case you're interested, this is the code: http://debugerr.vibeware.net/stackoverflow/ReadExportTables.cs – Ray Mar 03 '15 at 21:29
0

There is macro defined to get first section

PIMAGE_SECTION_HEADER FisrtSection = IMAGE_FIRST_SECTION(NtHeaders)

Sunil
  • 1
0

Not all PE images will have an export directory table. You need to check the optional header's Windows-specific "NumberOfRvaAndSizes" field. If it is less than or equal to IMAGE_DIRECTORY_ENTRY_EXPORT (0), then there is no export directory table (i.e. there is nothing valid located at ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).

See the answer to this question for an example.

Community
  • 1
  • 1
Dan Moulding
  • 211,373
  • 23
  • 97
  • 98
0

I have written the python code to print all import and export functions of pe file. You will get the nice idea of how to do that in C. In data directory we have to check if the export directory rva and size is '0' or not. if not '0' we can proceed. You can use tool 'CFF explorer' from Nt core website. this is very good tool which will show how the data maps into export directory and then you can parse it easily. Here is the blog.

doork
  • 1
  • 1
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/31006342) – Nuclear03020704 Feb 10 '22 at 16:25