使用GDB读取MSRs

11

在使用GDB调试程序时,是否有一种方法可以读取x86-64模型特定寄存器,特别是IA32_FS_BASE和IA32_GS_BASE?

更不理想的解决方案是使用像英特尔Pintool这样的动态检测工具包,但同样会受到赞赏。

3个回答

10
自 gdb 8 版本以来,寄存器 $fs_base$gs_base 也可用。这些寄存器在代码转储中同样适用,不仅限于实时程序。

就像给不太熟悉gdb的人(比如我)举个例子一样: pwndbg> i r $fs_base 命令会输出 fs_base 0x7f28edbd7540 139813764035904 - KoKlA

6

x86的MSRs可以使用RDMSR指令读取,该指令在特权级(Ring 0)下执行。在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;
    }
}

现在您可以从gdb中调用这些函数,并以十六进制打印它们的返回值,如下所示:
(gdb) p/x x86::fs_base()
$1 = 0x7ffff5e01780
(gdb) p/x x86::gs_base()
$2 = 0x0
(gdb)

1
最近的x86硬件还具有RDFSBASE和WRFSBASE,用于用户空间读取基本FS/GS寄存器。 - Peter Cordes

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接