In a 64 bit ELF binary I found it mainly uses fs register to get some values. How can I know which value it wants to access? I'm familiar with that NT kernel uses fs and gs register for TEB structure in 32 bit and 64 bit OS respectively.

Here are two examples:


mov rax, fs:28h
mov [rsp+88], rax


sub_a proc near
mov rax, fs:0
add rax, 44h
sub_a endp

The gs/fs segment can be used for thread local storage similar to what you have encountered in Windows. Variable specific to a thread such as errno, stack canary etc are usually stored here in Linux.

According to this, your first example is to save canary to the stack from fs:0x28. You can see some hacks here and read more here

Canary check from an example binary

$ tail x.c 

#include <stdio.h>

int main(int argc, char **argv)
    char s[32];
    scanf("%s", s);
    return 0;

$ gcc -no-pie -fno-pic x.c -o z64   
$ gcc -m32 -no-pie -fno-pic x.c -o z32   
$ r2 -AA z32 -qc "pdf @ sym.main"     
            ;-- main:
┌ (fcn) sym.main 86
│           0x080484bf      65a114000000   mov eax, dword gs:[0x14]    ; [0x14:4]=-1 ; 20
│           0x080484c5      8945f4         mov dword [local_ch], eax
│           0x080484c8      31c0           xor eax, eax
│           0x080484e3      8b55f4         mov edx, dword [local_ch]
│           0x080484e6      653315140000.  xor edx, dword gs:[0x14]
│       ┌─< 0x080484ed      7405           je 0x80484f4
│       │   0x080484ef      e85cfeffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
$ r2 -AA z64 -qc "pdf @ sym.main"
            ;-- main:
┌ (fcn) sym.main 79
│           0x00400586      64488b042528.  mov rax, qword fs:[0x28]    ; [0x28:8]=-1 ; '(' ; 40
│           0x0040058f      488945f8       mov qword [local_8h], rax
│           0x00400593      31c0           xor eax, eax
│           0x004005b0      488b55f8       mov rdx, qword [local_8h]
│           0x004005b4      644833142528.  xor rdx, qword fs:[0x28]
│       ┌─< 0x004005bd      7405           je 0x4005c4
│       │   0x004005bf      e8acfeffff     call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)

Also for your second request, yes that is pthread_t at offset 0 in fs/gs.

$ tail -n 30 x.c

#ifdef __x86_64__
#define val_t     uint64_t
#define INSN_READ    "movq %%fs:0, %0;"
#define FMT          "Found val: %#lx\n"

#elif __i386__
#define val_t     uint32_t
#define INSN_READ    "movl %%gs:0, %0;"
#define FMT          "Found val: %#x\n"

val_t read_val()
    val_t val = 0;

        : "=r"(val)

    return val;
int main(int argc, char **argv)
    printf(FMT, read_val());
    printf(FMT, (val_t)pthread_self());
    return 0;

$ gcc -no-pie -fno-pic x.c -o zm64
$ gcc -m32 -no-pie -fno-pic x.c -o zm32

$ ./zm32 
Found val: 0xf7f800c0
Found val: 0xf7f800c0

$ ./zm64 
Found val: 0x7fd50119f4c0
Found val: 0x7fd50119f4c0

