I am trying to code a tracer for any C program that displays all the functions that are being called. Here is an example:
$./tracer toto.out
+ Entering main at 0x123456789
'I am in Toto's main'
+ Entering toto at 0x123456AAA
'I am in toto'
+ Entering tutu at 0x123456BBB
'I am in tutu'
With toto.out being the simple program:
void tutu(void) {
char msg[] = "I am in tutun";
size_t len = strlen(msg);
write(1, msg, len);
}
void toto(void) {
char msg[] = "I am in toton";
size_t len = strlen(msg);
write(1, msg, len);
}
int main(void) {
char msg[] = "I am in toto's mainn";
size_t len = strlen(msg);
write(1, msg, len);
toto();
tutu();
return 0;
}
Here is everything I have for now:
I already parsed the /proc/[child_pid]/maps file and listed the symbol list from the ELF64 header of every executable file:
59bcd6a5f000-59bcd6a60000 r-xp 00001000 103:04 5244516 /home/julian/epitech/ftrace/toto.out
76ac3ba28000-76ac3bbbd000 r-xp 00028000 103:04 5899229 /usr/lib/x86_64-linux-gnu/libc.so.6
76ac3be00000-76ac3be06000 r-xp 00000000 103:04 5948263 /usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0
76ac3c049000-76ac3c04a000 r-xp 00001000 103:04 5907768 /usr/lib/x86_64-linux-gnu/libpthread.so.0
76ac3c06f000-76ac3c099000 r-xp 00002000 103:04 5898261 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
Which gives me the following list of symbols (excluding symbols that are on non executable segments) thanks to a simple math to retrieve the global / mapped address of the symbol.
Executable segment address – segment offset + symbol local address (Elf64_Sym->st_value)
ie for toto.out main: 0x59bcd6a5f000 – 0x1000 + 0x128d = 0x59bcd6a628d
/home/me/epitech/ftrace/toto.out at address 0x000059bcd6a5f000->0x000059bcd6a60000 (offset 0x1000) :
_init
0x000059bcd6a5f000-> 0x000059bcd6a5f000 (local addr 0x1000) (size 0x0).
main
0x000059bcd6a5f28d-> 0x000059bcd6a5f32d (local addr 0x128d) (size 0xa0).
_start
0x000059bcd6a5f0c0-> 0x000059bcd6a5f0e6 (local addr 0x10c0) (size 0x26).
_IO_stdin_used
0x000059bcd6a60000-> 0x000059bcd6a60004 (local addr 0x2000) (size 0x4).
tutu
0x000059bcd6a5f1a9-> 0x000059bcd6a5f21b (local addr 0x11a9) (size 0x72).
toto
0x000059bcd6a5f21b-> 0x000059bcd6a5f28d (local addr 0x121b) (size 0x72).
_fini
0x000059bcd6a5f330-> 0x000059bcd6a5f330 (local addr 0x1330) (size 0x0).
frame_dummy
0x000059bcd6a5f1a0-> 0x000059bcd6a5f1a0 (local addr 0x11a0) (size 0x0).
__do_global_dtors_aux
0x000059bcd6a5f160-> 0x000059bcd6a5f160 (local addr 0x1160) (size 0x0).
register_tm_clones
0x000059bcd6a5f120-> 0x000059bcd6a5f120 (local addr 0x1120) (size 0x0).
deregister_tm_clones
0x000059bcd6a5f0f0-> 0x000059bcd6a5f0f0 (local addr 0x10f0) (size 0x0).
-/usr/lib/x86_64-linux-gnu/libc.so.6 at address 0x000076ac3ba28000->0x000076ac3bbbd000 (offset 0x28000) :
I cannot find the .strtab to name the symbol...
-/usr/lib/x86_64-linux-gnu/libgtk3-nocsd.so.0 at address 0x000076ac3be00000->0x000076ac3be06000 (offset 0x0) :
Same .strtab issue...
-/usr/lib/x86_64-linux-gnu/libdl.so.2 at address 0x000076ac3c04e000->0x000076ac3c04f000 (offset 0x1000) :
Same...
-/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 at address 0x000076ac3c06f000->0x000076ac3c099000 (offset 0x2000) :
Same...
-/usr/lib/x86_64-linux-gnu/libpthread.so.0 at address 0x000076ac3c049000->0x000076ac3c04a000 (offset 0x1000) :
__libpthread_version_placeholder@GLIBC_2.3.2
0x000076ac3c049100-> 0x000076ac3c049105 (local 0x1100) (size 0x5).
..a lot of other irrelevant symbols for toto...
Whenever I detect the call near opcode using PTRACE_PEEKTEXT, I wait until the jump has been made to compare the RIP register to my list of symbol’s addresses:
// old rip before call
Re-Extended Instruction Pointer 0x000059bcd6a5f2f9. (+0x5)
// Debug printing the opcode and the operand when I find a near call (opcode 0xe8) to main
Opcode 0xe8b2 0xfd, 0xff, 0xff, 0xe8, 0x18, 0xff...
// Debug printing the new RIP
Re-Extended Instruction Pointer 0x000059bcd6a5f0b0. (-0x249)
// Current rip in indeed inside toto.out's executable segment but doesn't match toto function address 0x000059bcd6a5f28d
+ Entering unknow at 0x59bcd6a5f080
// Child process prints
'I am in toto'
// Same for tutu, somehow jumps to the same address as toto
Re-Extended Instruction Pointer 0x000059bcd6a5f1ff. (+0x5)
Opcode 0xe87c 0xfe, 0xff, 0xff, 0x90, 0x48, 0x8b...
Re-Extended Instruction Pointer 0x000059bcd6a5f080. (-0x17f)
+ Entering unknow at 0x59bcd6a5f080
'I am in tutu'
...
Here is the objdump of toto.out for reference:
...a lot of symbols omitted for shortening this post...
00000000000011a9 <tutu>:
11a9: f3 0f 1e fa endbr64
11ad: 55 push %rbp
11ae: 48 89 e5 mov %rsp,%rbp
11b1: 48 83 ec 20 sub $0x20,%rsp
11b5: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
11bc: 00 00
11be: 48 89 45 f8 mov %rax,-0x8(%rbp)
11c2: 31 c0 xor %eax,%eax
11c4: 48 b8 49 20 61 6d 20 movabs $0x206e69206d612049,%rax
11cb: 69 6e 20
11ce: 48 89 45 ea mov %rax,-0x16(%rbp)
11d2: c7 45 f2 74 75 74 75 movl $0x75747574,-0xe(%rbp)
11d9: 66 c7 45 f6 0a 00 movw $0xa,-0xa(%rbp)
11df: 48 8d 45 ea lea -0x16(%rbp),%rax
11e3: 48 89 c7 mov %rax,%rdi
11e6: e8 a5 fe ff ff call 1090 <strlen@plt>
11eb: 48 89 45 e0 mov %rax,-0x20(%rbp)
11ef: 48 8b 55 e0 mov -0x20(%rbp),%rdx
11f3: 48 8d 45 ea lea -0x16(%rbp),%rax
11f7: 48 89 c6 mov %rax,%rsi
11fa: bf 01 00 00 00 mov $0x1,%edi
11ff: e8 7c fe ff ff call 1080 <write@plt>
1204: 90 nop
1205: 48 8b 45 f8 mov -0x8(%rbp),%rax
1209: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
1210: 00 00
1212: 74 05 je 1219 <tutu+0x70>
1214: e8 87 fe ff ff call 10a0 <__stack_chk_fail@plt>
1219: c9 leave
121a: c3 ret
000000000000121b <toto>:
121b: f3 0f 1e fa endbr64
121f: 55 push %rbp
1220: 48 89 e5 mov %rsp,%rbp
1223: 48 83 ec 20 sub $0x20,%rsp
1227: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
122e: 00 00
1230: 48 89 45 f8 mov %rax,-0x8(%rbp)
1234: 31 c0 xor %eax,%eax
1236: 48 b8 49 20 61 6d 20 movabs $0x206e69206d612049,%rax
123d: 69 6e 20
1240: 48 89 45 ea mov %rax,-0x16(%rbp)
1244: c7 45 f2 74 6f 74 6f movl $0x6f746f74,-0xe(%rbp)
124b: 66 c7 45 f6 0a 00 movw $0xa,-0xa(%rbp)
1251: 48 8d 45 ea lea -0x16(%rbp),%rax
1255: 48 89 c7 mov %rax,%rdi
1258: e8 33 fe ff ff call 1090 <strlen@plt>
125d: 48 89 45 e0 mov %rax,-0x20(%rbp)
1261: 48 8b 55 e0 mov -0x20(%rbp),%rdx
1265: 48 8d 45 ea lea -0x16(%rbp),%rax
1269: 48 89 c6 mov %rax,%rsi
126c: bf 01 00 00 00 mov $0x1,%edi
1271: e8 0a fe ff ff call 1080 <write@plt>
1276: 90 nop
1277: 48 8b 45 f8 mov -0x8(%rbp),%rax
127b: 64 48 2b 04 25 28 00 sub %fs:0x28,%rax
1282: 00 00
1284: 74 05 je 128b <toto+0x70>
1286: e8 15 fe ff ff call 10a0 <__stack_chk_fail@plt>
128b: c9 leave
128c: c3 ret
000000000000128d <main>:
128d: f3 0f 1e fa endbr64
1291: 55 push %rbp
1292: 48 89 e5 mov %rsp,%rbp
1295: 48 83 ec 30 sub $0x30,%rsp
1299: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
12a0: 00 00
12a2: 48 89 45 f8 mov %rax,-0x8(%rbp)
12a6: 31 c0 xor %eax,%eax
12a8: 48 b8 49 20 61 6d 20 movabs $0x206e69206d612049,%rax
12af: 69 6e 20
12b2: 48 ba 74 6f 74 6f 27 movabs $0x6d2073276f746f74,%rdx
12b9: 73 20 6d
12bc: 48 89 45 e0 mov %rax,-0x20(%rbp)
12c0: 48 89 55 e8 mov %rdx,-0x18(%rbp)
12c4: c7 45 f0 61 69 6e 0a movl $0xa6e6961,-0x10(%rbp)
12cb: c6 45 f4 00 movb $0x0,-0xc(%rbp)
12cf: 48 8d 45 e0 lea -0x20(%rbp),%rax
12d3: 48 89 c7 mov %rax,%rdi
12d6: e8 b5 fd ff ff call 1090 <strlen@plt>
12db: 48 89 45 d8 mov %rax,-0x28(%rbp)
12df: 48 8b 55 d8 mov -0x28(%rbp),%rdx
12e3: 48 8d 45 e0 lea -0x20(%rbp),%rax
12e7: 48 89 c6 mov %rax,%rsi
12ea: bf 01 00 00 00 mov $0x1,%edi
12ef: e8 8c fd ff ff call 1080 <write@plt>
12f4: bf 01 00 00 00 mov $0x1,%edi
12f9: e8 b2 fd ff ff call 10b0 <sleep@plt>
12fe: e8 18 ff ff ff call 121b <toto>
1303: bf 01 00 00 00 mov $0x1,%edi
1308: e8 a3 fd ff ff call 10b0 <sleep@plt>
130d: e8 97 fe ff ff call 11a9 <tutu>
1312: b8 00 00 00 00 mov $0x0,%eax
1317: 48 8b 55 f8 mov -0x8(%rbp),%rdx
131b: 64 48 2b 14 25 28 00 sub %fs:0x28,%rdx
1322: 00 00
1324: 74 05 je 132b <main+0x9e>
1326: e8 75 fd ff ff call 10a0 <__stack_chk_fail@plt>
132b: c9 leave
132c: c3 ret
Finally, here are all the question I need help with:
- Am I getting the correct global address ?
- If the addresses are correct, why is the message printed although I am not on the main function ?
- Why is the RIP being jumped to the same address BEFORE main, toto and tutu for both function ?
Thanks to anyone who took the time to read this massive post and thanks + 1 for those knowledgeable enough to answer it