Search code examples
dllreverse-engineeringdllexportportable-executable

PE Export Directory Table's OrdinalBase field ignored?


In my experience and that of others (http://webster.cs.ucr.edu/Page_TechDocs/pe.txt), the PE/COFF specification document incorrectly claims that the Export Address Table indices that are contained in the Ordinal Table are relative to the Ordinal Base, and even gives an incorrect example (Section 5.3). In actuality, the indices in the Ordinal Table are 0-based indices into the Address Table for the normal case in which Ordinal Base = 1. I have seen this in VS Studio generated PE libraries and in system libraries like Kernel32.dll.

My question is, have you ever observed a binary with an Ordinal Base that was not equal to 1? I want to know if this an off-by-one error, or if the Ordinal Base is never applied to Ordinal Table entries.


Solution

  • Here's a dump for mfc42.dll, version 6.06.8064.0.

    Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    
    Dump of file mfc42.dll
    
    File Type: DLL
    
      Section contains the following exports for MFC42.dll
    
        00000000 characteristics
        4D79A4A3 time date stamp Fri Mar 11 05:27:15 2011
            0.00 version
               5 ordinal base
            6939 number of functions
               6 number of names
    
        ordinal hint RVA      name
    
              5    0 0000ED7C ?classCCachedDataPathProperty@CCachedDataPathProperty@@2UCRuntimeClass@@B
              6    1 0000ED44 ?classCDataPathProperty@CDataPathProperty@@2UCRuntimeClass@@B
              7    2 000DEEAC DllCanUnloadNow
              8    3 000DEE6C DllGetClassObject
              9    4 000DED0A DllRegisterServer
             10    5 000DEEDE DllUnregisterServer
            256      0004F84F [NONAME]
            [...]
           6943      0003B412 [NONAME]
    

    Here's how it looks in the binary:

    ;
    ; Export directory for MFC42.dll
    ;
                    dd 0                    ; Characteristics
                    dd 4D79A4A3h            ; TimeDateStamp: Fri Mar 11 05:27:15 2011
                    dw 0                    ; MajorVersion
                    dw 0                    ; MinorVersion
                    dd rva aMfc42_dll       ; Name
                    dd 5                    ; Base
                    dd 1B1Bh                ; NumberOfFunctions
                    dd 6                    ; NumberOfNames
                    dd rva functbl          ; AddressOfFunctions
                    dd rva nametbl          ; AddressOfNames
                    dd rva nameordtbl       ; AddressOfNameOrdinals
    ;
    ; Export Address Table for MFC42.dll
    ;
    functbl         dd rva ?classCCachedDataPathProperty@CCachedDataPathProperty@@2UCRuntimeClass@@B; 0
                    dd rva ?classCDataPathProperty@CDataPathProperty@@2UCRuntimeClass@@B; 1
                    dd rva DllCanUnloadNow  ; 2
                    dd rva DllGetClassObject; 3
                    dd rva DllRegisterServer; 4
                    dd rva DllUnregisterServer; 5
                    dd 0F5h dup(rva __ImageBase); 6
                    dd rva ??0_AFX_CHECKLIST_STATE@@QAE@XZ; 251
                    [...]
    ;
    ; Export Names Table for MFC42.dll
    ;
    nametbl         dd rva a?classccachedd, rva a?classcdatapat, rva aDllcanunloadno
                    dd rva aDllgetclassobj, rva aDllregisterser, rva aDllunregisters
    ;
    ; Export Ordinals Table for MFC42.dll
    ;
    nameordtbl      dw 0, 1, 2, 3, 4, 5
    

    So yes, it seems you're right and the indexes in the ordinal table are 0-based.