(ほぼ) すべてのプロセス strace
について、この初期化を追跡するのは簡単です。 プロセス実行の最初の段階で非常に疑わしいシステムコールを示しています:
arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0
それが man 2 arch_prctl
です 言います:
ARCH_SET_FS
Set the 64-bit base for the FS register to addr.
ええ、それが必要なようです。 arch_prctl
を呼び出す人を見つけるには 、バックトレースを探しましょう:
(gdb) catch syscall arch_prctl
Catchpoint 1 (syscall 'arch_prctl' [158])
(gdb) r
Starting program: <program path>
Catchpoint 1 (call to syscall arch_prctl), 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0 0x00007ffff7dd9cad in init_tls () from /lib64/ld-linux-x86-64.so.2
#1 0x00007ffff7ddd3e3 in dl_main () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7df04c0 in _dl_sysdep_start () from /lib64/ld-linux-x86-64.so.2
#3 0x00007ffff7dda028 in _dl_start () from /lib64/ld-linux-x86-64.so.2
#4 0x00007ffff7dd8fb8 in _start () from /lib64/ld-linux-x86-64.so.2
#5 0x0000000000000001 in ?? ()
#6 0x00007fffffffecef in ?? ()
#7 0x0000000000000000 in ?? ()
したがって、FS セグメント ベースは ld-linux
によって設定されます。 glibc
の一部です 、プログラムのロード中 (プログラムが静的にリンクされている場合、このコードはバイナリに埋め込まれます)。ここですべてが行われます。
起動時に、ローダーは TLS を初期化します。これには、メモリの割り当てと、TLS の開始点を指すように FS ベース値を設定することが含まれます。これは arch_prctl
経由で行われます システムコール。 TLS 初期化後 security_init
関数が呼び出され、スタック ガードの値が生成され、それが fs:[0x28]
のメモリ ロケーションに書き込まれます。 指し示す:
- スタック ガード値の初期化
- スタック ガード値の書き込み、詳細
そして 0x28
stack_guard
のオフセットです TLS の開始位置にある構造体のフィールド。
表示されているのは (GCC では) スタック スマッシング プロテクター (SSP) と呼ばれ、コンパイラによって生成されるバッファー オーバーフロー保護の形式です。値は起動時にプログラムによって生成される乱数であり、ウィキペディアの記事で言及されているように、スレッド ローカル ストレージ (TLS) に配置されます。他のコンパイラは、このタイプの保護を実装するために異なる戦略を使用する場合があります。
なぜ値を TLS に保存するのですか?値はそこにあるため、CS、DS、および SS レジスタからそのアドレスにアクセスすることはできず、悪意のあるコードからスタックを変更しようとしている場合、格納されている値を推測することは非常に困難です。