Printing the DLLs imported by a PE (64 bit)

Viewed 187

I seriously can't understand why this is happening. I'm able to correctly parse the majory of the PE format except for this. I'm trying to print all DLLs being used by a particular PE.

First I get the ImportTable from the Data Directory:

IMAGE_DATA_DIRECTORY importDir = (IMAGE_DATA_DIRECTORY)peHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

Then I just add its address to the address where I mapped it,i.e the address returned by MapViewOfFile:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)((ULONG *)pe + importDir.VirtualAddress);

    printf("%s\n", (ULONGLONG *)pe + importDescriptor[0].Name);

For some reason this is crashing, how do I go about this?

1 Answers

Your pointer arithmetic is wrong. (ULONG *)pe + ... and (ULONGLONG *)pe + ... don't do what you think they do.

When you advance a pointer T* by an integer N, the address stored in the pointer is advanced by N number of T elements - ie by N * sizeof(T) number of bytes.

When you type-cast pe to ULONG* and then add importDir.VirtualAddress to it, you are advancing the address stored in pe by sizeof(ULONG) * VirtualAddress number of bytes, rather than by VirtualAddress number of bytes.

Likewise, when you type-cast pe to ULONGLONG* and then add importDescriptor[0].Name to it, you are advancing the address in pe by sizeof(ULONGLONG) * Name number of bytes, rather than by Name number of bytes.

That is not what you want in this situation. Virtual addresses in a PE are absolute offsets from the base address, so you need to advance the base address by N bytes, not multiples of N bytes, so any T* used for such a type-cast needs to be a pointer to a 1-byte data type, such as BYTE or char.

So, in your example, to advance your base address pe by N number of bytes, use BYTE* for the type cast, eg:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)(((LPBYTE)pe) + importDir.VirtualAddress);
...
printf("%s\n", (char*)(((LPBYTE)pe) + importDescriptor[0].Name));

Alternatively, you can use integer arithmetic instead of pointer arithmetic, by type-casting your base address to an integer such as ULONG_PTR (a pointer-sized ULONG), eg:

PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
        (PIMAGE_IMPORT_DESCRIPTOR)(((ULONG_PTR)pe) + importDir.VirtualAddress);
...
printf("%s\n", (char*)(((ULONG_PTR)pe) + importDescriptor[0].Name));
Related