2016-03-23 4 views
2

私はGNU C標準ライブラリのソースを見ると、systemの実装では__fork()の呼び出しがあることがわかります。私は__forkLD_PRELOADテクニックのために私自身のラッパーでその呼び出しを傍受する必要があります。GNU C標準ライブラリで__fork()をインターセプトする方法は?

私はのでLD_PRELOADを使用する方法を知っていると思う:私は自分のアプリケーションで__fork()自分自身を呼び出した場合、それは正確に傍受され

  1. 。つまり、原理的に__fork()を傍受することができます。
  2. system()という標準ライブラリの実装で__fork()からfork()に変更し、標準ライブラリを再コンパイルして使用すると、fork()がインターセプトされます。

ただし、標準ライブラリの__fork()は傍受されません。ラッパーは呼び出されません。

なぜですか?

答えて

1

まず、__forkは、__libc_forkの同義語で、直接フォークシステムコールを行います。 forkは同じことを指す弱い記号です。他の共有ライブラリがその特定の関数を呼び出している場合は、これらの関数をオーバーライドすることができます。

$ readelf -Wa /lib/x86_64-linux-gnu/libc.so.6 | grep b84c0 
    42: 00000000000b84c0 784 FUNC GLOBAL DEFAULT 13 [email protected]@GLIBC_PRIVATE 
    80: 00000000000b84c0 784 FUNC GLOBAL DEFAULT 13 [email protected]@GLIBC_2.2.5 
    408: 00000000000b84c0 784 FUNC WEAK DEFAULT 13 [email protected]@GLIBC_2.2.5 

しかし、自身のlibc内、リンカは__forkが同じライブラリ内に位置していることを知っていて、その機能に到達するためにPLT通過しないことを選択します。それは直接コール命令を出すだけです。これは、モジュールが静的関数を呼び出すとき、またはライブラリがそれ自身の関数の1つを呼び出すときにGCCが行う一般的な最適化です。 (それはPLTを経た場合、コールは[email protected]になります)、以下を参照してください:

$ objdump -d /lib/x86_64-linux-gnu/libc.so.6 | grep __fork | head -n 4 
    6a074: e8 47 e4 04 00   callq b84c0 <[email protected]@GLIBC_2.2.5> 
00000000000b84c0 <[email protected]@GLIBC_2.2.5>: 
    b84da: 74 5c     je  b8538 <[email protected]@GLIBC_2.2.5+0x78> 
    b84e1: 74 ed     je  b84d0 <[email protected]@GLIBC_2.2.5+0x10> 

あなたはフォークを使用するlibcの変更した場合()内部で、それは弱いシンボルを呼んでいた、そしてそれらはoverridden by the userかもしれません。したがって、リンカはPLTを通過する呼び出しを出す以外に選択肢はありません。つまり、実際にはLD_PRELOADでオーバーロードすることができます。

一般的に、このようなフォークをハイジャックするのは簡単ではありません。関数は常にforkシステムコールを直接呼び出すことができ、それを傍受する方法はありません。コードでpthreadが使用されている場合は、pthread_atforkに興味があります。 glibc内の配列__fork_handlersに機能を追加します。残念ながら、その配列は保護されているとマークされ、シンボルに直接アクセスすることはできません。

+0

ちなみに、この種のものをデバッグするには、LDBIND_NOW = 1を設定し、GDBでシングルステップを実行して、どのシンボルが呼び出されたかを正確に監視すると便利です。 – dwks

関連する問題