windows驱动内核编程

image.png

搭建驱动开发环境 sdk10 wdk10
win7平台 降低警告级别

8086CPU 16位汇编
1982年 intel退出80286处理器,第一次提出保护模式
在保护模式下,段寄存器存储的段基址,而是段选择子

X86体系CPU支持三种模式
实模式:兼容16位CPU的模式
保护模式:操作系统所在模式
虚拟8086模式:可以模拟多个8086执行多任务

8086处理器的段寄存器是16位,共四个:
CS,DS,ES,SS
32位处理器内,增加两个 FS,GS
6个寄存器分为可见部分和不可见部分

不可见部分存放段的基地址,范围和段属性,处理器内部使用

段寄存器可见部分存储的值称为段选择子
13位:描述符表索引 1位:TI 2位:RPL
TI=0 全局描述符表GDT TI=1 局部描述符表LDT(windows系统并没有使用)

88位描述符高速缓存寄存器

描述符表中存放的是段描述符
描述符有效为P位
段限长Limit
粒度G位 0 limit字节 1 limit4KB
基地址字段base
s与TYPE s=0 系统段 1代码段或数据段
TYPE:
0EWA 数据段 扩展方向 是否可写 访问位
1CRA 代码段 一致性 可读 访问位

当前执行指令位置 cs eip决定
普通跨段跳转
非一致性
cpl==dpl rpl< =dpl
一致性
cpl>=dpl

s = 0,type=110 调用门
中断门 type=14
陷阱门 15
任务门 5

r gdtr
dp 地址

jmp far 跳转到同级非一致代码段
IDT 中断门描述符 陷阱门描述符 任务门描述符
存放中断处理函数地址 异常处理函数地址

DPL:描述符特权(Descriptor Privilege Level)
存储在描述符中的权限位,用于描述代码的所属的特权等级,也就是代码本身真正的特权级。一个程序可以使用多个段(Data,Code,Stack)也可以只用一个code段等。正常的情况下,当程序的环境建立好后,段描述符都不需要改变——当然DPL也不需要改变,因此每个段的DPL值是固定。

RPL:请求特权级RPL(Request Privilege Level)
RPL保存在选择子的最低两位。 RPL说明的是进程对段访问的请求权限,意思是当前进程想要的请求权限。RPL的值由程序员自己来自由的设置,并不一定RPL>=CPL,但是当RPL

CPL:当前任务特权(Current Privilege Level)
表示当前正在执行的代码所处的特权级。CPL保存在CS中的最低两位,是针对CS而言的。当选择子成功装入CS寄存器后,相应的选择子中的RPL就变成了CPL。因为它的位置变了,已经被装入到CS寄存器中了,所表达的意思也发生了变——原来的要求等级已经得到了满足,就是当前自己的等级。

分页机制
windows是通过页目录,页表(page table)与页表项(page table entry,pte)这种二级表的结构将虚拟地址转译成物理地址
页目录表PDT 页目录项PDE 页表PTT 页表索引PTE

页目录索引 页表索引 字节索引
10 10 12
虚拟页号

实验 虚拟地址转物理地址
查看记事本程序notepad.exe的进程信息
!process 0 0 notepad.exe
利用记事本的进程结构的起始地址,将windbg的当前进程切换到notepad.exe
.process 884ead40
搜索
s -u 0x00000000 L0x01000000 "hello 15pb"
查看位于本进程虚拟地址处的字符串
du 0x007c0bd4
查看一下notepad.exe进程页目录0x32303000
!dd 0x32303000
PTE位于0x32103000+0x3c04
!dd 0x32103000+0x3c0
4

X86映射表分两级
第一级:页目录表
第二级:页表

PTE与物理页
PTE可以没有物理页
PTE与物理页是多对一的关系

PDE与PTE都是4字节的数据,结构有相似性
P位 存在
R/W位 R/W = 0 只读 R/W = 1可读可写
U/S:0特权用户才能访问 1 普通用户,特权用户都能访问
P/S:只对PDE有意义
PS=1的时候 PDE直接指向物理页无PTE,低22位是页内偏移,所谓的大页,一页4MB
PS=0时,指向下一级页表
A位:只要被访问过一个字节,会被置为一
D位:是否被写过,写过就置1

PAE 物理扩展模式
PAE模式相比较传统模式多了一个PDPTE,PAE模式下的PDE与PTE都变成了8字节

驱动编程
进程空间分为用户空间与内核空间
驱动开发分为三类
NT WDM WDF
nt式驱动程序
1包含ntddk.h文件
2编写一个DriverEntry入口函数
3编写一个驱动卸载函数

NTSTATUS DriverEntry(
PDDRIVER_OBJECT driver,//驱动对象
PUNICODE_STRING path//路径
)
卸载函数
VOID DriverUnload(PDRIEVER_OBJECT driver){}

内核编程基础
驱动对象 设备对象 IRP io请求包(如同windows应用程序中的MSG)
程序 窗口 消息
设备对象
重要字段
DiverObject 指出设备对象属于哪个驱动对象
NextDevice 下一个设备对象
AttachedDevice 指向下一层驱动程序的设备对象
CurrentIrp 用来决策当前IRP完成还是挂起等
DeviceExtension 指向LDR链指针

设备对象 发送接收 IRP
驱动对象 处理 IRP

指定自己编写的函数所占内存的属性

pragma alloc_text(类型,函数名)

类型
INIT 调用完即可释放
PAGE 位于分页内存
NONE_PAGE 位于非分页内存

中断请求级别 Interrupt Request Level IRQL
dispatch apc passive

字符串表达方式
RTL_CONSTANT_STRING 初始化操作

内核api前缀
IoXX
ExXX
RtlXX
ReXX
ZwXX
NtXX
内存操作
申请内存ExAllocatePool
拷贝内存RtlCopyeMemory
填充内存RtlFillMemory
释放内存ExFreePool

你可能感兴趣的:(windows驱动内核编程)