Question about Resolving _IMAGE_DATA_DIRECTORY

Two Offset Both Resolves to _IMAGE_DATA_DIRECTORY

This is the question of the day.

Background

To write custom shellcode, break free from tools, and do more.

One way of achieving that is to dynamically resolve symbols from kernel32.dll. And to do that, I have to get reference to _IMAGE_DATA_DIRECTORY structure, step by step.

One of the very first step is to resolve the address of the _IMAGE_NT_HEADERS.

Interestingly, two offsets can both do the same thing.

Description

First I checked kernel32 module base address.

lm m kernel32

file

Then I dumped the _IMAGE_DOS_HEADER.

file

Here, I found that two of the addresses 0x3C, and 0xF8 (0n248) can both resolve to _IMAGE_DATA_DIRECTORY.

file

file

The difference is the value after colon.

Best Guesses and Leads

  1. It has got something to do with relative virtual memory address or virtual memory address conversion.

  2. What is the address part doing in dt command in WinDBG? Something information missing?

  3. Look into the values behind the :, there must be some kind of conversion going on in the back (wrong!).

file

Final Answer

This is kind of embarrassing, since I haven't thought about the process carefully. Or, it's indeed a deviation from dt command and the actual operation that the code does.

The code for resolving the _IMAGE_DATA_DIRECTORY is as follows:

file

mov eax, [ebx + 0x3c]
mov edi, [ebx + eax + 0x18 + 0x60]
add edi, ebx

First of all, ebx contains the base address of kernel32.dll, assuming it's 0x76d00000.

Then, the first line.

mov eax, [ebx + 0x3c]

The [] operator retrieves what's in that address, which is the offset to PE header, 0xf8. So, that being said, 0x3c is the offset to the offset to PE header.

This can be confirmed by single stepping through the code.

eax now contains 0xf8.

file

Then, the second line.

mov edi, [ebx + eax + 0x18 + 0x60]

The code retrieves what's in address 0x76d00000 + 0xf8 + 0x18 + 0x60, this is the relative virtual address (RVA) of _IMAGE_DATA_DIRECROTY. In this case, 0x75480.

file

And it can be confirmed with dt.

dt _IMAGE_DATA_DIRECTORY (0x76d00000 + 0xf8 + 0x18 + 0x60)

file

And last line of code.

add edi, ebx

It gets the virtual memory address (VMA) of _IMAGE_DATA_DIRECROTY by adding the base address to the RVA above.

If I do a dt command on the VMA, I got

file

which indicates there's no offset from base address anymore, I am right at the data directory (correct me if I'm wrong on this).

Do a dd and check if I can read that address.

I can, which indicates a valid memory address.

file

And from now on, I can retrieve the fields in the data directory by adding the offsets according to this post.

_IMAGE_EXPORT_DIRECTORY function prototype.

typedef struct _IMAGE_EXPORT_DIRECTORY {
  DWORD Characteristics;
  DWORD TimeDateStamp;
  WORD MajorVersion;
  WORD MinorVersion;
  DWORD Name;
  DWORD Base;
  DWORD NumberOfFunctions;
  DWORD NumberOfNames;
  DWORD AddressOfFunctions;
  DWORD AddressOfNames;
  DWORD AddressOfNameOrdinals;
}

And look at this. It's confirmed that I'm accessing the _IMAGE_DATA_DIRECROTY since the value match.

file

I think I was wrong about the conversion behind the scene if I use 0x3c to dump the _IMAGE_DATA_DIRECROTY structure using dt command. There is no conversion at all. Using 0x3c is simply wrong.

dt command will dump any symbol accurately only with a correct starting vma. As the next picture shows, it can resolve the symbol even without an address, it's just the two fields are not calculated.

file

And with 0x76d00000 + 0x3c + 0x18 + 0x60, I got this result.

file

And the address at 0x76d00000 + 0xd556e6c2 is not accessible.

file

Summary

That concludes this question. There's some misunderstanding about the dt command. The most reliable way is to debug through the code and see how things work.

References