2017-04-15 26 views
2

私の目的は、Linuxで使用するdlopenのオープン関数をフックすることです。何らかの理由で、このコードはdlopen-> openをフックしていませんが、オープンしているmain.c-> openの私のバージョンにフックします。 dlopenは何とか私のシンボルを使用していませんか?次のように可能な静的共有ライブラリ関数を持つLD_PRELOAD

コンパイルプロセスは、次のとおりです。私はプログラムを実行すると

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

、すべての作品。

オープン機能を直接的にまたは間接的にdlopenによって呼び出すときに問題がありますが、どういうわけかオープンのこの「バージョン」は解決されていない/リダイレクトされています。私のバージョン。

[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を呼び出すフックからオープン

..

を呼び出す

で何とかによるオープン呼び出しstraceに。

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は、実行時またはロード時に任意のシンボルを解決するためにオープンとdoesntの静的バージョンを使用している必要がありますか?

+0

興味深い質問です。私は現時点で正しい答えを知らないが、それについて考えている - 動的リンカーがシンボルを解決するためにオープンな解決を必要とするならば、これは無限ループに終わらないだろうか? –

答えて

2

まず、@ usrの答えとは逆に、dlopenopenライブラリです。

私たちは、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 

これは、代わりにopen64を呼び出すdlopen 64ビットシステム上でことを示していますopenの場合は、インターポーザーが機能しません(代わりにopen64を挿入する必要があります)。

しかし、あなたは(0x806c000によって証明されるようstraceによって印刷されたアドレス等)32ビットシステムであり、そこにスタックトレースは次のようになります。

#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からの呼び出しは、動的ローダ(ld-linux.so.2)は適切定義に解決手続きリンクテーブル(PLT)を通過します。

しかし、フレーム1のopenへのコールはPLTを経由しない(したがって、インタポーザブルではありません)。

なぜですか?そのコールは前を働かなければならないので、利用可能なopenの他の定義がある - それは使用される一方(通常openの定義を供給する)自体(ダイナミックローダによって)ロードされているlibc.so.6

このため、ダイナミックローダーは完全に自己完結型でなければなりません(実際には、libcのサブセットのコピーに静的にリンクされています)。

私の目的は、Linuxでdlopenが使用するopen関数をフックすることです。

上記の理由から、この目的はLD_PRELOADでは達成できません。実行時にローダ実行可能コードにパッチを当てるなど、他のフックメカニズムを使用する必要があります。

関連する問題