Windows驱动开发学习
- 链表的使用
main.h
#pragma once
#include<ntddk.h>
typedef struct _MYDATA {
LIST_ENTRY ListEntry;
DWORD64 Id;
UNICODE_STRING Name;
}MYDATA,*PMYDATA;
extern "C" {
VOID DrvUnload(IN PDRIVER_OBJECT pDriver);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING regPath);
VOID LinkListTest();
}
main.cpp
#include "main.h"
VOID DrvUnload(IN PDRIVER_OBJECT pDriver)
{
KdPrint(("驱动卸载成功\n"));
return VOID();
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING regPath)
{
NTSTATUS status = STATUS_SUCCESS;
pDriver->DriverUnload = ::DrvUnload;
KdPrint(("驱动加载成功\n"));
::LinkListTest();
return status;
}
VOID LinkListTest()
{
LIST_ENTRY ListHead;
InitializeListHead(&ListHead);
for (DWORD64 i = 0; i < 10; i++)
{
PMYDATA pData = (PMYDATA)ExAllocatePool(PagedPool, sizeof(MYDATA));
pData->Id = i;
RtlInitUnicodeString(&pData->Name, L"测试名称");
InsertHeadList(&ListHead, &pData->ListEntry);
}
KdPrint(("链表添加成功\n"));
while (!::IsListEmpty(&ListHead))
{
PMYDATA pData = (PMYDATA)CONTAINING_RECORD((PMYDATA)::RemoveHeadList(&ListHead), MYDATA, ListEntry);
KdPrint(("ID:%lld Name:%wZ\n", pData->Id, &pData->Name));
ExFreePool(pData); //释放空间
}
}
- 设备缓冲区读写方式
main.h
#pragma once
#include<ntddk.h>
#include<initguid.h>
constexpr USHORT DEVICE_NAME[] = L"\\Device\BufferIoTestDevice";
constexpr USHORT SYMBOL_NAME[] = L"\\??\\BufferIoTestDevice";
extern "C" {
VOID Unload(IN PDRIVER_OBJECT pDriver);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING regPath);
NTSTATUS DispatchDefaultRoutine(PDEVICE_OBJECT pDevice, PIRP pirp);
NTSTATUS DispatchWrite(PDEVICE_OBJECT pDevice, PIRP pirp);
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevice, PIRP pirp);
}
main.cpp
#include "main.h"
VOID Unload(IN PDRIVER_OBJECT pDriver)
{
if (pDriver->DeviceObject)
{
IoDeleteDevice(pDriver->DeviceObject);
UNICODE_STRING SymbolName = RTL_CONSTANT_STRING(SYMBOL_NAME);
NTSTATUS status = STATUS_SUCCESS;
status = IoDeleteSymbolicLink(&SymbolName);
if (!NT_SUCCESS(status))
{
KdPrint(("符号链接删除失败!%X\n", status));
}
}
KdPrint(("驱动卸载\n"));
return VOID();
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING regPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(DEVICE_NAME); //设备名称
UNICODE_STRING SymbolName = RTL_CONSTANT_STRING(SYMBOL_NAME); //符号名称
PDEVICE_OBJECT pDevice = nullptr;
pDriver->DriverUnload = ::Unload;
status = ::IoCreateDevice(pDriver, NULL, &DeviceName, FILE_DEVICE_UNKNOWN, NULL, TRUE, &pDevice);
if (!NT_SUCCESS(status))
{
KdPrint(("驱动设备创建失败!%X\n", status));
pDriver->DriverUnload(pDriver);
return status;
}
status = ::IoCreateSymbolicLink(&SymbolName, &DeviceName); //创建符号链接
if (!NT_SUCCESS(status))
{
KdPrint(("符号链接创建失败!%X\n", status));
pDriver->DriverUnload(pDriver);
return status;
}
pDevice->Flags &= ~DO_DEVICE_INITIALIZING;
//设置设备缓冲区读写
pDevice->Flags |= DO_BUFFERED_IO;
for (INT i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
{
pDriver->MajorFunction[i] = ::DispatchDefaultRoutine;
}
pDriver->MajorFunction[IRP_MJ_WRITE] = ::DispatchWrite;
pDriver->MajorFunction[IRP_MJ_READ] = ::DispatchRead;
KdPrint(("驱动加载成功\n"));
return status;
}
//默认的分发函数,什么都不做
NTSTATUS DispatchDefaultRoutine(PDEVICE_OBJECT pDevice, PIRP pirp)
{
pirp->IoStatus.Information = 0;
pirp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return NTSTATUS();
}
//写
NTSTATUS DispatchWrite(PDEVICE_OBJECT pDevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uLength = 0;
PIO_STACK_LOCATION pStack = ::IoGetCurrentIrpStackLocation(pirp);
__try
{
uLength = pStack->Parameters.Write.Length;
if (uLength > 1)
{
KdPrint(("%s\n", (PCHAR)pirp->AssociatedIrp.SystemBuffer));
}
else
{
status = STATUS_INVALID_PARAMETER;
uLength = 0;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
uLength = 0;
}
pirp->IoStatus.Information = uLength;
pirp->IoStatus.Status = status;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pStack = ::IoGetCurrentIrpStackLocation(pirp);
ULONG uLength = 0;
CHAR Buffer[] = "内核很好";
__try
{
uLength = pStack->Parameters.Read.Length;
if (uLength > sizeof(Buffer))
{
RtlCopyMemory(pirp->AssociatedIrp.SystemBuffer, Buffer, sizeof(Buffer));
}
else
{
status = STATUS_INVALID_PARAMETER;
uLength = 0;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
uLength = 0;
}
pirp->IoStatus.Information = uLength;
pirp->IoStatus.Status = status;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return status;
}
用户层应用
#include <iostream>
#include<Windows.h>
using namespace std;
int main()
{
//打开符号链接
HANDLE hDevice = ::CreateFile(L"\\\\.\\BufferIoTestDevice", GENERIC_ALL,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
cout << "设备打开失败" << endl;
return 1;
}
CHAR WriteBuffer[] = "3环呼叫";
DWORD dwWriteLength = 0;
BOOL res = ::WriteFile(hDevice, WriteBuffer, sizeof(WriteBuffer), &dwWriteLength, NULL);
CHAR ReadBuffer[1024] = { 0 };
DWORD dwReadLength = 0;
res = ::ReadFile(hDevice, ReadBuffer, sizeof(ReadBuffer), &dwReadLength, NULL);
if (res)
{
cout << "读取长度:" << dwReadLength << " 内容:" << ReadBuffer << endl;
}
else
{
cout << "读取内容失败:" << ::GetLastError() << endl;
}
::getchar();
return 0;
}
- 设备直接方式读写三环内存
其中关键设置有:
pDevice->Flags |= DO_DIRECT_IO;
以及对MdlAddress的操作
详细内容如下:
main.cpp
#include "main.h"
VOID Unload(IN PDRIVER_OBJECT pDriver)
{
if (pDriver->DeviceObject)
{
IoDeleteDevice(pDriver->DeviceObject);
UNICODE_STRING SymbolName = RTL_CONSTANT_STRING(SYMBOL_NAME);
NTSTATUS status = STATUS_SUCCESS;
status = IoDeleteSymbolicLink(&SymbolName);
if (!NT_SUCCESS(status))
{
KdPrint(("符号链接删除失败!%X\n", status));
}
}
KdPrint(("驱动卸载\n"));
return VOID();
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriver, IN PUNICODE_STRING regPath)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(DEVICE_NAME); //设备名称
UNICODE_STRING SymbolName = RTL_CONSTANT_STRING(SYMBOL_NAME); //符号名称
PDEVICE_OBJECT pDevice = nullptr;
pDriver->DriverUnload = ::Unload;
status = ::IoCreateDevice(pDriver, NULL, &DeviceName, FILE_DEVICE_UNKNOWN, NULL, TRUE, &pDevice);
if (!NT_SUCCESS(status))
{
KdPrint(("驱动设备创建失败!%X\n", status));
pDriver->DriverUnload(pDriver);
return status;
}
status = ::IoCreateSymbolicLink(&SymbolName, &DeviceName); //创建符号链接
if (!NT_SUCCESS(status))
{
KdPrint(("符号链接创建失败!%X\n", status));
pDriver->DriverUnload(pDriver);
return status;
}
pDevice->Flags &= ~DO_DEVICE_INITIALIZING;
//设置设备直接方式读写三环内存
pDevice->Flags |= DO_DIRECT_IO;
for (INT i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
{
pDriver->MajorFunction[i] = ::DispatchDefaultRoutine;
}
pDriver->MajorFunction[IRP_MJ_WRITE] = ::DispatchWrite;
pDriver->MajorFunction[IRP_MJ_READ] = ::DispatchRead;
KdPrint(("驱动加载成功\n"));
return status;
}
//默认的分发函数,什么都不做
NTSTATUS DispatchDefaultRoutine(PDEVICE_OBJECT pDevice, PIRP pirp)
{
pirp->IoStatus.Information = 0;
pirp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return NTSTATUS();
}
//写
NTSTATUS DispatchWrite(PDEVICE_OBJECT pDevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG uLength = 0;
PIO_STACK_LOCATION pStack = ::IoGetCurrentIrpStackLocation(pirp);
__try
{
ULONG ulOffset = MmGetMdlByteOffset(pirp->MdlAddress);
ULONG ulByteCount = MmGetMdlByteCount(pirp->MdlAddress);
PVOID Va = MmGetMdlVirtualAddress(pirp->MdlAddress);
KdPrint(("write ulOffset:%d ulByteCount:%d data:%s\n", ulOffset, ulByteCount, (PCHAR)Va));
uLength = ulByteCount;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
uLength = 0;
}
pirp->IoStatus.Information = uLength;
pirp->IoStatus.Status = status;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DispatchRead(PDEVICE_OBJECT pDevice, PIRP pirp)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pStack = ::IoGetCurrentIrpStackLocation(pirp);
ULONG uLength = 0;
__try
{
ULONG ulOffset = MmGetMdlByteOffset(pirp->MdlAddress);
ULONG ulByteCount = MmGetMdlByteCount(pirp->MdlAddress);
PVOID Va = MmGetMdlVirtualAddress(pirp->MdlAddress);
KdPrint(("read ulOffset:%d ulByteCount:%d address:%p\n", ulOffset, ulByteCount, Va));
ProbeForWrite(Va, ulByteCount, 8);
CHAR str[] = "内核的问候";
if (strlen(str) <= ulByteCount)
{
RtlCopyMemory(Va, str, strlen(str));
uLength = strlen(str);
}
else
{
status = STATUS_BUFFER_TOO_SMALL;
uLength = 0;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
uLength = 0;
}
pirp->IoStatus.Information = uLength;
pirp->IoStatus.Status = status;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
return status;
}
Windows驱动开发-三种通讯方式通过MDL映射跨进程读写三环内存
- 驱动中枚举进程信息
main.h
#pragma once
#include<ntifs.h>
#include<ntddk.h>
extern "C" {
NTSTATUS PsReferenceProcessFilePointer(IN PEPROCESS pEprocess, OUT PVOID* pFilePointer);//申明即可用
HANDLE PsGetProcessInheritedFromUniqueProcessId(IN PEPROCESS pEprocess);//申明即可用
VOID DrvUnload(PDRIVER_OBJECT pDriver);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING regPath);
PEPROCESS MyLookupProcess(HANDLE ProcessId);
VOID EnumProcess();
}
main.cpp
#include "main.h"
VOID DrvUnload(PDRIVER_OBJECT pDriver)
{
KdPrint(("驱动卸载成功1"));
return VOID();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING regPath)
{
NTSTATUS status = STATUS_SUCCESS;
pDriver->DriverUnload = DrvUnload;
::EnumProcess();
KdPrint(("驱动加载成功!"));
return status;
}
PEPROCESS MyLookupProcess(HANDLE ProcessId)
{
PEPROCESS pEprocess;
NTSTATUS status = PsLookupProcessByProcessId(ProcessId, &pEprocess);
if (NT_SUCCESS(status))
{
return pEprocess;
}
return nullptr;
}
VOID EnumProcess()
{
PEPROCESS pEprocess;
NTSTATUS status = STATUS_SUCCESS;
for (UINT64 i = 0; i < 0x50000; i += 4) //进程ID值偏移4
{
pEprocess = ::MyLookupProcess((HANDLE)i);
if (pEprocess)
{
PFILE_OBJECT pFileObject;
status = PsReferenceProcessFilePointer(pEprocess, (PVOID*)&pFileObject);//申明即可用
if (NT_SUCCESS(status))
{
POBJECT_NAME_INFORMATION pObjectNameInfo;
status = IoQueryFileDosDeviceName(pFileObject, &pObjectNameInfo);
if (NT_SUCCESS(status))
{
KdPrint(("Pid:%d --- ParentId:%d ---%wZ", PsGetProcessId(pEprocess), PsGetProcessInheritedFromUniqueProcessId(pEprocess), &pObjectNameInfo->Name));
}
}
ObDereferenceObject(pEprocess);
}
}
return VOID();
}
- 进程创建回调通知
注意:在链接器-命令行中增加/INTEGRITYCHECK
main.h
#pragma once
#include<ntifs.h>
#include<ntddk.h>
extern "C" {
VOID DrvUnload(PDRIVER_OBJECT pDriver);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING regPath);
VOID
MyNotifyProcess (
_Inout_ PEPROCESS Process,
_In_ HANDLE ProcessId,
_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo
);
}
main.cpp
#include "main.h"
VOID DrvUnload(PDRIVER_OBJECT pDriver)
{
PsSetCreateProcessNotifyRoutineEx(MyNotifyProcess, TRUE); //卸载创建进程通知
KdPrint(("驱动卸载成功1"));
return VOID();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING regPath)
{
NTSTATUS status = STATUS_SUCCESS;
pDriver->DriverUnload = DrvUnload;
status = PsSetCreateProcessNotifyRoutineEx(::MyNotifyProcess, FALSE);
if (!NT_SUCCESS(status))
{
KdPrint(("进程回调创建失败! %X\n", status));
}
KdPrint(("驱动加载成功!"));
return status;
}
VOID MyNotifyProcess(_Inout_ PEPROCESS Process,
_In_ HANDLE ProcessId,
_Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo)
{
__try {
if (CreateInfo)
{
KdPrint(("%wZ\n", CreateInfo->ImageFileName));
UNICODE_STRING Name = RTL_CONSTANT_STRING(L"测试程序.exe");
if (RtlSuffixUnicodeString(&Name, CreateInfo->ImageFileName, TRUE))
{
CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; //禁止打开该进程
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
KdPrint(("%X\n", GetExceptionCode()));
}
return VOID();
}
在Windows系统中,可以通过使用CmRegisterCallback来设置注册表监控的回调函数
定义如下:
NTSTATUS
CmRegisterCallback(_In_ PEX_CALLBACK_FUNCTION Function,
_In_opt_ PVOID Context,
_Out_ PLARGE_INTEGER Cookie
);
Function:指向RegistryCallback例程的指针,这个参数就是用来监控注册表操作的回调函数
Context:配置管理器将作为CallbackContext参数传递给RegistryCallback例程中由驱动程序定义的值。此处设置为NULL就好
Cookie:指向LARGE_INTEGER变量的指针,该变量接收标识回调例程的值。当取消主持时,作为Cookie参数值传递给CmUnRegisterCallback。
PEX_CALLBACK_FUNCTION回调函数定义如下,该函数的返回值为STATUS_SUCCESS之外的错误码时,则表示系统会拒绝操作相应的注册表。
NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2);
CallbackContext:在主持RegistryCallback例程时,驱动程序作为Context参数传递给CmRegisterCallback的值。
Argument1:REG_NOTIFY_CLASS联合体类型的值,用于标识正在执行的注册表的操作类型,以及是否在执行注册表操作之前或之后调用RegistryCallback例程。
Argument2:指向特定于注册表操作信息的结构指针。结构的类型取决于Argument1中的REG_NOTIFY_CLASS类型值
REG_NOTIFY_CLASS定义:
//
// Hook selector
//
typedef enum _REG_NOTIFY_CLASS {
RegNtDeleteKey,
RegNtPreDeleteKey = RegNtDeleteKey,
RegNtSetValueKey,
RegNtPreSetValueKey = RegNtSetValueKey,
RegNtDeleteValueKey,
RegNtPreDeleteValueKey = RegNtDeleteValueKey,
RegNtSetInformationKey,
RegNtPreSetInformationKey = RegNtSetInformationKey,
RegNtRenameKey,
RegNtPreRenameKey = RegNtRenameKey,
RegNtEnumerateKey,
RegNtPreEnumerateKey = RegNtEnumerateKey,
RegNtEnumerateValueKey,
RegNtPreEnumerateValueKey = RegNtEnumerateValueKey,
RegNtQueryKey,
RegNtPreQueryKey = RegNtQueryKey,
RegNtQueryValueKey,
RegNtPreQueryValueKey = RegNtQueryValueKey,
RegNtQueryMultipleValueKey,
RegNtPreQueryMultipleValueKey = RegNtQueryMultipleValueKey,
RegNtPreCreateKey,
RegNtPostCreateKey,
RegNtPreOpenKey,
RegNtPostOpenKey,
RegNtKeyHandleClose,
RegNtPreKeyHandleClose = RegNtKeyHandleClose,
//
// .Net only
//
RegNtPostDeleteKey,
RegNtPostSetValueKey,
RegNtPostDeleteValueKey,
RegNtPostSetInformationKey,
RegNtPostRenameKey,
RegNtPostEnumerateKey,
RegNtPostEnumerateValueKey,
RegNtPostQueryKey,
RegNtPostQueryValueKey,
RegNtPostQueryMultipleValueKey,
RegNtPostKeyHandleClose,
RegNtPreCreateKeyEx,
RegNtPostCreateKeyEx,
RegNtPreOpenKeyEx,
RegNtPostOpenKeyEx,
//
// new to Windows Vista
//
RegNtPreFlushKey,
RegNtPostFlushKey,
RegNtPreLoadKey,
RegNtPostLoadKey,
RegNtPreUnLoadKey,
RegNtPostUnLoadKey,
RegNtPreQueryKeySecurity,
RegNtPostQueryKeySecurity,
RegNtPreSetKeySecurity,
RegNtPostSetKeySecurity,
//
// per-object context cleanup
//
RegNtCallbackObjectContextCleanup,
//
// new in Vista SP2
//
RegNtPreRestoreKey,
RegNtPostRestoreKey,
RegNtPreSaveKey,
RegNtPostSaveKey,
RegNtPreReplaceKey,
RegNtPostReplaceKey,
//
// new to Windows 10
//
RegNtPreQueryKeyName,
RegNtPostQueryKeyName,
MaxRegNtNotifyClass //should always be the last enum
} REG_NOTIFY_CLASS;
其中比较常用的类型以及对应的Argument2的结构体内容如下:
REG_NOTIFY_CLASS | 说明 | Argument2结构体 |
---|---|---|
RegNtPreCreateKey | 创建注册表之前 | PREG_CREATE_KEY_INFORMATION |
RegNtPreOpenKey | 打开注册表之前 | PREG_CREATE_KEY_INFORMATION |
RegNtPreDeleteKey | 删除键之前 | PREG_DELETE_KEY_INFORMATION |
RegNtPreDeleteValueKey | 删除键值之前 | PREG_DELETE_VALUE_KEY_INFORMATION |
RegNtPreSetValueKey | 修改键值之前 | PREG_SET_VALUE_KEY_INFORMATION |
REG_CREATE_KEY_INFORMATION定义:
/* .Net Only */
typedef struct _REG_CREATE_KEY_INFORMATION {
PUNICODE_STRING CompleteName; // IN
PVOID RootObject; // IN
PVOID ObjectType; // new to Windows Vista
ULONG CreateOptions;// new to Windows Vista
PUNICODE_STRING Class; // new to Windows Vista
PVOID SecurityDescriptor;// new to Windows Vista
PVOID SecurityQualityOfService;// new to Windows Vista
ACCESS_MASK DesiredAccess;// new to Windows Vista
ACCESS_MASK GrantedAccess;// new to Windows Vista
// to be filled in by callbacks
// when bypassing native code
PULONG Disposition; // new to Windows Vista
// on pass through, callback should fill
// in disposition
PVOID *ResultObject;// new to Windows Vista
// on pass through, callback should return
// object to be used for the return handle
PVOID CallContext; // new to Windows Vista
PVOID RootObjectContext; // new to Windows Vista
PVOID Transaction; // new to Windows Vista
PVOID Reserved; // new to Windows Vista
} REG_CREATE_KEY_INFORMATION, REG_OPEN_KEY_INFORMATION,*PREG_CREATE_KEY_INFORMATION, *PREG_OPEN_KEY_INFORMATION;
关键的成员:
成员 | 说明 |
---|---|
CompleteName | 指向包含新注册表项路径的UNICODE_STRING字符串结构的指针。路径可以是绝对的,也可以是相对的。如果是绝对路径,则此结构包含以“"字符开头的完全限定路径。对于绝对路径,RootObject成员指定\注册表项,它是注册表树的根目录。如果路径是相对的,则路径以""以外的字符开头,并且与RootObject成员指定的键相对 |
RootObject | 指向注册表项对象的指针,该对象用作CompleteName成员指定的路径的根 |