53

I've written a piece of C code and I've disassembled it as well as read the registers to understand how the program works in assembly.

int test(char *this){
    char sum_buf[6];
    strncpy(sum_buf,this,32);
    return 0;
}

The piece of my code that I've been examining is the test function. When I disassemble the output my test function I get ...

   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 

What I would like to know is what mov %fs:0x28,%rax is really doing?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
Dr.Knowitall
  • 10,080
  • 23
  • 82
  • 133

3 Answers3

92

Both the FS and GS registers can be used as base-pointer addresses in order to access special operating system data-structures. So what you're seeing is a value loaded at an offset from the value held in the FS register, and not bit manipulation of the contents of the FS register.

Specifically what's taking place, is that FS:0x28 on Linux is storing a special sentinel stack-guard value, and the code is performing a stack-guard check. For instance, if you look further in your code, you'll see that the value at FS:0x28 is stored on the stack, and then the contents of the stack are recalled and an XOR is performed with the original value at FS:0x28. If the two values are equal, which means that the zero-bit has been set because XOR'ing two of the same values results in a zero-value, then we jump to the test routine, otherwise we jump to a special function that indicates that the stack was somehow corrupted, and the sentinel value stored on the stack was changed.

If using GCC, this can be disabled with:

-fno-stack-protector
Jason
  • 31,834
  • 7
  • 59
  • 78
  • Ok, that makes sense. How could I read this address and value with gdb? – Dr.Knowitall Apr 26 '12 at 01:18
  • 4
    The simplest way is to look at the contents of the RAX register directly after the MOV operation. – Jason Apr 26 '12 at 01:37
  • 3
    _segmented addressing is no longer used_ — this is not true, the segmented addressing is still used 100%, although the usage shifted _dramatically_ to become a virtual space instead of a segment. Since we can address the entire memory with a single register in 64 bits (although in most cases only 48 are used), we do not modify those registers, but they are really important in link with the MMU and memory protection schemes. – Alexis Wilke Nov 21 '20 at 15:40
  • 1
    Hey, i know this is really old but I just wanted to ask why does `%fs:0x28` have to go through `rax` and _then_ get added to the stack? Why can't we directly just add it like `mov %fs:0x28, -0x8(%rbp)`? – need_to_know_now Apr 16 '21 at 05:41
  • 6
    @need_to_know_now: That would be a memory-to-memory move, and x86 doesn't have any such instruction. Try assembling it and you'll get an error. If you want to move memory to memory, you have to load into a register and then store with a second instruction. – Nate Eldredge Jun 12 '21 at 23:23
0
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.
leesagacious
  • 182
  • 1
  • 8
-3

Looking at http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm, I think %fs:28 is actually an offset of 28 bytes from the address in %fs. So I think it's loading a full register size from location %fs + 28 into %rax.

Edmund
  • 10,533
  • 3
  • 39
  • 57
  • 15
    This is just not correct. `fs` is not a "normal" register. It is a segment register. In protected mode, `fs` is a *selector* into the GDT. There are hidden "base" and "limit" registers associated with it, that you cannot see. So `fs:0x28` is really `[hidden_fs_base + 0x28]`. – Jonathon Reinhart Jan 21 '13 at 08:24