没有合适的资源?快使用搜索试试~ 我知道了~
Windows内核源码详尽分析
需积分: 50 84 下载量 39 浏览量
2018-03-13
13:38:22
上传
评论 4
收藏 8.42MB PDF 举报
温馨提示
试读
595页
详尽分析windows内核源码, 本文结合《Windows 内核情景分析》(毛德操著)、《软件调试》(张银奎著)、《Windows 核心编程》、《寒江独 钓-Windows 内核安全编程》、《Windows PE 权威指南》、《C++反汇编与逆向分析揭秘》以及 ReactOS 操作系 统 (V0.3.12)源码, 以《Windows 内核情景分析》为蓝本, 对 Windows 内核重要框架、函数、结构体进行 解析
资源推荐
资源详情
资源评论
说明
本文结合《Windows 内核情景分析》(毛德操著)、《软件调试》(张银奎著)、《Windows 核心编程》、《寒江独
钓-Windows 内核安全编程》、《Windows PE 权威指南》、《C++反汇编与逆向分析揭秘》以及 ReactOS 操作系
统 (V0.3.12)源码,以《Windows 内核情景分析》为蓝本,对 Windows 内核重要框架、函数、结构体进行
解析
由于工程庞大,我能理解到的只是冰山一角,但本文力求做到让每个读者都能从整体上理解 Windows 内核
的架构,并大量解释一些关键细节。
本文适合读者:熟悉 C 语言、汇编,PE 文件格式,有一定驱动/内核程序开发经历的读者
本文阅读顺序:基础较弱的读者请遵循篇章序号,否则可能会吃力。
本文解读方式:1、源码、伪码结合,展示主流程,很多时候忽略权限、错误检查,多线程互斥等旁枝末节
2、函数的参数没有严格排序,很多不重要的参数也省略了,要注意
3、结构体内的成员没有严格排序,成员名称也不严格对应,并只列出一些重要成员
4、一些清理工作,如关闭句柄、释放内存、释放互斥对象等工作省略
5、很多时候,函数体开头声明的那些没有初始值的局部变量我都略去了
(我所做的修改基本不影响从代码层次理解 Windows 内核的原理)
写作初衷 1: 我一直对 Rootkit 感兴趣,但是以前在不熟悉内核的情况下,总是不知道要在哪个位置挂钩,
要 Hook 哪些函数才能达到我的目的。
写作初衷 2:以前在写文件系统过滤驱动、Ndis 过滤驱动以及其他驱动时遇到的种种疑惑,因此,总想看
一下 ddk 提供的内核函数到底是怎么实现的。
于是,翻看了毛老师的大作,受益匪浅,在基本理清了原理与细节后,特此做了一番总结,希望这篇文章
能够为安全界的朋友尽一点绵薄之力。由于工作原因,我接触到的知识面有限,不可能逐一摸透 Windows
的方方面面,再说,ReactOS 本来就与 Windows 有一些小差别,因此,希望各位朋友带着批判的态度去阅
读本文。(当然,我是尽我所能,认真写完逐篇的)
分析的部分项目截图:
本文术语约定:
描述符:指用来描述一件事物的“结构体”。如缓冲描述符,描述了一个缓冲的基址、长度等信息。中断描
述符,描述了那个中断向量对应的分配状态、isr 等信息
Entry:指表中的表项、条目,有时也指函数入口
SSDT:基本系统服务表(其实全称应叫系统服务派遣表)
Shadow SSDT:GUI/GDI 系统服务函数表,这是第二张 SSDT
SSDTDT:系统服务表描述符表,表中每个元素是一个 SSDT 描述符(注意内核中有两张 SSDT 和两张 SSDTDT)
IDT:中断描述符表,每个 cpu 一个。(每个表项是一个描述符,可以简单视为 isr)
ISR:中断服务例程,IDT 表中的中断描述符所描述的中断处理函数
EPR:异常处理例程,IDT 表中的异常描述符所描述的异常处理函数
VA:虚拟地址, PA:物理地址, LA:线性地址, RVA:相对虚拟地址 foa:文件偏移
PDE:页目录中的表项,保存着对应二级页表的物理地址,又叫“二级页表描述符”
PTE:二级页表中的表项,真正记录着每个虚拟页面的映射情况以及其他信息,又叫“映射描述符”
页目录:(又叫一级页表、总页表),一个 PDE 数组,这个数组的大小刚好占据一个页面
二级页表:一个 PTE 数组,这个数组的大小也刚好占据一个页面(进程有一个总页表+1024 个二级页表)
AREA:地址空间中的一块连续的区段,VirtualAlloc 分配内存都是以区段为单位
内存分配:表示从地址空间中用 VirtualAlloc 预定或者提交映射一块内存,不是指 malloc、new、HeapAlloc
PID:进程 ID、进程号。(其实也是个句柄)
TID:线程 ID、线程号。(其实也是个句柄)
PDO:物理设备对象,相对于 fdo 而言。Pdo 并不一定是最底层的那个硬件 pdo
FDO:功能设备对象,相对于 pdo 而言。Fdo 也可能直接访问硬件芯片。fdo 与 pdo 只是一种相对概念。
栈底 pdo:又叫‘基石 pdo’,‘硬件 pdo’, 指用作堆栈基石的那个 pdo,它是由相应的总线驱动内部创建的 。
端口设备对象:端口驱动或者小端口驱动中创建的设备对象(他下面是硬件 pdo)
总线驱动:用来驱动总线的驱动(总线本身也是一种特殊的设备),如 pci.sys 总线驱动
端口驱动:由厂家提供的真正用来直接访问硬件芯片的驱动,位于总线驱动上层
功能驱动:指类驱动。如鼠标类驱动 mouseclass.sys,磁盘类驱动 disk.sys
上层过滤驱动:位于功能类驱动上面的驱动
下层过滤驱动:位于功能驱动下面,端口驱动上面的驱动
顶层驱动:指位于栈顶的驱动
中间驱动:intermediate drivers,凡是夹在顶层驱动与端口驱动之间的那些驱动都叫中间驱动
设备树:由 PnP 管理器构造的一颗用来反映物理总线布局的‘硬件设备树’。
设备节点:设备树中的节点。每个节点都表示一个真正的‘硬件 pdo’
老式驱动:即 NT 式驱动,指不提供 AddDevice 或通过 NtLoadDriver 加载的驱动
WDM 驱动:指提供了 AddDevice 并且不是通过 NtLoadDriver 加载的驱动
IRP 派遣例程:又叫分发例程、派遣函数。驱动程序中用来响应处理 irp 的函数。( Dispatch)
设备绑定:指将设备‘堆栈’到原栈顶设备上面,成为新的栈顶设备。
文件:指物理介质上的文件(磁盘、光盘、U 盘)
文件对象:每次打开设备时生成一个文件对象(文件对象不是文件,仅仅表示对设备的一次打开上下文,
因此文件对象又叫打开者)
套接字驱动:afd.sys
套接字设备:\Device\Afd\Endpoint
套接字文件对象:每打开一次套接字设备生成一个套接字文件对象
套接字FCB:每个套接字文件对象关联的FCB,用来描述套接字的其他信息
地址文件对象:每次打开传输层的tdi设备时生成的一个文件对象,用于套接字绑定
地址对象:传输层中为每个地址文件对象创建一个地址对象,用来描述一个地址(IP、端口号、协议等)
Socket irp:发往 afd 套接字设备(即\Device\Afd\Endpoint)的 irp
Tdi irp:发往传输层设备(即\Device\Tcp,\Device\Udp,\Device\RawIp)的 irp
物理卷设备:指磁盘卷、光盘卷、磁带卷等物理卷设备,由相应类型的硬件驱动创建
磁盘卷设备:指磁盘分区,设备对象名为\Device\HarddiskN\PartitionN 形式(N 从 0 开始)
文件卷设备:由文件系统内部创建的挂载(即绑定)在物理卷上的匿名设备
Cdo:控制设备对象。一个驱动通常创建有一个 cdo,用来与外界通信。
FSD:文件系统驱动,File System Driver 缩写。
簇:文件以簇为分配单位。一个文件包含 N 个簇,簇之间不必物理连续,一个簇一般为 4KB
扇区:系统以扇区为单位进行磁盘 IO。一个簇包含 N 个扇区,一个扇区一般为 512B
文件块:磁盘文件中的文件块,对应于内核中的文件缓冲段
缓冲段:文件块在内核中的缓冲
ACL:访问控制表。每个 Ntfs 文件、内核对象都有一份 ACL,记录了各用户、组的访问权限
Token:访问令牌。每个线程、进程都有一个 Token,记录了包含的特权、用户、组等信息
SID:指用户 ID、组 ID、机器 ID,用来唯一标识。
主令牌:进程自己的令牌
客户令牌:也即模拟令牌。每个线程默认使用进程的令牌,但也可模式使用其他进程的令牌
Windows 的地址空间分用户模式与内核模式,低 2GB 的部分叫用户模式,高 2G 的部分叫内核模式,位于用户
空间的代码不能访问内核空间,位于内核空间的代码却可以访问用户空间
一个线程的运行状态分内核态与用户态,当指令位于用户空间时,就表示当前处于内核态,当指令位于内核
空间时,就处于内核态.
一个线程由用户态进入内核态的途径有 3 种典型的方式:
1、 主动通过 int 2e(软中断自陷方式)或 sysenter 指令(快速系统调用方式)调用系统服务函数,主
动进入内核
2、 发生异常,被迫进入内核
3、 发生硬件中断,被迫进入内核
现在讨论第一种进入内核的方式:(又分为两种方式)
1、 通过老式的 int 2e 指令方式调用系统服务(因为老式 cpu 没提供 sysenter 指令)
如 ReadFile 函数调用系统服务函数 NtReadFile
Kernel32.ReadFile() //点号前面表示该函数的所在模块
{
//所有 Win32 API 通过 NTDLL 中的系统服务存根函数调用系统服务进入内核
NTDLL.NtReadFile();
}
NTDLL.NtReadFile()
{
Mov eax,152 //我们要调用的系统服务函数号,也即 SSDT 表中的索引,记录在 eax 中
If(cpu 不支持 sysenter 指令)
{
Lea edx,[esp+4] //用户空间中的参数区基地址,记录在 edx 中
Int 2e //通过该自陷指令方式进入 KiSystemService,‘调用’对应的系统服务
}
Else
{
Lea edx,[esp +4] //用户空间中的参数区基地址,记录在 edx 中
Sysenter //通过 sysenter 方式进入 KiFastCallEntry,‘调用’对应的系统服务
}
Ret 36 //不管是从 int 2e 方式还是 sysenter 方式,系统调用都会返回到此条指令处
}
Int 2e 的内部实现原理:
该指令是一条自陷指令,执行该条指令后,cpu 会自动将当前线程的当前栈切换为本线程的内核栈(栈分
用户栈、内核栈),保存中断现场,也即那 5 个寄存器。然后从该 cpu 的中断描述符表(简称 IDT)中找到
这个 2e 中断号对应的函数(也即中断服务例程,简称 ISR),jmp 到对应的 isr 处继续执行,此时这个 ISR
本身就处于内核空间了,当前线程就进入内核空间了
Int 2e 指令可以把它理解为 intel 提供的一个内部函数,它内部所做的工作如下
Int 2e
{
Cli //cpu 一中断,立马自动关中断
Mov esp, TSS.内核栈地址 //切换为内核栈,TSS 中记录了当前线程的内核栈地址
Push SS
Push esp
Push eflags
Push cs
Push eip //这 5 项工作保存了中断现场【标志、ip、esp】
Jmp IDT[中断号] //跳转到对应本中断号的 isr
}
IDT 的整体布局:【 异常->空白->5 系->硬】(推荐采用 7 字口诀的方式重点记忆)
异常:前 20 个表项存放着各个异常的描述符(IDT 表不仅可以放中断描述符,还放置了所有异常的异常处
理描述符,0x00-0x13)
保留:0x14-0x1F,忽略这块号段
空白:接下来存放一组空闲的保留项(0x20-0x29),供系统和程序员自己分配注册使用
5 系:然后是系统自己注册的 5 个预定义的软中断向量(软中断指手动的 INT 指令)
(0x2A-0x2E 5 个系统预注册的中断向量,0x2A:KiGetTickCount, 0x2B:KiCallbaclReturn
0x2C:KiRaiseAssertion, 0x2D:KiDebugService, 0x2E:KiSystemService)
硬: 最后的表项供驱动程序注册硬件中断使用和自定义注册其他软中断使用(0x30-0xFF)
下面是中断号的具体的分配情况:
0x00-0x13 固定分配给异常:
0x00: Divide error(故障)
0x01: Debug (故障或陷阱)
0x02: 保留未用(为非屏蔽中断保留的,NMI)
0x03: breakpoint(陷阱)
0x04: Overflow(陷阱)
0x05: Bounds check(故障)
0x06: Invalid Opcode(故障)
0x07: Device not available(故障)
0x08: Double fault(异常中止)
0x09: Coprocessor segment overrun(异常中止)
0x0A: Invalid TSS(故障)
0x0B: Segment not present(故障)
0x0C: Stack segment(故障)
0x0D: General protection(故障)
0x0E: Page fault(故障)
0x0F: Intel 保留
0x10: Floating point error(故障)
0x11: Alignment check(故障)
0x12: Machine check(异常中止)
0x13: SIMD floating point(故障)
0x14-0x1f:Intel 保留给他公司将来自己使用(OS 和用户都不要试图去使用这个号段,不安全)
----------------------以下的号段可用于自由分配给 OS、硬件、用户使用-----------------------
linux 等其他系统是怎么划分这块号段的,不管,我们只看 Windows 的情况
0x20-0x29:Windows 没占用,因此这块号段我们也可以自由使用
0x2A-0x2E:Windows 自己本身使用的 5 个中断号
剩余594页未读,继续阅读
资源评论
广西wsz
- 粉丝: 1
- 资源: 7
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功