我正在尝试使用调用门而不是 SYSRET 和 SYSENTER 执行环 3 到环 0 的转换,以查看调用门如何在 IA-32e(64 位)处理器上工作。
我所知道的是呼叫门是您可以放入 GDT 的特殊结构,因此可以使用它来执行不同环之间的转换。
调用门的结构是这样的:
typedef struct CALL_GATE
{
unsigned __int32 offset0_15 : 16;
unsigned __int32 selector :16;
union {
struct {
unsigned __int16 ist : 3;
unsigned __int16 ignored : 5;
unsigned __int16 type : 5;
unsigned __int16 dpl : 2;
unsigned __int16 p : 1;
} part;
unsigned __int16 all;
} dummy;
unsigned __int64 offset16_63 : 48;
unsigned __int32 reserved : 32;
}CALL_GATE, *PCALL_GATE;
我设置了一个windbg 远程Windows 内核调试器。现在假设我的调度例程(处理器从环 3 转移到环 0 后我想要去的位置)位于,0xfffff8027f258bc0
所以我在这个位置放置了一个硬件断点:
ba e 1 fffff802`7f258bc0
现在我使用以下信息创建了一个调用门结构:
- DPL:0x3
- 选择器:0x10 (KGDT64_R0_CODE)
- 类型:0xc
- p(现在):0x1
- 并附加 offset0_15 和 offset16_63 : fffff8027f258bc0
结果结构(十六进制)是这样的:
00000000 fffff8027f25 ec00 0010 8bc0
现在,调用门(和每个 GDT 条目)都是 128 位或 0x10 字节。我选择 GDT 的第 8 个条目将其转换为调用门,因此首先使用 GDTR 找到 GDT 位置,然后修改其第 8 个条目(第 0x8 个条目 * 每个条目的 0x10 大小)。
kd> r gdtr
gdtr=fffff8028185afb0
kd> eb fffff8028185afb0+(0x8 * 0x10) 00 00 00 00 ff ff f8 02 7f 25 ec 00 00 10 8b c0
是时候使用 far call 或 far jmp 来使用我们的条目了。我的用户模式应用程序(希望将执行转移到环 0)执行以下指令:
00000000`00d2114e ea000000000800 jmp 0008:00000000
但问题是什么也没有发生,用户模式应用程序既没有崩溃也没有将执行转移到环 0(因为我的硬件断点没有触发。)。
现在我的问题是,我的假设有什么问题导致问题从环 3 转移到环 0?
更新:我还测试了 0x40 和 0x43 作为 far jmp 的选择器。