7

dlopen() 内で発生するすべてのファイル システム アクセスをインターセプトしたい。最初は、実行可能な解決策のように見えますが、いくつLD_PRELOAD-Wl,-wrap,の技術的な理由により、それらを機能させるのに問題がありました。

  • ld.so は、LD_PRELOAD が処理されるまでに、独自のシンボルを既にマップしています。最初の読み込みをインターセプトすることは重要ではありませんが、_dl_*ワーカー関数はこの時点で解決されるため、以降の呼び出しはそれらを通過します。LD_PRELOAD遅すぎると思います。

  • ld.soの内部には機能的な がなく、 を呼び出すだけなmallocので、上記の問題を何らかの形で回避します。malloc()free()memset()

  • __libc_read()に含まれるファイル システム ワーカー関数ld.soは静的であるため、 でインターセプトできません-Wl,-wrap,__libc_read

これはすべてld.so、ソースをラッパーにリンクするのではなく、ソースから直接ビルドする必要があることを意味する場合があります。ここでの課題は、 と の両方libcrtld-libc同じソースから構築されていることです。のビルド時にマクロIS_IN_rtldが定義されることはわかってrtld-libcいますが、パブリック インターフェイス関数をエクスポートしながら、静的データ構造のコピーが 1 つだけであることをどのように保証できますか? (これは glibc ビルド システムに関する質問ですが、これらの詳細に関するドキュメントは見つかりませんでした。)

中に入るより良い方法はありますdlopen()か?

注:FUSEこれは、そのようなことをサポートしない最小限の「計算ノード」カーネル用であるため、Linux固有のソリューションは使用できません。

4

1 に答える 1

5

LD_PRELOAD または -Wl,-wrap が実行可能な解決策のようです

解決策は実行可能ではない可能性があります。--wrap(静的) リンク時にのみ機能し、ld.solibc.so.6およびlibdl.so.2はすべて既にリンクされているため、 を使用するには遅すぎます--wrap

LD_PRELOADld.soは、内部実装の詳細を呼び出すという事実dlopen()を考慮します。open()そのため、内部__open関数、バイパスPLT、およびそれに介入する機能を呼び出すだけopenです。

どういうわけか malloc は問題を回避します

これは、 (デバッグ目的などで)libc独自に実装するユーザーをサポートするためです。mallocそのため、eg callocfromへの呼び出しdlopenは を通過しPLT、 を介して挿入可能LD_PRELOADです。

これはすべて、独自の ld.so をラッパーにリンクするのではなく、ソースから直接ビルドする必要があることを意味している可能性があります。

再建されたものは何をld.soしますか?__libc_open(in )を呼び出したいと思いますlibc.so.6が、それは明らかな理由で機能しない可能性があります。最初に (プロセスの起動時に) sであるld.soということです。openlibc.so.6

ld.soへの呼び出しを への呼び出しに__open置き換えて再構築できopenます。これにより、ld.soが通過し、介入PLTにさらされます。LD_PRELOAD

その方法をとる場合は、新しいコピーでシステムを上書きしないことをお勧めしますld.so(間違いを犯してシステムが起動できなくなる可能性が非常に高くなります)。代わりに、それを eg にインストールしてから/usr/local/my-ld.so、バイナリを にリンクします-Wl,--dynamic-linker=/usr/local/my-ld.so

別の代替手段: ランタイム パッチ。これはちょっとしたハックですが、(メインで制御を取得したら) の をスキャンして.text、指示ld.soを探すだけです。CALL __openが削除されていない場合は、パッチを適用するld.so内部関数と関数の両方を見つけることができます(例:内)。興味深いを見つけたら、それを含むページを書き込み可能にし、独自のインターポーザー (必要に応じて呼び出し可能) のアドレスにパッチを適用してから、元に戻します。今後はインターポーザーを通過します。__openopen_verifydl-load.cCALLmprotect__libc_openmprotectdlopen()

于 2011-10-17T05:11:49.293 に答える