4

I'm trying to get to IAT of a PE file. My plan is eventually overwrite some values so I can hook some stuff to help with unpacking, etc. I'm using this post https://stackoverflow.com/questions/7673754/pe-format-iat-questions as a guide. I'm currently on number 4 and that's where things are getting a little fuzzy for me. I'm able to get a pointer to an entry within the DataDirectory array. I chose the 13th entry because from my research http://msdn.microsoft.com/en-us/library/windows/desktop/ms680305%28v=vs.85%29.aspx it looks like that will lead me to the IAT. I'm not sure I'm on the right track because this DataDirectory has the value for size = 0 and virtualaddress = 172. Is the virtualsize of 172 an offset that must be added to some base address? I'm just working with a simple C program with no debug info that prints, "Hello World". Any help is greatly appreciated. Not sure how much showing the code will help my methodology but I'll post the relevant parts below. Any help is appreciated. Thanks!

pDOSHeader = ctypes.cast(hModule, ctypes.POINTER(IMAGE_DOS_HEADER)).contents

e_lfanew_offset = pDOSHeader.e_lfanew

offset_to_NTHeaders = e_lfanew_offset + hModule
pNTHeaders = ctypes.cast(offset_to_NTHeaders,ctypes.POINTER(IMAGE_NT_HEADERS)).contents

pImage_NT_Headers = pNTHeaders.OptionalHeader
pDataDirectory = pImage_NT_Headers.DataDirectory
pDataDirectory_IAT = pDataDirectory[13]

2 Answers 2

7

Don't rely on the IAT entry in the PE Data Directory to be accurate. The only truly accurate way to find the IAT(s) is to find actual calls from the disassembled code to statically imported API functions.

Let's use the following code in IDA as an example:

FF 15 44 60 03 01    call    ds:GetVersion

The actual disassembly of FF 15 44 60 03 01 is call dword ptr ds:[1036044h], but IDA knows this points to GetVersion(), so it shows the "pretty" disassembly instead. In this example, the address 1036044h is actually the virtual address of GetVersion()'s entry in the IAT for kernel32.dll. As such, you can now look "up" and "down" in memory near virtual address 1036044h to find the beginning and end of the IAT for kernel32.dll.

99% of the time, all IATs will be back-to-back in memory, so you should be able to find all IATs knowing only a single IAT entry address.

I recommend the method above instead of relying on content in the PE Import Tables since relying on the PE Import Tables will fail if the disassembled code had been packed, whereas the method above will work on packed and non-packed samples.

3

Note: only applicable if reading the PE from disk

You could simplify your code if you used pefile rather than Python ctypes. Here's a quick script for getting the hex address of some API name.

import pefile

try:
        pe = pefile.PE(f)
    except:
        print 'could not load file...exiting'
        return
ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint
ep_ava = ep+pe.OPTIONAL_HEADER.ImageBase
API_addr = None
for entry in pe.DIRECTORY_ENTRY_IMPORT:
      for imp in entry.imports:
          if 'SOME_API' in imp.name:
               API_addr = hex(imp.address).lower()

If you have questions about pefile check out the usage examples.

2
  • This will fail if the disassembled code had been packed; it's more reliable to find IAT references made from the code itself. Sep 26, 2013 at 21:54
  • 1
    @JasonGeffner You are right, I didn't realize he was referencing a memory handle. Maybe next time the user asks a question here he will add a little more details like in this other question... stackoverflow.com/questions/19018906/…
    – alexanderh
    Sep 26, 2013 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.