我是靠谱客的博主 矮小樱桃,最近开发中收集的这篇文章主要介绍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的sectionSection 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附表所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复