3

Linux で Mach カーネル API エミュレーションを行うには、タスクの作成直後または終了時にカーネル モジュールが呼び出されるようにする必要があります。

私のカーネル モジュールでは、Linux セキュリティ モジュールを介してこれを行うのが最もうまくいきましたが、数年前、必要なシンボルをアンエクスポートすることで、外部モジュールが LSM として機能するのを防いでいました。

私が見つけた他の唯一の方法は、モジュールをルートキットのように動作させることでした。syscall テーブルを見つけてそこにフックします。

カーネルにパッチを当てることは問題外です。アプリを簡単にインストールする必要があります。他に方法はありますか?

4

1 に答える 1

3

Kprobesを使用すると、カーネル内のコードに動的にフックできます。必要な情報を提供するプロセスの作成と破棄に関連する機能の中から、適切な機能を見つける必要があります。たとえば、作成されたタスクの場合、fork.c の do_fork() が開始するのに適しています。破棄されたタスクの場合、do_exit. retprobe を作成することをお勧めします。これは kprobe の一種であり、関数の実行の最後に、関数が戻る前に制御を追加で提供します。関数が戻る前に制御が必要な理由は、戻り値を確認してプロセスの作成に成功したかどうかを確認するためです。エラーが発生した場合、関数は負の値を返すか、場合によっては 0 を返します。

これを行うには、kretprobe 構造体を作成します。

static struct kretprobe do_fork_probe = {
    .entry_handler = (kprobe_opcode_t *) my_do_fork_entry,
    .handler = (kprobe_opcode_t *) my_do_fork_ret,
    .maxactive = 20,
    .data_size = sizeof(struct do_fork_ctx)
};

my_do_fork_entry は制御がフックされた関数に入ると実行され、 my_do_fork_ret はそれが戻る直前に実行されます。次のようにフックします。

do_fork_probe.kp.addr =
    (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");

if ((ret = register_kretprobe(&do_fork_probe)) <0) {
    // handle error
}

フックの実装では、引数と戻り値を取得するのは少し扱いに​​くいです。これらは、保存されたレジスタ pt_regs データ構造を介して取得します。return フックを見てみましょう。x86 では、regs->ax を介して戻り値を取得します。

static int my_do_fork_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
{
    struct do_fork_ctx *ctx = (struct do_fork_ctx *) ri->data;
    int ret = regs->ax; // This is on x86
    if (ret > 0) {
        // It's not an error, probably a valid process
    }
}

エントリ ポイントでは、レジスタを介して引数にアクセスできます。たとえば、x86 では、regs->di が最初の引数、regs->si が 2 番目の引数などです。Google で完全なリストを取得できます。レジスタは他の計算のために上書きされている可能性があるため、return フックの引数としてこれらのレジスタに依存しないでください。

これを機能させるには、確かに多くのフープをジャンプする必要がありますが、うまくいけば、このメモが正しい方向に進むはずです.

于 2012-12-20T02:18:18.647 に答える