当 `OrdinalBase` 字段设置为 1 时,`kernel32.dll` 如何导出 0 的序数?
Posted
技术标签:
【中文标题】当 `OrdinalBase` 字段设置为 1 时,`kernel32.dll` 如何导出 0 的序数?【英文标题】:How can `kernel32.dll` export an ordinal of 0, when its `OrdinalBase` field is set to 1? 【发布时间】:2017-02-21 03:29:52 【问题描述】:查看加载到内存中的 kernel32.dll,我看到以下导出序数表:
(gdb) x /400hd $eax
0x776334b0 <Wow64Transition+71576>: 3 4 5 6 7 8 9 10
0x776334c0 <Wow64Transition+71592>: 11 12 13 14 15 16 17 18
0x776334d0 <Wow64Transition+71608>: 19 20 21 22 23 24 25 26
0x776334e0 <Wow64Transition+71624>: 27 28 29 30 31 32 33 34
0x776334f0 <Wow64Transition+71640>: 35 36 37 38 39 40 41 42
0x77633500 <Wow64Transition+71656>: 43 44 45 46 47 48 49 50
0x77633510 <Wow64Transition+71672>: 51 52 53 54 55 56 57 58
0x77633520 <Wow64Transition+71688>: 59 60 61 62 63 64 65 66
0x77633530 <Wow64Transition+71704>: 67 68 69 70 0 71 72 73
0x77633540 <Wow64Transition+71720>: 74 75 76 77 78 79 80 81
0x77633550 <Wow64Transition+71736>: 82 83 84 85 86 87 88 89
0x77633560 <Wow64Transition+71752>: 90 91 92 93 94 95 96 97
可以验证,导出的序数为 0。
但是既然导出目录表的OrdinalBase字段设置为1,那么序数怎么会小于1呢?:
Ordinal Base:此中导出的起始序号 图片。此字段指定导出的起始序号 地址表。它通常设置为 1。
文档说序数是有偏差的,即:
导出序号表是导出的 16 位索引数组 地址表。序数受到 Ordinal Base 字段的影响 导出目录表。换句话说,序数基数必须是 从序数中减去以获得导出的真实索引 地址表。
现在,这意味着 0 的序数会在导出地址表中产生 -1 的索引?
在我看来,序数似乎是预先调整的(即从每个中减去 1),但是“官方”算法(也在 PE 文档中说明)失败了:
因此,当搜索导出名称指针表并匹配 字符串在位置 i 找到,用于查找符号的算法 地址是:
i = Search_ExportNamePointerTable (ExportName);
ordinal =
ExportOrdinalTable [i];
SymbolRVA = ExportAddressTable [ordinal - OrdinalBase];
想到的唯一想法如下:加载器在将 DLL 加载到内存时调整了导出序号表中的序号。
谁能解释一下?
【问题讨论】:
但是PE文档中查找符号RVA的算法呢?那么这个算法不正确呢?它使用序数作为 RVA 查找的一部分。另外,如果不是正确的序数(对应于使用 dumpbin 看到的那些),序数表中的数字是多少? 还有,你说entry 0是序数4,那为什么会显示3呢? @HansPassant :另外,为什么从每个序数中减去 1(OrdinalBase)?如果你能回答这些问题,你就能让今年的圣诞节提前到来:) 【参考方案1】:这是 PE/COFF 规范中的一个已知错误。指定的算法完全错误,应该是
ordinal = ExportOrdinalTable [i] + OrdinalBase;
不是
ordinal = ExportOrdinalTable [i];
因为序数表实际上包含无偏序数。
【讨论】:
谢谢,你有来源还是个人经验? 前一个项目写PE解析器和加载器的经验:) 我开始考虑以下问题:该算法适用于静态检查 DLL?似乎将 DLL 加载到内存中会改变序数,例如从 348(使用 DUMPBIN 验证)更改为 347(在运行时验证)。你的身份似乎很荒谬:ordinal = ExportOrdinalTable [i] + OrdinalBase; - 为什么添加 OrdinalBase 只是为了在之后立即减去它? 实际上,DUMPBIN 输出有偏序数,而不是存储在序数表中的无偏序数(我不得不重新访问我的一些 PE 解析代码来验证这一点)。换句话说,加载器不改变序数。在 ExitProcess 的情况下,存储在表中的值为 347,“实际”(有偏差)序数为 248。 W.r.t.序数身份,这是一个语义问题。当然,你可以只做SymbolRVA = ExportAddressTable[ExportOrdinalTable[i]]
(我同意添加 OrdinalBase,然后减去它看起来有点愚蠢) - 我只是想指出文档中实际错误的位置,因为 real ordinal value 是 biased 之一(在添加 OrdinalBase 之后)。也就是说,分配变量ordinal = ExportOrdinalTable[i]
是没有意义的,因为这个“无偏序数”实际上只是一个索引。以上是关于当 `OrdinalBase` 字段设置为 1 时,`kernel32.dll` 如何导出 0 的序数?的主要内容,如果未能解决你的问题,请参考以下文章