Search code examples
c++dlldependenciesportable-executable

import directory of a DLL does not work on 64bit dll


I am trying to print the bitness and dll's that needs to be loaded for a given dll.

My code looks like this (simplified version;without error checking):

fh = CreateFile("my_dll_file.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
fm = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL);
base_pointer = (char *)MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
pe = ImageNtHeader(base_pointer);
oh = pe->OptionalHeader;
mi = oh.Magic;
    switch (mi) {
    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
        puts("64-bit");
        break;
    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
        puts("32-bit");
        break;
    default:
        puts("no match bitness\n");
        break;
    }
rva = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
sec = ImageRvaToSection(pe, base_pointer, rva);
sb = (char *)(base_pointer + sec->PointerToRawData);
sa = (char *)(sb - sec->VirtualAddress);
id = (IMAGE_IMPORT_DESCRIPTOR *)(sa + rva);
while (!IsBadReadPtr(id, sizeof(*id)) && id->Name) {
printf("\ndependency \"%s\":\n", (char *)(sa + id->Name));
id++;
}

However this only works with 32bit dll's. My 'rva' turns out to be 0 when tried on 64 bit dll. Bitness check in the lines above work fine though. Any pointers on what might be going wrong with 64 bit dll's?

EDIT: I guess the problem might be that my target is x86 (and im linking against dbghelp.lib which is 32bit). Changing the target to x64 obviously gives me linker errors. However I dont have any dbghelp.lib 64 bit version to link against. Is that even available. I couldnt find it.


Solution

  • For the bitness you should use pe->FileHeader.Machine:

    switch (pe->FileHeader.Machine) {
    case IMAGE_FILE_MACHINE_AMD64:
        puts("64-bit");
        break;
    case IMAGE_FILE_MACHINE_I386:
        puts("32-bit");
        break;
    default:
        puts("no match bitness\n");
        break;
    }
    

    Yours didn't work because there are 2 different variants of IMAGE_OPTIONAL_HEADER depending on the bitness.
    So this should work for rva:

    if (pe->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
      rva = ((PIMAGE_OPTIONAL_HEADER32)&pe->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    else
      rva = ((PIMAGE_OPTIONAL_HEADER64)&pe->OptionalHeader)->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;