Reputation: 28699
I have been using Anthony Shoumikhin's elfhook utility to redirect certain function calls in a shared library.
As a proof of concept, I've created a shared library which calls various functions from the posix socket api.
void TestAPI::work()
{
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
char buf[1024];
recv(fd, buf, sizeof(buf), 0);
listen(fd, 1);
}
I've then hooked these functions:
elf_hook(filename, base_address, "socket", hook_socket);
elf_hook(filename, base_address, "listen", hook_listen);
elf_hook(filename, base_address, "recv", hook_recv);
where a hooked function calls the original api function, but also logs what is happening, for example:
int hook_socket(int domain, int type, int protocol)
{
int fd = socket(domain, type, protocol);
printf("fd=%d domain=%d type=%d protocol=%d\n", fd, domain, type, protocol);
return fd;
}
This all works fine, until I attempt to hook a function which isn't called in my TestAPI
shared library
elf_hook(filename, base_address, "bind", hook_bind);
elf_hook(filename, base_address, "connect", hook_connect);
As soon as I do this, I get a segmentation fault:
#0 elf_machine_fixup_plt (map=<optimized out>, t=<optimized out>, reloc=<optimized out>, value=139753823227104, reloc_addr=0x7f1afa15e188) at ../sysdeps/x86_64/dl-machine.h:235
#1 _dl_fixup (l=<optimized out>, reloc_arg=<optimized out>) at ../elf/dl-runtime.c:148
#2 0x00007f1afa176753 in _dl_runtime_resolve_avx () at ../sysdeps/x86_64/dl-trampoline.h:112
#3 0x0000000000561b20 in ?? ()
#4 0x00007f1afa16f8e0 in ?? () at dl-fini.c:105 from /lib64/ld-linux-x86-64.so.2
#5 0x00007f1afa16f5fb in call_init (env=0x7ffff0e3aae0, argv=0x4a7390 <_start>, argc=-253515440, l=<optimized out>) at dl-init.c:30
#6 _dl_init (main_map=0x0, argc=-253515440, argv=0x4a7390 <_start>, env=0x7ffff0e3aae0) at dl-init.c:120
#7 0x000000000000001c in ?? ()
#8 0x0000000000000001 in ?? ()
#9 0x00007ffff0e3c21f in ?? ()
#10 0x0000000000000000 in ?? ()
I've tested this by hooking a function, running my application, seeing it segfault, calling that function in my shared library, running again, and seeing work correctly.
My knowledge of libdl
and elf
is not up to scratch to know what is happening here or how to prevent it / catch the fact that I've tried to hook a function which doesn't get called.
How can I prevent this from happening?
Edit:
Per request, here is the output of readelf
:
$ readelf -s -S --dyn-syms -r ./libtest_api.so
There are 36 section headers, starting at offset 0x14a208:
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 00000000000001c8 000001c8
0000000000000024 0000000000000000 A 0 0 4
[ 2] .gnu.hash GNU_HASH 00000000000001f0 000001f0
0000000000000044 0000000000000000 A 3 0 8
[ 3] .dynsym DYNSYM 0000000000000238 00000238
0000000000000240 0000000000000018 A 4 2 8
[ 4] .dynstr STRTAB 0000000000000478 00000478
00000000000001b4 0000000000000000 A 0 0 1
[ 5] .gnu.version VERSYM 000000000000062c 0000062c
0000000000000030 0000000000000002 A 3 0 2
[ 6] .gnu.version_r VERNEED 0000000000000660 00000660
0000000000000070 0000000000000000 A 4 3 8
[ 7] .rela.dyn RELA 00000000000006d0 000006d0
00000000000000f0 0000000000000018 A 3 0 8
[ 8] .rela.plt RELA 00000000000007c0 000007c0
00000000000000d8 0000000000000018 AI 3 22 8
[ 9] .init PROGBITS 0000000000000898 00000898
000000000000001a 0000000000000000 AX 0 0 4
[10] .plt PROGBITS 00000000000008c0 000008c0
00000000000000a0 0000000000000010 AX 0 0 16
[11] .plt.got PROGBITS 0000000000000960 00000960
0000000000000010 0000000000000000 AX 0 0 8
[12] .text PROGBITS 0000000000000970 00000970
0000000000000253 0000000000000000 AX 0 0 16
[13] .fini PROGBITS 0000000000000bc4 00000bc4
0000000000000009 0000000000000000 AX 0 0 4
[14] .rodata PROGBITS 0000000000000bd0 00000bd0
0000000000000105 0000000000000000 A 0 0 8
[15] .eh_frame_hdr PROGBITS 0000000000000cd8 00000cd8
0000000000000034 0000000000000000 A 0 0 4
[16] .eh_frame PROGBITS 0000000000000d10 00000d10
00000000000000cc 0000000000000000 A 0 0 8
[17] .init_array INIT_ARRAY 0000000000201dc0 00001dc0
0000000000000010 0000000000000000 WA 0 0 8
[18] .fini_array FINI_ARRAY 0000000000201dd0 00001dd0
0000000000000008 0000000000000000 WA 0 0 8
[19] .jcr PROGBITS 0000000000201dd8 00001dd8
0000000000000008 0000000000000000 WA 0 0 8
[20] .dynamic DYNAMIC 0000000000201de0 00001de0
00000000000001f0 0000000000000010 WA 4 0 8
[21] .got PROGBITS 0000000000201fd0 00001fd0
0000000000000030 0000000000000008 WA 0 0 8
[22] .got.plt PROGBITS 0000000000202000 00002000
0000000000000060 0000000000000008 WA 0 0 8
[23] .data PROGBITS 0000000000202060 00002060
0000000000000008 0000000000000000 WA 0 0 8
[24] .bss NOBITS 0000000000202068 00002068
0000000000000008 0000000000000000 WA 0 0 1
[25] .comment PROGBITS 0000000000000000 00002068
0000000000000034 0000000000000001 MS 0 0 1
[26] .debug_aranges PROGBITS 0000000000000000 0000209c
0000000000000040 0000000000000000 0 0 1
[27] .debug_info PROGBITS 0000000000000000 000020dc
0000000000007a3b 0000000000000000 0 0 1
[28] .debug_abbrev PROGBITS 0000000000000000 00009b17
00000000000009e1 0000000000000000 0 0 1
[29] .debug_line PROGBITS 0000000000000000 0000a4f8
00000000000052dd 0000000000000000 0 0 1
[30] .debug_str PROGBITS 0000000000000000 0000f7d5
000000000011cb84 0000000000000001 MS 0 0 1
[31] .debug_ranges PROGBITS 0000000000000000 0012c359
0000000000000030 0000000000000000 0 0 1
[32] .debug_macro PROGBITS 0000000000000000 0012c389
000000000001c8a8 0000000000000000 0 0 1
[33] .shstrtab STRTAB 0000000000000000 0014a0b4
0000000000000151 0000000000000000 0 0 1
[34] .symtab SYMTAB 0000000000000000 00148c38
0000000000000ba0 0000000000000018 35 102 8
[35] .strtab STRTAB 0000000000000000 001497d8
00000000000008dc 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Relocation section '.rela.dyn' at offset 0x6d0 contains 10 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000201dc0 000000000008 R_X86_64_RELATIVE a40
000000201dc8 000000000008 R_X86_64_RELATIVE ba2
000000201dd0 000000000008 R_X86_64_RELATIVE a00
000000202060 000000000008 R_X86_64_RELATIVE 202060
000000201fd0 000200000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
000000201fd8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 _Jv_RegisterClasses + 0
000000201fe0 000800000006 R_X86_64_GLOB_DAT 0000000000000000 _ZNSt8ios_base4InitD1E@GLIBCXX_3.4 + 0
000000201fe8 000900000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0
000000201ff0 000a00000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0
000000201ff8 000c00000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0
Relocation section '.rela.plt' at offset 0x7c0 contains 9 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000202018 000400000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
000000202020 000500000007 R_X86_64_JUMP_SLO 0000000000000000 _ZNSt8ios_base4InitC1E@GLIBCXX_3.4 + 0
000000202028 001600000007 R_X86_64_JUMP_SLO 0000000000000bb8 _ZN5boost6none_tC1ENS0 + 0
000000202030 000600000007 R_X86_64_JUMP_SLO 0000000000000000 recv@GLIBC_2.2.5 + 0
000000202038 000700000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_atexit@GLIBC_2.2.5 + 0
000000202040 000b00000007 R_X86_64_JUMP_SLO 0000000000000000 listen@GLIBC_2.2.5 + 0
000000202048 000d00000007 R_X86_64_JUMP_SLO 0000000000000000 socket@GLIBC_2.2.5 + 0
000000202050 000e00000007 R_X86_64_JUMP_SLO 0000000000000000 __stack_chk_fail@GLIBC_2.4 + 0
000000202058 000f00000007 R_X86_64_JUMP_SLO 0000000000000000 send@GLIBC_2.2.5 + 0
Symbol table '.dynsym' contains 24 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000898 0 SECTION LOCAL DEFAULT 9
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (3)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND recv@GLIBC_2.2.5 (4)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (2)
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (3)
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND listen@GLIBC_2.2.5 (2)
12: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND socket@GLIBC_2.2.5 (2)
14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail@GLIBC_2.4 (5)
15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND send@GLIBC_2.2.5 (4)
16: 0000000000202070 0 NOTYPE GLOBAL DEFAULT 24 _end
17: 0000000000202068 0 NOTYPE GLOBAL DEFAULT 23 _edata
18: 0000000000000a70 172 FUNC GLOBAL DEFAULT 12 _ZN10ElfHookAPI4workEv
19: 0000000000202068 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
20: 0000000000000898 0 FUNC GLOBAL DEFAULT 9 _init
21: 0000000000000bc4 0 FUNC GLOBAL DEFAULT 13 _fini
22: 0000000000000bb8 11 FUNC WEAK DEFAULT 12 _ZN5boost6none_tC1ENS0_8i
23: 0000000000000bb8 11 FUNC WEAK DEFAULT 12 _ZN5boost6none_tC2ENS0_8i
Symbol table '.symtab' contains 124 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000000001c8 0 SECTION LOCAL DEFAULT 1
2: 00000000000001f0 0 SECTION LOCAL DEFAULT 2
3: 0000000000000238 0 SECTION LOCAL DEFAULT 3
4: 0000000000000478 0 SECTION LOCAL DEFAULT 4
5: 000000000000062c 0 SECTION LOCAL DEFAULT 5
6: 0000000000000660 0 SECTION LOCAL DEFAULT 6
7: 00000000000006d0 0 SECTION LOCAL DEFAULT 7
8: 00000000000007c0 0 SECTION LOCAL DEFAULT 8
9: 0000000000000898 0 SECTION LOCAL DEFAULT 9
10: 00000000000008c0 0 SECTION LOCAL DEFAULT 10
11: 0000000000000960 0 SECTION LOCAL DEFAULT 11
12: 0000000000000970 0 SECTION LOCAL DEFAULT 12
13: 0000000000000bc4 0 SECTION LOCAL DEFAULT 13
14: 0000000000000bd0 0 SECTION LOCAL DEFAULT 14
15: 0000000000000cd8 0 SECTION LOCAL DEFAULT 15
16: 0000000000000d10 0 SECTION LOCAL DEFAULT 16
17: 0000000000201dc0 0 SECTION LOCAL DEFAULT 17
18: 0000000000201dd0 0 SECTION LOCAL DEFAULT 18
19: 0000000000201dd8 0 SECTION LOCAL DEFAULT 19
20: 0000000000201de0 0 SECTION LOCAL DEFAULT 20
21: 0000000000201fd0 0 SECTION LOCAL DEFAULT 21
22: 0000000000202000 0 SECTION LOCAL DEFAULT 22
23: 0000000000202060 0 SECTION LOCAL DEFAULT 23
24: 0000000000202068 0 SECTION LOCAL DEFAULT 24
25: 0000000000000000 0 SECTION LOCAL DEFAULT 25
26: 0000000000000000 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 SECTION LOCAL DEFAULT 28
29: 0000000000000000 0 SECTION LOCAL DEFAULT 29
30: 0000000000000000 0 SECTION LOCAL DEFAULT 30
31: 0000000000000000 0 SECTION LOCAL DEFAULT 31
32: 0000000000000000 0 SECTION LOCAL DEFAULT 32
33: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
34: 0000000000201dd8 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__
35: 0000000000000970 0 FUNC LOCAL DEFAULT 12 deregister_tm_clones
36: 00000000000009b0 0 FUNC LOCAL DEFAULT 12 register_tm_clones
37: 0000000000000a00 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
38: 0000000000202068 1 OBJECT LOCAL DEFAULT 24 completed.7585
39: 0000000000201dd0 0 OBJECT LOCAL DEFAULT 18 __do_global_dtors_aux_fin
40: 0000000000000a40 0 FUNC LOCAL DEFAULT 12 frame_dummy
41: 0000000000201dc0 0 OBJECT LOCAL DEFAULT 17 __frame_dummy_init_array_
42: 0000000000000000 0 FILE LOCAL DEFAULT ABS lib_elfhook.cpp
43: 0000000000000bd0 1 OBJECT LOCAL DEFAULT 14 _ZStL19piecewise_construc
44: 0000000000202069 1 OBJECT LOCAL DEFAULT 24 _ZStL8__ioinit
45: 0000000000000bd1 1 OBJECT LOCAL DEFAULT 14 _ZStL13allocator_arg
46: 0000000000000bd2 1 OBJECT LOCAL DEFAULT 14 _ZStL6ignore
47: 0000000000000bd3 1 OBJECT LOCAL DEFAULT 14 _ZStL10defer_lock
48: 0000000000000bd4 1 OBJECT LOCAL DEFAULT 14 _ZStL11try_to_lock
49: 0000000000000bd5 1 OBJECT LOCAL DEFAULT 14 _ZStL10adopt_lock
50: 0000000000000bd8 4 OBJECT LOCAL DEFAULT 14 _ZN9__gnu_cxxL21__default
51: 0000000000000bdc 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobuf8inter
52: 0000000000000be0 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobuf8inter
53: 0000000000000be4 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL9kint
54: 0000000000000be8 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL9kint
55: 0000000000000bf0 8 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL9kint
56: 0000000000000bf8 8 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL9kint
57: 0000000000000c00 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL10kui
58: 0000000000000c08 8 OBJECT LOCAL DEFAULT 14 _ZN6google8protobufL10kui
59: 0000000000000c10 4 OBJECT LOCAL DEFAULT 14 _ZN6google8protobuf8inter
60: 0000000000000c14 4 OBJECT LOCAL DEFAULT 14 _ZN3cay3logL9Level_MINE
61: 0000000000000c18 4 OBJECT LOCAL DEFAULT 14 _ZN3cay3logL9Level_MAXE
62: 0000000000000c1c 4 OBJECT LOCAL DEFAULT 14 _ZN3cay3logL15Level_ARRAY
63: 0000000000000c20 4 OBJECT LOCAL DEFAULT 14 _ZN3cay3logL13DEFAULT_LEV
64: 000000000020206a 1 OBJECT LOCAL DEFAULT 24 _ZN5boostL4noneE
65: 0000000000000c24 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL13days_per
66: 0000000000000c28 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL18days_per
67: 0000000000000c2c 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL16days_per
68: 0000000000000c30 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL18days_per
69: 0000000000000c34 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL18days_per
70: 0000000000000c38 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL12min_per_
71: 0000000000000c40 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL12sec_per_
72: 0000000000000c48 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL11ms_per_h
73: 0000000000000c50 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL11us_per_h
74: 0000000000000c58 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL11ns_per_h
75: 0000000000000c60 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL11sec_per_
76: 0000000000000c68 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10ms_per_m
77: 0000000000000c70 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10us_per_m
78: 0000000000000c78 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10ns_per_m
79: 0000000000000c80 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10ms_per_s
80: 0000000000000c84 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10us_per_s
81: 0000000000000c88 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10ns_per_s
82: 0000000000000c90 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10sec_per_
83: 0000000000000c98 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9us_per_ms
84: 0000000000000c9c 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9ns_per_ms
85: 0000000000000ca0 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10sec_per_
86: 0000000000000ca8 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9ms_per_us
87: 0000000000000cb0 4 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9ns_per_us
88: 0000000000000cb8 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL10sec_per_
89: 0000000000000cc0 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9ms_per_ns
90: 0000000000000cc8 8 OBJECT LOCAL DEFAULT 14 _ZN3cay6chronoL9us_per_ns
91: 0000000000000b1c 134 FUNC LOCAL DEFAULT 12 _Z41__static_initializati
92: 0000000000000ba2 21 FUNC LOCAL DEFAULT 12 _GLOBAL__sub_I_lib_elfhoo
93: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
94: 0000000000000dd8 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__
95: 0000000000201dd8 0 OBJECT LOCAL DEFAULT 19 __JCR_END__
96: 0000000000000000 0 FILE LOCAL DEFAULT ABS
97: 0000000000000cd8 0 NOTYPE LOCAL DEFAULT 15 __GNU_EH_FRAME_HDR
98: 0000000000202000 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_
99: 0000000000202068 0 OBJECT LOCAL DEFAULT 23 __TMC_END__
100: 0000000000202060 0 OBJECT LOCAL DEFAULT 23 __dso_handle
101: 0000000000201de0 0 OBJECT LOCAL DEFAULT 20 _DYNAMIC
102: 0000000000000a70 172 FUNC GLOBAL DEFAULT 12 _ZN10ElfHookAPI4workEv
103: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
104: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
105: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
106: 0000000000000bc4 0 FUNC GLOBAL DEFAULT 13 _fini
107: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@@
108: 0000000000000bb8 11 FUNC WEAK DEFAULT 12 _ZN5boost6none_tC1ENS0_8i
109: 0000000000000000 0 FUNC GLOBAL DEFAULT UND recv@@GLIBC_2.2.5
110: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@@GLIBC_2.2.5
111: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@@
112: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
113: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
114: 0000000000000000 0 FUNC GLOBAL DEFAULT UND listen@@GLIBC_2.2.5
115: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2
116: 0000000000000bb8 11 FUNC WEAK DEFAULT 12 _ZN5boost6none_tC2ENS0_8i
117: 0000000000000000 0 FUNC GLOBAL DEFAULT UND socket@@GLIBC_2.2.5
118: 0000000000202068 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
119: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail@@GLIBC_2
120: 0000000000000000 0 FUNC GLOBAL DEFAULT UND send@@GLIBC_2.2.5
121: 0000000000202070 0 NOTYPE GLOBAL DEFAULT 24 _end
122: 0000000000202068 0 NOTYPE GLOBAL DEFAULT 23 _edata
123: 0000000000000898 0 FUNC GLOBAL DEFAULT 9 _init
Upvotes: 1
Views: 2092
Reputation: 848
So what basically his code does is when you create shared library libtest.so
that calls libc.so
within it the following items are created within your library
libc.so
)libc.so
, every entry in a relocation table says that function X that belongs to libc.so
was called in libtest.so
in lines a,b,c...His code parses your shared library, pulls the dynsymtable
and the relocation table out of it and swaps symbols to your request by calling elf_hook()
(see elf_hook.c
lines 434 - 442).
You called three functions out of the libc.so
API, which is a HUGE API, hence the dynsym
in your table should contain symbols for socket()
listen()
and recv()
We can see dyn-symbols
13 11 and 6 are accordingly socket@GLIBC
, listen@GLIBC
and recv@GLIBC
.
What the relocation table does is basically say where within the ACTUAL code of yours are those functions called, and when those symbols would have a resolved address which addresses would need to be replaced in order for your code to call the actual functions, as we also can see at .rela.plt
you've posted as an output of the readelf
command we see that on 3 different entries you've called theses symbols. These are what we need to replace.
So what his code does is find the index of the symbol you're looking to replace, go through ALL relocations, and see if they are relevant to the index-symbol. If so that means that in the place this relocation entry is relevant, it needs to replace it with the code you want.
Back with our previous example, lets say you want to replace socket()
with y()
in your libtest.so
. His code finds the symbol index of socket()
, finds where in code have you called socket()
and replaces that with the address of y()
instead.
Trying to hook symbols which don't exist
What can go wrong is the fact that when trying to hook symbols that weren't called is that simply there are no relocation entries for that symbol AND that symbol doesn't exist, you can see that e.g there is no entry in the dynsym
table ( readelf
output ) of bind()
.
What SHOULD happen is that he wouldn't find the according symbol and wont hook anything.
I honestly haven't gone through his entire code but my guess is that something went wrong there and he didn't handle the case of trying to hook a symbol that doesn't exist right...
Note:
Another thing that I've noticed that seems to be terrible wrong is the filling relocations of rel.dyn
.
He has chosen to load the libs in his example with RTLD_LAZY
, which basically means that every call to a DLL function would end up in jumping to some table of offsets, which point to your dynamic linker, and when the dynamic linker is called it replaces the offset which it was called from with the actual offset of the function... this is run-time relocation...
As far as I know rel.dyn
is usually meant for load-time relocation, when the operating system loads an executable it copies it's code and looks at all the relocation entries and replaces them in code....
During run-time the offsets a rel.dyn
table entries are pointing at would be within an executable section of the executable image, which means they SHOULD have only READ / EXECUTE permissions, not WRITE hence attempting to write into them SHOULD cause some segfault....
To sum things up, this probably happens because his utility didn't handle trying to hook an API function that does not exist within symbol table ( not called within your code ) right... hopefully I've helped you understand a little bit more of what happened...
Also, try reading this, it helped me to learn a lot about the ELF subject back in the day :)
http://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf
Upvotes: 4