概述:驱动开发过程中,相关API的学习整理
[toc]
链表
定义链表结构体
1 2 3 4 5 6 7
| typedef struct { DWORD Pid; UCHAR ProcessName[2048]; DWORD Handle; LIST_ENTRY ListEntry; } ProcessList;
|
初始化 InitializeListHead
1 2 3 4
| LIST_ENTRY linkListHead;
InitializeListHead(&linkListHead);
|
插入链表 InsertTailList
1 2 3
| pData = (ProcessList*)ExAllocatePool(PagedPool, sizeof(ProcessList));
InsertTailList(&linkListHead, &pData->ListEntry);
|
判断是否为空 IsListEmpty
1 2 3 4
| if(!IsListEmpty(&linkListHead)) { DbgPrint("Empty"); }
|
移除链表 RemoveHeadList
1
| LIST_ENTRY* pEntry = RemoveHeadList(&linkListHead);
|
获取链表当中的结构
1 2
| pData = CONTAINING_RECORD(pEntry, ProcessList, ListEntry); DbgPrint("Pid[%d], ProcessName[%s], Handle[0x%x] \n", pData->Pid, pData->ProcessName, pData->Handle);
|
安装卸载相关
WdfDriverCreate
WdfDriverCreate 是 Windows Driver Frameworks (WDF) 中用于创建驱动程序的函数。它用于初始化驱动程序,并将其与 Windows 操作系统进行集成。
WdfDriverCreate 函数需要填写一个 WDFDRIVER 结构体来定义驱动程序的属性和行为。以下是一些常见的参数:
- DriverName: 驱动程序的名称,用于在调试和日志记录中标识驱动程序。
- DriverVersion: 驱动程序的版本号,用于标识驱动程序的版本。
- DeviceAddVersion: 用于添加新设备的 WDF 函数版本。
- DriverUnload: 驱动程序卸载时的回调函数,用于清理资源并执行其他必要的操作。
- DispatchTable: 一个包含驱动程序处理 IRP 请求的回调函数的表。
- RegistryPath: 驱动程序在注册表中的路径,用于存储配置信息和设置。
WdfDeviceCreate
WdfDeviceCreate 是 Windows Driver Frameworks (WDF) 中的一个函数,用于创建设备对象并初始化与设备相关的数据结构。它是 WDF 中非常重要和常用的函数之一。
WdfDeviceCreate 函数需要填写一个 WDFDEVICE_INIT 结构体来定义设备的属性和行为。以下是一些常见的参数:
- Driver: 指向驱动程序的指针,用于关联设备和驱动程序。
- DeviceAttributes: 指向调用方分配的 WDF_OBJECT_ATTRIBUTES 结构的指针,该结构包含新设备的属性。
- StackSize: 设备的堆栈大小,用于定义设备对象的执行环境。
- DeviceInit: 指向 WDFDEVICE_INIT 结构的指针的地址,用于初始化设备的状态和行为。
在调用 WdfDeviceCreate 之后,WDF 将使用提供的参数来创建并初始化一个设备对象。然后,设备可以使用 WDF 提供的其他函数来管理设备的状态、处理请求以及与其他设备或驱动程序进行交互。
需要注意的是,WdfDeviceCreate 是一个高级别的函数,通常用于创建完整的设备对象。对于较简单的设备或需要更精细控制的情况,可能需要使用其他 WDF 函数来手动创建和配置设备对象。同时,在使用 WdfDeviceCreate 和其他 WDF 函数时,应注意遵循正确的使用方法和规范,以避免产生潜在的问题和风险。
实用函数
绕过签名检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject) { #ifdef _WIN64 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG64 __Undefined1; ULONG64 __Undefined2; ULONG64 __Undefined3; ULONG64 NonPagedDebugInfo; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG64 __Undefined6; ULONG CheckSum; ULONG __padding1; ULONG TimeDateStamp; ULONG __padding2; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; #else typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG unknown1; ULONG unknown2; ULONG unknown3; ULONG unknown4; ULONG unknown5; ULONG unknown6; ULONG unknown7; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; } KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY; #endif
PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20;
return TRUE; }
|
如何使用
1 2 3 4 5 6 7 8 9 10 11
| NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath) { if (BypassCheckSign(Driver)) DbgPrint("Bypass Sign Success.");
DbgPrint("Driver loaded. \n");
Driver->DriverUnload = UnDriver; return STATUS_SUCCESS; }
|
内存相关
申请内存 ExAllocatePool
申请内存使用 ExAllocatePool
、ExAllocatePoolWithTag
、ExAllocatePool2
接口
原型
1 2 3 4
| PVOID ExAllocatePool( IN POOL_TYPE PoolType, IN SIZE_T NumberOfBytes );
|
- PoolType:指定内存池的类型,可以是
NonPagedPool
(非分页内存池)或 PagedPool
(分页内存池)等。
- NumberOfBytes:指定要分配的内存大小,最好是4的倍数。
- 返回值:返回分配的内存地址,一定是内核模式地址。如果返回NULL,则代表分配失败。
ExAllocatePool 与 ExAllocatePool2/ExAllocatePool3
从 Windows 10 版本 2004 开始,推荐使用 ExAllocatePool2
和 ExAllocatePool3
来替代 ExAllocatePool
。新的 API 默认会将分配的内存初始化为零,有助于避免内存泄漏相关的bug。
示例代码
1 2 3 4 5 6
| PVOID Allocation = ExAllocatePool(PagedPool, 100); if (Allocation == NULL) { } else { }
|
在新的驱动中,应该使用 ExAllocatePool2
接口
1 2 3 4 5 6
| PVOID Allocation = ExAllocatePool2(POOL_FLAG_PAGED, 100, 'abcd'); if (Allocation == NULL) { } else { }
|
填充内存 RtlZeroMemory
1 2 3
| pData = (ProcessList*)ExAllocatePool(PagedPool, sizeof(ProcessList)); RtlZeroMemory(pData, sizeof(ProcessList));
|
拷贝内存 RtlCopyMemory
1 2 3 4
| pData->Pid = (DWORD)PsGetProcessId(eproc); RtlCopyMemory(pData->ProcessName, PsGetProcessImageFileName(eproc), strlen(PsGetProcessImageFileName(eproc))); pData->Handle = (DWORD)PsGetProcessInheritedFromUniqueProcessId(eproc);
|
释放内存 ExFreePool
进程相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <windef.h>
extern PVOID PsGetProcessPeb(_In_ PEPROCESS Process);
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS* Process);
extern NTKERNELAPI PVOID PsGetProcessWow64Process(_In_ PEPROCESS Process);
extern NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
extern NTKERNELAPI HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS Process);
|