Что устанавливает 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]? Регенерация канарейки - при загрузке или процесс порождения? Где это задокументировано?

Эван Кэрролл
источник

Ответы:

18

Эту инициализацию легко отследить, так как (почти) каждый процесс 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 . Это включает выделение памяти и установку базового значения FS, чтобы указывать на начало TLS. Это делается через arch_prctl системный вызов . После инициализации TLS вызывается security_init функция , которая генерирует значение стекового сторожа и записывает его в ячейку памяти, которая fs:[0x28]указывает на:

И 0x28это смещение stack_guardполя в структуре, которая находится в начале TLS.

Данила Кивер
источник
zomfg, действительно отличный ответ. Я пытался разобрать двоичный файл с Radare. это имеет форму и содержание, которые я искал. Благодаря тонну.
Эван Кэрролл
Что инициализирует процесс, которого arch_prctl(ARCH_SET_FS..)я не вижу в исполняемом файле? Это код ядра?
Эван Кэрролл
Смотрите ссылку "syscall" в посте. Это приводит к фактическому сайту вызова ( git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153 ), где выполняется системный вызов. Это выполняется ld-linuxво время инициализации TLS.
Данила Кивер
6

То, что вы видите, называется (в GCC) Stack Smashing Protector (SSP) , который является формой защиты от переполнения буфера, генерируемой компилятором. Значение представляет собой случайное число, сгенерированное программой при запуске и, как упоминается в статье в Википедии, помещается в Thread Local Storage (TLS) . Другие компиляторы могут использовать разные стратегии для реализации этого типа защиты.

Зачем хранить значение в TLS? Поскольку значение находится там, его адрес не доступен для регистров CS, DS и SS, что затрудняет определение сохраненного значения, если вы пытаетесь изменить стек из вредоносного кода.

ErikF
источник
Это не то, что я ищу, поэтому я немного разъяснил, пытаясь прояснить ситуацию. "случайное число, сгенерированное программой при запуске", можете ли вы показать, где в исполняемом файле оно сгенерировано и что помещает код для его генерации?
Эван Кэрролл