2

GNU C 標準ライブラリのソースを見ると、system関数呼び出しの実装が表示されます__fork()。独自のラッパー__forkLD_PRELOADテクニックでその呼び出しをインターセプトする必要があります。

私は使用方法を知っていると思いますLD_PRELOAD

  1. __fork()アプリケーションで自分自身を呼び出すと、正しくインターセプトされます。__fork()ということは、原則 として傍受できるということです。
  2. 標準ライブラリの実装に変更__fork()し、標準ライブラリを再コンパイルして使用すると、傍受されます。fork()system()fork()

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

どうして??

4

1 に答える 1

1

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

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

ただし、libc 自体の内部では、リンカー__forkは が同じライブラリ内にあることを認識しており、その関数に到達するためにPLTを経由しないことを選択します。直接呼び出し命令を発行するだけです。これは、モジュールが静的関数を呼び出すとき、またはライブラリが独自の関数の 1 つを呼び出すときに、GCC が行う一般的な最適化です。以下を参照してください (コールが__fork@pltPLT を通過した場合、コールは to になります):

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

内部で fork() を使用するように libc を変更したとき、それは弱いシンボルを呼び出していましたが、それらはユーザーによってオーバーライドされる可能性があります。したがって、リンカーは、PLT を通過する呼び出しを発行するしかありません。これは、実際に でオーバーロードできることを意味しますLD_PRELOAD

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

于 2016-03-27T02:24:17.097 に答える