fs:[0x28](スタックカナリア)を設定するものは何ですか?


11

この投稿からFS:[0x28]、スタックカナリアであることが示されています。この関数でGCCを使用して同じコードを生成しています。

void foo () {
    char a[500] = {};
    printf("%s", a);
}

具体的には、このアセンブリを取得しています。

    0x000006b5      64488b042528.  mov rax, qword fs:[0x28]                ; [0x28:8]=0x1978 ; '(' ; "x\x19"
    0x000006be      488945f8       mov qword [local_8h], rax
...stuff...
    0x00000700      488b45f8       mov rax, qword [local_8h]
    0x00000704      644833042528.  xor rax, qword fs:[0x28]
    0x0000070d      7405           je 0x714
    0x0000070f      e85cfeffff     call sym.imp.__stack_chk_fail           ; void __stack_chk_fail(void)
    ; CODE XREF from 0x0000070d (sym.foo)
    0x00000714      c9             leave
    0x00000715      c3             ret

の値を設定することはfs:[0x28]何ですか?カーネル、またはGCCがコードをスローしていますか?カーネルでコードを表示したり、設定するバイナリにコンパイルしたりできますfs:[0x28]か?カナリアは再生成されますか-起動時、またはプロセススポーンですか?これはどこに文書化されていますか?

回答:


17

(ほぼ)すべてのプロセスstraceは、プロセス実行の最初の段階で非常に疑わしいsyscallを示しているため、この初期化を追跡するのは簡単です。

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 syscallを介して行われます。TLS初期化security_init 関数が呼び出された後、スタックガードの値を生成し、それをメモリロケーションに書き込みますfs:[0x28]

そして、TLS開始点にある構造体0x28stack_guardフィールドのオフセットです。


zomfg、本当に素晴らしい答えです。レーダーでバイナリを分解しようとしていました。これは私が探していた形と内容を持っています。トンありがとう。
エヴァンキャロル

arch_prctl(ARCH_SET_FS..)実行可能ファイルに表示されないプロセスを初期化するものは何ですか?そのカーネルコードですか?
エヴァンキャロル

投稿の「syscall」リンクを参照してください。これは、syscallが実行される実際の呼び出しサイト(git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153)につながります。ld-linuxTLSの初期化中に実行されます。
Danila Kiver

6

表示されているのは(GCCでは)スタックスマッシングプロテクター(SSP)と呼ばれ、コンパイラーによって生成されるバッファーオーバーフロー保護の一種です。この値は、起動時にプログラムによって生成される乱数であり、Wikipediaの記事で言及されているように、スレッドローカルストレージ(TLS)に配置されます。他のコンパイラは、このタイプの保護を実装するために異なる戦略を使用する場合があります。

なぜ値をTLSに保存するのですか?値がそこにあるため、CS、DS、およびSSレジスタからそのアドレスにアクセスできないため、悪意のあるコードからスタックを変更しようとすると、格納されている値を推測することが非常に困難になります。


これは私が探しているものではないので、明確にするために少し明確にしました。「起動時にプログラムによって生成される乱数」は、それが生成された実行可能ファイルのどこにあるか、そしてそれを生成するためのコードをどこに配置しているのかを示すことができますか?
エヴァンキャロル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.