C 为什么这个内存地址%fs:0x28(fs[0x28])有一个随机值?

C 为什么这个内存地址%fs:0x28(fs[0x28])有一个随机值?,c,gcc,x86-64,buffer-overflow,disassembly,C,Gcc,X86 64,Buffer Overflow,Disassembly,我已经写了一段C代码,我已经对它进行了反汇编,并读取了寄存器,以了解程序在汇编中是如何工作的 int test(char *this){ char sum_buf[6]; strncpy(sum_buf,this,32); return 0; } 我一直在检查的代码部分是测试函数。当我拆开输出我的测试功能,我得到 0x00000000004005c0 <+12>: mov %fs:0x28,%rax => 0x00000000

我已经写了一段C代码,我已经对它进行了反汇编,并读取了寄存器,以了解程序在汇编中是如何工作的

int test(char *this){
    char sum_buf[6];
    strncpy(sum_buf,this,32);
    return 0;
}
我一直在检查的代码部分是测试函数。当我拆开输出我的测试功能,我得到

   0x00000000004005c0 <+12>:        mov    %fs:0x28,%rax
=> 0x00000000004005c9 <+21>:        mov    %rax,-0x8(%rbp)
... stuff ..
   0x00000000004005f0 <+60>:        xor    %fs:0x28,%rdx
   0x00000000004005f9 <+69>:        je     0x400600 <test+76>
   0x00000000004005fb <+71>:        callq  0x4004a0 <__stack_chk_fail@plt>
   0x0000000000400600 <+76>:        leaveq 
   0x0000000000400601 <+77>:        retq 
0x00000000004005c0:mov%fs:0x28,%rax
=>0x00000000004005c9:mov%rax,-0x8(%rbp)
... 东西
0x00000000004005f0:xor%fs:0x28,%rdx
0x00000000004005f9:je 0x400600
0x00000000004005fb:callq 0x4004a0
0x00000000000400600:LEVEQ
0x00000000000400601:retq

我想知道的是mov%fs:0x28,%rax到底在做什么?

看,我认为
%fs:28
实际上是从
%fs
中的地址偏移了28字节。因此,我认为它正在将一个完整的寄存器大小从位置
%fs+28
加载到%rax。

可以将
fs
GS
寄存器用作基指针地址,以便访问特殊的操作系统数据结构。因此,您看到的是加载的值与
FS
寄存器中保存的值的偏移量,而不是
FS
寄存器内容的位操作

具体来说,Linux上的
FS:0x28
正在存储一个特殊的sentinel堆栈保护值,并且代码正在执行堆栈保护检查。例如,如果进一步查看代码,您将看到
FS:0x28
处的值存储在堆栈上,然后调用堆栈的内容,并使用
FS:0x28
处的原始值执行
XOR
。如果两个值相等,这意味着设置了零位,因为将两个相同的值进行异或将导致零值,那么我们跳转到
测试
例程,否则我们跳转到一个特殊函数,该函数指示堆栈以某种方式损坏,并且堆栈上存储的哨兵值已更改

如果使用GCC,则:


好的,这是有道理的。如何使用gdb读取此地址和值?最简单的方法是在MOV操作后直接查看RAX寄存器的内容。分段寻址不再使用-这不是真的,分段寻址仍然使用100%,尽管使用率急剧变化,变成了虚拟空间而不是段。由于我们可以用一个64位的寄存器来寻址整个内存(虽然在大多数情况下只使用48位),我们不会修改这些寄存器,但它们在与MMU和内存保护方案的链接中非常重要。嘿,我知道这很旧,但我只是想问为什么
%fs:0x28
必须经过
rax
然后才能添加到堆栈中?为什么我们不能直接添加它,就像
mov%fs:0x28,-0x8(%rbp)
?@need\u to\u know\u现在你可以这样做了。上面的代码段没有用于生成它的编译器设置的任何上下文。请记住,使用在高优化级别编译的C代码可能非常困难,因此这可能是在低优化级别编译的,或者是禁用优化的情况下编译的。这是不正确的<代码>fs不是“正常”寄存器。它是一个段寄存器。在保护模式下,
fs
是GDT的选择器。有隐藏的“基本”和“限制”寄存器与之关联,您无法看到。所以
fs:0x28
实际上是
[hidden\u fs\u base+0x28]
-fno-stack-protector
glibc:
  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
  THREAD_SET_STACK_GUARD (stack_chk_guard); 

the _dl_random from kernel.