驱动入口函数DriverEntry的简单概述

概述

每一个驱动都有一个驱动入口函数DriverEntry
当IO Manager记载驱动时,就会调用驱动入口函数DriverEntry

当添加驱动折别是,该驱动入口函数负责驱动初始化。
初始化任务主要有确定驱动使用对象,设置驱动系统资源。

驱动入口只有IRQL=PASSIVE_LEVEL级别的系统线程可以调用

驱动对象简介DRIVER_OBJECT

I / O管理器为已安装和加载的每个驱动程序创建一个驱动程序对象DRIVER_OBJECT,该结构体提供驱动程序的驱动程序对象的地址,包含用于存储许多驱动程序标准例程的入口点的存储。

typedef struct _DRIVER_OBJECT {
  CSHORT             Type;
  CSHORT             Size;
  PDEVICE_OBJECT     DeviceObject;
  ULONG              Flags;
  PVOID              DriverStart;
  ULONG              DriverSize;
  PVOID              DriverSection;
  PDRIVER_EXTENSION  DriverExtension;
  UNICODE_STRING     DriverName;
  PUNICODE_STRING    HardwareDatabase;
  PFAST_IO_DISPATCH  FastIoDispatch;
  PDRIVER_INITIALIZE DriverInit;
  PDRIVER_STARTIO    DriverStartIo;
  PDRIVER_UNLOAD     DriverUnload;
  PDRIVER_DISPATCH   MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT, *PDRIVER_OBJECT;
DeviceObject

指向驱动程序创建的设备对象的指针。
驱动程序成功调用IoCreateDevice时,该成员将自动更新。
驱动程序可以使用该成员和DEVICE_OBJECT的NextDevice成员来逐步浏览该驱动程序创建的所有设备对象的列表。

DriverExtension

指向驱动程序扩展的指针。
驱动程序扩展的唯一可访问成员是DriverExtension-> AddDevice,驱动程序的DriverEntry例程将驱动程序的AddDevice例程存储在该例程中。

HardwareDatabase

指向注册表中硬件配置信息的\ Registry \ Machine \ Hardware路径的指针。

DriverInitDriverEntry

例程的入口点,由I / O管理器设置。

DriverStartIo

驱动程序的StartIo例程的入口点(如果有),由驱动程序初始化时由DriverEntry例程设置。如果驱动程序没有StartIo例程,则此成员为NULL。

DriverUnload

驱动程序的卸载例程的入口点(如果有),由驱动程序初始化时由DriverEntry例程设置。如果驱动程序没有卸载例程,则此成员为NULL。

MajorFunction

驱动程序的DispatchXxx例程的入口点的调度表。如下代码:

DriverObject->MajorFunction[IRP_MJ_PNP] = XxxDispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = XxxDispatchPower;

数组的索引值是代表每个IRP主要功能代码的IRP_MJ_ XXX值。
每个驱动程序必须在该数组中为驱动程序处理的IRP_MJ_ XXX请求设置入口点。
必要的Dispatch例程有:
IRP_MJ_PNP
IRP_MJ_POWER
IRP_MJ_CREATE
IO管理器在一个文件或目录创建时,或一个已存在的文件,设备,目录,Volume被打开时,发送此IRP。
通常在应用层调用CreateFile,或内核层调用IoCreateFile、IoCreateFileSpecifyDeviceObjectHint、ZwCreateFile、ZwOpenFile引发此IRP的发送。
IRP_MJ_CLOSE
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_DEVICE_CONTROL
如果该设备存在一组系统定义的I / O控制代码(IOCTL),则要求其设备对象属于特定设备类型的每个驱动程序都必须在DispatchDeviceControl例程中支持此请求。
成功完成创建请求后的任何时间,都可以发送请求
输入参数:I / O控制代码包含在IRP的驱动程序I / O堆栈位置的Parameters.DeviceIoControl.IoControlCode中。
输出参数:取决于I / O控制代码的值。
IRP_MJ_INTERNAL_DEVICE_CONTROL
IRP_MJ_SYSTEM_CONTROL用于指定对驱动程序的WMI请求。

必要职责,一个最简单驱动的代码内容

一个驱动入口DriverEntry的必要的内容:
1、提供驱动标准入口
主要包含添加AddDevice例程,dispatch 例程,StartIo例程,以及Unload例程入口。
2、IOCreateDevice创建和初始化驱动对象,类型,或者驱动使用的资源
在执行AddDevice例程后,或者收到IRP_MN_START_SWVICE请求之后,驱动将会创建对象。
如果驱动有一个device-dedicated例程,或者等待一任何内核模式dispatcher对象,驱动则可能需要初始化 kernel dispatcher objects
3、释放所有允许的和不在需要的资源
4、当驱动成功加载,能接收和驱动PnP Manager识别,添加和开始当前驱动时,返回NTSTATUS

可选职责

1、使用IoAllocateDriverObjectExtension创建和初始化一个驱动扩展内存。
可以用来存储注册表路径或者其它全局信息
被设置的内存,都要在DriverEntry返回时,被ExFreePool释放
2、PsCreateSystemThread负责创建新线程
一种是用户线程,它属于当前进程中的线程。另一种是系统线程,系统线程不属于当前用户进程,而是属于系统进程,一般PID为4,名字为“System”的进程。
3、注册一个Reinitialize 例程
4、处理特殊类的初始化需求
例如与端口或类驱动程序协同工作的特定于设备的miniport或miniclass驱动程序可能具有的需求。

AddDevice例程

分为两种:in Function or Filter Drivers和in Bus Drivers
1、调用IoCreateDevice为驱动创建设备对象。

DriverUnload例程

pDriverObj->DriverUnload = DriverUnload;
VOID DriverUnload(IN PDRIVER_OBJECT pDriverObj)
{
//code
}

卸载函数中主要用来释放驱动资源。

必要的Dispatch例程

一个Dispatch例程的基本结构为:

NTSTATUS  DispatchXxx(
    struct _DEVICE_OBJECT  *DeviceObject,
    struct _IRP  *Irp
    )
  {
      // Function body
  }

DispatchDeviceControl和DispatchInternalDeviceControl例程

I / O管理器设置一个IRP,并将主要功能代码IRP_MJ_DEVICE_CONTROL和给定的I / O控制代码存储在Parameters.DeviceIoControl.IoControlCode的IO_STACK_LOCATION结构中
使用IoGetCurrentIrpStackLocation从输入参数struct _IRP *Irp中提取PIO_STACK_LOCATION结构,并在结构中获取IoControlCode。
I / O控制代码是一个32位值,由几个字段组成。下图说明了I / O控制代码的布局。
在这里插入图片描述
控制码的定义使用以下宏定义,定义于devioctl.h文件中:

#define CTL_CODE( DeviceType, Function, Method, Access ) (                 
    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) 
)//Method is TransferType
  • 1.DeviceType
    标识设备类型。
  • 2.FunctionCode
    标识驱动程序要执行的功能。
    小于0x800的值保留给Microsoft。供应商可以使用0x800及更高的值。请注意,供应商分配的值将设置“ 自定义”位。
  • 3.TransferType
    指示系统如何在DeviceIoControl的调用方与处理IRP的驱动程序之间传递数据。
    METHOD_BUFFERED
    指定缓冲的I / O方法,通常用于每个请求传输少量数据。
    METHOD_IN_DIRECT或METHOD_OUT_DIRECT
    将数据传递给驱动程序,请指定METHOD_IN_DIRECT 。
    将从驱动程序接收数据,请指定METHOD_OUT_DIRECT 。
    METHOD_NEITHER
    指定既不是缓冲也不是直接I / O。
  • 4.RequiredAccess
    指示打开代表设备的文件对象时调用者必须请求的访问类型
    FILE_ANY_ACCESS
    I / O管理器将任何具有句柄的调用者的IRP发送到代表目标设备对象的文件对象。
    FILE_READ_DATA
    I / O管理器仅向具有读取访问权限的调用方发送IRP,从而允许基础设备驱动程序将数据从设备传输到系统内存。
    FILE_WRITE_DATA
    I / O管理器仅向具有写访问权限的调用方发送IRP,从而允许基础设备驱动程序将数据从系统内存传输到其设备。

