通过解析 ELF C++ 程序,将字符串文字的地址映射到字符串文字
Posted
技术标签:
【中文标题】通过解析 ELF C++ 程序,将字符串文字的地址映射到字符串文字【英文标题】:map the address of string literal to string literal, by parsing ELF C++ program 【发布时间】:2015-02-20 05:08:00 【问题描述】:字符串文字的地址在编译时确定。该地址和字符串文字可以在构建的可执行程序(ELF 格式)中找到。比如下面的代码输出String Literal: 0x400674
printf("String Literal: %p\n", "Hello World");
而objdump -s -j .rodata test1
显示
.rodata 部分的内容:
400670 01000200 48656c6c 6f20576f 726c6400 ....你好世界。
....
所以看起来我可以通过读取可执行程序本身来获取“Hello World”的虚拟地址。
问题:如何通过读取 ELF 格式在字符串文字的地址和字符串本身之间建立表/映射/字典?
我正在尝试编写一个独立的 python 脚本或 c++ 程序来读取 elf 程序并生成表。如果表中有额外的映射(不是字符串文字)是可以的,只要表包含字符串文字的整个映射。
【问题讨论】:
这是 ELF 不是 EFL。您发现自己是一个 ELF 阅读库并使用它,或者为您感兴趣的版本找到自己的 ELF 格式规范并编写自己的。图书馆推荐在这里是题外话。 你为什么要问?你知道strings
命令吗?
请编辑您的问题以改进它并提供一些动力...
@BasileStarynkevitch 动机是以最小的开销将字符串文字传递给另一个进程。由于我们可以从 exe 文件中获取字符串文字,因此无需将字符串复制到内存中以便另一个进程可以使用。
请编辑您的问题。你绝对错了:根据定义,两个不同的进程在虚拟内存中有不同的地址空间!
【参考方案1】:
我不确定你的问题总是有意义的。细节是特定于实现的(操作系统和编译器以及编译标志特定)。
首先,允许(但不是必需)在同一翻译单元中同时看到 "abcd"
和 "cd"
文字字符串的编译器共享它们的存储空间,并将 "abcd"+2
作为第二个编译器使用。见this answer。
然后,在ELF 文件中,字符串只是简单的初始化只读数据(通常在text segment 的.rodata
或.text
部分),它们可能恰好与一些非字符串常量。 ELF 文件不保留任何类型信息(除了使用-g
编译时的调试DWARF 信息)。换句话说,以下
const uint8_t constable[] = 0x65, 0x68, 0x6c, 0x6c, 0x6f, 0 ;
具有与 "hello"
文字字符串完全相同的机器表示,但不是源字符串。更糟糕的是,机器代码的某些部分可能恰好看起来像字符串。
顺便说一句,您可以使用strings(1) 命令,或者研究它的源代码并根据您的需要进行调整。
另请参阅 dladdr(3) 和 this question。
请记住,两个不同的processes(根据定义!)在virtual memory 中有不同的address spaces。另请阅读ASLR。字符串字面量也可能出现在共享对象(例如libc.so
等共享库)中,这些对象通常在不同的地址段中以mmap
-ed(因此相同的字面量字符串在不同的进程中会有不同的地址!)。
您可能有兴趣通过libelf 或readelf(1) 或bfd 阅读ELF 文件。
【讨论】:
谢谢。我确实使用字符串,但似乎只输出字符串,没有地址。您是否有参考描述答案中的“第一”段。如果编译器可以重用存储,那么映射对我的用例来说不是那么有趣。至于您对非字符串常量的评论,就像我的问题中所说的那样。只要表中包含字符串字面量地址的映射,表对我有好处。 非常感谢。我刚刚确认了 .rodata 中字符串文字的重叠!我有一个测试程序打印出“Hello”、“ello”、“llo”、“lo”、“o”的地址。使用g++ -Os
,这些地址只有一个字节。 .rodata 显示 ELF rodata 部分中只有一个字符串文字。以上是关于通过解析 ELF C++ 程序,将字符串文字的地址映射到字符串文字的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 代码解析 ELF 文件 ( PyCharm 中创建 Python 程序 | 导入 ELFFile 库 | 解析 ELF 文件 )
Android 逆向ELF 文件格式 ( ELF 程序头入口大小 | ELF 程序头入口个数 | ELF 文件节区头入口大小 | ELF 文件节区头入口个数 | 字符表序号 )