将字符串常量的地址映射到字符串常量,通过解析 ELF C++ 程序。

3

字符串常量的地址是在编译时决定的。这个地址和字符串常量可以在可执行程序中找到(以ELF格式)。例如,以下代码输出:String Literal: 0x400674

printf("String Literal: %p\n", "Hello World");   

执行objdump -s -j .rodata test1命令后,显示如下:

部分.rodata节的内容如下:

400670 01000200 48656c6c 6f20576f 726c6400 ....Hello World.

....

因此,看起来我可以通过读取可执行程序本身来获取“Hello World”的虚拟地址。

问题:我如何通过读取ELF格式在地址和字符串本身之间建立表/映射/字典?

我正在尝试编写一个独立的Python脚本或C ++程序来读取elf程序并生成该表。如果表中包含额外的映射(而不是字符串文字),则也可以接受,只要表包含整个字符串文字的映射即可。


你为什么问呢?你知道strings命令吗? - Basile Starynkevitch
1
请编辑您的问题。而且您绝对是错的:根据定义,两个不同的进程在虚拟内存中具有不同的地址空间! - Basile Starynkevitch
@BasileStarynkevitch 另一个程序/进程 Y 读取 exe 文件 X,创建一个映射,其中键是 X 中字符串字面量的虚拟地址,值是字符串字面量。当然,Y 并没有访问 X 中的地址。 - Peng Zhang
你应该改进你的问题并提供一个使用案例。我相信你误解了很多东西... - Basile Starynkevitch
@BasileStarynkevitch 我会查阅更多有关 ELF 格式的详细信息,然后发布另一个问题来描述我正在处理的内容。我只是好奇,如果我们可以从可执行文件中知道字符串内容,为什么我们需要在运行时将整个字符串传递给另一个进程呢?我们可以只传递一个整数,尤其是当字符串很长时可以节省很多空间。把这种想法看作一个非常有趣的问题。但是,似乎人们并没有这样做。 - Peng Zhang
显示剩余3条评论
1个回答

3
我不确定您的问题是否总是有意义。详细信息是实现特定的(操作系统和编译器以及编译选项特定)。
首先,在同一翻译单元中同时看到"abcd""cd"文字字符串的编译器被允许(但不是必须)共享它们的存储,并使用"abcd"+2作为第二个字符串。请参见此答案
然后,在ELF文件中,字符串仅是已初始化的只读数据(通常在文本段.rodata.text部分),它们可能与某些非字符串常量相同。 ELF文件不保留任何类型信息(除了使用-g编译时的调试DWARF信息)。换句话说,以下内容:
const uint8_t constable[] = { 0x65, 0x68, 0x6c, 0x6c, 0x6f, 0 };

这个变量与字符串常量"hello"的机器表示完全相同,但它不是一个源字符串。更糟糕的是,机器代码的某些部分可能看起来像字符串。

顺便说一下,您可以使用strings(1)命令,或者学习它的源代码并根据您的需要进行修改。

另请参阅dladdr(3)此问题

请记住,两个不同的进程(按定义!)在虚拟内存中具有不同的地址空间。还要阅读关于ASLR的文章。字符串常量也可能出现在共享对象中(例如共享库,如libc.so),这些对象通常在不同的地址段上进行mmap(因此,在不同的进程中,相同的字符串常量将具有不同的地址!)。

您可能会对libelfreadelf(1)bfd感兴趣,以读取ELF文件。


谢谢。我确实使用字符串,但似乎只输出字符串而没有地址。您是否有参考文献描述您答案中的“第一”段?如果编译器可以重用存储空间,则对于我的用例来说,映射并不那么有趣。至于您对非字符串常量的评论,在我的问题中已经说过了,所以没关系。只要表格包含字符串文字地址的映射,该表格对我就很好。 - Peng Zhang
非常感谢。我刚刚确认了.rodata中字符串字面量的重叠!我有一个测试程序,打印出“Hello”、“ello”、“llo”、“lo”、“o”的地址。使用g++ -Os编译,这些地址只相差一个字节。而且.rodata显示ELF rodata部分只有一个字符串字面量。 - Peng Zhang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接