【问题标题】:Using GDB to read MSRs使用 GDB 读取 MSR
【发布时间】:2014-05-30 12:18:19
【问题描述】:

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

不太可取的是使用动态仪器包(如英特尔的 Pintool)的解决方案,但同样值得赞赏。

【问题讨论】:

    标签: x86 gdb x86-64 memory-segmentation msr


    【解决方案1】:

    x86 MSRs 可以通过RDMSR 指令读取,即privileged (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)
    

    【讨论】:

    • 最近的 x86 硬件也有 RDFSBASE 和 WRFSBASE 用于基本 FS/GS 基本寄存器的用户空间读取。
    【解决方案2】:

    如果您不想更改代码(或者代码不可用),您可以通过以下方式执行类似于 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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 只是作为一个不太有 gdb 经验的人(比如我)的例子:pwndbg&gt; i r $fs_base prints fs_base 0x7f28edbd7540 139813764035904
      猜你喜欢
      • 2017-04-02
      • 2012-05-02
      • 2015-03-18
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2013-09-10
      • 1970-01-01
      相关资源
      最近更新 更多