Cosa imposta fs: [0x28] (stack canary)?


11

Da questo post viene mostrato che FS:[0x28]è uno stack-canary. Sto generando lo stesso codice utilizzando GCC su questa funzione,

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

In particolare, sto ricevendo questo assembly ..

    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

Qual è l'impostazione del valore di fs:[0x28]? Il kernel o GCC sta inserendo il codice? Puoi mostrare il codice nel kernel o compilato nel binario che imposta fs:[0x28]? Il canarino è rigenerato - all'avvio o viene generato il processo? Dove è documentato?

Risposte:


18

È facile tenere traccia di questa inizializzazione, in quanto per (quasi) ogni processo stracemostra un syscall molto sospetto all'inizio del processo:

arch_prctl(ARCH_SET_FS, 0x7fc189ed0740) = 0

Questo è ciò che man 2 arch_prctldice:

   ARCH_SET_FS
          Set the 64-bit base for the FS register to addr.

Sì, sembra che sia quello di cui abbiamo bisogno. Per trovare chi chiama arch_prctl, cerchiamo un 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 ?? ()

Pertanto, la base del segmento FS viene impostata da ld-linux, che fa parte di glibc, durante il caricamento del programma (se il programma è staticamente collegato, questo codice viene incorporato nel file binario). Questo è dove succede tutto.

Durante l'avvio, il caricatore inizializza TLS . Ciò include l'allocazione di memoria e l'impostazione del valore base FS in modo che punti all'inizio TLS. Questo viene fatto tramite arch_prctl syscall . Dopo che viene chiamata la security_init funzione di inizializzazione TLS , che genera il valore dello stack guard e lo scrive nella posizione di memoria, che fs:[0x28]punta a:

Ed 0x28è l'offset del stack_guardcampo nella struttura che si trova all'inizio TLS.


zomfg, davvero un'ottima risposta. Stavo cercando di smontare un binario con radare. questo ha la forma e il contenuto che stavo cercando. Grazie mille.
Evan Carroll,

Cosa inizializza un processo con arch_prctl(ARCH_SET_FS..)non lo vedo nell'eseguibile? È quel codice del kernel?
Evan Carroll,

Vedi il link "syscall" nel post. Porta al sito di chiamata effettivo ( git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153 ) dove viene eseguita la syscall. Viene eseguito ld-linuxdurante l'inizializzazione TLS.
Danila Kiver,

6

Quello che vedi è chiamato (in GCC) Stack Smashing Protector (SSP) , che è una forma di protezione da buffer overflow generata dal compilatore. Il valore è un numero casuale generato dal programma all'avvio e, come menzionato nell'articolo di Wikipedia, viene inserito in Thread Local Storage (TLS) . Altri compilatori possono utilizzare strategie diverse per implementare questo tipo di protezione.

Perché archiviare il valore in TLS? Poiché il valore si trova lì, il suo indirizzo non è accessibile dai registri CS, DS e SS, rendendo molto difficile indovinare il valore memorizzato se si sta tentando di modificare lo stack da codice dannoso.


Non è quello che sto cercando, quindi ho chiarito un po 'nel tentativo di essere chiaro. "numero casuale generato dal programma all'avvio" puoi mostrare dove viene generato un eseguibile e cosa sta mettendo il codice per generarlo?
Evan Carroll,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.