objdump 之类的工具如何在 ELF 二进制文件中查找函数名称及其起始地址?

逆向工程 小精灵 转储
2021-07-11 15:19:06

我编写了一个 ELF 解析器,它使用顶石对 .text 部分进行反汇编

我的问题是我不知道如何根据函数分割文本部分并像 objdump -d 的输出一样打印函数的名称

因为 objdump 输出是这样的:

0x01000 功能 1:

0x01000 ..

0x01001 ..

我如何找出 .text 中每个函数的名称和起始地址,以便我可以输出类似 objdump 的内容?

我尝试使用字符串来查看名称是否存储在二进制文件中的某个位置,例如在符号表中,但在其中的任何地方都找不到它们!

(请注意,我不是在谈论导入函数等,只是在 .text 部分中实际主代码中的函数)

1个回答

为了实现这一点,您需要一些有关 ELF 文件的知识。我不会解释有关 ELF 文件的每一个细节,因为要涵盖的内容很多,所以我会尽量做到准确。

注意 #01:我将使用radare2 来剖析文件,但您可以使用任何十六进制编辑器来完成。

注意 #02:这是我编译的 cpp 文件链接,用于解释 ELF 文件。随意拿走它或自己做。

首先,您需要了解 ELF 文件中标头的结构。在这里您可以看到标题的结构。

我们要查找的第一件事是e_ident表示文件的格式(32 位或 64 位),因为文件头会因文件格式而异。

e_ident偏移=0x04,大小=1byte

转到文件的 0x04 偏移量并检查一个字节。s意思是寻找)

:> s 0x04
0x00000004  02

e_ident = 0x02 表示 64 位格式。

现在我们知道了文件格式,我们需要知道节头(e_shoff的偏移量、每个条目的大小(e_shentsize)以及节头中的条目数(e_shnum)。

e_shoff offset=0x28 size=8bytes
e_shentsize offset=0x3A size=2bytes
e_shnum offset=0x3C size=2bytes

:> s 0x28
0x00000028  e03b 0000 0000 0000

:> s 0x3A
0x0000003a  4000

:> s 0x3C
0x0000003c  1d00

e_shoff = 0x3be0 这是节头的偏移量。
e_shentsize = 0x40(64 字节)
e_shnum = 0x1d(29 个条目)

我们还需要包含每个部分标题名称的部分标题的索引。这是存储在e_shstrndx

e_shstrndx offset=0x3E size=2bytes

:> s 0x3e
0x0000003e  1c00

e_shstrndx = 0x1c(条目 28)

有了入口号就可以得到shstrtab的地址:

// e_shoff+(e_shentsize*e_shstrndx)+sh_offset
:> s 0x3be0+(0x40*0x1c)+0x18
0x000042f8  df3a 0000 0000 0000

shstrtab = 0x3adf

既然您有了这些信息,就可以运行一个循环来检查所有部分条目:

//pseudocode
for (i=0; i<e_shnum; i++)
    entryN = e_shoff+(e_shentsize*i);

注意 #03:我不会在这里打印这些值,因为我必须解释更多,但这会给你类似于命令的东西 readelf -W -l [program]

每个条目都有一个类似于节标题的结构。要获取每个条目的名称,请添加sh_nameshstrtab

我只会向您展示我是如何得到的,.text但任何部分条目的想法都是相同的。在我的例子中.text是条目 0x0e(14)。我将需要sh_name文件中的偏移量sh_offset和大小sh_size

sh_name offset=0x00 size=
4bytes sh_offset offset=0x18 size=8bytes
sh_size offset=0x20 size=8bytes

//e_shoff+(e_shentsize*e_shstrndx)+sh_name
:> s 0x3be0+(0x40*0x0e)+0x00
0x00003f60  9d00 0000

// Get the name
:> s 0x3adf+0x9d
0x00003b7c  2e74 6578 7400 2e66 696e 6900 2e72 6f64  .text..fini..rod

//e_shoff+(e_shentsize*e_shstrndx)+sh_offset
:> s 0x3be0+(0x40*0x0e)+0x18
0x00003f78  9010 0000 0000 0000

//e_shoff+(e_shentsize*e_shstrndx)+sh_size
:> s 0x3be0+(0x40*0x0e)+0x20
0x00003f80  3102 0000 0000 0000

entryName = 0x3be0 // .text
sh_offset = 0x1090
sh_size = 0x0231 (561bytes)

如果您无法通过这种方式找到它,那么您的 ELF 文件肯定已损坏。你可以拿我编译的来按照这个解释。祝你好运。