不以物喜,不以己悲

Windows驱动开发学习

  1. 链表的使用
    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); //释放空间
	}
	
}
  1. 设备缓冲区读写方式
    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;
}
  1. 设备直接方式读写三环内存
    其中关键设置有:
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映射跨进程读写三环内存

  1. 驱动中枚举进程信息
    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();
}

  1. 进程创建回调通知
    注意:在链接器-命令行中增加/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();
}

  1. 注册表监控
    参考来源:https://mp.weixin.qq.com/s/12hYucSfJI1oL7lWj9j-rA

在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成员指定的路径的根
posted @ 2022-05-31 21:21  这种人  阅读(369)  评论(0编辑  收藏  举报