PE 导出目录表的 OrdinalBase 字段被忽略?

Posted

技术标签:

【中文标题】PE 导出目录表的 OrdinalBase 字段被忽略?【英文标题】:PE Export Directory Table's OrdinalBase field ignored? 【发布时间】:2011-08-04 22:18:39 【问题描述】:

根据我和其他人的经验 (http://webster.cs.ucr.edu/Page_TechDocs/pe.txt),PE/COFF 规范文档错误地声称包含在序数中的导出地址表索引表是相对于序数基数的,甚至给出了一个不正确的例子(第 5.3 节)。实际上,Ordinal Table 中的索引是地址表中基于 0 的索引,在 Ordinal Base = 1 的正常情况下。我在 VS Studio 生成的 PE 库和 Kernel32.dll 等系统库中看到了这一点。

我的问题是,你有没有观察过序数基数不等于 1 的二进制文件?我想知道这是否是一个错误的错误,或者 Ordinal Base 是否从未应用于 Ordinal Table 条目。

【问题讨论】:

【参考方案1】:

这是 mfc42.dll 的转储,版本 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]

这是它在二进制文件中的样子:

;
; 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

是的,看来您是对的,序数表中的索引是基于0的

【讨论】:

甜蜜!感谢您确认。你是怎么得到导出表列表的,那是 IdaPro 的输出吗? 是的,它来自 IDA。我只用默认名称重命名了表。【参考方案2】:

这不是一个错误的错误,序数基数不应用于序数表条目,而是应用于序数本身的计算。是的,Microsoft PE 规范(http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx,第 5.3.4 节)是错误的。应该这样计算:

i = Search_ExportNamePointerTable(ExportName);
ordinal = ExportOrdinalTable[i] + OrdinalBase;  // The "+ OrdinalBase" is missing in the official PE specification
SymbolRVA = ExportAddressTable[ordinal - OrdinalBase];

或者,用不同的方式表达:

i = Search_ExportNamePointerTable(ExportName);
offset = ExportOrdinalTable[i];
SymbolRVA = ExportAddressTable[offset];
ordinal = OrdinalBase + offset;

如果我转储我的 mfc42.dll...

dumpbin mfc42.dll /exports |more

...这是我得到的:

Microsoft (R) COFF/PE Dumper Version 12.00.20827.3
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
    4D798B26 time date stamp Fri Mar 11 03:38:30 2011
        0.00 version
           5 ordinal base
        6888 number of functions
           8 number of names

    ordinal hint RVA      name

       1452    0 000EF5D8 ?AfxFreeLibrary@@YAHPEAUHINSTANCE__@@@Z
       1494    1 000EF5A4 ?AfxLoadLibrary@@YAPEAUHINSTANCE__@@PEBD@Z
       1497    2 000F8344 ?AfxLockGlobals@@YAXH@Z
       1587    3 000F83DC ?AfxUnlockGlobals@@YAXH@Z
          7    4 000FC83C DllCanUnloadNow
          8    5 000FC7E0 DllGetClassObject
          9    6 000FC870 DllRegisterServer
         10    7 000FC87C DllUnregisterServer
          5      0001C910 [NONAME]
          6      0001C8E8 [NONAME]
        256      0005DEC0 [NONAME]
        257      000423C0 [NONAME]
        258      00042400 [NONAME]
        259      00042440 [NONAME]
        [...]

上面的第7个函数(例如)是DllRegisterServer,它对应mfc42.dll下面的十六进制转储中导出序号表中的第7个字(0x0004)。开头是A7 05

59 CC 12 00 6B CC 12 00 A7 05 D1 05 D4 05 2E 06
02 00 03 00 04 00 05 00 4D 46 43 34 32 2E 64 6C

计算:

i = Search_ExportNamePointerTable("DllRegisterServer") = 7 - 1 = 6  // zero-based
offset = ExportOrdinalTable[6] = 4
SymbolRVA = ExportAddressTable[4] = ...
ordinal = OrdinalBase + offset = 5 + 4 = 9

【讨论】:

【参考方案3】:

NO,PE 导出目录表的 OrdinalBase 字段不会被忽略!

上面提供的示例 (mfc42.dll) 是一个很好的示例(因为它的 Ordinal Base 不是 1)。

这里有两个关于这个问题的评论:

。就序数字段而言,转储工具的输出是正确的。它显示 Base 字段为 5。这意味着,当按名称从 mfc42.dll 导入导出函数时,导出地址表中计算的偏移量将为 x-5。 Microsoft 规范第 5.3 节是正确的。

。就提示而言,转储工具的输出不正确。导出表没有提示字段,只有导入表有提示字段。

事实上,在检索地址表的索引时,Ordinal Base 不是在 Ordinal Table 中应用的!

【讨论】:

以上是关于PE 导出目录表的 OrdinalBase 字段被忽略?的主要内容,如果未能解决你的问题,请参考以下文章

RVA to RAW

PE 导出表

PE 导出表

《初识PE》导出表

SQL 导出表的问题?字段类型为啥会改变~

2018/10/30-PE文件-导出函数