使用GDB读取MSR

shi*_*oel 4 x86 gdb x86-64 msr memory-segmentation

在使用GDB调试程序时,有什么方法可以读取特定于x86-64模型的寄存器,尤其是IA32_FS_BASE和IA32_GS_BASE?

使用像Intel的Pintool这样的动态工具包的解决方案是不太可取的,但是同样可以理解。

Avi*_*ity 8

从 gdb 8 开始,寄存器$fs_base$gs_base也可用。这些也适用于代码转储,而不仅仅是实时程序。


amd*_*mdn 6

可以使用特权(Ring 0)RDMSR指令读取x86 MSR。在Linux中,用户线程可以调用一些系统调用来读取FS_BASE和GS_BASE。它们没有库包装器,因此您必须编写代码以自己调用它们。

这是在C ++中执行此操作的一种方法,可以将这些全局函数定义添加到程序中:

#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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以从gdb调用这些函数,并以十六进制打印其返回值,如下所示:

(gdb) p/x x86::fs_base()
$1 = 0x7ffff5e01780
(gdb) p/x x86::gs_base()
$2 = 0x0
(gdb)
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您不想更改代码(或者如果代码不可用),您可以通过以下方式执行类似于 amdn 的回答的操作。对 arch_prctl 的调用需要一个指向 uint64_t 的指针,为此我使用指向堆栈空部分的地址(当前堆栈指针下方 8 个字节)。调用返回后,读取存储在该位置的 8 字节值。

使用的常量: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
Run Code Online (Sandbox Code Playgroud)