首先,与@ usr的回答相反,dlopen
确实是open
这个库。
我们可以通过GDB下运行一个简单的测试证实了这一点:
// main.c
#include <dlfcn.h>
int main()
{
void *h = dlopen("./foo.so", RTLD_LAZY);
return 0;
}
// foo.c; compile with "gcc -fPIC -shared -o foo.so foo.c"
int foo() { return 0; }
让我们编译和运行这个:
gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x400605: file main.c, line 4.
Starting program: /tmp/a.out
Temporary breakpoint 1, main() at main.c:4
4 void *h = dlopen("./foo.so", RTLD_LAZY);
(gdb) catch syscall open
Catchpoint 2 (syscall 'open' [2])
(gdb) c
Continuing.
Catchpoint 2 (call to syscall open), 0x00007ffff7df3497 in open64() at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0 0x00007ffff7df3497 in open64() at ../sysdeps/unix/syscall-template.S:81
#1 0x00007ffff7ddf5bd in open_verify (name=0x602010 "./foo.so", fbp=0x7fffffffd568, loader=<optimized out>, whatcode=<optimized out>, found_other_class=0x7fffffffd550, free_name=<optimized out>) at dl-load.c:1930
#2 0x00007ffff7de2d6f in _dl_map_object ([email protected]=0x7ffff7ffe1c8, [email protected]=0x4006a4 "./foo.so", [email protected]=2, [email protected]=0, [email protected]=-1879048191, nsid=0) at dl-load.c:2543
#3 0x00007ffff7deea14 in dl_open_worker ([email protected]=0x7fffffffdae8) at dl-open.c:235
#4 0x00007ffff7de9fc4 in _dl_catch_error ([email protected]=0x7fffffffdad8, [email protected]=0x7fffffffdae0, [email protected]=0x7fffffffdad0, [email protected]=0x7ffff7dee960 <dl_open_worker>, [email protected]=0x7fffffffdae8) at dl-error.c:187
#5 0x00007ffff7dee37b in _dl_open (file=0x4006a4 "./foo.so", mode=-2147483647, caller_dlopen=<optimized out>, nsid=-2, argc=1, argv=0x7fffffffde28, env=0x7fffffffde38) at dl-open.c:661
#6 0x00007ffff7bd702b in dlopen_doit ([email protected]=0x7fffffffdd00) at dlopen.c:66
#7 0x00007ffff7de9fc4 in _dl_catch_error (objname=0x7ffff7dd9110 <last_result+16>, errstring=0x7ffff7dd9118 <last_result+24>, mallocedp=0x7ffff7dd9108 <last_result+8>, operate=0x7ffff7bd6fd0 <dlopen_doit>, args=0x7fffffffdd00) at dl-error.c:187
#8 0x00007ffff7bd762d in _dlerror_run ([email protected]=0x7ffff7bd6fd0 <dlopen_doit>, [email protected]=0x7fffffffdd00) at dlerror.c:163
#9 0x00007ffff7bd70c1 in __dlopen (file=<optimized out>, mode=<optimized out>) at dlopen.c:87
#10 0x0000000000400614 in main() at main.c:4
这就告诉你,在64位系统,dlopen
调用open64
代替open
,所以你的插件不起作用(你需要设置open64
)。
,但使用的是32位系统上(由strace
打印0x806c000
等地址证明),并有堆栈跟踪看起来是这样的:
#0 0xf7ff3774 in open() at ../sysdeps/unix/syscall-template.S:81
#1 0xf7fe1211 in open_verify (name=0x804b008 "./foo.so", [email protected]=0xffffc93c, loader=0xf7ffd938, [email protected]=0, [email protected]=0xffffc933, [email protected]=true) at dl-load.c:1930
#2 0xf7fe4114 in _dl_map_object ([email protected]=0xf7ffd938, [email protected]=0x8048590 "./foo.so", [email protected]=2, [email protected]=0, [email protected]=-1879048191, nsid=0) at dl-load.c:2543
#3 0xf7feec14 in dl_open_worker (a=0xffffccdc) at dl-open.c:235
#4 0xf7feac06 in _dl_catch_error ([email protected]=0xffffccd4, [email protected]=0xffffccd8, [email protected]=0xffffccd3, [email protected]=0xf7feeb50 <dl_open_worker>, [email protected]=0xffffccdc) at dl-error.c:187
#5 0xf7fee644 in _dl_open (file=0x8048590 "./foo.so", mode=-2147483647, caller_dlopen=0x80484ea <main+29>, nsid=<optimized out>, argc=1, argv=0xffffcf74, env=0xffffcf7c) at dl-open.c:661
#6 0xf7fafcbc in dlopen_doit (a=0xffffce90) at dlopen.c:66
#7 0xf7feac06 in _dl_catch_error (objname=0xf7fb3070 <last_result+12>, errstring=0xf7fb3074 <last_result+16>, mallocedp=0xf7fb306c <last_result+8>, operate=0xf7fafc30 <dlopen_doit>, args=0xffffce90) at dl-error.c:187
#8 0xf7fb037c in _dlerror_run ([email protected]=0xf7fafc30 <dlopen_doit>, [email protected]=0xffffce90) at dlerror.c:163
#9 0xf7fafd71 in __dlopen (file=0x8048590 "./foo.so", mode=1) at dlopen.c:87
#10 0x080484ea in main() at main.c:4
那么,为什么不open_verify
小号致电open
重定向到您的open
中介片?
首先,让我们看看实际调用指令在第1帧:
(gdb) fr 1
#1 0xf7fe1211 in open_verify (name=0x804b008 "./foo.so", [email protected]=0xffffc93c, loader=0xf7ffd938, [email protected]=0, [email protected]=0xffffc933, [email protected]=true) at dl-load.c:1930
1930 dl-load.c: No such file or directory.
(gdb) x/i $pc-5
0xf7fe120c <open_verify+60>: call 0xf7ff3760 <open>
在框架10与此相比,调用指令:
(gdb) fr 10
#10 0x080484ea in main() at main.c:4
4 void *h = dlopen("./foo.so", RTLD_LAZY);
(gdb) x/i $pc-5
0x80484e5 <main+24>: call 0x80483c0 <[email protected]>
注意到有什么不同?
这是正确的:从main
呼叫经过过程链接表(PLT),其动态加载程序(ld-linux.so.2
)解析为适当定义。
但是在帧1中调用open
不会经过PLT(因此不能通过)。
这是为什么?由于这一呼吁必须工作之前存在的open
其他任何可用的定义 - 它是用来而的libc.so.6
(通常提供的open
定义)是本身被加载(通过动态加载器)。
由于这个原因,动态加载器必须是完全独立的(实际上包含一个静态链接的子集libc
的副本)。
我的目标是挂钩在Linux上使用的开放函数。
由于上述原因,该目标不能通过LD_PRELOAD
来实现。您需要使用其他挂钩机制,例如在运行时修补加载器可执行代码。
有趣的问题。我现在还不知道正确的答案,但是考虑一下 - 如果动态链接器需要解决任何符号的解决方案,这是否会最终陷入无限循环? –