カーネル シンボルを調べると、それらが読み取り専用かどうかを確認できます。 「R」は読み取り専用を意味します。
$ grep sys_call_table /proc/kallsyms
0000000000000000 R sys_call_table
0000000000000000 R ia32_sys_call_table
0000000000000000 R x32_sys_call_table
だから彼らは 読み取り専用で、カーネル 2.6.16 以降です。ただし、カーネル ルートキットには、それらを再度書き込み可能にする機能があります。各アドレスを引数として、カーネル モードで (直接または十分に柔軟な ROP ガジェットを介して、十分に柔軟なガジェットを使用して) 次のような関数を実行するだけで済みます。
static void set_addr_rw(const unsigned long addr)
{
unsigned int level;
pte_t *pte = lookup_address(addr, &level);
if (pte->pte &~ _PAGE_RW)
pte->pte |= _PAGE_RW;
local_flush_tlb();
}
これにより、syscall テーブルの権限が変更され、編集できるようになります。何らかの理由でこれが機能しない場合は、次の ASM を使用してカーネルの書き込み保護をグローバルに無効にすることができます:
cli
mov %cr0, %eax
and $~0x10000, %eax
mov %eax, %cr0
sti
これにより、割り込みが無効になり、CR0 の WP (書き込み保護) ビットが無効になり、割り込みが再度有効になります。アセンブリを使用すると、 write_cr0(read_cr0() & ~0x10000)
にもかかわらずこれが機能します CR0 への書き込み用の定義済み関数が機密ビットをピン留めするようになったため、エラーが発生しました。ただし、後で必ず WP を再度有効にしてください!
では、簡単に無効にできるのに、なぜ読み取り専用としてマークされているのでしょうか?理由の 1 つは、カーネル メモリを変更できるがコードを直接実行できるとは限らない脆弱性が存在することです。カーネルの重要な領域を読み取り専用としてマークすることにより、追加を見つけずにそれらを悪用することがより困難になります。 ページを書き込み可能としてマークする (または書き込み保護を完全に無効にする) 脆弱性。現在、これは非常に強力なセキュリティを提供していないため、読み取り専用としてマークされている主な理由は、偶発的を簡単に停止できるようにするためです。 壊滅的で回復不能なシステム クラッシュを引き起こすことから上書きします。
* 与えられた特定の例は、x86_64 プロセッサ用です。最初の表は、ネイティブ 64 ビット モード (x64) の syscall 用です。 2 つ目は、32 ビット モード (IA32) の syscall 用です。 3 つ目は、32 ビットのポインターと値を使用しながら、プログラムが 64 ビット モードのすべての機能を使用できるようにする、めったに使用されない x32 syscall ABI 用です (たとえば、浮動小数点演算用の x87 の代わりに SSE)。
† カーネルの内部 API は常に変更されるため、この正確な関数は古いカーネルまたは新しいカーネルでは機能しない可能性があります。 CR0.WP
をグローバルに無効化 ただし、ASM では、カーネルのバージョンに関係なく、すべての x86 システムで動作することが保証されています。
フォレストが指摘したように、最新の Linux ではこれが許可されていませんが、オーバーライドするのは簡単です。
ただし、歴史的には役に立ちました (そして今もそうかもしれません) セキュリティ上の目的:脆弱性に対するホットパッチ。 1990 年代から 2000 年代初頭にかけて、まったく必要のないシステムコール (ptrace
) の新しい脆弱性が発表されるたびに return -ENOSYS;
を実行したばかりの関数のアドレスで syscall テーブルの関数アドレスを上書きするカーネル モジュールを作成します。 .これにより、アップグレードされたカーネルが利用可能になるまで、攻撃対象領域が排除されました。繰り返し脆弱性があり、必要のない疑わしいシステムコールについては、先制的にこれを行い、モジュールを常に有効のままにしました.