0

I'm trying to parse the PE files using C. The imports parsing is good but i have problem with the exports parsing. This is the code that I have wrote in order to parse the exports:

void PrintExports(DWORD imageBase) {

// Get the export section.
PIMAGE_DOS_HEADER ptrDosHeader = (PIMAGE_DOS_HEADER)imageBase;
PIMAGE_NT_HEADERS32 ptrNtHeaders = (PIMAGE_NT_HEADERS32)(ptrDosHeader->e_lfanew + imageBase);
DWORD exportsStartRVA = ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD exportsEndRVA = exportsStartRVA + ptrNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
PIMAGE_SECTION_HEADER ptrExportsHeader = GetSectionHeaderByRVA(exportsStartRVA, ptrNtHeaders);

// Check it's not null..
if (!ptrExportsHeader) 
    return;

PIMAGE_EXPORT_DIRECTORY ptrExportsDirectory = (PIMAGE_EXPORT_DIRECTORY)(imageBase + exportsStartRVA );

printf("Exports\n");
printf("    Exports.section: %s\n", ptrExportsHeader->Name);
printf("    Exports.ordinalBase: %x\n", ptrExportsDirectory->Base);
printf("    Exports.NumberOfFunctions: %x (hex)\n", ptrExportsDirectory->NumberOfFunctions);
printf("    Exports.NumberOfNames: %x (hex)\n", ptrExportsDirectory->NumberOfNames);

PDWORD ptrExportsFunctions = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfFunctions + imageBase);
PDWORD ptrExportsNamesOrdinals = (PDWORD)((DWORD)ptrExportsDirectory->AddressOfNameOrdinals + imageBase);
PDWORD * ptrExportsNames = (PDWORD *)((DWORD)ptrExportsDirectory->AddressOfNames + imageBase);

printf("    Exports.functions:\n");
printf("        EntryPoint  Ordinal  Name\n");

for (int i = 0; i < ptrExportsDirectory->NumberOfFunctions; i++) {
    if (ptrExportsFunctions[i] == 0)
        continue;

    printf("        %010x  %07x", ptrExportsFunctions[i], i + ptrExportsDirectory->Base);

    if ((ptrExportsFunctions[i] >= exportsStartRVA) && (ptrExportsFunctions[i] <= exportsEndRVA))
        printf(" (forwarder -> %s)", ptrExportsFunctions[i] + imageBase);

    printf("\n");
}

return;
}

As a result of running this code, I get the ordinals and the addresses of the exports. The problem starts when I'm trying to get the names with the code below (this code should be inside the "for" loop). What happens is that I get access violation exception (the PE I'm trying to parse in this example is shell32.dll):

for (int j = 0; j < ptrExportsDirectory->NumberOfNames; j++) {
        if (ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base) {
            printf("  %s", ptrExportsNames[j]);
        }
    }

Moreover, in some cases (for example if the PE I'm trying to parse is user32.dll) the ptrExportsNamesOrdinal[j] has value that can never be equal to i + ptrExportsDirectory->Base. You can see the screenshot below:

enter image description here

Orih90
  • 77
  • 1
  • 3
  • 9
  • You can use [dumpbin](https://learn.microsoft.com/en-us/cpp/build/reference/dash-exports?view=vs-2019) utility to get the result and compare with yours. Refer to [here](https://stackoverflow.com/questions/4298331/exe-or-dll-image-base-address). – Rita Han Sep 19 '19 at 08:51
  • See, how it's done [here](https://github.com/jovibor/libpe/blob/689f352c7d4433fd217454d019611486418d6a50/libpe/src/clibpe.cpp#L1126). – Jovibor Sep 19 '19 at 13:28
  • Possible duplicate of [Show info about IMAGE\_EXPORT\_DIRECTORY](https://stackoverflow.com/questions/49705700/show-info-about-image-export-directory) – Erlend Graff Sep 23 '19 at 16:52

2 Answers2

1

The condition

(ptrExportsNamesOrdinals[j] == i + ptrExportsDirectory->Base)

used in the if test is wrong. The Export Ordinal Table actually does not contain ordinals, but indices into the Export Address Table (this is an error in the PE/COFF specification - see https://stackoverflow.com/a/40001778/2646573).

The test condition you should use instead is

(ptrExportsNamesOrdinals[j] == i)

as shown in the example here: https://stackoverflow.com/a/49708023/2646573.

Erlend Graff
  • 1,098
  • 16
  • 27
  • This is not working. I put the new condition instead of the old one and tried it over user32.dll. – Orih90 Sep 22 '19 at 16:43
  • Even when I try only to iterate the names it failed. What is wrong with this code: `for (int j = 0; j < ptrExportsDirectory->NumberOfNames; j++) { DWORD export_symname_rva = ptrExportsNamesOrdinals[j]; const char *export_symname = (const char *)(export_symname_rva + imageBase); printf("%s", export_symname); }` – Orih90 Sep 22 '19 at 17:08
0

What I did to fix it:

PDWORD ptrExportsFunctions = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfFunctions);
PDWORD ptrExportsNames = (PDWORD)(imageBase + ptrExportsDirectory->AddressOfNames);
PWORD ptrExportsNamesOrdinals = (PWORD)(imageBase + ptrExportsDirectory->AddressOfNameOrdinals);

And than in the loop:

for (DWORD j = 0; j < ptrExportsDirectory->NumberOfNames; j++)
    {
        if(ptrExportsNamesOrdinals[j] == i){
            printf("%s", (char*)imageBase + ptrExportsNames[j]);
        }
    }

Now Everything works well.

Orih90
  • 77
  • 1
  • 3
  • 9