【问题标题】:Where is the string table in a Windows DLL?Windows DLL 中的字符串表在哪里?
【发布时间】:2013-10-08 18:24:11
【问题描述】:

我已经编写了一个例程来从加载了LoadLibrary 的 DLL 中转储符号和节,但不知道如何解码节名长于 IMAGE_SIZEOF_SHORT_NAME 的 MinGW DLL

例如,如果我将以下部分打印为字符串,则 MinGW DLL 会输出它们:

[".text", ".data", ".rdata", ".pdata", ".xdata", ".bss", ".edata", ".idata",
 ".CRT", ".tls", ".reloc", "/4", "/19", "/31", "/45", "/57", "/70", "/81",
 "/92"]

objdump.exe 的其他部分得到它们:

.debug_aranges
.debug_info
.debug_abbrev
.debug_line
.debug_frame
.debug_str
.debug_loc
.debug_ranges

都比IMAGE_SIZEOF_SHORT_NAME长。 MSDN 解释说:

For longer names, this member contains a forward slash (/) followed by an ASCII representation of a decimal number that is an offset into the string table.

所以我有以下代码:

  Char buffer[IMAGE_SIZEOF_SHORT_NAME + 1];
  std::strncpy(buffer, reinterpret_cast<const Char * const>(section_header_ptr[i].Name), IMAGE_SIZEOF_SHORT_NAME);
  buffer[IMAGE_SIZEOF_SHORT_NAME] = '\0';
  const Char * name = buffer;
  if (name[0] == '/') {
    const Long rva = std::strtol(name + 1, NULL, 10);
    if ((LONG_MAX == rva) || (LONG_MIN == rva) || ((0 == rva) && (name[0] != '0'))) {
      static const Char * const failure = "failed to convert offset";
      name = failure;
    }
    // -- How do I get the string table here? and use the offset? --
  }

阅读 COFF 规范,我发现字符串表在符号条目之后,所以它应该是

HMODULE handle = LoadLibrary("some_mingw_library.dll");
PIMAGE_DOS_HEADER idh = (PIMAGE_DOS_HEADER)(handle);
PIMAGE_NT_HEADERS inh = (PIMAGE_NT_HEADERS)(((const uint8_t*)(idh)) + idh->e_lfanew)
PIMAGE_FILE_HEADER ifh = &inh->FileHeader;
PIMAGE_SYMBOL is = (PIMAGE_SYMBOL)(((const uint8_t*)(idh)) + ifh->PointerToSymbolTable)
const char * const string_table = &is[ifh->NumberOfSymbols];

但我得到的东西绝对不是字符串表。我可以在我的十六进制编辑器中看到字符串表。可移植可执行文件中的字符串表在哪里?

【问题讨论】:

  • MSDN 还说(您放置的链接)...“可执行图像不使用字符串表并且不支持超过八个字符的部分名称”。
  • @mox 在微软的世界里,当然。 MSDN 是 Microsoft 的文档,但 PE 和 COFF 规范是公开的,并且也在 UNIX 中使用。您可以查看 GNU binutils 并查看 PE 规范是通过非Windows.h 标头编写的。 Microsoft 的“已弃用”意味着他们不再使用它,没有理由不能在野外的图像中填写这些部分 - 它完全受规范支持。

标签: c++ winapi dll mingw portable-executable


【解决方案1】:

当一个可执行文件被映射到内存时,它不会作为一个连续的块加载。部分分散在部分标题中。

符号根本不必映射到内存中。

PointerToSymbolTable 是(我认为)文件偏移量,而不是内存偏移量(而且,如上所述,它们不是一回事)。

EXE 和 DLL 根本不应该有 COFF 符号,虽然这个文件很明显。

大多数此类问题的答案都可以在PEDUMP 中找到。

【讨论】:

  • PointerToSymbolTable 已弃用且从未使用过。
  • 我有PEDUMP 源代码,它使用PointerToSymbolTable 作为文件偏移量(你是对的),因为它通过将文件映射到虚拟内存来读取DLL,但我正在使用结果的LoadLibrary。这些部分分散在各处,我通常可以找到大部分信息。我也认为符号没有映射到内存是正确的。
  • 我猜你必须直接从文件中读取符号表。你已经得到了偏移量。
【解决方案2】:

我知道我来晚了,但问题似乎没有得到完全回答。在找到解决方案之前,我自己来这里寻找相同的答案。

可移植可执行文件中的字符串表在哪里?

字符串表紧跟在符号表之后。符号数与符号表起始地址一起在文件头信息中,每个符号为 18 个字节。很容易计算到字符串表。

前 4 个字节是字符串表本身的大小(因此 /4 表示第一个条目)。每个字符串都从前一个字符串开始。每个字符串都以 null 结尾。这并不重要,因为偏移量在部分名称本身中,因此您可以直接查看它们。

【讨论】:

    【解决方案3】:

    字符串表在可执行文件 (DLL) 中不可用,仅在 OBJ 文件中可用。这就是为什么在分析 PE 文件时无法枚举这些的原因。 PE 文件的部分名称不得超过 8 个字符。

    【讨论】:

    • 原始发布者有一个名称超过 8 个字符的 DLL,并且 objdump 可以正确解码它们。 “已弃用”和“从未使用”不是同义词。
    • PE 图像的部分名称永远不会超过 8 个字符。
    • 发帖人说他有一个由 MinGW 生成的 DLL,其部分名称如“/19”,objdump 将其解码为较长的名称,如“.debug_info”。你认为这些细节是他发明的吗?
    • @mox 说真的,MinGW 仍然使用旧的 COFF 格式作为符号。尽管pecoff_v83.docx 规范说它们已被弃用,但这是针对 Windows 编译器的。老实说,老实说,我不是在说谎 - MinGW 创建的 DLL 的节名长度超过 8 个字符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    相关资源
    最近更新 更多