驱动学习6----字符串系列函数
6.1.2 ANSI_STRING字符串和UNICOCE_STRING
用KdPrint表示分别%Z和%wZ表示
如:
extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntryp RegistryPath:%wZ\n",pRegistryPath) );要注意的是%wZ,w必须是小写,如果是%WZ,是不会打印的.
6.1.3字符串初始化
VOID RtlInitAnsiString( IN OUT PANSI_STRING DestinationString, IN PCSZ SourceString );这种方式有个坏处是,如果SourceString改变了,DestinationSting的Buff也会变,因为二者指针相同
以下代码用windbg调试:
UNICODE_STRING symLinkName; WCHAR *wString = L"\\??\\HelloDDK"; RtlInitUnicodeString(&symLinkName,wString);如下图:
可以看到symLinkName的Buffer和wString的地址完全一样,所以二者会同时变化
另一种方式是程序员自己申请内存,并初始化内存,当不用字符串时,需要回收字符串占的内存。
注意的是UNICODE_STRING中的大小都是以字节来计算的,
自己写个小示例:
VOID CopyString() { KdPrint(("CopyString start")); // 第一种方式 WCHAR *wString = L"first copy"; UNICODE_STRING Unicode_String; RtlInitUnicodeString(&Unicode_String, wString); KdPrint(("Unicode_String:%wZ\n", &Unicode_String)); // 第二种方式 UNICODE_STRING Second_String = {0}; Second_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024); if (Second_String.Buffer) { Second_String.MaximumLength = 1024; Second_String.Length = 2*wcslen(wString); RtlCopyMemory(Second_String.Buffer, wString, Second_String.Length); KdPrint(("Second_String:%wZ\n", &Second_String)); RtlFreeUnicodeString(&Second_String); } // 第三种方式 UNICODE_STRING Third_String; Third_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024); if (Third_String.Buffer) { Third_String.MaximumLength = 1024;// length就不用初始化了,在copy中完成 RtlCopyUnicodeString(&Third_String, &Unicode_String); KdPrint(("Third_String:%wZ, len:%d\n", &Third_String, Third_String.Length)); RtlFreeUnicodeString(&Third_String); } KdPrint(("CopyString end")); }
需要注意的是第二种第三种方式都需要自己分配、释放内存
6.1.5 字符串比较
LONG RtlCompareUnicodeString( IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, IN BOOLEAN CaseInSensitive );写了一段测试代码:
#pragma PAGEDCODE VOID First_StringCompare() { //第一种方式 UNICODE_STRING First_String; RtlInitUnicodeString(&First_String, L"\\??\\First"); KdPrint(("First_String.Length:%d, First_String.MaximumLength:%d, First_String.Buffer:%s\n", First_String.Length, First_String.MaximumLength, First_String.Buffer)); UNICODE_STRING First_StringCompare = {0}; First_StringCompare.MaximumLength = 1024; First_StringCompare.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024); if (First_StringCompare.Buffer) { RtlCopyUnicodeString(&First_StringCompare, &First_String); KdPrint(("First_StringCompare.Length:%d, First_StringCompare.MaximumLength:%d, First_StringCompare.Buffer:%s\n", First_StringCompare.Length, First_StringCompare.MaximumLength, First_StringCompare.Buffer)); LONG bRet = RtlCompareUnicodeString(&First_StringCompare, &First_String, FALSE); KdPrint(("bRet:%d\n",bRet)); } }结果bRet返回0,这两个打印的MaximunLength明显是不同的,只是比较buffer和length
windbg跟进这个函数内部:
nt!RtlCompareUnicodeString: 805e2b0a 8bff mov edi,edi 805e2b0c 55 push ebp 805e2b0d 8bec mov ebp,esp 805e2b0f 83ec0c sub esp,0Ch 805e2b12 8b4508 mov eax,dword ptr [ebp+8] 805e2b15 8b4d0c mov ecx,dword ptr [ebp+0Ch]打印下,ecx和eax保存了比较双方
3: kd> r eax, ecx eax=bad17c70 ecx=bad17c68 3: kd> dt bad17c70 UNICODE_STRING HelloDDK!UNICODE_STRING "\??\First" +0x000 Length : 0x12 +0x002 MaximumLength : 0x400 +0x004 Buffer : 0xe115c7f8 "\??\First" 3: kd> dt bad17c68 UNICODE_STRING HelloDDK!UNICODE_STRING "\??\First" +0x000 Length : 0x12 +0x002 MaximumLength : 0x14 +0x004 Buffer : 0xbac44920 "\??\First"可以看到MaximunLength的大小的确不同
805e2b1b 0fb709 movzx ecx,word ptr [ecx]取得第一个比较数的length到ecx中
805e2b23 0fb700 movzx eax,word ptr [eax]取得第二个比较数的length到eax中
805e2b26 3bc1 cmp eax,ecx比较Length
805e2b2f 7e02 jle nt!RtlCompareUnicodeString+0x29 (805e2b33) 805e2b31 8bc1 mov eax,ecx 805e2b33 03c6 add eax,esi小或等于转移,所以上面的会直接跳转到805e2b33
05e2b33 03c6 add eax,esi其中eax是length,esi是buffer起始
3: kd> du esi e115c7f8 "\??\First"
805e2b35 807d1000 cmp byte ptr [ebp+10h],0 805e2b39 8945fc mov dword ptr [ebp-4],eax 805e2b3c 0f84fe000000 je nt!RtlCompareUnicodeString+0x136 (805e2c40) [br=1]比较buffer[Lengh]是否为0,为0则跳转到805e2c40
5e2c40 3bf0 cmp esi,eax最后是一个循环比较,直到esi=eax
3: kd> r eax, esi eax=e115c80a esi=e115c80a
805e2c04 0f8246ffffff jb nt!RtlCompareUnicodeString+0x46 (805e2b50) 805e2c0a 8b45f8 mov eax,dword ptr [ebp-8] 805e2c0d 2b45f4 sub eax,dword ptr [ebp-0Ch] 805e2c10 5f pop edi 805e2c11 5e pop esi 805e2c12 5b pop ebx 805e2c13 c9 leave 805e2c14 c20c00 ret 0Ch其中ebp-8的内存中保存了第一个len,ebp-0c保存了第二个len,两者相差,明显为0
整个过程和max大小没有关系.
另写了一段测试代码,同样ret为0,
#pragma PAGEDCODE VOID First_StringCompare() { //第二种方式 UNICODE_STRING First_String = {0}; First_String.MaximumLength = 100; First_String.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 100); if (First_String.Buffer) { First_String.Buffer[0] = 0x5c; First_String.Buffer[1] = 0x6c; First_String.Buffer[2] = 0x7c; First_String.Length = 4; KdPrint(("First_String.Length:%d, First_String.MaximumLength:%d, First_String.Buffer:%s\n", First_String.Length, First_String.MaximumLength, First_String.Buffer)); } UNICODE_STRING First_StringCompare = {0}; First_StringCompare.MaximumLength = 1024; First_StringCompare.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 1024); if (First_StringCompare.Buffer) { First_StringCompare.Buffer[0] = 0x5c; First_StringCompare.Buffer[1] = 0x6c; First_StringCompare.Buffer[2] = 0x8c; First_StringCompare.Length = 4; KdPrint(("First_StringCompare.Length:%d, First_StringCompare.MaximumLength:%d, First_StringCompare.Buffer:%s\n", First_StringCompare.Length, First_StringCompare.MaximumLength, First_StringCompare.Buffer)); LONG bRet = RtlCompareUnicodeString(&First_StringCompare, &First_String, FALSE); KdPrint(("bRet:%d\n",bRet)); } }
同样bRet为0,说明只是比较了buffer的length长度
6.1.6字符串转化为大写
VOID RtlUpperString( IN OUT PSTRING DestinationString, IN PSTRING SourceString );
NTSTATUS RtlUpcaseUnicodeString( IN OUT PUNICODE_STRING DestinationString, IN PCUNICODE_STRING SourceString, IN BOOLEAN AllocateDestinationString );小示例
#pragma PAGEDCODE VOID UpperCase() { // ANSI_STRING转换成大写 // 1.自己转换 ANSI_STRING Ansi_String = {0}; RtlInitString(&Ansi_String, "Ansi_String"); KdPrint(("Ansi_String.Length:%d, %d, %s", Ansi_String.Length, Ansi_String.MaximumLength,Ansi_String.Buffer)); RtlUpperString(&Ansi_String, &Ansi_String); KdPrint(("Ansi_String.Length:%d, %d, %s", Ansi_String.Length, Ansi_String.MaximumLength,Ansi_String.Buffer));
这样会挂掉,跟进RtlUpperString后,可以看到:
kd> p nt!RtlUpperString+0x36: 805e3cb6 8806 mov byte ptr [esi],al kd> r esi esi=f892e770 kd> !vad f892e770 1 VAD @ f892e770 Start VPN 69736e41 End VPN 7274535f Control Area 43676e69 FirstProtoPte 3a79706f LastPte 0a5a7725 Commit Charge 4535f (283487.) Secured.Flink 0 Blink 0 Banked/Extend 0 File Offset 0 ImageMap ViewUnmap NoChange LargePages AWE MemCommit EXECUTE GUARD因为这个内存是GUARD,所以会直接异常
当然,把属性改成#pragma INITCODE应该就OK,以下是改成INITCODE属性时这部分代码:
kd> !vad f8957230 1 VAD @ f8957230 Start VPN 69736e41 End VPN 7274535f Control Area 20797274 FirstProtoPte 0a646e65 LastPte cccccc00 Commit Charge 57265 (356965.) Secured.Flink cccccccc Blink cccccccc Banked/Extend 0 File Offset cccccc ViewShare NoChange CopyOnWrite LargePages MemCommit EXECUTE_READWRITE NOCACHE MultipleSecured ReadOnly建议使用自己分配内存的字符串:
#pragma PAGEDCODE VOID Upper() { ANSI_STRING Ansi_String = {0}; RtlInitString(&Ansi_String, "Ansi_String"); ANSI_STRING Ansi_StringCopy = {0}; Ansi_StringCopy.MaximumLength = 100; Ansi_StringCopy.Buffer = (PCHAR)ExAllocatePool(PagedPool, 100); if (Ansi_StringCopy.Buffer) { RtlCopyString(&Ansi_StringCopy, &Ansi_String); KdPrint(("Ansi_StringCopy:%Z\n", Ansi_StringCopy)); RtlUpperString(&Ansi_StringCopy, &Ansi_StringCopy); KdPrint(("Ansi_StringCopy:%Z\n", Ansi_StringCopy)); ExFreePool(Ansi_StringCopy.Buffer); } }
肯定没问题
6.1.7 字符串和整型数字互换
NTSTATUS RtlUnicodeStringToInteger( IN PUNICODE_STRING String, IN ULONG Base OPTIONAL, OUT PULONG Value );
NTSTATUS RtlIntegerToUnicodeString( IN ULONG Value, IN ULONG Base OPTIONAL, IN OUT PUNICODE_STRING String );写了个小示例:
#pragma PAGEDCODE VOID ConvertInteger() { UNICODE_STRING Unicode_String = {0}; RtlInitUnicodeString(&Unicode_String, L"10"); ULONG lNumber = 0; NTSTATUS nStatus = RtlUnicodeStringToInteger(&Unicode_String, 16, &lNumber); UNICODE_STRING Unicode_String2 = {0}; Unicode_String2.Buffer = (PWCHAR)ExAllocatePool(PagedPool, 100); Unicode_String2.MaximumLength = 100; nStatus = RtlIntegerToUnicodeString(lNumber, 16, &Unicode_String2); RtlFreeUnicodeString(&Unicode_String2); }注意RtlIntegerToUnicodeString这个函数,字符串要先分配足够的大小,
RtlIntegerToUnicodeString returns an NTSTATUS value. Possible return values include : STATUS_SUCCESS The routine successfully converted Value to a Unicode string. STATUS_BUFFER_OVERFLOW Value is too large to convert, or the UNICODE_STRING structure is too small to hold the result. STATUS_INVALID_PARAMETER The specified code base is not valid. The only valid values are 0, 2, 8, 10, and 16.
NTSTATUS RtlUnicodeStringToAnsiString( IN OUT PANSI_STRING DestinationString, IN PUNICODE_STRING SourceString, IN BOOLEAN AllocateDestinationString );一般当然是分配内存,第三个参数为true
6.2内核模式下的文件操作
NTSTATUS ZwCreateFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength );
VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor );
注意,初始化时文件名必须是符号链接或设备名,如"c:\1.log"应该写成"\??\c:\1.log“
测试小代码:
#pragma PAGEDCODE VOID CreateFileTest() { UNICODE_STRING objName; RtlInitUnicodeString(&objName, L"\\??\\c:\\yy.log"); // 初始化obj OBJECT_ATTRIBUTES objAttr; InitializeObjectAttributes(&objAttr, &objName, OBJ_CASE_INSENSITIVE, NULL, NULL); // 创建文件 HANDLE hFile; IO_STATUS_BLOCK iostatus; NTSTATUS ntStatus = ZwCreateFile (&hFile, GENERIC_ALL, &objAttr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("[CreateFileTest]--ZwCreateFile sucess\n")); } else { KdPrint(("[CreateFileTest]--ZwCreateFile fail\n")); } //关闭文件句柄 ZwClose(hFile); // 打开文件 ntStatus = ZwCreateFile (&hFile, GENERIC_ALL, &objAttr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN,//打开文件 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("[CreateFileTest]--[ZwCreateFile] open file sucess\n")); } else { KdPrint(("[CreateFileTest]--[ZwCreateFile] open file fail\n")); } //关闭文件句柄 ZwClose(hFile); // 打开文件 ntStatus = ZwOpenFile (&hFile, GENERIC_ALL, &objAttr, &iostatus, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(ntStatus)) { KdPrint(("[CreateFileTest]--[ZwOpenFile] open file sucess\n")); } else { KdPrint(("[CreateFileTest]--[ZwOpenFile] open file fail\n")); } //关闭文件句柄 ZwClose(hFile); }
注意每次创建或打开后都要调一下ZwCreateFile(hFile);,上面三次使用hFile,少一个关闭,外部打开yy.log就会提示文件被占用.
获取或修改文件属性
NTSTATUS ZwSetInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass );
NTSTATUS ZwQueryInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass );FileHandle:文件句柄
FileInformationClass可以理解为文件信息的类型,不同的类型有不同的Length,而FileInformation则依据前者类型不同而不同,
Set就是设置进去FileInformation,Query就是FileInformation返回
typedef struct FILE_STANDARD_INFORMATION { LARGE_INTEGER AllocationSize;//为文件分配的大小(簇大小,非文件大小) LARGE_INTEGER EndOfFile;//距文件结尾还有多少字节 ULONG NumberOfLinks;//有多少个链接文件 BOOLEAN DeletePending;//是否准备删除 BOOLEAN Directory;//是否为文件夹 } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
typedef struct FILE_BASIC_INFORMATION { LARGE_INTEGER CreationTime;//文件创建时间 LARGE_INTEGER LastAccessTime;//最后访问时间 LARGE_INTEGER LastWriteTime;//最后写时间 LARGE_INTEGER ChangeTime;//最后修改时间 ULONG FileAttributes;//文件属性,如FILE_ATTRIBUTE_READONLY } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
#pragma PAGEDCODE VOID FileTest() { UNICODE_STRING ObjName; RtlInitUnicodeString(&ObjName, L"\\??\\c:\\1234.log"); OBJECT_ATTRIBUTES ObjAttr; InitializeObjectAttributes(&ObjAttr, &ObjName, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; NTSTATUS ntStatus = ZwCreateFile (&hFile, GENERIC_READ, &ObjAttr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- open file success\n")); } //读取文件长度 FILE_STANDARD_INFORMATION fsi; ntStatus = ZwQueryInformationFile (hFile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- len:%u\n", fsi.EndOfFile.QuadPart)); } //读取文件的创建访问系列时间 FILE_BASIC_INFORMATION fbi; ntStatus = ZwQueryInformationFile (hFile, &iostatus, &fbi, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- time:%u\n", fbi.CreationTime.QuadPart)); } //读取文件名 FILE_NAME_INFORMATION fni; PWCHAR pName = (PWCHAR)ExAllocatePool(PagedPool, 100); RtlZeroMemory(pName, 100); PFILE_NAME_INFORMATION pfni = (PFILE_NAME_INFORMATION)pName; pfni->FileNameLength = 95; ntStatus = ZwQueryInformationFile (hFile, &iostatus, pfni, sizeof(FILE_NAME_INFORMATION), FileNameInformation ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- name:%s\n", fni.FileName)); ExFreePool(pName); } KdPrint(("ntStatus:0x%08x\n", ntStatus)); ZwClose(hFile); }
6.2.4 文件的写操作
NTSTATUS ZwWriteFile( IN HANDLE FileHandle,//文件打开句柄 IN HANDLE Event OPTIONAL,//设为NULL IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,//设为NULL IN PVOID ApcContext OPTIONAL,//设为NULL OUT PIO_STATUS_BLOCK IoStatusBlock,//写操作的状态 IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL,//从文件的多少偏移地址开始写 IN PULONG Key OPTIONAL//设为NULL )小示例
#pragma PAGEDCODE VOID FileTest() { UNICODE_STRING ObjName; RtlInitUnicodeString(&ObjName, L"\\??\\c:\\1234.log"); OBJECT_ATTRIBUTES ObjAttr; InitializeObjectAttributes(&ObjAttr, &ObjName, OBJ_CASE_INSENSITIVE, NULL, NULL); HANDLE hFile; IO_STATUS_BLOCK iostatus; NTSTATUS ntStatus = ZwCreateFile (&hFile, GENERIC_WRITE,//请求写权限 &ObjAttr, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- open file success\n")); } PCHAR pBuffer = (PCHAR)ExAllocatePool(PagedPool, 100); RtlFillMemory(pBuffer, 100, 0xAA); //写文件 LARGE_INTEGER Offset; Offset.QuadPart = 2; ntStatus = ZwWriteFile (hFile, NULL, NULL, NULL, &iostatus, pBuffer, 100, &Offset, NULL ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[FileTest] -- write file success\n")); } KdPrint(("ntStatus :0x%08x\n", ntStatus)); ZwClose(hFile); }注意打开时文件句柄要获得写权限,写完后用UE在16进制下观看
NTSTATUS ZwReadFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL,//设为NULL IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,//设为NULL IN PVOID ApcContext OPTIONAL,//设为NULL OUT PIO_STATUS_BLOCK IoStatusBlock,//状态,Information 成员记录读了多少 OUT PVOID Buffer,//指向调用者已分配的内存 IN ULONG Length,//buffer的长度 IN PLARGE_INTEGER ByteOffset OPTIONAL,//文件指针的偏移 IN PULONG Key OPTIONAL//设为NULL );
6.3内核模式下注册表操作
应用编程中对应的子键 驱动编程中的路径写法
HKEY_LOCAL_MACHINE \Registry\Machine
HKEY_USERS \Registry\User
HKEY_CLASSES_ROOT 没有对应的路径
HKEY_CURRENT_USER 没有简单的对应路径,但是可以求得
#pragma PAGEDCODE VOID RegeditTest() { UNICODE_STRING KeyPath; RtlInitUnicodeString(&KeyPath, L"\\Registry\\Machine\\system\\hgy413"); OBJECT_ATTRIBUTES ObjAttr; InitializeObjectAttributes(&ObjAttr, &KeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建注册表 HANDLE hKey; ULONG ulResult; NTSTATUS ntStatus = ZwCreateKey (&hKey, KEY_ALL_ACCESS, &ObjAttr, 0, NULL, REG_OPTION_NON_VOLATILE, &ulResult ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[RegeditTest]--ulResult:%d\n", ulResult)); } KdPrint(("ntStatus:0x%08x", ntStatus)); ZwClose(hKey); hKey = NULL; //打开注册表 ntStatus = ZwOpenKey (&hKey, KEY_ALL_ACCESS, &ObjAttr ); if (NT_SUCCESS(ntStatus)) { KdPrint(("[RegeditTest]--ZwOpenKey success\n")); } UNICODE_STRING ValueName; RtlInitUnicodeString(&ValueName, L"REG_SZ value"); UNICODE_STRING Value; RtlInitUnicodeString(&Value, L"Reg_sz"); //设置子键 ntStatus = ZwSetValueKey ( hKey, &ValueName, 0, REG_SZ, Value.Buffer, Value.MaximumLength ); KdPrint(("ntStatus:0x%08x", ntStatus)); if (NT_SUCCESS(ntStatus)) { KdPrint(("[RegeditTest]--ZwSetValueKey success\n")); } KdPrint(("ntStatus:0x%08x", ntStatus)); //查询子键内容大小 ULONG ulSize; ntStatus = ZwQueryValueKey ( hKey, &ValueName, KeyValuePartialInformation, NULL, 0, &ulSize ); KdPrint(("ntStatus:0x%08x", ntStatus)); if (STATUS_BUFFER_TOO_SMALL == ntStatus) { PKEY_VALUE_PARTIAL_INFORMATION pVaule = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize); //查询子键内容 ntStatus = ZwQueryValueKey ( hKey, &ValueName, KeyValuePartialInformation, pVaule, ulSize, &ulSize ); KdPrint(("ntStatus:0x%08x", ntStatus)); } ZwClose(hKey); hKey = NULL; }
也可以使用Rtl系列封装函数来实现:
#pragma PAGEDCODE VOID RtlRegeditTest() { // 创建子项 NTSTATUS ntStatus = RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\system\\hgy413"); KdPrint(("ntStatus:0x%08x", ntStatus)); // 确认子项是否存在 ntStatus = RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\system\\hgy413"); KdPrint(("ntStatus:0x%08x", ntStatus)); // 写注册表 PWCHAR szString = L"sz_Reg"; ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\system\\hgy413", L"sz_Value", REG_SZ, szString, wcslen(szString)*2+2); KdPrint(("ntStatus:0x%08x", ntStatus)); }