【发布时间】:2015-09-16 19:55:39
【问题描述】:
我正在尝试修改 linux 系统调用的默认行为。目前,我正在尝试在它们实际被调用之前挂钩并添加一个简单的打印语句。我知道 GCC 链接器的标准“包装”选项以及如何使用它来挂钩包装器Link to GCC Linker options。这非常适用于 open()、fstat()、fwrite() 等(我实际上是在挂钩 libc 包装器)。
更新:
限制是并非所有系统调用都与这种方法挂钩。 为了说明这一点,让我们以一个简单的静态编译二进制文件为例。当我们尝试添加包装器时,它们会受到我们在 main() 之后引入的调用的影响(请参阅下面显示的 strace 输出)
> strace ./sample
execve("./sample", ["./sample"], [/* 72 vars */]) = 0
uname({sys="Linux", node="kumar", ...}) = 0
brk(0) = 0x71f000
brk(0x7201c0) = 0x7201c0
arch_prctl(ARCH_SET_FS, 0x71f880) = 0
readlink("/proc/self/exe", "/home/admin/sample"..., 4096) = 41
brk(0x7411c0) = 0x7411c0
brk(0x742000) = 0x742000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbcc54d1000
write(1, "Hello from the wrapped readlink "..., 36Hello from the wrapped readlink :з
) = 36
readlink("/usr/bin/gnome-www-browser", "/etc/alternatives/gnome-www-brow"..., 255) = 35
write(1, "/etc/alternatives/gnome-www-brow"..., 36/etc/alternatives/gnome-www-browser
) = 36
exit_group(36) = ?
+++ exited with 36 +++
如果我们仔细注意到二进制文件,第一个“未拦截”调用 readlink()(系统调用 89 即 0x59)来自这些行——一些链接器相关的代码部分(即 _dl_get_origin)确实readlink() 用于其功能。这些隐式系统调用(尽管存在于二进制代码中)永远不会被我们的“包装”方法所吸引。
000000000051875c <_dl_get_origin>:
51875c: b8 59 00 00 00 mov $0x59,%eax
518761: 55 push %rbp
518762: 53 push %rbx
518763: 48 81 ec 00 10 00 00 sub $0x1000,%rsp
51876a: 48 89 e6 mov %rsp,%rsi
51876d: 0f 05 syscall
如何将包装思想扩展到像 readlink() 这样的系统调用(包括所有被调用的隐式调用)?
【问题讨论】:
-
为了简单起见,我正在做静态链接。所以我认为 LD_PRELOAD 对我没有帮助。
标签: linux gcc linker system-calls binutils