以上整理内容均来源于https://docs.microsoft.com/,整理结构属于原创,如有雷同,纯属巧合,如有使用,请引用谢谢。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Windows 内核模式下,我们可以使用 Zw 拦截函数来获取 NtFlushKey 函数的地址。Zw 拦截函数是 Windows 内核中的一种机制,它可以拦截用户态进程调用的系统调用,并将其转换为内核态下的函数调用。因此,我们可以通过 Zw 拦截函数来获取 NtFlushKey 函数的地址。 以下是一个示例代码,用于在 Windows 内核模式下获取 NtFlushKey 函数的地址: ```cpp #include <ntddk.h> // 定义 NtFlushKey 函数原型 typedef NTSTATUS (__stdcall* PFN_NTFLUSHKEY)(HANDLE); // 定义全局变量保存 NtFlushKey 函数地址 PFN_NTFLUSHKEY g_NtFlushKey = NULL; // Zw 拦截函数,用于获取 NtFlushKey 函数地址 NTSTATUS MyZwFlushKey(HANDLE KeyHandle) { // 获取 NtFlushKey 函数地址 if (g_NtFlushKey == NULL) { UNICODE_STRING functionName; RtlInitUnicodeString(&functionName, L"NtFlushKey"); g_NtFlushKey = (PFN_NTFLUSHKEY)MmGetSystemRoutineAddress(&functionName); if (g_NtFlushKey == NULL) { DbgPrint("Failed to get address of NtFlushKey\n"); return STATUS_UNSUCCESSFUL; } DbgPrint("Address of NtFlushKey: %p\n", g_NtFlushKey); } // 调用 NtFlushKey 函数 return g_NtFlushKey(KeyHandle); } // 驱动入口函数 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { // 注册 ZwFlushKey 拦截函数 UNICODE_STRING functionName; RtlInitUnicodeString(&functionName, L"ZwFlushKey"); DriverObject->MajorFunction[IRP_MJ_CREATE] = NULL; DriverObject->MajorFunction[IRP_MJ_CLOSE] = NULL; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NULL; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = NULL; DriverObject->DriverUnload = NULL; DriverObject->MajorFunction[IRP_MJ_CREATE] = NULL; DriverObject->MajorFunction[IRP_MJ_CLOSE] = NULL; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NULL; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = NULL; DriverObject->MajorFunction[IRP_MJ_PNP] = NULL; DriverObject->MajorFunction[IRP_MJ_POWER] = NULL; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyZwFlushKey; IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, NULL); IoCreateSymbolicLink(RtlInitUnicodeString(&functionName, L"\\??\\MyZwFlushKey"), RtlInitUnicodeString(&functionName, L"\\Device\\MyZwFlushKey")); return STATUS_SUCCESS; } ``` 上面的代码定义了 MyZwFlushKey 函数作为 ZwFlushKey 的拦截函数,在第一次调用该函数时获取 NtFlushKey 函数的地址,并保存到全局变量 g_NtFlushKey 中。在后面的调用中,直接使用 g_NtFlushKey 函数指针调用 NtFlushKey 函数。注意,在驱动入口函数中,我们需要将 ZwFlushKey 拦截函数注册到 IRP_MJ_DEVICE_CONTROL 处理函数中,以便驱动程序能够接收到系统调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值