我试图了解如何解决段寻址(特别是 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 ????????`???????? ????????`????????
所以...
为什么我的
GS寄存器解析为偏移 0x0?以及从哪里/如何
mov rdx,qword ptr gs:[30h]读取内存?