【问题标题】:Why does this memory address %fs:0x28 ( fs[0x28] ) have a random value?为什么这个内存地址 %fs:0x28 ( fs[0x28] ) 有一个随机值?
【发布时间】:2012-05-06 17:32:24
【问题描述】:

我已经编写了一段 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 

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

【问题讨论】:

标签: c gcc x86-64 buffer-overflow disassembly


【解决方案1】:

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

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

如果使用 GCC,this can be disabled with:

-fno-stack-protector

【讨论】:

  • 好的,这很有道理。我怎样才能用 gdb 读取这个地址和值?
  • 最简单的方法是在MOV操作后直接查看RAX寄存器的内容。
  • 不再使用分段寻址 — 这不是真的,分段寻址仍被 100% 使用,尽管用法发生了戏剧性的转变为一个虚拟空间而不是一个段。由于我们可以使用 64 位的单个寄存器来寻址整个内存(尽管在大多数情况下只使用 48 个),因此我们不会修改这些寄存器,但它们在与 MMU 和内存保护方案的链接中非常重要。
  • 嘿,我知道这真的很老了,但我只想问为什么%fs:0x28 必须经过rax然后 被添加到堆栈中?为什么不能像mov %fs:0x28, -0x8(%rbp)一样直接添加?
  • @need_to_know_now:这将是内存到内存的移动,而 x86 没有任何这样的指令。尝试组装它,你会得到一个错误。如果要将内存移动到内存,则必须加载到寄存器中,然后使用第二条指令进行存储。
【解决方案2】:
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.

【讨论】:

    【解决方案3】:

    http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm,我认为%fs:28实际上是从%fs中的地址偏移了28个字节。所以我认为它正在将位置 %fs + 28 的完整寄存器大小加载到 %rax 中。

    【讨论】:

    • 这是不正确的。 fs 不是“正常”寄存器。它是一个段寄存器。在保护模式下,fs 是 GDT 中的 选择器。有与之相关的隐藏的“基本”和“限制”寄存器,你看不到。所以fs:0x28 真的是[hidden_fs_base + 0x28]
    猜你喜欢
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    • 2023-03-07
    • 2015-05-22
    • 1970-01-01
    • 2021-10-17
    相关资源
    最近更新 更多