是什么设置fs:[0x28](堆栈金丝雀)?


13

这篇文章中可以看出,这FS:[0x28]是一个堆栈-canary。我正在使用此功能的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]?金丝雀是否已重新生成-在启动时还是在进程生成时?这在哪里记录?

Answers:


18

跟踪此初始化很容易,因为(几乎)每个进程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。这包括内存分配和将FS基本值设置为指向TLS开头。这是通过arch_prctl syscall完成的。调用TLS初始化security_init 函数后,它将生成堆栈保护的值并将其写入内存位置,该fs:[0x28]值指向:

并且0x28stack_guard位于TLS开头的结构中字段的偏移量。


zomfg,非常好的答案。我试图用雷达拆解二进制文件。它具有我一直在寻找的形式和内容。万分感谢。
埃文·卡罗尔

初始化进程的原因是什么,arch_prctl(ARCH_SET_FS..)我看不到可执行文件?那是内核代码吗?
埃文·卡洛尔

请参阅文章中的“ syscall”链接。它会导致执行系统调用的实际调用站点(git.launchpad.net/glibc/tree/sysdeps/x86_64/nptl/tls.h#n153)。它是ld-linux在TLS初始化期间执行的。
Danila Kiver

6

您所看到的称为(在GCC中)堆栈粉碎保护器(SSP),它是编译器生成的缓冲区溢出保护的一种形式。该值是程序在启动时生成的随机数,并且如Wikipedia文章所述,该值放置在线程本地存储(TLS)中。其他编译器可能会使用不同的策略来实现这种类型的保护。

为什么将值存储在TLS中?由于该值位于此处,因此CS,DS和SS寄存器无法访问其地址,因此,如果您试图从恶意代码中更改堆栈,则很难猜测存储的值。


这不是我想要的,所以我做了一些澄清,以使其清晰。您可以显示“程序在启动时生成的随机数”在可执行文件中的何处生成,以及如何将代码生成该文件吗?
埃文·卡罗尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.