Sangat mudah untuk melacak inisialisasi ini, seperti untuk (hampir) setiap proses strace
menunjukkan syscall yang sangat mencurigakan selama awal proses dijalankan:
arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0
Itulah man 2 arch_prctl
mengatakan:
ARCH_SET_FS
Set the 64-bit base for the FS register to addr.
Yay, sepertinya itu yang kita butuhkan. Untuk menemukan, siapa yang memanggil arch_prctl
, mari kita cari backtrace:
(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 ?? ()
Jadi, basis segmen FS diatur oleh ld-linux
, yang merupakan bagian dari glibc
, selama pemuatan program (jika program ditautkan secara statis, kode ini disematkan ke dalam biner). Di sinilah semuanya terjadi.
Selama startup, loader menginisialisasi TLS. Ini termasuk alokasi memori dan pengaturan nilai dasar FS untuk menunjuk ke awal TLS. Hal ini dilakukan melalui arch_prctl
syscall. Setelah inisialisasi TLS security_init
fungsi dipanggil, yang menghasilkan nilai pelindung tumpukan dan menuliskannya ke lokasi memori, yang fs:[0x28]
menunjuk ke:
- Inisialisasi nilai penjaga tumpukan
- Penulisan nilai stack guard, lebih detail
Dan 0x28
adalah offset dari stack_guard
bidang dalam struktur yang terletak di awal TLS.
Apa yang Anda lihat disebut (di GCC) Stack Smashing Protector (SSP), yang merupakan bentuk perlindungan buffer overflow yang dihasilkan oleh kompiler. Nilainya adalah angka acak yang dihasilkan oleh program saat startup dan seperti yang disebutkan artikel Wikipedia, ditempatkan di Thread Local Storage (TLS). Kompiler lain mungkin menggunakan strategi berbeda untuk menerapkan jenis perlindungan ini.
Mengapa menyimpan nilai di TLS? Karena nilainya terletak di sana, alamatnya tidak dapat diakses oleh register CS, DS, dan SS, sehingga sulit untuk menebak nilai yang disimpan jika Anda mencoba mengubah tumpukan dari kode berbahaya.