Shigeaki Matsumura

CEO of Backflip180, LLC.

Mac OSで関数をフックする方法

概要

Mac OSを触るようになって初めて知ったのですが、Mac OSのバイナリ形式は他のUnixと異なり、ELFではなく、Mach-Oと呼ばれるファイル形式です。 そのため、LD_PRELOADは使えず、代わりにDYLD_INSERT_LIBRARIESを使う必要があります。

サンプルコード

まずは以下のように今回使用するサンプルコードを書きます。

#include <stdio.h>

int main()
{
  char * s = "aaa\n";
  printf(s);
  return 0;
}

コンパイル、実行して動作することを確認します。

$ gcc main.c 
$ ./a.out
aaa

"aaa"が表示されていることが確認されます。

フック用コード

ここでは先程のコードのprintf関数をフックし、"aaa"を"bbb"に置き換えるコードを作成します。

#include <dlfcn.h>
#include <stdio.h>

int printf(const char * _restrict, ...)
{
  typedef int (*ftype)(const char *, ...);
  return ((ftype)dlsym(RTLD_NEXT, "printf"))("bbb\n");
}

コンパイルし、dylibファイルを作成します。

$ gcc -ldl -dynamiclib printf.c -o printf.dylib

DYLD_INSERT_LIBRARIESとDYLD_FORCE_FLAT_NAMESPACEを設定してフック

先程作成したdylibファイルを読み込ませて関数をフックしたいのですが、上述のとおりLD_PRELOADは使えません。 代わりにDYLD_INSERT_LIBRARIESが使えます。 しかし、ここで注意が必要なのが、同時にDYLD_FORCE_FLAT_NAMESPACE=YESを設定する必要がある、ということです。

$ DYLD_INSERT_LIBRARIES=printf.dylib DYLD_FORCE_FLAT_NAMESPACE=YES ./a.out
bbb

"bbb"と表示されることが確認されました。 この手法を応用すればMac OSでHappy Hackingライフを送れるでしょう。