昨天断网,写程序调试弄到2点多,没有网络干着急,也无法写心得,早上8点起来还是没有网络,WinDbg与VM问题还没搞定,只好先向下进行.第二个驱动程序.串行端口的简单过滤
参考书籍为:<<寒江独钓:Windows内核安全编程>>第三章内容
首先了解到,内核与用户态,用户态的API都是通过层层包装过的,API通过层层传递, 由sysenter进入R0,最终操控硬件比如,CreateFile,调用NtCreateFile,CreateFile并不直接创建文件,而是调用NtCreateFile,然后再向下传递最终向设备发送请求,请求成功后,创建文件.
用户态下每一个进程的空间是独立的,低2G位该进程独立使用,高2G供给操作系统内核,内核空间却是共享的,所以每个进程看到的高2G的内容是一样的.高2G的空间是被保护的,无法由用户级的API修改,只有R0层的代码才可以访问内核空间,驱动程序可以不驱动任何硬件,可以成为软驱,也可以叫内核模块,内核模块位于内核空间,编写驱动作为R0级的代码,可以任意修改内核的,做到许多用户态应用程序无法做到的事,比如杀软,防火墙,这些过滤器.由此可见,想做一些深层次的东西,学习驱动编写技术是必须的.
驱动程序的入口是DriverEntry,定义为 NASTATUS DriverEntry(PDRIVER_OBJECT DirverObject,PUNICODE_STRING RegistryPath);
PDRIVER_OBJECT是一个驱动对象,每个驱动程序只有一个驱动对象,由操作系统传入,一个驱动对象代表了一个驱动程序,或一个内核模块,在WinDDK安装目录下的inc\ddk\wdm.h中有定义,其中包含了一个关键项,PDEVICE_OBJECT DeviecObject;
该对象是一个设备对象,Windows窗口应用程序是以消息为基础的,窗口是唯一一个可以接受消息的东西,在内核态下,大部分"消息"通过叫做请求(IRP)的方式传递,设备对象是唯一可以接受请求的实体.设备对象结构体同样在wdm.h可以找到,里面有一个重要参数PDEVICE_OBJECT *NextDevice;该设备对象指针指向下一个对象的指针,所以,可以看出来,驱动对象生成多个设备对象,形成了一个链表式,WIndows向设备发送请求,会被驱动对象的分发函数捕获,引申出分发函数的重要概念.
请求. 要求写入文件数据是一个请求,读取文件数据是一个请求,对于用户态下IRP是不可见的.只需要调用相对应的API,同样数据结构也可以在wdm.h内找到
在请求中有一个重要概念IRP栈空间,一个IRP通常需要传递N个设备才可以完成,传递过程中可能发生一些"中转变换",导致参数变化,为了保存这种参数变化,我们给每次"中转",都留一个栈空间,保存中间参数.每中转一次都可以使用其中一个位置,在结构中CurrentLocation表示使用哪一个. IRP有主要的几个
生成请求:主功能号为IRP_MJ_CREATE的IRP
查询请求:主功能号为IRP_MJ_QUERY_INFORMATION的IRP
设置请求:主功能号为IRP_MJ_SET_INFORMATION的IRP
控制请求:主功能号为IRP_MJ_DEVICE_CONTROL或者IRP_MJ_INTERNAL_DEVICE_CONTORL的IRP
关闭请求:主功能号为IRP_MJ_CLOSE的IRP
请求指针:IRP指针,PIRP
关于驱动模型:有KDM,WDM,WDF 主要区分为KDM不支持即插即用,通称NT式驱动或传统型驱动,WDM后支持即插即用,相当于KMD升级版.
在内核开发中断级很重要,主要有Passive和Dispatch,Dispatch比Passive级别高,许多复杂的内核API需要在Passive级别才能执行.有如下规则
1.如果在调用路径上没有特殊情况(导致中断提高或降低),则一个函数执行时的中断级和它的调用源中断级相同.
2.如果在调用路径上有获取自选锁,则中断级随之升高,如果调用路径上有释放自选锁,中断级随之下降.
节属性问题:
#pragmaalloc_text(INIT,DriverEntry)
#pragmaalloc_text(PAGE,NdisProtUnload)
#pragmaalloc_text(PAGE,NdisProtOpen)
#pragmaalloc_text(PAGE,NdisProtClose)
#pragma alloc_text指定某个函数的可执行代码在编译后出现在sys文件中的位置,
INIT节:初始化完毕后就被释放,.
PAGE节:位于可以进行分页交换的内存空间,这些空间在内存紧张时,可以被交换到硬盘上以节省内存
PAGELK节:默认在此节,加载后位于不可分页交换的内存空间
为了节约内存,可以将很多函数放在PAGE节中,但是PAGE节中的函数不可以在Dispatch级调用,因为这种函数可能诱发缺页中断.缺页中断处理不能在Dispatch级完成.,可以使用PAGE_CODE()宏进行测试~.