LD_PRELOAD トリックと、特定の syscall をあなたが提供したものに置き換える Linux カーネル モジュール以外に、syscall をインターセプトする可能性はありますか?
10 に答える
LD_PRELOAD トリックを使用できない/使用したくないのはなぜですか?
ここにコード例:
/*
* File: soft_atimes.c
* Author: D.J. Capelis
*
* Compile:
* gcc -fPIC -c -o soft_atimes.o soft_atimes.c
* gcc -shared -o soft_atimes.so soft_atimes.o -ldl
*
* Use:
* LD_PRELOAD="./soft_atimes.so" command
*
* Copyright 2007 Regents of the University of California
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <sys/types.h>
#include <bits/fcntl.h>
#include <stddef.h>
extern int errorno;
int __thread (*_open)(const char * pathname, int flags, ...) = NULL;
int __thread (*_open64)(const char * pathname, int flags, ...) = NULL;
int open(const char * pathname, int flags, mode_t mode)
{
if (NULL == _open) {
_open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open");
}
if(flags & O_CREAT)
return _open(pathname, flags | O_NOATIME, mode);
else
return _open(pathname, flags | O_NOATIME, 0);
}
int open64(const char * pathname, int flags, mode_t mode)
{
if (NULL == _open64) {
_open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64");
}
if(flags & O_CREAT)
return _open64(pathname, flags | O_NOATIME, mode);
else
return _open64(pathname, flags | O_NOATIME, 0);
}
私が理解していることから...それはほとんどLD_PRELOADトリックまたはカーネルモジュールです。関数をトラップできるエミュレーターで実行したり、実際のバイナリでコードを書き直して関数をトラップしたりしない限り、妥協点はあまりありません。
プログラムを変更できず、カーネルを変更できない (または変更したくない) と仮定すると、アプリケーションがかなり標準的であり、実際には悪意を持って通り抜けようとしているアプリケーションではない場合、LD_PRELOAD アプローチが最適です。あなたの傍受。(その場合、他のテクニックのいずれかが必要になります。)
Valgrindを使用して、関数呼び出しをインターセプトできます。完成した製品でシステム コールをインターセプトする必要がある場合、これは役に立ちません。ただし、開発中に傍受しようとする場合は、非常に便利です。私はこの手法を頻繁に使用してハッシュ関数をインターセプトし、返されたハッシュをテスト目的で制御できるようにしました。
ご存じないかもしれませんが、Valgrind は主にメモリ リークやその他のメモリ関連のエラーを検出するために使用されます。しかし、基盤となるテクノロジーは基本的に x86 エミュレーターです。プログラムをエミュレートし、malloc/free などの呼び出しをインターセプトします。良い点は、使用するために再コンパイルする必要がないことです。
Valgrind には、関数のインターセプトを制御するために使用されるFunction Wrappingと呼ばれる機能があります。詳細については、 Valgrind マニュアルのセクション 3.2 を参照してください。好きな関数の関数ラッピングを設定できます。呼び出しがインターセプトされると、指定した代替関数が呼び出されます。
一部のアプリケーションは strace/ptrace をだまして実行しないようにすることができるため、私が持っていた唯一の現実的なオプションは systemtap を使用することです
Systemtap は、ワイルド カード マッチングが原因で必要に応じて一連のシステム コールをインターセプトできます。Systemtap は C ではなく、別の言語です。基本モードでは、systemtap は愚かなことをしないようにする必要がありますが、必要に応じて開発者が C を使用できるようにする「エキスパート モード」で実行することもできます。
カーネルにパッチを適用する必要はありません (または、少なくともパッチを適用する必要はありません)。モジュールがコンパイルされたら、テスト/開発ボックスからコピーして、(insmod を介して) 運用システムに挿入できます。
systemtap に引っかかるのを回避/回避する方法を見つけた Linux アプリケーションをまだ見つけていません。
LKM をオフハンドで適切に実行するための構文はありませんが、この記事では、何をする必要があるかについての概要を説明しています 。
sys_open 関数にパッチを適用することもできます。linux-2.6.26 の時点では、file/open.c の 1084 行目から始まります。
また、新しいシステムを構築することなく、inotify、systemtap、または SELinux を使用してこのすべてのロギングを行うことができないかどうかを確認することもできます。
何が開いているかだけを見たい場合は、ptrace() 関数、またはコマンドライン strace ユーティリティのソース コードを調べます。実際に呼び出しを傍受したい場合、おそらく別のことをさせるために、リストしたオプション-LD_PRELOADまたはカーネルモジュール-が唯一のオプションだと思います。
デバッグ目的でのみ実行したい場合は、ptrace(2) システム コールの上に組み込まれている strace を調べて、システム コールが完了したときにコードを接続できるようにします。man ページの PTRACE_SYSCALL の部分を参照してください。
ソリューションが本当に必要な場合は、これを実現する DR ルートキットに興味があるかもしれません。http://www.immunityinc.com/downloads/linux_rootkit_source.tbz2それに関する記事はhttp://www.theregister.coにあります。英国/2008/09/04/linux_rootkit_released/
auditd が必要なようです。
Auditd を使用すると、ログを使用して、すべてのシステムコールまたはファイルへのアクセスをグローバルに追跡できます。関心のある特定のイベントのキーを設定できます。