我需要在程序中找到指令的偏移量。假设我想在程序cat中找到open * system_call *的位置。
我使用objdump来查找bin文件中的位置。
objdump -T /bin/cat | grep open :
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 fdopen
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 open
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 iconv_ope
不幸的是,分析sible表我无法检索该信息,因为open函数是动态链接的。 open函数在 glibc 中实现。
在Glibc库上使用相同的方法我检索了open函数的偏移量,尽管这个偏移量指的是/lib/libc.so.6
内的位置所以这对我没用。
00000000000778d0 g DF .text 00000000000004e3 GLIBC_2.2.5 _IO_file_fopen
000000000006be50 g DF .text 000000000000000a GLIBC_2.2.5 fopen
0000000000073540 g DF .text 00000000000000f6 GLIBC_2.4 open_wmemstream
0000000000121cf0 w DF .text 0000000000000107 GLIBC_2.2.5 posix_openpt
000000000006d480 g DF .text 00000000000003bf GLIBC_2.2.5 _IO_proc_open
00000000000e38b0 g DF .text 0000000000000021 GLIBC_2.7 __open64_2
000000000006bfe0 g DF .text 00000000000000fa GLIBC_2.2.5 fopencookie
000000000006d840 g DF .text 0000000000000098 GLIBC_2.2.5 popen
00000000000ddd30 w DF .text 000000000000005e GLIBC_2.2.5 __open64
000000000006be50 g DF .text 000000000000000a GLIBC_2.2.5 _IO_fopen
00000000000de020 w DF .text 0000000000000020 GLIBC_2.7 __openat64_2
00000000000e84d0 g DF .text 0000000000000066 GLIBC_2.2.5 openlog
00000000000ddd30 w DF .text 000000000000005e GLIBC_2.2.5 open64
00000000003aa630 g DO .bss 0000000000000008 GLIBC_PRIVATE _dl_open_hook
00000000000ec840 g DF .text 000000000000005e GLIBC_2.14 open_by_handle_at
0000000000034250 g DF .text 0000000000000254 GLIBC_2.2.5 catopen
000000000006d840 g DF .text 0000000000000098 GLIBC_2.2.5 _IO_popen
0000000000075330 g DF .text 0000000000000355 GLIBC_2.2.5 freopen64
0000000000075eb0 g DF .text 00000000000001d8 GLIBC_2.2.5 fmemopen
00000000000b5b90 w DF .text 000000000000008b GLIBC_2.4 fdopendir
00000000000de020 g DF .text 0000000000000020 GLIBC_2.7 __openat_2
00000000000b5640 w DF .text 000000000000000d GLIBC_2.2.5 opendir
00000000000e3880 g DF .text 0000000000000021 GLIBC_2.7 __open_2
00000000000ddd30 w DF .text 000000000000005e GLIBC_2.2.5 __open
00000000000777f0 g DF .text 00000000000000d2 GLIBC_2.2.5 _IO_file_open
0000000000074370 g DF .text 00000000000000e6 GLIBC_2.2.5 open_memstream
0000000000073ab0 g DF .text 000000000000035d GLIBC_2.2.5 freopen
00000000000345a0 g DF .text 0000000000000837 GLIBC_PRIVATE __open_catalog
00000000000ddd30 w DF .text 000000000000005e GLIBC_2.2.5 open
000000000006b540 g DF .text 0000000000000249 GLIBC_2.2.5 fdopen
0000000000022b20 g DF .text 000000000000020a GLIBC_2.2.5 iconv_open
00000000000e2130 g DF .text 0000000000000373 GLIBC_2.2.5 fts_open
00000000000ddf80 w DF .text 0000000000000092 GLIBC_2.4 openat
000000000006be50 w DF .text 000000000000000a GLIBC_2.2.5 fopen64
00000000000ddf80 w DF .text 0000000000000092 GLIBC_2.4 openat64
0000000000122f30 g DF .text 0000000000000046 GLIBC_PRIVATE __libc_dlopen_mode
00000000000dc650 g DF .text 00000000000000b8 GLIBC_2.2.5 posix_spawn_file_actions_addopen
000000000006b540 g DF .text 0000000000000249 GLIBC_2.2.5 _IO_fdopen
当cat程序调用open函数时,我需要偏移来设置跟踪器。如果我在Glibc lib上放置一个跟踪器,我将在每次调用它时跟踪该系统调用。
你能帮帮我吗? 我清楚地解释了我的问题吗?谢谢
答案 0 :(得分:3)
好吧,cat
本身不包含open
系统调用。它住在glibc.so
。 cat
调用库来使用该函数。这就是为什么当您查看cat
内部时,其中没有open
函数,它是“未定义”并且引用glibc.so
。
您当然可以找到cat
调用open
的位置:
如果您在符号表中搜索符号open@plt
,那就是它打开的位置。例如,objdump -d
cat |grep open@plt
显示0000000000401910 <open@plt>:
,这是跳转到glibc函数的位置。
我希望这会有所帮助。
答案 1 :(得分:1)
使用/proc/$PID/maps
查看共享对象库的段在进程内存中的加载位置。 E.g:
# grep libc /proc/$$/maps
7f3243879000-7f3243a2e000 r-xp 00000000 08:01 270246 /lib/x86_64-linux-gnu/libc-2.15.so
7f3243a2e000-7f3243c2d000 ---p 001b5000 08:01 270246 /lib/x86_64-linux-gnu/libc-2.15.so
7f3243c2d000-7f3243c31000 r--p 001b4000 08:01 270246 /lib/x86_64-linux-gnu/libc-2.15.so
7f3243c31000-7f3243c33000 rw-p 001b8000 08:01 270246 /lib/x86_64-linux-gnu/libc-2.15.so
- 所以有4个libc.so
段加载到进程的地址空间,我们需要一个可执行文件,标记为r-xp
(“Read,no write,eXecute,Private” ),它的开始时间是*0x7f3243879000
。您已经知道如何获得符号的相对偏移量,例如您的示例中的freopen
位于可执行段开头的000000000000035d
处,因此在我的示例中,可以在进程内存中的7f3243879000 + 35d
= *0x7f324387935d
处找到该符号。
答案 2 :(得分:1)
具有良好动态链接器集成的调试器应该为您处理此问题,解析您希望设置断点的符号名称。它甚至可以在您尝试设置断点时尚未加载库时执行此操作。
但是,请注意,使用用户模式调试器可以跟踪的系统调用不多。您可以跟踪可能执行某些操作的小libc存根,例如在平台的C调用约定与其通常不同的系统调用约定之间重新排序参数,或者实现不推荐使用的系统调用作为新服务器的包装,但实际的内核模式实现只能用内核调试器跟踪。
您可能也对strace程序感兴趣,该程序打印出参数并返回所有系统调用的值。在某些情况下,另一件有用的事情是动态库拦截,例如使用LD_PRELOAD。