【问题标题】:How to determine which glibc function is called from binary?如何确定从二进制调用哪个 glibc 函数?
【发布时间】:2015-12-21 08:19:41
【问题描述】:

有什么方法可以说明从 ARM elf 二进制文件中调用了哪个 glibc 函数?例如,考虑以下反汇编:

8300 <printf@plt-0x40>:
   ....
8320:   e28fc600    add ip, pc, #0, 12
8324:   e28cca08    add ip, ip, #8, 20  ; 0x8000
8328:   e5bcf344    ldr pc, [ip, #836]! ; 0x344

   ....
83fc <main>:
   ...
8424:ebffffbd   bl  8320 <_init+0x2c>

在这里,我们怎么能说 bl 8320 是对 printf 的调用呢?这些信息是否存储在 ELF 二进制文件中?

【问题讨论】:

  • 该二进制文件是否还有符号表或已被剥离(链接时-s)? nm a.out 报告什么?
  • 符号表和动态符号都存在。 nm 报告二进制文件中的所有符号。有办法吗?
  • 如果真的 所有 符号,甚至 printf,都在 a.out 中,那么你有一个静态链接的二进制文件,可能无法确定哪个符号来自特定库,而不是为每个库制作符号列表并将列表与 a.out 中的符号进行比较。
  • 我的意思是,printf 在动态符号表中。二进制是动态链接的。我只想知道哪个库例程“bl 8310”实际上是通过 plt 调用的?.. 二进制文件中应该有一些关于此的信息,否则动态链接器将如何知道在运行时调用哪个例程?

标签: binaryfiles elf


【解决方案1】:

有什么方法可以说是从 ARM elf 二进制文件中调用了哪个 glibc 函数?

不是真的。

您可以简单地问“二进制调用了哪些外部函数”,如下所示:

nm -D a.out | grep ' U '

在哪个库中定义了未定义的函数没有记录下来,实际上是可以改变的。例如,您可以使用LD_PRELOAD=libfoo.so 来注入在libfoo.so 中定义的不同printf,并抢占printfglibc 定义。

【讨论】:

  • 好的。但在那种情况下,反汇编程序如何能够识别出它是对 printf 的调用这一事实?它清楚地显示 8300 : 在开头。
  • 实际上也是当.plt调用动态链接器时,链接器如何知道调用了哪个库例程?
  • @VasantK 好吧,符号表的重点是为数字命名。这里没有魔法。反汇编器知道这是对 printf 的调用,因为符号表将该地址映射到 printf 符号。剥离符号表,反汇编程序将不再显示 printf,只显示数字。
  • 我也是这么想的。动态符号表应将地址映射到符号。但是 dynsym 中的符号的值为 0 。我在这里发布了一个问题:stackoverflow.com/questions/32737355/elf-dynamic-symbol-table。请看一看。
  • 好吧,你不能剥离(动态)符号表,否则 PLT 一开始就无法工作……
【解决方案2】:

TLDR:您必须计算 GOT 条目的地址(存储在 IP 但 PLT 中)并找到与此 GOT 条目对应的重定位条目。此重定位条目引用符号名称(通过动态符号表和动态字符串表)。

你的例子

此 PLT 条目计算 IP 寄存器中 PLTGOT 条目的地址:

8320: e28fc600 添加 ip, pc, #0, 12
8324: e28cca08 添加 ip, ip, #8, 20 ; 0x8000
8328:e5bcf344 ldr 电脑,[ip,#836]! ; 0x344

这会计算地址的 GOT 条目:0x8320 + 0x8 + 0x8000 + 0x344 = 0x1066c。重定位表中有一个重定位条目,它将这个 GOT 条目绑定到给定的符号。

另一个例子

让我们从我的 libc 中获取这个 PLT 条目:

00015b98 :
   15b98: e28fc601 添加 ip, pc, #1048576 ; 0x100000
   15b9c: e28cca2f 添加 ip, ip, #192512 ; 0x2f000
   15ba0:e5bcf46c ldr 电脑,[ip,#1132]! ; 0x46c

GOT入口地址为:0x15b98 + 0x8 + 0x100000 + 0x2f000 + 0x46c = 0x14500c。

如果你想知道为什么是“+ 0x8”,这里是because

在ARM状态下,PC的值是当前的地址 指令加 8 个字节。

我们来看重定位入口:

 偏移信息类型 Sym.Value Sym。姓名
0014500c 0001e416 R_ARM_JUMP_SLOT 00077c28 重新分配

所以这个 PLT 条目是 realloc 的 PLT,这是我们期望得到的! \o/

查找符号名称

您可能想知道如何找到符号名称。在我的示例中,信息字段为 0x0001e416:此重定位使用动态符号表中的符号条目 0x1e4 = 484 (.dynsym)

Num:值大小类型绑定 Vis Ndx 名称 484: 00077c28 760 FUNC 全局默认值 11 realloc@@GLIBC_2.4

其实realloc这个字符串并不是直接在符号表中找到的,而是在字符串表中(.dynstr)。符号表存储字符串在字符串表中的偏移量。

【讨论】:

    猜你喜欢
    • 2013-10-23
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-19
    • 2011-03-27
    • 2010-11-15
    • 2016-12-21
    相关资源
    最近更新 更多