7

只是为了给您一些上下文,这就是我想要实现的目标:我将 const char* 嵌入到共享对象文件中,以便在 .so 文件本身中有一个版本字符串。我正在做数据分析,这个字符串让我可以让数据知道是哪个版本的软件产生的。这一切都很好。

我遇到的问题是当我尝试直接从 .so 库中读取字符串时。我试着用

nm libSMPselection.so | grep _version_info

并得到

000000000003d968 D __SMPselection_version_info

这一切都很好,正如预期的那样(char* 被称为 _SMPselection_version_info)。但是我希望现在能够打开文件,寻找 0x3d968 并开始读取我的字符串,但我得到的只是垃圾。

当我打开 .so 文件并简单地搜索字符串的内容(我知道它是如何开始的)时,我可以在地址 0x2e0b4 找到它。在这个地址它在那里,零终止并且如预期的那样。(我现在正在使用这种方法。)

我不是计算机科学家。有人可以向我解释为什么 nm 显示的符号值不正确,或者不同的是,如果它不是符号的地址,符号值是什么?

(顺便说一句,我正在使用 OSX 10.7 的 Mac 上工作)

4

4 回答 4

7

假设它是 ELF 或类似结构的二进制文件,您必须考虑加载内容的地址,该地址受 ELF 标头中内容的影响。

在您的二进制文件上使用objdump -Fd,您可以让反汇编程序还显示符号的确切文件偏移量。

使用objdump -x你可以找到这个加载器地址,对于标准的 linux 可执行文件,通常是 0x400000。

接下来需要注意的是查看它是否是间接字符串,这可以通过使用objdump -g. 当字符串被发现为间接字符串时,在你输出的位置,objdump -Fd你不会找到字符串,而是地址。从中您需要再次减去加载程序地址。让我向您展示我的一个二进制文件的示例:

objdump -Fd BIN | grep VersionString
  45152f:       48 8b 1d 9a df 87 00    mov    0x87df9a(%rip),%rbx        # ccf4d0 <acVersionString> (File Offset: 0x8cf4d0)

objdump -x BIN
...
LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12
...

于是我们查看文件中的0x8cf4d0,在hexeditor中找到:

008C:F4D0 D8 C1 89 00  00 00 00 00  01 00 00 00  FF FF FF FF

所以我们在那里取 0x89C1D8,减去 0x400000 并得到 0x49c1d8,当我们在 hexeditor 中查看时,我们发现:

0049:C1D0 FF FF 7F 7F  FF FF 7F FF  74 72 75 6E  6B 5F 38 30
0049:C1E0 34 33 00 00  00 00 00 00  00 00 00 00  00 00 00 00

这意味着“trunk_8043”。

YMMV,特别是当它是其他一些文件格式时,但这是这些东西如何构造的一般方式,有很多缺陷和细节会因特殊情况而异。

于 2012-05-03T12:26:26.973 回答
2

没有人建议最简单的方法:做一个动态加载你的库的二进制文件(在命令行上给它命名)并为你的符号执行 dlsym() (或者它也可以在命令行上得到它)将它转换为字符串指针和将其打印到标准输出。

于 2012-05-03T18:07:38.333 回答
1

为什么您希望显示nm的偏移量是.so文件中的偏移量? .so文件不仅仅是内存图像;它们还包含许多其他信息,并且具有或多或少复杂的格式。在 Unix 下(至少在大多数 Unices 下),共享对象使用 elf 格式。要查找信息,您必须解释文件中的各个字段,以查找所需符号的位置、段以及该段在文件中的开始位置。(您可能会找到一个可以简化阅读它们的库。)

此外,如果您说您嵌入了 a 是正确的char const*,即您的代码包含以下内容:

char const* version = "...";

那么地址或偏移量version就是指针的地址或偏移量,而不是它所指向的字符串数据。将其定义为:

char const version[] = "...";

将解决这个问题。

最后,最简单的解决方案可能是确保字符串具有一些高度可识别的模式,然后线性扫描整个文件以查找该模式。

于 2012-05-03T12:30:16.720 回答
1

在 Linux 上,您有“字符串”命令,可以帮助您从二进制文件中提取字符串。

http://linux.about.com/library/cmd/blcmdl1_strings.htm

在 HPUX 中(我认为在其他 Unix 风格中也是如此)有一个类似的命令称为“what”。它只提取以“@(#)”开头的字符串,但如果您控制字符串的内容,这不是问题。

于 2012-05-03T11:59:56.617 回答