Windows 内核技术与驱动开发笔记(完整版)
Windows驱动学习笔记

需要说明的是,本书并不是一本详尽的入门书籍,它只是根据我本人的学习过程进行的 经验总结,适合作为专门教程的辅助读物。
灰狐 [iCoodle] :
邪恶八进制社区和泡面代码社区同时享有本书的任何处理权利。
作者简介
灰狐,又名 grayfox、nokyo 等,马甲众多,自 2005 年至 2009 年就读于成都信息工程 学院,喜编程、擅灌水,以结识志同道合者为好,常混迹于各大 BBS ,潜水居多。
MSN:peiyaoq iang@ms Gtalk :peiyaoq iang@gma il. c om Ema il:peiyaoq iang@126. c om QQ 群:醉爱编程 [iCoodle](群号:78298479) 个人主页:
1.1 关于 DDK............................................................................................................................ 5 1.2 关于驱动程序的编译.......................................................................................................... 5 1.3 驱动程序的运行.................................................................................................................. 6 第二章 驱动程序的结构.......
《Windows驱动开发技术详解》之Windows内核函数

《Windows驱动开发技术详解》之Windows内核函数内核模式下字符串操作ANSI_STRING和UNICODE_STRING分别定义如下:以UnicodeString类型对象进⾏初始化为例,代码如下:输出:进⾏复制字符串操作,代码如下:输出:但是如果这⾥改为:加载驱动运⾏就会蓝屏。
Why?其实,RltFreeUnicodeString是⽤来释放利⽤申请的堆空间初始化的UnicodeString类型对象的,⽽RtlInitUnicodeString对UniStr1进⾏初始化时,只是让Buffer指向了⼀个常量区。
进⾏ANSI_STRING字符串与UNICODE_STRING字符串相互转换操作,代码如下:注意这⾥要利⽤RtlFreeUnicodeString释放通过RtlAnsiStringToUnicodeString得到的UniStr2。
为什么这个需要释放?我们利⽤Windbg跟踪下代码。
⾸先,跟踪时要逐⼀,这⾥的勾如果不去掉,就是在源码下单步跟踪,⽽不是在汇编指令⾥单步跟踪:在RtlUnicodeStringToAnsiString函数中,有这么⼀个系统API此时的参数是正好是传⼊的字节数的⼤⼩。
⽽这个API最终调⽤了:所以,我们要利⽤RtlFreeUnicodeString进⾏释放。
内核模式下的⽂件操作:创建⽂件:代码⼊下:1 VOID FILEOPERATION(){2 OBJECT_ATTRIBUTES ObjAttributes;3 IO_STATUS_BLOCK iostatus;4 HANDLE hfile;5 UNICODE_STRING logFileUnicodeString;67 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log");8 InitializeObjectAttributes(&ObjAttributes,9 &logFileUnicodeString,10 OBJ_CASE_INSENSITIVE,11 NULL,12 NULL);13//创建⽂件14 NTSTATUS status = ZwCreateFile(&hfile, GENERIC_WRITE,15 &ObjAttributes,16 &iostatus,17 NULL,18 FILE_ATTRIBUTE_NORMAL,19 FILE_SHARE_READ,20 FILE_OPEN_IF,//这⾥是FILE_OPEN_IF则不论⽂件是否存在都可以Create成功,⽽如果改为FILE_OPEN,则只当⽂件存在时create成功。
Windows 驱动程序开发指导说明书

课程内容驱动基本概念介绍驱动核心代码分析WDM和WDF介绍Windows 10通用驱动平台驱动程序是一个软件模块,可以使操作系统和硬件设备进行交互驱动程序是操作系统的一个扩展驱动程序一般是由硬件的设计者或厂商进行编写Microsoft已经为符合公共设计规范的硬件设备提供了内置的驱动程序可执行文件,扩展名是.exe入口函数是Main()Main()函数完成大部分工作应用程序完成工作后返回,并释放内存空间在用户态运行可执行文件,扩展名是.sys入口函数是DriverEntry()DriverEntry()不会做很多工作,只是初始化驱动驱动其他部分会注册很多回调函数,会被系统的不同模块调用驱动不会返回,会一直存在直至被显示的释放在内核态或用户态运行Driver StacksPDO位于驱动栈的最底层,和总线驱动相关联当总线驱动被加载时,它会枚举所有挂载在总线上面的设备并请求设备所需要的资源每个设备都有自己对应的PDOPnP管理器会确定每个设备的驱动并在设备的PDO 之上构建适当的设备栈设备栈的核心部分,FDO和设备功能驱动相关联设备功能驱动完成Windows和设备交互的核心功能对上向应用程序和服务提供上层接口对下为设备或其他驱动提供数据交换的接口一个设备栈可以包含多个FiDO,可以在FDO之上或之下每个FiDO和一个过滤驱动相关联,FiDO是可选的通常的目的是修改一些在设备栈中传输的I/O请求,例如可以加密和解密读写请求当一个新设备被插入到系统后,系统总线驱动会向PnP管理器报告这个新设备PnP管理器通过总线驱动查询这个设备的更多信息,比如设备ID和设备所需要的资源PnP管理器利用这个信息去查找是否有有对应的驱动在本地或WU(Windows Update)上面一旦查找到设备对应的驱动,Windows便会安装并加载这个驱动加载驱动到地址空间解析驱动中引入的函数-调用其他模块调用驱动的入口函数(DriverEntry()),因此驱动可以注册回调函数调用AddDevice(),驱动此时可以创建一个“设备对象”,并将这个对象加入到设备栈中所有的事物在驱动框架中都是用对象呈现的(驱动,设备,请求等等)对象拥有属性,方法和事件WDF 对象方法属性事件操作对象的函数被WDF 框架调用用于通知某些事件设置或获取单个属性值的方法Driver (WDFDRIVER)Device (WDFDEVICE)Device (WDFDEVICE)Queue (WDFQUEUE)Queue (WDFQUEUE)……ObjectOperation方法:Status = Wdf Device Create ();属性:Cannot failWdfInterrupt Get Device();WdfInterrupt Set Policy();Can fail:Status = WdfRegistry Assign Value();Status = WdfRegistry Query Value();Status = WdfRequest Retrieve InputBuffer();回调事件:PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable初始化宏:WDF_XXX_CONFIG_INITWDF_XXX_EVENT_CALLBACKS_INIT当驱动被加载时,DriverEntry是第一个被操作系统调用的函数WdfDriverCreate( RawDriverObject, […] , attributes, &driver )NTSTATUS DriverEntry(_In_PDRIVER_OBJECT DriverObject ,_In_PUNICODE_STRING RegistryPath ) {[…]// Create WDF Driver ObjectWDF_OBJECT_ATTRIBUTES_INIT(&attributes);attributes.EvtDriverUnload = OnDriverUnload;WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd);status = WdfDriverCreate(DriverObject ,RegistryPath ,&attributes,&config,&driver );}WDF EventWDF MethodWDF ObjectDeclare vars这是一个过滤驱动程序吗?驱动程序是电源管理策略的所有者吗?为设备对象创建I/O队列创建辅助对象,例如计时器,工作者对象,锁等NTSTATUS OnDeviceAdd( WDFDRIVER Driver,PWDFDEVICE_INIT DeviceInit) {WDFDEVICE device;IWDFIoQueue* pDefaultQueue= NULL;DeviceInit->SetPowerPolicyOwnership(TRUE );status= WdfDeviceCreate(&DeviceInit,&deviceAttributes, &device);context = GetContext(device);context->WdfDevice= device;status = pIWDFDevice->CreateIoQueue(NULL, TRUE, WdfIoQueueDispatchParallel,TRUE, FALSE, &pDefaultQueue);return status;}Static Configuration Device CreateSetting ContextQueue Create进入电源状态管理(D0Entry)使能中断(InterruptEnable)…获取硬件资源,进行一些静态配置,(PrepareHardware)进入电源状态管理(D0Entry)使能中断(InterruptEnable)…获取硬件资源,进行一些静态配置,(PrepareHardware)NTSTATUS OnPrepareHardware(WDFDEVICE Device ,WDFCMRESLIST ResourcesRaw ,WDFCMRESLIST ResourcesTranslated ) {int ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated );for (i=0; i < ResourceCount; i++) {descriptor =WdfCmResourceListGetDescriptor(ResourcesTranslated , i);switch (descriptor->Type) {case CmResourceTypePort : […]case CmResourceTypeMemory : […]case CmResourceTypeInterrupt : […]default : break ;}}return STATUS_SUCCESS ;}进入电源状态管理(D0Entry)使能中断(InterruptEnable)…获取硬件资源,进行一些静态配置,(PrepareHardware)NTSTATUS OnD0Entry(IN WDFDEVICE Device ,IN WDF_POWER_DEVICE_STATE RecentPowerState ){PADXL345AccDevice pAccDevice = nullptr pAccDevice = GetContext(Device);WdfWaitLockAcquire(pAccDevice->m_WaitLock);I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, MY_REGISTER,MY_VALUE, sizeof (MY_VALUE) );pAccDevice->m_PoweredOn = true ;WdfWaitLockRelease(pAccDevice->m_WaitLock);return STATUS_SUCCESS ;}进入电源状态管理(D0Entry)使能中断(InterruptEnable)…获取硬件资源,进行一些静态配置,(PrepareHardware)NTSTATUS OnInterruptEnable(IN WDFINTERRUPT Interrupt,IN WDFDEVICE Device){PDEVICE_EXTENSION devExt;ULONG regUlong;PULONG intCsr;devContext = GetDeviceContext(WdfInterruptGetDevice(Interrupt) );intRegId = &devContext->IntRegisterId regVal = READ_REGISTER_ULONG( intRegId );regVal = ENABLE_INTERRUPT_BYTE( regVal );WRITE_REGISTER_ULONG( intRegId, regVal );return STATUS_SUCCESS;}进入电源状态管理(D0Entry)使能中断(InterruptEnable)…获取硬件资源,进行一些静态配置,(PrepareHardware)EvtIoResume EvtDMAEnablerFillEvtDeviceSelfManagedIoInitEvtDeviceDisarmWakeFromSxEventChildListScanForChildren EvtDeviceRemoveAddedResourcesStart power-managed queuesEvtIoResume Disarm wake signal, if it was armed. (called onlyduring power up; not called during resource rebalance)EvtDeviceDisarmWakeFromSx EvtDeviceDisarmWakeFromS0Request information about child devicesEvtChildListScanForChildren Enable DMA, if driver supports it EvtDmaEnablerSelfManagedIoStartEvtDmaEnablerEnableEvtDmaEnablerFillConnect interruptsEvtDeviceD0EntryPostInterruptsEnabledEvtInterruptEnable Notify Driver of state change EvtDeviceD0EntryDevice OperationalRestart from here if device is in low power statePrepare hardware for power EvtDevicePrepareHardwareChange resources requirements EvtDeviceRemoveAddedResourcesEvtDeviceFilterAddResourceRequirementsEvtDeviceFilterRemoveResourcRequirementsRestart from here if rebalancing resourcesCreate Device object EvtDriverDeviceAddDevice arrivedEnable self-managed I/O, if driver supports it.EvtDeviceSelfManagedIoInit (implicit power up),EvtDeviceSelfManagedIoRestart (explicit power up)Stop power-managed queuesEvtIoStop Arm wake signal, if it was not armed. (calledonly during power up; not called duringresource rebalance)EvtDeviceArmWakeFromSx EvtDeviceArmWakeFromS0Disable DMA, if driver supports it EvtDmaEnablerSelfManagedIoStopEvtDmaEnablerDisableEvtDmaEnablerFlushDisconnect interrupts EvtDeviceD0EntryPostInterruptsDisabledEvtInterruptDisableNotify Driver of state changeEvtDeviceD0Exit Device OperationalStop here if transitioning to low power stateRelease hardware EvtDeviceReleaseHardwarePurge power-managed queuesEvtIoStop Stop here if rebalancing resourcesFlush I/O if driver supports self-managedI/OEvtDeviceSelfManagedIoFlush Device removedSuspend self-managed I/O, if driver supports it.EvtDeviceSelfManagedIoSuspend Cleanup I/O buffers if driver supports self-managed i/o EvtDeviceSelfManagedIoCleanupDelete device object s context area.EvtDeviceContextCleanupEvtDeviceContextDestroyWDM和操作系统深度耦合,WDM驱动程序直接调用系统服务例程,直接操作系统数据结构WDM驱动程序全部为内核态程序,操作系统对驱动输入只做有限的检查WDF框架处理与操作系统的交互,驱动本身专注于和设备交互WDF基于对象模型和事件驱动WDF支持内核态程序和用户态程序将操作系统底层的复杂逻辑抽象化使驱动代码有可能<20行对不同的硬件设备使用相同的编程模型例如GPIO,UART,I2C,NFC,传感器驱动框架内置的日志系统为数据分析定制的工具支持上千种不同的硬件设备最初UMDF V1基于C++ COMUMDF V2使用和内核态驱动开发相同的模型和语法支持USB周边设备,传感器,NFC,智能卡,HID(包括触控)等等驱动崩溃只会影响宿主进程,不会影响整个操作系统系统重启策略可以自动恢复崩溃的UMDF驱动Windows 10提供了一系列API和DDI,对于所有的Windows平台都是通用的,被称为Universal Windows Platform(UWP) Windows通用驱动是指一个内核态或用户态的驱动并能运行在所有基于UWP的系统上面Windows通用驱动只能调用属于UWP部分的DDI,这部分DDI会在MSDN文档中标记为Universal确定你的驱动是否支持UWP,把你的驱动标记为通用驱动然后重新编译在Visual Studio中打开驱动项目工程在配置选项中把操作系统选择为Windows 10在工程属性中把目标平台改为“通用”,其他选项还有“桌面”和“手机”重新编译驱动,这时可以会出现一些链接器错误尝试修复这些错误,对于出现错误的API,请参考文档是否有通用平台的API可以替代,如果没有,您可能需要重新设计你的驱动KMDF version Release method Included in this versionof Windows Drivers using it run on1.19Windows 10, version1607 WDK Windows 10, version1607Windows 10 version1607 and later,Windows Server 20161.17Windows 10, version1511 WDK Windows 10, version1511Windows 10 version1511 and later,Windows 10 Mobile,Windows 10 IoT Core,Windows Server 20161.15Windows 10 WDK Windows 10Windows 10 for desktop editions, Windows 10 Mobile, IoT Core, Windows Server 2016UMDF version Release method Included in this version ofWindows Drivers using it can run on2.19Windows 10, version 1607WDK Windows 10, version 1607Windows 10, version 1607 (all SKUs), Windows Server 20162.17Windows 10, version 1511WDK Windows 10, version 1511Windows 10 for desktop editions (Home, Pro, Enterprise, and Education), Windows 10 Mobile, Windows 10 IoT Core (IoT Core), Windows Server 20162.15Windows 10 WDK Windows 10Windows 10 for desktop editions, Windows 10 Mobile, IoT Core, Windows Server 2016驱动程序运行在哪个版本的操作系统上驱动程序支持的硬件类型驱动程序使用的驱动模型确定驱动程序是否使用了只有KMDF支持的功能,如果驱动程序没有使用KMDF的功能,并且驱动运行在Windows 8.1或以后的系统上,则可以迁移到UMDF 2https:///en-us/windows/hardware/drivers/wdf/wdf-porting-guide Which Drivers Can Be Ported and WhereDifferences Between WDM and WDFPreparing for PortingSteps in PortingSummary of KMDF and WDM Equivalents。
《Windows核心编程》读书笔记上

6. 对象句柄继承:创建内核对象的时候可以指定SECURITY_ATTRIBUTES. bInheritHandle表示可继承(任何时候可以使用 SetHandleInformation修改可继承性等属性),创建子进程时指定CreateProcess的参数bInheritHandles为TRUE,则子进程从父进程的对象 表中拷贝所有可继承的对象到自己的对象表的相同表位置中(并增加引用计数),因为表项结构被完全拷贝且内核对象实际地址在地址空间 后2G的内核地址段中,所以拷贝过来的表项完全有效,进而父子进程的可继承内核对象的句柄值完全相同,于是只要以任何方式将要继承 的对象的句柄值跨进程交给子进程(创建子进程时的命令行参数、环境变量、共享内存、消息等手段),则后者可以使用。
看如下代码:
_chdir("D:/Downloaloads,且进程当前驱动器为D:
_chdir("F:/Projects"); // 修改F:的当前路径为Projects,且进程当前驱动器为F:
std::ofstream("1.txt"); // 当前驱动器是F:,所以绝对路径是F:/Projects/1.txt
7. 命名内核对象:要访问已经存在的命名内核对象,可以使用CreateXXX或者OpenXXX,后者在对象不存在的时候返回NULL。如果打 开了一个已经存在的命名对象,在打开时为API指定的对象名以外的参数被忽略。注意,一个进程打开同一对象两次,除了增加引用两次 外,返回的句柄值是不同的,需要分别关闭一次,即打开和关闭完全对称(很合理的行为)。在Vista及以上的系统,对象名可以包括在命名 空间下,避免被低授权用户访问。
12. GetVersionEx获取系统版本信息。VerifyVersionInfo检测当前系统是否满足版本需要。
DDK驱动开发笔记

DDK驱动开发笔记1、windows驱动分为NT式驱动和WDM式驱动,前者为非即插即用,后者为即插即用驱动。
需要头文件分别为NTDDK.h和WDM.h2、驱动的入口函数均为extern "C" NTSTA TUS DriverEntry(IN PDRIVER_OBJECTpDriverObject, IN PUNICODE_STRING pRegistryPath),它由I/O管理器负责调用,前参数为传递进来的驱动对象,后参数为Unicode字符串,指向此驱动的注册表。
3、驱动程序向windows的I/O管理器注册一些回调函数,回调函数是由程序员定义的函数,由操作系统负责调用,只要把地址告诉操作系统即可如:pDriverObject->DriverUnload=HelloDDKUnload;4、使用CreateDevice函数创建驱动设备对象如:CreateDevice(pDriverObject);返回NTSTATUS类型5、KdPrint是一个宏,用于打印输出信息,在Checked中会使用DbgPrint代替,在Free版本中无效果,用法和TRACE一致。
6、Windows的设备管理是使用线性链表进行管理,每一个节点记录了设备对象的地址,每次要对指定驱动进行操作,就必须先遍历设备对象链表。
7、设备对象函数NextDevice域记录下一个设备对象的地址,IoDeleteDevice用于删除设备对象如:IoDeleteDevice(pDevExt->pDevice),IoDeleteSymbolicLink用于删除设备符号链接。
8、DDK环境编译驱动源程序,需要使用两个自己创建的脚本makefile和Sources,最好使用二进制文本格式,makefile的内容固定为:!INCLUDE $(NTMAKEENV)\makefile.def。
sources文件记录了驱动的名称、驱动类型、编译输出目录、include目录、指定源文件。
学习笔记windows驱动开发技术详解

<学习笔记>Windows驱动开发技术详解派遣函数是Windows驱动程序中的重要概念。
驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的。
用户模式下所有对驱动程序的I/O请求,全部由操作系统转换为一个叫做IRP数据结构,不同的IRP会被“派遣”到不同的派遣函数中。
IRP与派遣函数IRP的处理机制类似于Windows应用程序中的“消息处理”,驱动程序接收到不同的IRP后,会进入不同的派遣函数,在派遣函数中IRP得到处理。
1.IRP在Windows内核中,有一种数据结构叫做IRP(I/O Request Package),即输入输出请求包。
上层应用程序与底层驱动程序通信时,应用程序会发出I/O请求。
操作系统将I/O请求转化为相应的IRP数据,不同类型的IRP会被传递到不同的派遣函数中。
IRP有两个基本的重要属性,一个是MajorFunction,另一个MinorFunction,分别记录IRP的主类型和子类型,操作系统根据MajorFunction将IRP“派遣”到不同的派遣函数中,在派遣函数中还可以继续判断这个IRP属于哪种MinorFunction。
下面是HelloDDK的DriverEntry中关于派遣函数的注册:view plaincopy to clipboardprint?#pragma INITCODEextern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegisterPath){NTSTATUS status;KdPrint(("Enter DriverEntry\n"));//设置卸载函数pDriverObject->DriverUnload = HelloDDKUnload;//设置派遣函数pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_SET_INFORMATI ON] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTR OL] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutine;pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTR OL] = HelloDDKDispatchRoutine;//创建驱动设备对象status = CreateDevice(pDriverObject);KdPrint(("Leave DriverEntry\n"));return status;} 2.IRP的类型文件I/O的相关函数,如CreateFile,ReadFile,WriteFile,CloseHandle等函数会使操作系统产生出IRP_MJ_CREATE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_CLOSE等不同的IRP。
驱动开发学习笔记

驱动开发学习笔记1很久没有网了,出了一段时间的差,近来,莫名的就有点郁闷!前不久在大富翁上发了一份帖子是关于delphi程序员的发展,大家的反应并不都是很好。
于是开始觉得可以考虑换个方向。
以前我是做MIS开发的。
换哪个方向呢?人越多的方向,好像越是没有前途。
想想当初上大学,那可是越多人考的学校,学费越贵啊!可现在的职业呢?越多人干的事,越是没有前途了。
考虑来考虑去,决定学习一下驱动程序的开发吧!于是从网上查找了一些资料,看的懂的觉得蛮不错适合我这种小学生的就贴了出来,算是学习笔记吧!用户模式与内核模式从Intel80386开始,出于安全性和稳定性的考虑,该系列的CPU可以运行于ring0~ring3从高到低四个不同的权限级,对数据也提供相应的四个保护级别。
运行于较低级别的代码不能随意调用高级别的代码和访问较高级别的数据,而且也只有运行在ring0层的代码可以直接对物理硬件进行访问。
由于WindowsNT是一个支持多平台的操作系统,为了与其他平台兼容,它只利用了CPU的两个运行级别。
一个被称为内核模式,对应80x86的ring0层,是操作系统的核心部分,设备驱动程序就是运行在该模式下;另一个被称为用户模式,对应80x86的ring3层,操作系统的用户接口部分(就是我们通常所说的win32 API)以及所有的用户应用程序都运行在该级别。
操作系统对运行在内核模式下的代码是不设防的,所以不管是建设还是破坏内核模式下的编程都是值得去研究的。
图1-WIN2000系统的分层结构在物理硬件与系统核心之间有一个硬件抽象层(HardwareAbstractionLayer),它屏蔽了不同平台硬件的差异,向操作系统的上层提供了一套统一的接口。
从图中我们还可以看到,设备驱动程序(DeviceDriver)是被I/O管理器(I/OManager)包围起来的,即驱动程序与操作系统上层的通信全部都要通过I/O管理器。
这给驱动程序的编写带来了很大的便利,因为很多诸如接收用户的请求、与用户程序交换数据、内存映射、挂接中断、同步等等麻烦的工作都由I/O管理器代劳了。
windows文件核心驱动结构简介、FileMon例程简介、开发注意要点

本帖子是《注册表实时监控拦截》的下篇,也是本系列的最后一篇。
主要讲述如何自己动手做一个在windows系统下的文件操作拦截的小驱动。
利用本驱动,可以实现对本机的所有文件操作请求进行实时监视、拦截,可以完全保护文件系统,在此基础上的进行深入开发后,可以做到文件加密、病毒防护等功能。
本帖子分三个部分:windows文件核心驱动结构简介、FileMon例程简介、开发注意要点。
一、windwos文件核心驱动结构简介在windows操作系统中(NT以上版本),规定了一套严格的文件操作请求处理流程,总体结构如下图:在图中上部分有一条虚线,这是“用户态”软件和“核心驱动”的分界线(用户态软件可以理解为普通的、可见的软件,如各类exe类型的软件)。
当用户态软件需要操作文件时,则发出文件操作请求,然后统一发送给系统的I/O管理器,I/O管理器把这个操作请求依次向下传递给“文件系统驱动”、“磁盘驱动”等,后者执行真正的文件操作。
上图是在本机上进行文件操作的流程,那么在访问网络上的文件,则处理流程如下:可以看到,在目标计算机(即文件所处的计算机)上,文件操作请求同样经过了“本地文件系统”和“磁盘驱动”,在这一点上,两者没有区别。
那么,如果我们要自己做一个文件的驱动,应该放在什么位置?下图给出了详细的“自定义驱动”的插入位置:图中以深色表示的部分,即留给用户可以插入“自定义驱动”的位置,可以看到,新插入的驱动和系统的驱动是“串接”在一起的。
所以,所有的文件操作均会通过“自定义驱动”(当然了,如果有人又开发了另外一个驱动,并插入到你所开发的驱动的下面,然后不通过正规的文件驱动而是直接发送消息到下层他的驱动,这样是拦截不到的)。
此时,你可以在你的驱动中很悠闲地处理这些请求,而且想啥时候丢弃、修改这些文件请求,那是全凭自己的心情了。
二、FileMon例程简介在了解了windows文件核心驱动的大致结构后,我们可以动手来试试了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Windows 内核技术与驱动开发笔记
1.简述Driver Entry例程
动程序的某些全局初始化操作只能在第一次被装入时执行一次,而Driver Entry例程就是这个目的。
* Driver Entry是内核模式驱动程序主入口点常用的名字。
* Driver Entry的第一个参数是一个指针,指向一个刚被初始化的驱动程序对象,该对象就代表你的驱动程序。
WDM驱动程序的Driver Entry例程应完成对这个对象的初始化并返回。
非WDM驱动程序需要做大量额外的工作,它们必须探测自己的硬件,为硬件创建设备对象(用于代表硬件),配置并初始化硬件使其正常工作。
* Driver Entry的第二个参数是设备服务键的键名。
这个串不是长期存在的(函数返回后可能消失)。
如果以后想使用该串就必须先把它复制到安全的地方。
* 对于WDM驱动程序的Driver Entry例程,其主要工作是把各种函数指针填入驱动程序对象,这些指针为操作系统指明了驱动程序容器中各种例程的位置。
2.简述使用VC进行内核程序编译的步骤
编译方式是使用VC++进行编译
1.用VC新建工程。
2.将两个源文件Driver.h和Driver.cpp拷贝到工程目录中,并添加到工程中。
3.增加新的编译版本。
4.修改工程属性,选择“project | setting”将IterMediate file和Output file 都改为MyDriver_Check。
5.选择C/C++选项卡,将原有的Project Options内容全部删除替换成相关参数。
6.选择Link选项卡,将原有的Project Options内容删除替换成相关Link。
7.修改VC的lib目录和include的目录。
8.在VC中选择tools | options,在弹出的对话框中选择“Directories”选项卡,在“Show directories for”下拉菜单中选择“Include file”菜单。
添加DDK的相关路径。
3.简述单机内核调试技术
答:1.下载和安装WinDbg能够调试windows内核模块的调试工具不多,其中一个选择是微软提供的WinDbg
下载WinDbg后直接双击安装包执行安装。
2.安装好虚拟机以后必须把这个虚拟机上的windows设置为调试执行。
在被调试系统2000、2003或是xp的情况下打开虚拟机中的windows系统盘。
3.将boot.ini文件最后一行复制一下,并加上新的参数使之以调试的方法启动。
重启系统,在启动时就可以看到菜单,可以进入正常windows xp,也可以进入Debug模式的windows xp。
4.设置VMware管道虚拟串口。
调试机与被调试机用串口相连,但是有被调试机是虚拟机的情况下,就不可能用真正的串口连接了,但是可以在虚拟机上生成一个用管道虚拟机的串口,从而可以继续内核调试。
4.请画出Windows架构简图
Windows 结构简图
5.对象管理程序的作用
Windows操作系统中提供的所有服务几乎是以对象的形式存在。
对象管理器程序就是创建、管理、回收、这些对象的组建涉及很多对象,如驱动程序对象、设备对象等。
6.写出打开注册表的内核函数原型
NTSTATUS
ZwOpenksy(
OUT PHANDLE key Handle
IN ACCESS_MASK
Desired Access
IN POBJECT_ATT
IN ACCESS_MASK
Desired Access
IN POBJECT_ATTRIBUTES
ObjectAttributes
);
7.画出I/O请求包数据结构图
8.简述I/0堆栈
任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序。
另外还有一个堆栈单元供IRP的创建者使用。
堆栈单元中包含该IRP的类型代码和参考信息以及完成函数的地址。
9.写出常见的四种创建IRP的内核函数
* 可以使用下面任何一种函数创建IRP:
* Io Bulid Asgnechronous Fsd Request创建异步IPR(不需要等待其完成)。
该函数和下一个函数仅适用于创建某些类型的IRP
* Io Build Synchronous Fsd Request创建同步IRP(需要等待其完成)
* Io Build Devicelo Control Request 创建一个同步IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE CONTROL 请求
* Io Allocatelrp创建上面桑函数不支持的其他种类的IRP
10.简述分层驱动技术
分层驱动是指两个或两个以上的驱动程序,他们分别建立设备对步。
并且形成一个由高到低的设备对象栈。
IRP异步会被传送到设备栈的最顶层的设备对象,顶层的设备可以选择直接结束IRP请求。
也可以选择将IRP请求向下层的设备对象转发。
如果是向下层的对象设备转发IRP请求。
当IRP请求结束时,IRP顺着设备栈的反方向原路返回。
当得知下层驱动程序已经结束IRP请求时,本层设备对象可以选择继续将IRP向上返回或者重新将IRP再次传递到底层设备驱动。