LD_PRELOAD を Mac で
昨日、大学の図書館で偶然 BINARY HACKS という以前から読んでみたかった本を見つけた。
Binary Hacks ―ハッカー秘伝のテクニック100選
- 作者: 高林哲,鵜飼文敏,佐藤祐介,浜地慎一郎,首藤一幸
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2006/11/14
- メディア: 単行本(ソフトカバー)
- 購入: 23人 クリック: 383回
- この商品を含むブログ (223件) を見る
Valgrind とか strace, ltrace とかも Mac OS X で使いたいなー。
で、HACK #60 に「LD_PRELOAD で共有ライブラリを差し換える」というのがあったんだけど、これと同様なことを Mac OS X でやる方法がわかったから、ここに書いておく。
gethostname(3) を差し換えて、hostname(1) の挙動を変えようというストーリー。
差し換える gethostname のコードは原本のまんまで。
/* gethostname.c */ #include <stdlib.h> #include <string.h> int gethostname(char *name, size_t len) { char *p = getenv("FAKE_HOSTNAME"); if (p == NULL) p = "localhost"; strncpy(name, p, len-1); name[len-1] = '\0'; return 0; }
何はともあれ、共有ライブラリとしてコンパイル。
$ gcc -shared -fPIC -o gethostname.dylib gethostname.c
GNU/Linux の場合、
$ LD_PRELOAD=./gethostname.dylib FAKE_HOSTNAME=foo hostname foo
となるらしいのだけど、Mac の場合は
$ DYLD_INSERT_LIBRARIES=gethostname.dylib DYLD_FORCE_FLAT_NAMESPACE=YES FAKE_HOSTNAME=bar hostname bar
とする。
DYLD_INSERT_LIBRARIES が LD_PRELOAD にあたると考えていいと思う。
その次の DYLD_FORCE_FLAT_NAMESPACE ってのは、どうやら Mac ではデフォルトで two-level namespace という環境でビルドされているがために必要な環境変数らしい。
http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/compiling/chapter_4_section_7.html を読んでみたけど、一体 two-level namespace がどういうものかは分からなかった。
とにかく、two-level namespace だと DYLD_INSERT_LIBRARIES で指定したにもかかわらず、オリジナルの gethostname を呼んでしまうらしい。
そこで、シンボルの解決方法を強制的に flat namespace にするのが DYLD_FORCE_FLAT_NAMESPACE=YES というわけだ。
うぅむ、GNU/Linux の場合と違ってなかなかめんどくさいな。タイプ数的に。
もう一つの差し換える方法
あまり実践的な方法じゃないけど。
それは、プログラムをコンパイルするときに、リンカに -flat_namespace という引数を与えてやるという方法。
/* myhostname.c */ #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { char name[128]; gethostname(name, sizeof(name)); puts(name); return 0; }
こんな、hostname(1) もどきのプログラムを書いてみる。
そして、
$ cc -Wl,-flat_namespace -o myhostname myhostname.c $ DYLD_INSERT_LIBRARIES=gethostname.dylib FAKE_HOSTNAME=baz ./myhostname baz
こうやってコンパイル&リンクすることで、DYLD_FORCE_FLAT_NAMESPACE=YES といちいち指定する必要がなくなる。
そのバイナリが flat_namespace かどうか判定する方法はあるのかなぁ?otool で見れたりするんだろうか。
参考:
http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/dyld.1.html
http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/ld.1.html#//apple_ref/doc/man/1/ld