簡體   English   中英

LD_PRELOAD具有可能的靜態共享庫功能

[英]LD_PRELOAD with possible static shared library functions

我的目標是掛鈎linux上dlopen使用的open函數。 出於某種原因,此代碼未鈎住dlopen-> open,但確實鈎住了我的open main.c-> open版本。 dlopen是否以某種方式不使用我的符號?

編譯過程如下:

  1. gcc main.c -ldl -ggdb
  2. gcc fake-open.c -o libexample.so -fPIC -shared
  3. export LD_PRELOAD="$PWD/libexample.so"

當我運行程序時,一切正常。 確保設置了LD_PRELOAD變量。等等。

這就是問題所在,當我嘗試直接或間接鈎接dlopen調用的open函數時,我的版本無法以某種方式解決open的“版本”問題。

[main.c]
#include <dlfcn.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
    puts("calling open");
    int fd = open("/tmp/test.so", O_RDONLY|O_CLOEXEC);

    puts("calling dlopen");
    int *handle = dlopen("/tmp/test.so", RTLD_LAZY);
}


[fake-open.c]
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <fcntl.h>

int open(const char *pathname, int flags)
{
    puts("from hooked..");

    return 1;
}

控制台輸出:

叫開

從迷上了..

調用dlopen


我知道dlopen由於某種原因以某種方式稱為open。

write(1, "calling open\n", 13calling open
)          = 13
write(1, "from hooked..\n", 14from hooked..
)         = 14
write(1, "calling dlopen\n", 15calling dlopen
)        = 15
brk(0)                                  = 0x804b000
brk(0x806c000)                          = 0x806c000
open("/tmp/test.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\2\0\3\0\1\0\0\0`\205\4\0104\0\0\0"..., 512) = 512

但是,由於某種原因,當dlopen調用open時,它沒有使用我的open版本。 這必須是某種形式的運行時符號解析問題的鏈接,或者dlopen使用的是open的靜態版本,並且不需要在運行或加載時解析任何符號嗎?

首先,與@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 (loader=loader@entry=0x7ffff7ffe1c8, name=name@entry=0x4006a4 "./foo.so", type=type@entry=2, trace_mode=trace_mode@entry=0, mode=mode@entry=-1879048191, nsid=0) at dl-load.c:2543
#3  0x00007ffff7deea14 in dl_open_worker (a=a@entry=0x7fffffffdae8) at dl-open.c:235
#4  0x00007ffff7de9fc4 in _dl_catch_error (objname=objname@entry=0x7fffffffdad8, errstring=errstring@entry=0x7fffffffdae0, mallocedp=mallocedp@entry=0x7fffffffdad0, operate=operate@entry=0x7ffff7dee960 <dl_open_worker>, args=args@entry=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 (a=a@entry=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 (operate=operate@entry=0x7ffff7bd6fd0 <dlopen_doit>, args=args@entry=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", fbp=fbp@entry=0xffffc93c, loader=0xf7ffd938, whatcode=whatcode@entry=0, found_other_class=found_other_class@entry=0xffffc933, free_name=free_name@entry=true) at dl-load.c:1930
#2  0xf7fe4114 in _dl_map_object (loader=loader@entry=0xf7ffd938, name=name@entry=0x8048590 "./foo.so", type=type@entry=2, trace_mode=trace_mode@entry=0, mode=mode@entry=-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 (objname=objname@entry=0xffffccd4, errstring=errstring@entry=0xffffccd8, mallocedp=mallocedp@entry=0xffffccd3, operate=operate@entry=0xf7feeb50 <dl_open_worker>, args=args@entry=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 (operate=operate@entry=0xf7fafc30 <dlopen_doit>, args=args@entry=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_verifyopen調用沒有重定向到您的open interposer?

首先,讓我們看一下第1幀中的實際調用指令:

(gdb) fr 1
#1  0xf7fe1211 in open_verify (name=0x804b008 "./foo.so", fbp=fbp@entry=0xffffc93c, loader=0xf7ffd938, whatcode=whatcode@entry=0, found_other_class=found_other_class@entry=0xffffc933, free_name=free_name@entry=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 <dlopen@plt>

注意到有什么不同嗎?

沒錯:來自main的調用經過過程鏈接表(PLT),動態加載程序( ld-linux.so.2 )將其解析為適當的定義。

但是在第1幀中open的調用不會通過PLT(因此不可插入)。

這是為什么? 由於這一呼吁必須工作在此之前還有其他任何定義open可用-它是用來 libc.so.6 (通常提供的定義open )被加載本身 (通過動態加載器)。

因此,動態加載程序必須完全獨立(實際上在libc子集的副本中包含靜態鏈接)。

我的目標是掛鈎linux上dlopen使用的open函數。

由於上述原因,無法通過LD_PRELOAD實現此目標。 您將需要使用其他掛鈎機制,例如在運行時修補加載程序可執行代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM