win x64内核(1)——x64内核与x86的一些区别
Windows x64内核
x64下的分段机制
前情回顾:
1. GDT(全局描述符表)
- 分段机制: GDT是分段机制的核心部分。它定义了系统中所有的段描述符,供处理器在保护模式下使用。GDT中的描述符用于定义代码段、数据段以及系统段的基地址、段限长、访问权限等。
- 功能:
- 代码段和数据段: GDT包含代码段(代码段描述符)和数据段(数据段描述符)的定义,描述段的起始地址、段限长、段的特权级(DPL,Descriptor Privilege Level)、段类型等。
- 系统段: 包括TSS(任务状态段)、LDT(局部描述符表)等的描述符,用于任务切换和其他系统级功能。
2. LDT(局部描述符表)
- 分段机制: LDT也是分段机制的一部分,但它是GDT的一个补充。LDT允许每个进程或任务有自己独立的段描述符表,从而支持每个进程或任务使用不同的段设置。
- 功能:
- 局部描述符: LDT提供了局部段描述符,用于定义特定于某个任务或进程的代码段和数据段。每个LDT包含的描述符范围仅限于该LDT,而不是整个系统。
- 任务隔离: 通过使用LDT,操作系统可以实现任务间的段隔离,允许不同任务使用不同的段配置,而不影响其他任务。
3. IDT(中断描述符表)
- 分段机制: IDT不是分段机制的一部分。它专门用于处理中断和异常,定义中断服务例程(ISR)的地址和中断处理相关的信息。
- 功能:
- 中断向量: IDT包含中断向量和异常向量的描述符,指定每个中断或异常的处理程序的地址及其特权级。
- 中断门、陷阱门和任务门: IDT条目可以是中断门、陷阱门或任务门,决定了在发生中断或异常时如何处理,特别是在特权级转换和堆栈切换时的行为。
分段机制的基本变化
- 在 64 位模式下(长模式),大多数段寄存器(如
CS
,DS
,ES
,SS
)的段基址被强制设置为 0,这意味着这些段寄存器的作用被弱化,不能用来做实际的内存分段。 - 在 64 位模式下,
CS
段寄存器的作用是定义代码执行的特权级别(CPL),并设置 64 位模式的特定标志,而不是用于传统的分段基址计算。 - 段长度限制在 64 位模式下被忽略,代码和数据段的大小被假定为整个地址空间(即从 0 到 2^64-1)。
Code段(灰色属于无效)
数据段(灰色属于无效)
系统段
系统段(如GDT中的某些条目)仍然被使用
**Task-State Segment (TSS)**:尽管x64不使用硬件任务切换,TSS仍然用于保存中断处理期间的特定信息,例如指定的堆栈指针(在处理双重故障或其他异常时)。在x64系统中,每个处理器通常仍然有一个TSS段,尽管其功能已经简化。
TSS在X64主要为每个特权级别(尤其是从用户模式切换到内核模式)提供了专用的堆栈指针(Rsp0,Rsp1,Rsp2,Rbp0,Rbp1,Rbp2), TSS中的IST(Interrupt Stack Table)机制提供了多个备用堆栈,用于在异常或中断处理时切换到安全的堆栈。这在处理某些关键中断时非常重要,以确保系统有一个可靠的执行环境。总结下来,TSS在x64只用于切换栈
**Local Descriptor Table (LDT)**:LDT在x64模式下基本被废弃了。在现代操作系统(包括Windows x64)中,LDT已经很少使用,主要是在一些极少数的向后兼容情况下才被需要。
**Global Descriptor Table (GDT)**:GDT仍然存在于x64模式下,主要用于定义代码段、数据段、TSS段以及其他系统段的描述符。然而,这些段的基址通常为0,限长为全64位地址范围,因此它们实际上是被扁平化处理的。
保留的段寄存器 FS
和 GS
FS
和 GS
寄存器在 64 位模式下仍然保留了一些特定的用途:
FS
和GS
寄存器可以通过 MSR(Model-Specific Registers)来设置基址,这些基址用于访问线程或进程特定的内存区域。- 在 Windows x64 系统中,
GS
寄存器通常用于指向当前的进程控制块(KPRCB),而FS
通常用于线程环境块(TEB)。这允许操作系统在多线程环境下快速访问线程或进程特定的数据。
IA32_EFER_MSR
索引0位表示SYSCALL/SYSRET
这类指令是否启用,索引8位表示IA-32e
模式是否启用,索引10位表示IA-32e
模式是否处于处于活动状态,索引11位知识是否启用PAE
分页的XD
位是否有效。
IA32_FS_BASE
这个MSR
寄存器保存的是fs
的基址,由于是64位内核,直接读取的话该值是0
IA32_GS_BASE
这个MSR
寄存器保存的是gs
的基址,内核指向KPCR
结构体(和32位的fs
一样的作用),我们可以尝试以下:
IA32_KERNEL_GS_BASE
这个MSR
的作用是作为GS
基址的交换目标。说人话的话就是一个缓存,交换比较方便。我们从3环到0环。从0环到3环,GS
内核指向KPCR
,3环指向TEB
,是如何做到呢?这个就是一个非常重要的寄存器.进0环的时候,把3环的交给它;出0环的时候, 把零环的交给它
分段机制的简化和页表的依赖性增加
在 64 位模式下,由于分段机制被极大简化,内存保护和管理更多依赖于分页机制(paging)。分页机制通过使用页表(Page Table)来管理内存,提供地址转换、内存保护(通过访问权限控制),以及内存隔离等功能。
- 页表的层次增加:x64 架构使用了四级页表(PGD、PUD、PMD、PTE),允许管理更大的虚拟地址空间(高达 256 TB)。
- 内存保护主要通过页表条目中的访问权限位来控制(如可读、可写、可执行等)。
特权级别和堆栈切换
虽然分段机制的角色在 64 位模式下被弱化,但特权级别(Privilege Level)依然通过 CS
段寄存器控制:
CS
寄存器的低 2 位(RPL - Requested Privilege Level)用于指示当前的特权级别(0-3),其中 0 是最高特权级别(内核模式),3 是最低特权级别(用户模式)。- 内核与用户模式之间的堆栈切换依然基于特权级别实现,但不再依赖于段选择子,而是依赖于任务状态段(TSS)中的堆栈指针。
x64的中断门
相比于X86,中断门扩展为16个字节
1 |
|
x64的调用门
相比于x86,差不多只是多了个高地址
1 |
|
64位MSR寄存器
在 x64 架构中,FS
寄存器通常用于指向用户模式下的线程环境块(TEB),而 GS
寄存器则被保留用于内核模式下的使用。这种分工有助于在 64 位系统中提供更清晰的模式划分和访问控制。
在 64 位模式下,分段机制的作用被弱化,GS
寄存器的基址通过 MSR(Model-Specific Register)进行设置,而不是通过段描述符。因此,dg gs
这样的命令在 64 位模式下不会显示 GS
段基址的信息,因为长模式下不再使用段描述符表来定义 GS
的基址。
**MSR_GS_BASE
(0xC0000101)**:用于内核态,存储内核模式下GS
寄存器的基地址,通常指向KPCR
,用于访问处理器和线程相关的内核数据。
**MSR_KERNEL_GS_BASE
(0xC0000102)**:用于用户态,存储切换回用户模式时GS
寄存器的基地址,确保用户态程序能够正确访问TLS和其他基于GS
的机制。
看MSR存的RIP 0xc0000082
,叫做KiSystemCall64,进零环的指令变为Syscall,回用户模式SysRet
其余的0xc0000080
存着标志寄存器 0xc0000081
存着EIP,0xc0000100
存着FS0
64位SSDT表
通过逆向可以发现,拿SSDT表已经不是从KTHREAD拿了
而且也不好Hook
后续说