windbg - 为什么 GS 寄存器解析为偏移量 0x0?

逆向工程 视窗 风袋 核心
2021-06-21 18:53:07

我试图了解如何解决段寻址(特别是 X64 中的 GS 寄存器)。

我的玩具程序:

int main()
{
    unsigned long long x;
    __debugbreak();
    x = __readgsqword(0x30);
    printf("0x%I64X", x);
}

编译为:

kd> u
00007ff6`10201074 cc                 int     3
00007ff6`10201075 65488b142530000000 mov   rdx,qword ptr gs:[30h]
...

然后我一步一步到达使用GS寄存器读取内存的指令,并检索GS寄存器的值、GDT 的内容等。

kd> r @gs
gs=002b

kd> r @gdtr
gdtr=fffff80105471fb0

kd> .formats @gs
Evaluate expression:
  Hex:     00000000`0000002b
  ...
  Binary:  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101011

kd> dq (@gdtr + (5 * 8)) L1
fffff801`05471fd8  00cff300`0000ffff

kd> .formats poi(@gdtr + (5 * 8))
Evaluate expression:
  Hex:     00cff300`0000ffff
  ...
  Binary:  00000000 11001111 11110011 00000000 00000000 00000000 11111111 11111111

kd> dg gs
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
002B 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

因此,从dg gs,我可以看到该GS段位于 offset 处0x0,这与使用GS寄存器值从 GDT 检索到的条目一致

观察到此时,偏移量0x0不是“有效”内存:

kd> dq gs:[30]
002b:00000000`00000030  ????????`???????? ????????`????????

kd> dq 30
00000000`00000030  ????????`???????? ????????`????????

还要注意此时的值RDX(在存储从内存中检索到的 QWORD 之前):

kd> r @rdx
rdx=000001dfbf892d40

然后我一步,期待在我检索无效内存时进行错误检查。

但令人惊讶的是,它没有,而且RDX似乎从某个地方获得了一个值

kd> r @rdx
rdx=00000035ed53f000

更令人惊讶的是,GS寄存器仍然解析为0x0仍然包含“无效”内存的偏移量

kd> r @gs
gs=002b

kd> r @gdtr
gdtr=fffff80105471fb0

kd> dq (@gdtr + (5 * 8)) L1
fffff801`05471fd8  00cff300`0000ffff

kd> dg gs
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
002B 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

kd> dq gs:[30]
002b:00000000`00000030  ????????`???????? ????????`????????

所以...

  1. 为什么我的GS寄存器解析为偏移 0x0?

  2. 以及从哪里/如何mov rdx,qword ptr gs:[30h]读取内存?

2个回答

在长模式下,实际上并不使用分段,所有段寄存器的基数为 0。fs并且gs是为寻址线程特定数据而添加的例外情况。它们的实际基地址存储在 MSR(特定于模型的寄存器)而不是描述符表中。MSR 只能在内核模式下访问,但您可以GS通过!teb命令或~(列出线程)间接获取 的值Teb:字段将显示与该GS线程基数匹配的 TEB 基数欲了解更多信息,请SWAPGS在Osdev维基。

gs 只是内核模式

如果你在kd会话中,你可以在windbg中看到数据

0: kd> ? @@c++(@$pcr->GdtBase)
Evaluate expression: -8781100130384 = fffff803`7da55fb0
0: kd> dq gs:[0] l1
002b:00000000`00000000  fffff803`7da55fb0

__readgsword() 是一个内在的,它必须有一些魔法:)

1: kd> rdmsr c0000101
msr[c0000101] = ffffe601`555ea000
1: kd> dq ffffe601`555ea000 l1
ffffe601`555ea000  ffffe601`555fdfb0
1: kd> ? @@c++(@$pcr->GdtBase)
Evaluate expression: -28581575008336 = ffffe601`555fdfb0
1: kd> dq gs:[0] l1
002b:00000000`00000000  ffffe601`555fdfb0

!teb 是 user_gs_base (在进入 kmode 时由 swapgs 交换)

1: kd> rdmsr c0000102
msr[c0000102] = 00000080`56086000
1: kd> !teb
TEB at 0000008056086000
    ExceptionList:        0000000000000000
    StackBase:            0000008055f40000
    StackLimit:           0000008055f00000