I tried to look for your second snippet in my libc but couldn't find it. SO can't answer for sure what it contains at 0x44. While debugging I only got 0s at that offset.

  $ r2 /lib/x86_64-linux-gnu/libc.so.6
   -- There is only one binary, and we are all just reversing pieces of it.
  [0x00021cb0]> /x `!rasm2 -a x86.as -b 64 "mov rax, fs:[0]"`
  Searching 9 bytes in [0x0-0x1e6aa0]
  hits: 7
  Searching 9 bytes in [0x3e7620-0x3f0ae0]
  hits: 0
  0x000e18c9 hit0_0 64488b042500000000
  0x000e1d8a hit0_1 64488b042500000000
  0x00105cff hit0_2 64488b042500000000
  0x00105e50 hit0_3 64488b042500000000
  0x00105f21 hit0_4 64488b042500000000
  0x00106865 hit0_5 64488b042500000000
  0x0014a18a hit0_6 64488b042500000000
  [0x00021cb0]> pd10 @@ hit0_*
              ;-- hit0_0:
              0x000e18c9      64488b042500.  mov rax, qword fs:[0]
              0x000e18d2      31db           xor ebx, ebx
              0x000e18d4      48c744241800.  mov qword [rsp + 0x18], 0
              0x000e18dd      4c8b25849530.  mov r12, qword [0x003eae68] ; [0x3eae68:8]=0
              0x000e18e4      48890424       mov qword [rsp], rax
              0x000e18e8      488d442450     lea rax, [rsp + 0x50]       ; "@" ; 'P'
              0x000e18ed      4889442430     mov qword [rsp + 0x30], rax
              0x000e18f2      488d442460     lea rax, [rsp + 0x60]       ; '`'
              0x000e18f7      4889442420     mov qword [rsp + 0x20], rax
              0x000e18fc      488d442458     lea rax, [rsp + 0x58]       ; "@" ; 'X'
              ;-- hit0_1:
              0x000e1d8a      64488b042500.  mov rax, qword fs:[0]
              0x000e1d93      31db           xor ebx, ebx
              0x000e1d95      48c744242800.  mov qword [rsp + 0x28], 0
              0x000e1d9e      4c8b25c39030.  mov r12, qword [0x003eae68] ; [0x3eae68:8]=0
              0x000e1da5      4889442410     mov qword [rsp + 0x10], rax
              0x000e1daa      488d442460     lea rax, [rsp + 0x60]       ; '`'
              0x000e1daf      4889442440     mov qword [rsp + 0x40], rax
              0x000e1db4      488d442470     lea rax, [rsp + 0x70]       ; 'p'
              0x000e1db9      4889442430     mov qword [rsp + 0x30], rax
              0x000e1dbe      488d442468     lea rax, [rsp + 0x68]       ; 'h'
              ;-- hit0_2:
              0x00105cff      64488b042500.  mov rax, qword fs:[0]
              0x00105d08      488b1d41512e.  mov rbx, qword [0x003eae50] ; [0x3eae50:8]=0
              0x00105d0f      4c8b2d52512e.  mov r13, qword [0x003eae68] ; [0x3eae68:8]=0
              0x00105d16      4c8d3c18       lea r15, [rax + rbx]
              0x00105d1a      48898560feff.  mov qword [rbp - 0x1a0], rax
              0x00105d21      4c89e7         mov rdi, r12
              0x00105d24      e807060600     call sym._dl_mcount_wrapper_check
              0x00105d29      488b8560feff.  mov rax, qword [rbp - 0x1a0]
              0x00105d30      4883ec08       sub rsp, 8
              0x00105d34      498b4e08       mov rcx, qword [r14 + 8]    ; sym.__resp ; [0x8:8]=0
              ;-- hit0_3:
              0x00105e50      64488b042500.  mov rax, qword fs:[0]
              0x00105e59      4c8b2d08502e.  mov r13, qword [0x003eae68] ; [0x3eae68:8]=0
              0x00105e60      4c8dbd98feff.  lea r15, [rbp - 0x168]
              0x00105e67      488b1de24f2e.  mov rbx, qword [0x003eae50] ; [0x3eae50:8]=0
              0x00105e6e      48c78598feff.  mov qword [rbp - 0x168], 0
              0x00105e79      48898560feff.  mov qword [rbp - 0x1a0], rax
              0x00105e80      4c01e8         add rax, r13                ; 'o'
              0x00105e83      48898508feff.  mov qword [rbp - 0x1f8], rax
              0x00105e8a      660f1f440000   nop word [rax + rax]
              0x00105e90      4c89e7         mov rdi, r12
              ;-- hit0_4:
              0x00105f21      64488b042500.  mov rax, qword fs:[0]
              0x00105f2a      4c8b2d374f2e.  mov r13, qword [0x003eae68] ; [0x3eae68:8]=0
              0x00105f31      4c8dbd98feff.  lea r15, [rbp - 0x168]
              0x00105f38      488b1d114f2e.  mov rbx, qword [0x003eae50] ; [0x3eae50:8]=0
              0x00105f3f      48c78598feff.  mov qword [rbp - 0x168], 0
              0x00105f4a      48898560feff.  mov qword [rbp - 0x1a0], rax
              0x00105f51      4c01e8         add rax, r13                ; 'o'
              0x00105f54      48898508feff.  mov qword [rbp - 0x1f8], rax
              0x00105f5b      0f1f440000     nop dword [rax + rax]
              0x00105f60      4c89e7         mov rdi, r12
              ;-- hit0_5:
              0x00106865      64488b042500.  mov rax, qword fs:[0]
              0x0010686e      488db5c0feff.  lea rsi, [rbp - 0x140]
              0x00106875      4c8b0dd4452e.  mov r9, qword [0x003eae50]  ; [0x3eae50:8]=0
              0x0010687c      488b8d20feff.  mov rcx, qword [rbp - 0x1e0]
              0x00106883      ba00010000     mov edx, 0x100
              0x00106888      4885ff         test rdi, rdi
              0x0010688b      490f44fd       cmove rdi, r13
              0x0010688f      4901c1         add r9, rax                 ; '#'
              0x00106892      480305cf452e.  add rax, qword [0x003eae68]
              0x00106899      4989c0         mov r8, rax
              ;-- hit0_6:
              0x0014a18a      64488b042500.  mov rax, qword fs:[0]
              0x0014a193      4c89fb         mov rbx, r15
              0x0014a196      4889442440     mov qword [rsp + 0x40], rax
              0x0014a19b      488d442460     lea rax, [rsp + 0x60]       ; '`'
              0x0014a1a0      4889442408     mov qword [rsp + 8], rax
              0x0014a1a5      488b4500       mov rax, qword [rbp]
              0x0014a1a9      488b7c2458     mov rdi, qword [rsp + 0x58] ; [0x58:8]=64 ; 'X'
              0x0014a1ae      4889442410     mov qword [rsp + 0x10], rax
              0x0014a1b3      488b03         mov rax, qword [rbx]
              0x0014a1b6      4889442418     mov qword [rsp + 0x18], rax
  • Thank you for the full answer. One side-question. I've not found the definition of pthread structure to get the variable at rax + 0x44. – Biswapriyo Nov 28 '18 at 7:15
  • @Biswapriyo I added a link. The definition of that type ought to be in sys/types.h (e.g. in /usr/include/x86_64-linux-gnu/sys/types.h) ... which in turn includes pthreadtypes.h (e.g. /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h) which has typedef unsigned long int pthread_t;. But mind that this is system/architecture-specific. – 0xC0000022L Nov 28 '18 at 8:27
  • @Biswapriyo did you actually head to the files I pointed out? There is an interesting comment just above the definition of pthread_t which I gave you above ... – 0xC0000022L Nov 28 '18 at 9:10
  • I found the answer. The rax+0x40 is the offset of errno (4 bytes takes rax+0x44). There may be some relation between pthread and errno. – Biswapriyo Nov 28 '18 at 18:10

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.