LoginSignup
16
17

More than 5 years have passed since last update.

LD_PRELOADで差し替えた関数から元の関数を呼び出す

Last updated at Posted at 2016-04-13

TL;DR

LD_PRELOADで特定関数の差し替えをおこない、かつ場合によっては元の関数呼び出しをできるようにする。
dlsymRTLD_NEXT を指定して元の関数の関数ポインタを取得し、それを実行すれば良い。

実行方法まとめ

まずは差し替え対象の関数を定義する。今回は puts を対象とする。

print.c
#include <stdio.h>

int main(int argc, char const* argv[])
{
    puts("hoge");

    return 0;
}
ビルドと実行結果
$ gcc print.c 
$ ./a.out 
hoge

LD_PRELOADで差し替えるための関数を定義する。内部で元の関数を呼び出し、その前後でログを出力する。
そのまま puts を呼ぶと無限再帰呼び出しになってスタックオーバーフローするので、dlsym(RTLD_NEXT, "puts") を使用して、元の関数のの関数ポインタを取得して、そちらを呼び出すようにしている。
(RTLD_NEXT は、ライブラリ検索順序の中で現在のライブラリ以降で最初に 関数が現れるところを探す。)

override.c
#include <stdio.h>
#include <assert.h>
#define __USE_GNU
#include <dlfcn.h>

int puts(const char *__s) {
    fprintf(stdout, "before\n");

    void *handle = dlsym(RTLD_NEXT, "puts");
    assert(handle);

    int (*func)(const char *) = (int (*)(const char*))handle;
    int ret = func(__s);

    fprintf(stdout, "after\n");
}
ビルドと実行結果
$ gcc -shared -fPIC override.c -ldl -o liboverride.so
$ LD_PRELOAD=./liboverride.so ./a.out 
before
hoge
after

これで対象のバイナリを再ビルドせずにputsの呼び出し前後にログを入れることができた。

関連

LD_PRELOADでprintfを後から差し替える - Qiita

参考書籍

『BINARY HACKS』 #HACK 61 : LD_PRELOADで既存の関数をラップする

参考

Man page of DLOPEN
LD_PRELOADを使ったテスト(C言語編)
[Debug] LD_PRELOAD, dlsym, GCC拡張機能によって共有ライブラリの関数の呼出し前後で任意の処理を実行する - th0x4c 備忘録

16
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
17