我是靠谱客的博主 矮小樱桃,最近开发中收集的这篇文章主要介绍ELF文件动态重定向loader如何实现对shared library中的函数调用进行重定向loader如何实现对shared library中变量的重定向与重定向相关的section附表,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文分析ELF文件在运行时动态重定向的实现。


以下面的两个程序为例:

$ cat mlib.c
int boo()
{
return 0;
}
int foo()
{
void *fn = boo;
boo();
return 0;
}

$ cat ./main.c
int boo();
int main()
{
void *fn = boo;$ cat ./main.c
int boo();
int main()
{
void *fn = boo;
boo();
}
boo();
}

$ gcc -o libmlib.so -shared -fPIC ./mlib.c
$ gcc -o main -lmlib -L. ./main.c

main函数中引用的函数boo定义在shared library中。

loader如何实现对shared library中的函数调用进行重定向

初始时,main函数中对boo的调用实际call的是boo@plt,地址为0x400560,位置处于section .plt中(参见表一)。


(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400660 <+0>:     push   %rbp
   0x0000000000400661 <+1>:     mov    %rsp,%rbp
=> 0x0000000000400664 <+4>:     sub    $0x10,%rsp
   0x0000000000400668 <+8>:     movq   $0x400560,-0x8(%rbp)
   0x0000000000400670 <+16>:    mov    $0x0,%eax
   0x0000000000400675 <+21>:    callq  0x400560 <boo@plt>  <---- call boo()
   0x000000000040067a <+26>:    leaveq
   0x000000000040067b <+27>:    retq
End of assembler dump.


对boo@plt进行反汇编,可以看出第一条jmp语句跳到了下一行0x400566。0x2被push到了堆栈。0x2应该代表.rela.plt中的第三项(0为第一项),该信息将被传递给loader。


(gdb) disassemble 0x400560
Dump of assembler code for function boo@plt:
   0x0000000000400560 <+0>:     jmpq   *0x2004f2(%rip)        # 0x600a58 <boo@got.plt>
   0x0000000000400566 <+6>:     pushq  $0x2
   0x000000000040056b <+11>:    jmpq   0x400530


(gdb) x /xg 0x600a58
0x600a58 <boo@got.plt>: 0x0000000000400566


push操作后,jmp到了0x400530,接着又把0x600a38中的数据push到了堆栈。注意0x600a38是.got.plt 中的第二个entry(每个entry的size是8)。最后又jmp到了0x00007ffff7def2d0(地址0x600a40中的数据)。


(gdb) x /5i 0x400530
   0x400530:    pushq  0x200502(%rip)        # 0x600a38
   0x400536:    jmpq   *0x200504(%rip)        # 0x600a40
   0x40053c:    nopl   0x0(%rax)
   0x400540 <__libc_start_main@plt>:    jmpq   *0x200502(%rip)        # 0x600a48 <__libc_start_main@got.plt>
   0x400546 <__libc_start_main@plt+6>:  pushq  $0x0


(gdb) x /xg 0x600a38
0x600a38:       0x00007ffff7ffe190
(gdb) x /xg 0x600a40
0x600a40:       0x00007ffff7def2d0


从shared library map中可以看出,0x00007ffff7def2d0对应到/lib64/ld-linux-x86-64.so.2中。loader将利用之前push的两个参数0x2和0x00007ffff7ffe190对boo@got.plt(即0x600a58)中的数据进行更新,修改成函数boo的实际地址。


(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddbba0  0x00007ffff7df4baa  Yes (*)     /lib64/ld-linux-x86-64.so.2
                                        No          linux-vdso.so.1
0x00007ffff7bda5b0  0x00007ffff7bda6c8  Yes (*)     ./libmlib.so
0x00007ffff784c470  0x00007ffff7978aa0  Yes (*)     /usr/lib/libc.so.6
(*): Shared library is missing debugging information.


将程序运行到断点0x000000000040067a,检查0x600a58的数值,可以看出已经变成了函数boo的地址。


(gdb) x /xg 0x600a58
0x600a58 <boo@got.plt>: 0x00007ffff7bda698
(gdb) p boo

$1 = {<text variable, no debug info>} 0x7ffff7bda698 <boo>


loader如何实现对shared library中变量的重定向

在main函数中对boo的地址进行了引用。可以看出boo的地址就是0x400560,即<boo@plt>,而非boo的真正地址。后面可以看出,即使在libmlib.so中对boo的引用同样也指向0x400560。××这样做的目的应当是确保在main和library当中对同一函数的地址引用是相等的××。


   0x0000000000400668 <+8>:     movq   $0x400560,-0x8(%rbp)


在shared library中的foo函数中对boo也做了引用,可以看出boo的地址被用0x200978中的数据间接代替了,而且0x200978中的数值是0,显然不对。


gdb ./libmlib.so
(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000000006a3 <+0>:     push   %rbp
   0x00000000000006a4 <+1>:     mov    %rsp,%rbp
   0x00000000000006a7 <+4>:     sub    $0x10,%rsp
   0x00000000000006ab <+8>:     mov    0x2002c6(%rip),%rax        # 0x200978
   0x00000000000006b2 <+15>:    mov    %rax,-0x8(%rbp)
   0x00000000000006b6 <+19>:    mov    $0x0,%eax
   0x00000000000006bb <+24>:    callq  0x590 <boo@plt>
   0x00000000000006c0 <+29>:    mov    $0x0,%eax
   0x00000000000006c5 <+34>:    leaveq
   0x00000000000006c6 <+35>:    retq
(gdb) x /xg 0x200978
0x200978:       0x0000000000000000


这是因为在.rela.dyn中有一个boo的重定向项。当libmlib.so被load进main中时,loader将会根据相应symbol的地址修正所有R_X86_64_GLOB_DAT重定向项的值。这些重定向项所指向的需要修改的地址都位于section .got中(参见表三)。


$ readelf -r ./libmlib.so


Relocation section '.rela.dyn' at offset 0x430 contains 9 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000200780  000000000008 R_X86_64_RELATIVE                    660
000000200788  000000000008 R_X86_64_RELATIVE                    620
0000002009b8  000000000008 R_X86_64_RELATIVE                    2009b8
000000200958  000200000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000200960  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000200968  000400000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0
000000200970  000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000200978  000a00000006 R_X86_64_GLOB_DAT 0000000000000698 boo + 0
000000200980  000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize + 0


Relocation section '.rela.plt' at offset 0x508 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
0000002009a0  000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
0000002009a8  000a00000007 R_X86_64_JUMP_SLO 0000000000000698 boo + 0
0000002009b0  000600000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_finalize + 0


下面可以看出,在load之后foo中所引用的boo的地址更新成了0x400560,即<boo@plt>。


gdb ./main


(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00007ffff7bda6a3 <+0>:     push   %rbp
   0x00007ffff7bda6a4 <+1>:     mov    %rsp,%rbp
   0x00007ffff7bda6a7 <+4>:     sub    $0x10,%rsp
   0x00007ffff7bda6ab <+8>:     mov    0x2002c6(%rip),%rax        # 0x7ffff7dda978
   0x00007ffff7bda6b2 <+15>:    mov    %rax,-0x8(%rbp)
   0x00007ffff7bda6b6 <+19>:    mov    $0x0,%eax
   0x00007ffff7bda6bb <+24>:    callq  0x7ffff7bda590 <boo@plt>
   0x00007ffff7bda6c0 <+29>:    mov    $0x0,%eax
   0x00007ffff7bda6c5 <+34>:    leaveq
   0x00007ffff7bda6c6 <+35>:    retq
End of assembler dump.
(gdb) x /xg 0x7ffff7dda978

0x7ffff7dda978: 0x0000000000400560



与重定向相关的section

.plt

重定向的入口代码。对于每一个需要重定向的函数,都会类似下面的代码。其中push的数值应该代表.rela.plt中的对应entry。
(gdb) disassemble 0x400560
Dump of assembler code for function boo@plt:
   0x0000000000400560 <+0>:     jmpq   *0x2004f2(%rip)        # 0x600a58 <boo@got.plt>
   0x0000000000400566 <+6>:     pushq  $0x2
   0x000000000040056b <+11>:    jmpq   0x400530

.got

R_X86_64_GLOB_DAT重定向项所指向的需要修改的地址。用于重定向对于变量的引用。

.got.plt

每一项占8个字节。
第一项的数值是0x0000000000600848,即dynamic section的起始地址。
第二项的数值是0x00007ffff7ffe190,据说代表link_map的起始地址?loader用它进行relocation.
第三项的数值是0x00007ffff7def2d0,是loader的_dl_runtime_resolve函数起始地址。


(gdb) disassemble 0x00007ffff7def2d0
Dump of assembler code for function _dl_runtime_resolve:


之后的每一项对应一个函数的重定向地址。初始时,如boo@got.plt所示,该值指向下一条汇编指令。重定向完成后,该值指向真正的函数地址。


(gdb) x /8xg 0x600a30
0x600a30:       0x0000000000600848      0x00007ffff7ffe190
0x600a40:       0x00007ffff7def2d0      0x00007ffff784e920

附表

表一,main的section
Section Headers:
[Nr] Name
Type
Address
Offset
Size
EntSize
Flags
Link
Info
Align
[ 0]
NULL
0000000000000000
00000000
0000000000000000
0000000000000000
0
0
0
[ 1] .interp
PROGBITS
0000000000400200
00000200
000000000000001c
0000000000000000
A
0
0
1
[ 2] .note.ABI-tag
NOTE
000000000040021c
0000021c
0000000000000020
0000000000000000
A
0
0
4
[ 3] .note.gnu.build-i NOTE
000000000040023c
0000023c
0000000000000024
0000000000000000
A
0
0
4
[ 4] .gnu.hash
GNU_HASH
0000000000400260
00000260
000000000000003c
0000000000000000
A
5
0
8
[ 5] .dynsym
DYNSYM
00000000004002a0
000002a0
0000000000000120
0000000000000018
A
6
1
8
[ 6] .dynstr
STRTAB
00000000004003c0
000003c0
00000000000000b5
0000000000000000
A
0
0
1
[ 7] .gnu.version
VERSYM
0000000000400476
00000476
0000000000000018
0000000000000002
A
5
0
2
[ 8] .gnu.version_r
VERNEED
0000000000400490
00000490
0000000000000020
0000000000000000
A
6
1
8
[ 9] .rela.dyn
RELA
00000000004004b0
000004b0
0000000000000018
0000000000000018
A
5
0
8
[10] .rela.plt
RELA
00000000004004c8
000004c8
0000000000000048
0000000000000018
A
5
12
8
[11] .init
PROGBITS
0000000000400510
00000510
000000000000001a
0000000000000000
AX
0
0
4
[12] .plt
PROGBITS
0000000000400530
00000530
0000000000000040
0000000000000010
AX
0
0
16
[13] .text
PROGBITS
0000000000400570
00000570
0000000000000184
0000000000000000
AX
0
0
16
[14] .fini
PROGBITS
00000000004006f4
000006f4
0000000000000009
0000000000000000
AX
0
0
4
[15] .rodata
PROGBITS
0000000000400700
00000700
0000000000000004
0000000000000004
AM
0
0
4
[16] .eh_frame_hdr
PROGBITS
0000000000400704
00000704
0000000000000034
0000000000000000
A
0
0
4
[17] .eh_frame
PROGBITS
0000000000400738
00000738
00000000000000f4
0000000000000000
A
0
0
8
[18] .init_array
INIT_ARRAY
0000000000600830
00000830
0000000000000008
0000000000000000
WA
0
0
8
[19] .fini_array
FINI_ARRAY
0000000000600838
00000838
0000000000000008
0000000000000000
WA
0
0
8
[20] .jcr
PROGBITS
0000000000600840
00000840
0000000000000008
0000000000000000
WA
0
0
8
[21] .dynamic
DYNAMIC
0000000000600848
00000848
00000000000001e0
0000000000000010
WA
6
0
8
[22] .got
PROGBITS
0000000000600a28
00000a28
0000000000000008
0000000000000008
WA
0
0
8
[23] .got.plt
PROGBITS
0000000000600a30
00000a30
0000000000000030
0000000000000008
WA
0
0
8
[24] .data
PROGBITS
0000000000600a60
00000a60
0000000000000010
0000000000000000
WA
0
0
8
[25] .bss
NOBITS
0000000000600a70
00000a70
0000000000000008
0000000000000000
WA
0
0
4
[26] .comment
PROGBITS
0000000000000000
00000a70
000000000000004e
0000000000000001
MS
0
0
1
[27] .shstrtab
STRTAB
0000000000000000
00000abe
0000000000000108
0000000000000000
0
0
1
[28] .symtab
SYMTAB
0000000000000000
00001348
0000000000000648
0000000000000018
29
47
8
[29] .strtab
STRTAB
0000000000000000
00001990
000000000000022f
0000000000000000
0
0
1

表二,main的重定向信息
注意.rela.plt中的第三行boo的重定向信息,其中offset是000000600a58,刚好在section .got.plt中。
$ readelf -r ./main
Relocation section '.rela.dyn' at offset 0x4b0 contains 1 entries:
Offset
Info
Type
Sym. Value
Sym. Name + Addend
000000600a28
000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
Relocation section '.rela.plt' at offset 0x4c8 contains 3 entries:
Offset
Info
Type
Sym. Value
Sym. Name + Addend
000000600a48
000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
000000600a50
000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
000000600a58
000800000007 R_X86_64_JUMP_SLO 0000000000400560 boo + 0

表三,libmlib.so的section(部分)
$ readelf -S ./libmlib.so
There are 27 section headers, starting at offset 0xad8:
Section Headers:
[Nr] Name
Type
Address
Offset
Size
EntSize
Flags
Link
Info
Align
[ 0]
NULL
0000000000000000
00000000
0000000000000000
0000000000000000
0
0
0
[ 1] .note.gnu.build-i NOTE
0000000000000190
00000190
0000000000000024
0000000000000000
A
0
0
4
[ 2] .gnu.hash
GNU_HASH
00000000000001b8
000001b8
0000000000000040
0000000000000000
A
3
0
8
..........
[19] .got
PROGBITS
0000000000200958
00000958
0000000000000030
0000000000000008
WA
0
0
8





最后

以上就是矮小樱桃为你收集整理的ELF文件动态重定向loader如何实现对shared library中的函数调用进行重定向loader如何实现对shared library中变量的重定向与重定向相关的section附表的全部内容,希望文章能够帮你解决ELF文件动态重定向loader如何实现对shared library中的函数调用进行重定向loader如何实现对shared library中变量的重定向与重定向相关的section附表所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部