检索 .rodata 和 .rodata1 中的偏移量、字符串和虚拟地址

Posted

技术标签:

【中文标题】检索 .rodata 和 .rodata1 中的偏移量、字符串和虚拟地址【英文标题】:Retrieving Offsets, Strings and Virtual Address in .rodata and .rodata1 【发布时间】:2018-08-19 16:52:08 【问题描述】:

我正在尝试获取偏移量/虚拟地址、.rodata 和 .rodata1 部分中的字符串。

例如:

#include <cstdio>

void myprintf(const char* ptr) 
        printf("%p\n", ptr);


int main() 
        myprintf("hello world");
        myprintf("\0\0");
        myprintf("ab\0cde");

上面的程序每个readelf -a的输出都有.rodata:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [16] .rodata           PROGBITS         0000000000400600  00000600

readelf -W -p .rodata 给了我偏移量和相关的 non 空字符串:

String dump of section '.rodata':
  [    10]  %p^J
  [    14]  hello world
  [    23]  ab
  [    26]  cde

我想写一段 C 或 C++ 代码来检索:

    所有字符串字面量的偏移量(例如上面的 10、14、23 和 "\0\0" 缺少的一个)

    字符串字面量(例如上面的“%p\n”、“hello wolrd”、“\0\0”)

    .rodata 文件的偏移量(例如上面的 400600;它保证是虚拟内存地址吗?至少我看到上面测试代码中的所有字符串文字都是这种情况。)

因为我的最终目标是编写一个 C/C++ 代码来读取可执行文件并接受用户的输入作为偏移量/虚拟内存地址,如果输入与任何字符串文字的偏移量/虚拟内存地址匹配,则使用 @ 987654328@打印出来。否则,忽略。 (感谢@Armali 帮助我澄清)

我已阅读this article。我可以访问.rodata 中的整个字符串表,但不能访问“字符串表索引”。文章提到了“字符串表索引”,但没有具体说明如何检索索引。

提示?

另外,我想知道为什么会有一个名为.rodata1 的部分。根据精灵手册页:

.rodata1

此部分包含只读数据,这些数据通常构成过程映像中的不可写段。此部分的类型为 SHT_PROGBITS。使用的属性是 SHF_ALLOC。

它的描述与.rodata 完全相同。那么,为什么我们有.rodata1

谢谢!

【问题讨论】:

解析system("readelf -W -p .rodata")system("readelf -a | grep .rodata | awk 'print $4'");的输出还不够吗? @KamilCuk 我在网上遇到了来自 readelf -a 的不同输出。所以我认为通过elf.h基于ELF解析更安全。 @KamilCuk 我也刚刚发现readelf -W -p .rodata 不输出空字符串的偏移量(例如“\0\0”和“\0”)。因此,我不能使用 readelf。让我更新我的问题。谢谢你的建议! 是的,readelf -p 的输出确实让我觉得偏移量存储在 elf 中。而readelf source code 相当复杂(见dump_section_as_strings()),这让我觉得我不能只使用\0 作为分隔符来解析字符串表。 @Armali 你介意用“ELF 部分不包含字符串文字的偏移量/索引”来更新你的答案吗?那么,我会接受你的回答。谢谢。 【参考方案1】:

我正在尝试获取 .rodata 和 .rodata1 部分中的偏移量、字符串和虚拟地址。

我想写一段 C 或 C++ 代码来检索:

    所有字符串字面量的偏移量(例如上面的 10、14、23 和 "\0\0" 缺少的一个)

    字符串字面量(例如上面的“%p\n”、“hello wolrd”、“\0\0”)

字符串文字是用双引号括起来的字符序列。我们实际上无法分辨 ELF 数据部分中的什么是字符串文字的表示。考虑将这些行添加到您的main()

        static const int s = '\0fg\0';
        myprintf((char *)&s);

虽然没有字符串字面量,readelf -p .rodata … 可能会输出类似 e 的行。 g.

  [    21]  gf

因此,要真正识别数据部分中字符串文字的表示,有必要将数据与源代码标记(困难)或汇编代码(可能更容易)相关联。

如果.rodata 中不存在字符串文字对我来说将是一个问题

这很容易发生。考虑:

        static char hello[] = "Hi";
        myprintf(hello);

由于字符串字面量用于初始化字符数组,它必须是可修改的,它可以进入.data 而不是.rodata 部分,正如readelf -p .data … 可能显示的那样。

如果 ELF 部分包含所有有效的偏移量,为什么不使用它们?

有效的偏移量没有收集到任何可以方便访问的地方,所以出于实际目的,我们可以说ELF部分不包含字符串文字的偏移量/索引.


我可以访问.rodata 中的整个字符串表,但不能访问“字符串表索引”。文章提到了“字符串表索引”,但没有具体说明如何检索索引。

字符串表索引没有与.rodata相关,但与 字符串表部分 .strtab:

此部分包含字符串,最常见的是表示相关名称的字符串 带有符号表条目。

【讨论】:

感谢您的回复。我实际上不介意在.rodata 部分看到非字符串文字。但是,如果.rodata 中不存在字符串文字(假设仅链接到静态库),这对我来说将是一个问题。所以你是说.strtab 部分有.rodata 的字符串表索引?但是根据您引用的内容,听起来.strtab 仅包含字符串,但不包含偏移量/索引。也许我误解了。你介意详细说明吗?谢谢! 不,我不是.strtab 部分具有.rodata 的字符串表索引,而是.strtab 拥有符号表 名称,因此那些 字符串表索引 与您的目标无关。 关于提到的issue,我会修改答案。 您的反例(静态数组)非常好。感谢您指出了这一点。然后,现在,我也必须考虑如何处理它。谢谢! 感谢更新。只是一个侧面但相关的问题,你知道.rodata 的前 16 个字节是什么吗?我注意到它有 1 0x1 和 1 0x2,然后其余的是 0x0。提前致谢。【参考方案2】:

只是一个侧面但相关的问题,你知道.rodata 的前 16 个字节是什么吗?我注意到它有 1 0x1 和 1 0x2,然后其余的是 0x0。

并非总是如此;它仅取决于程序使用的只读数据。例如,如果我编译您的示例程序,字符串%p\n 从偏移量 4 开始,在此之前我还有 1 和 2(作为 16 位字),但没有零。进一步查看.rodata 开头的符号可能是

> readelf -s … | grep 400738
    14: 0000000000400738     0 SECTION LOCAL  DEFAULT   14
    59: 0000000000400738     4 OBJECT  GLOBAL DEFAULT   14 _IO_stdin_used

400738 是这里的.rodata 起始地址),我得到_IO_stdin_used,一个大小为 4 的全局对象,听起来像是标准库中的东西。

【讨论】:

以上是关于检索 .rodata 和 .rodata1 中的偏移量、字符串和虚拟地址的主要内容,如果未能解决你的问题,请参考以下文章

R中的偏相关值大于正常相关

Scala中的偏函数

通过JTAG对比内核启动后text/rodata段内容

在“.rodata”部分中引用

重定位被截断以适应:R_386_8 针对“.rodata”

链接器为rodata 部分计算错误的地址