Linux延迟绑定

January 13, 2021 Linux 访问: 121 次

linux 延迟绑定

基本思想

当函数第一次在程序中被调用的时候才进行绑定(符号查找、重定位等),如果没有用到则不进行绑定。

程序开始执行时,模块间的函数调用都没有进行换呢过绑定,而是需要用到时由动态链接器负责绑定

ELF文件是用PLT的方式实现的

PLT 结构

例子如下所示,每个函数的.plt表里面有三行汇编代码

第一行汇编的意思是跳转到函数相对应的.got.plt表里,如果程序第一次调用该函数的话,此时.got.plt表里存放的是.plt表第二行的代码,如果不是第一次调用的话,那.got.plt表里存放的就是函数在libc里的内存地址

第二行汇编的意思是将一个数字n压入栈中,这个数字是该函数的符号在.rel.plt的下表

第三行汇编会统一跳转到另一个地址0x400460

0x400460地址处的代码是将模块的ID压入堆栈中,然后跳转到_dl_runtime_resolve_xsavec函数执行,_dl_runtime_resolve_xsavec函数进行一系列操作之后会把真正的地址填入到函数对应的.got.plt表里

pwndbg> plt
0x400470: getpid@plt
0x400480: printf@plt
0x400490: __libc_start_main@plt
0x4004a0: sleep@plt

pwndbg> x/12i 0x400470
   0x400470 <getpid@plt>:    jmp    QWORD PTR [rip+0x200ba2]        # 0x601018
   0x400476 <getpid@plt+6>:    push   0x0
   0x40047b <getpid@plt+11>:    jmp    0x400460
   0x400480 <printf@plt>:    jmp    QWORD PTR [rip+0x200b9a]        # 0x601020
   0x400486 <printf@plt+6>:    push   0x1
   0x40048b <printf@plt+11>:    jmp    0x400460
   0x400490 <__libc_start_main@plt>:    jmp    QWORD PTR [rip+0x200b92]        # 0x601028
   0x400496 <__libc_start_main@plt+6>:    push   0x2
   0x40049b <__libc_start_main@plt+11>:    jmp    0x400460
   0x4004a0 <sleep@plt>:    jmp    QWORD PTR [rip+0x200b8a]        # 0x601030
   0x4004a6 <sleep@plt+6>:    push   0x3
   0x4004ab <sleep@plt+11>:    jmp    0x400460
   
   
   .plt:0000000000400460 sub_400460      proc near               ; CODE XREF: .plt:000000000040047B↓j
.plt:0000000000400460                                         ; .plt:000000000040048B↓j ...
.plt:0000000000400460 ; __unwind {
.plt:0000000000400460                 push    cs:qword_601008
.plt:0000000000400466                 jmp     cs:qword_601010
.plt:0000000000400466 sub_400460      endp

GOT表

ELF文件将GOT表拆分为两个部分,其中got表里存放全局变量引用的地址,.got.plt用来保存函数引用的地址,而且.got.plt的前三项是由特殊含义的
第一项:.dynamic段的地址
第二项:本模块的ID(link_map)
第三项:_dl_runtime_resolve_xsavec函数的地址

第二项和第三项由动态链接器在装载共享模块的时候负责将他们初始化

延迟绑定流程

  • 通过第一个参数访问到.dynamic,从.dynamic中取出.dynstr,.dynsym,.rel.plt的指针
  • .rel.plt+第二个参数 求出当前函数在.rel.plt中的地址
  • 在.rel.plt当前的结构体取出第二个变量>>8求出该函数在.dynsym段下的地址
  • .dynstr+该函数在.dynsym段下的地址的第一个变量求出该函数在.dynstr下的地址
  • 在动态链接库查找这个函数的地址,并且把地址赋值给GOT表
    调用这个函数

已有 2 条评论

  1. Du4t Du4t

    萝卜神太强了!!

添加新评论