10

Is there some way to read the x86-64 model-specific registers, specifically IA32_FS_BASE and IA32_GS_BASE, while debugging a program using GDB?

Less preferable would be a solution using a dynamic instrumentation package like Intel's Pintool, but it would be appreciated all the same.

Community
  • 1
  • 1
shigoel
  • 447
  • 4
  • 11

3 Answers3

10

Since gdb 8 the registers $fs_base and $gs_base are also available. These work in code dumps too, not just live programs.

Avi Kivity
  • 1,362
  • 9
  • 17
  • just as an example for the not so gdb experienced people(like me): ```pwndbg> i r $fs_base``` prints ```fs_base 0x7f28edbd7540 139813764035904``` – KoKlA Mar 29 '20 at 11:45
6

The x86 MSRs can be read with the RDMSR instruction, which is privileged (Ring 0). In Linux there are system calls that a user thread can invoke to read FS_BASE and GS_BASE. There are no library wrappers for them, so you have to write code to invoke them yourself.

Here's one way to do it in C++, you add these global function definitions to your program:

#include <cstdint>
#include <asm/prctl.h>
#include <sys/syscall.h>
namespace x86 {
    uint64_t fs_base() {
        uint64_t fs_base;
        syscall(SYS_arch_prctl,ARCH_GET_FS,&fs_base);
        return fs_base;
    }
    uint64_t gs_base() {
        uint64_t gs_base;
        syscall(SYS_arch_prctl,ARCH_GET_GS,&gs_base);
        return gs_base;
    }
}

Now you can call these functions from gdb and print their return value in hex, like this:

(gdb) p/x x86::fs_base()
$1 = 0x7ffff5e01780
(gdb) p/x x86::gs_base()
$2 = 0x0
(gdb)
Community
  • 1
  • 1
amdn
  • 11,314
  • 33
  • 45
  • 1
    Recent x86 HW also has [RDFSBASE](https://www.felixcloutier.com/x86/rdfsbase:rdgsbase) and WRFSBASE for user-space read of the base FS/GS base regs. – Peter Cordes Dec 01 '19 at 11:26
5

If you prefer not changing your code (or if the code is not available) you could do something similar to amdn's answer in the following way. The call to arch_prctl requires a pointer to a uint64_t, for which I use the address to an empty portion of the stack (8 bytes below the current stack pointer). After the call returns, read the 8 byte value stored at the location.

Constants used: ARCH_GET_FS = 0x1003, ARCH_GET_GS = 0x1004

(gdb) p $rsp
$1 = (void *)0x7fffffffe6f0

(gdb) call arch_prctl(0x1003, $rsp - 0x8)    
$2 = 0 
(gdb) x /gx $rsp - 0x8
0x7fffffffe6e8: 0x00007ffff7fe0700   => IA32_FS_BASE

(gdb) call arch_prctl(0x1004, $rsp - 0x8)
$3 = 0 
(gdb) x /gx $rsp - 0x8
0x7fffffffe6e8: 0x0000000000000000   => IA32_GS_BASE
Soumava
  • 78
  • 6