《Windows驱动开发技术详解》之Windows内核函数

  • 内核模式下字符串操作

ANSI_STRING和UNICODE_STRING分别定义如下:

以UnicodeString类型对象进行初始化为例,代码如下:

输出:

进行复制字符串操作,代码如下:

输出:

但是如果这里改为:

加载驱动运行就会蓝屏。Why?其实,RltFreeUnicodeString是用来释放利用申请的堆空间初始化的UnicodeString类型对象的,而RtlInitUnicodeString对UniStr1进行初始化时,只是让Buffer指向了一个常量区。

进行ANSI_STRING字符串与UNICODE_STRING字符串相互转换操作,代码如下:

 

注意这里要利用RtlFreeUnicodeString释放通过RtlAnsiStringToUnicodeString得到的UniStr2。为什么这个需要释放?我们利用Windbg跟踪下代码。

首先,跟踪时要逐一,这里的勾如果不去掉,就是在源码下单步跟踪,而不是在汇编指令里单步跟踪:

在RtlUnicodeStringToAnsiString函数中,有这么一个系统API

此时的参数是

正好是传入的字节数的大小。而这个API最终调用了:

所以,我们要利用RtlFreeUnicodeString进行释放。

  • 内核模式下的文件操作:

创建文件:

代码入下:

 1 VOID FILEOPERATION(){
 2     OBJECT_ATTRIBUTES ObjAttributes;
 3     IO_STATUS_BLOCK iostatus;
 4     HANDLE hfile;
 5     UNICODE_STRING logFileUnicodeString;
 6 
 7     RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log");
 8     InitializeObjectAttributes(&ObjAttributes,
 9         &logFileUnicodeString,
10         OBJ_CASE_INSENSITIVE,
11         NULL,
12         NULL);
13     //创建文件
14     NTSTATUS status = ZwCreateFile(&hfile, GENERIC_WRITE,
15         &ObjAttributes,
16         &iostatus,
17         NULL,
18         FILE_ATTRIBUTE_NORMAL,
19         FILE_SHARE_READ,
20         FILE_OPEN_IF,//这里是FILE_OPEN_IF则不论文件是否存在都可以Create成功,而如果改为FILE_OPEN,则只当文件存在时create成功21         FILE_SYNCHRONOUS_IO_NONALERT,
22         NULL,
23         0);
24     if (NT_SUCCESS(status)){
25         DbgPrint("Create file succeed!\n");
26     }
27     else{
28         DbgPrint("Create file failed!\n");
29     }
30     ZwClose(hfile);
31 }

如图

 把“1.log”文件删除后,改为OPEN_FILE标志,则会失败:

除了使用ZwCreateFile加上标志FILE_OPEN之外,还可以使用ZwOpenFile来直接打开文件。只需将ZwCreateFile改为ZwOpenFile即可:

获取或修改文件的属性,其代码如下:

你要去查询、设置一个文件不同的属性,那么就要定义不同的FileInformationClass

文件写操作,其代码如下:

 1 VOID WRITEREADFILE(){
 2     OBJECT_ATTRIBUTES ObjAttributes;
 3     IO_STATUS_BLOCK iostatus;
 4     HANDLE hfile;
 5     UNICODE_STRING logFileUnicodeString;
 6 
 7     RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log");
 8     InitializeObjectAttributes(&ObjAttributes,
 9         &logFileUnicodeString,
10         OBJ_CASE_INSENSITIVE,
11         NULL,
12         NULL);
13     //创建文件
14     NTSTATUS status = ZwCreateFile(&hfile, GENERIC_WRITE,
15         &ObjAttributes,
16         &iostatus,
17         NULL,
18         FILE_ATTRIBUTE_NORMAL,
19         FILE_SHARE_READ,
20         FILE_OPEN_IF,
21         FILE_SYNCHRONOUS_IO_NONALERT,
22         NULL,
23         0);
24 
25     if (NT_SUCCESS(status)){
26         DbgPrint("Create file succeed!\n");
27     }
28     else{
29         DbgPrint("Create file failed!\n");
30     }
31     //构造要填充的数据
32     PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, BUFFER_SIZE);
33     RtlFillMemory(pBuffer, BUFFER_SIZE, 0x65);
34     //写文件
35     ZwWriteFile(hfile, NULL, NULL, NULL, &iostatus, pBuffer, BUFFER_SIZE, NULL, NULL);
36     DbgPrint("Write file 0x65");
37 
38     //构造要填充的数据
39     RtlFillMemory(pBuffer, BUFFER_SIZE, 0xBB);
40     LARGE_INTEGER number;
41     number.QuadPart = 1024i64;//设置文件指针,再次写入文件
42     ZwWriteFile(hfile, NULL, NULL, NULL, &iostatus, pBuffer, BUFFER_SIZE, &number, NULL);
43     DbgPrint("Write file 0xBB");
44     ZwClose(hfile);
45     ExFreePool(pBuffer);
46 }

运行后可以看到文件中被写入数据:

注意这个API:

如果这里填充了大于已经开辟了的堆空间的数据,如改为2*BUFFER_SIZE,则会造成蓝屏:

说明这个API是会覆盖一些正常的数据的。

文件读操作,代码如下:

 1 VOID ReadFileTest(){
 2     OBJECT_ATTRIBUTES ObjAttributes;
 3     IO_STATUS_BLOCK iostatus;
 4     HANDLE hfile;
 5     UNICODE_STRING logFileUnicodeString;
 6 
 7     RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log");
 8     InitializeObjectAttributes(&ObjAttributes,
 9         &logFileUnicodeString,
10         OBJ_CASE_INSENSITIVE,
11         NULL,
12         NULL);
13     //创建文件
14     NTSTATUS status = ZwCreateFile(&hfile, GENERIC_WRITE,
15         &ObjAttributes,
16         &iostatus,
17         NULL,
18         FILE_ATTRIBUTE_NORMAL,
19         FILE_SHARE_READ,
20         FILE_OPEN_IF,
21         FILE_SYNCHRONOUS_IO_NONALERT,
22         NULL,
23         0);
24 
25     if (NT_SUCCESS(status)){
26         DbgPrint("Create file succeed!\n");
27     }
28     else{
29         DbgPrint("Create file failed!\n");
30     }
31     FILE_STANDARD_INFORMATION fsi;
32     status = ZwQueryInformationFile(hfile, &iostatus, &fsi,
33         sizeof(FILE_STANDARD_INFORMATION),
34         FileStandardInformation);
35     PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, (LONG)fsi.EndOfFile.QuadPart);
36 
37     ZwReadFile(hfile, NULL, NULL, NULL, &iostatus, pBuffer,
38         (LONG)fsi.EndOfFile.QuadPart,
39         NULL, NULL);
40     DbgPrint("Read %d bytes\n", iostatus.Information);
41     DbgPrint("Content:%s\n", pBuffer);
42     ZwClose(hfile);
43     ExFreePool(pBuffer);
44 }

输出结果:

  • 内核模式下的注册表操作:

 

 1 //新建注册表项为HKEY_LOCAL_MACHINE\SOFTWARE\HELLODDK
 2 #define  MY_REG_SOFTWARE_KEY_NAME  L"\\Registry\\Machine\\Software\\HELLODDK"
 3 
 4 VOID CreateRegisterTest(){
 5     UNICODE_STRING RegUnicodeString;
 6     HANDLE hRegister;
 7     RtlInitUnicodeString(&RegUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
 8     OBJECT_ATTRIBUTES objectAttributes;
 9     InitializeObjectAttributes(&objectAttributes,
10         &RegUnicodeString,
11         OBJ_CASE_INSENSITIVE,
12         NULL, NULL);
13     ULONG ulResult;
14     //创建或打开注册表项目
15     NTSTATUS status = ZwCreateKey(&hRegister, KEY_ALL_ACCESS,
16         &objectAttributes,
17         0, NULL,
18         REG_OPTION_NON_VOLATILE,
19         &ulResult);
20     if (NT_SUCCESS(status)){
21         if (ulResult == REG_CREATED_NEW_KEY){
22             DbgPrint("Register item is created!\n");
23         }
24         else if(ulResult == REG_OPENED_EXISTING_KEY){
25             DbgPrint("Register item was created!\n");
26         }
27     }
28     //***************************************************//
29     //创建或打开某注册表项的子项
30     UNICODE_STRING subRegUnicodeString;
31     HANDLE hSubRegister;
32     RtlInitUnicodeString(&subRegUnicodeString, L"SubItem");
33     OBJECT_ATTRIBUTES subObjectAttributes;
34     InitializeObjectAttributes(&subObjectAttributes,
35         &subRegUnicodeString,
36         OBJ_CASE_INSENSITIVE,
37         hRegister, NULL);
38     //对于InitializeObjectAttributes的倒数第二个参数
39     //与ObjectName参数匹配的根目录对象,如果ObjectName是对象的全路径则设置此参数为NULL,
40     //使用ZwCreateDirectoryObject 获取一个目录对象。
41     status = ZwCreateKey(&hSubRegister,
42         KEY_ALL_ACCESS,
43         &subObjectAttributes,
44         0, NULL,
45         REG_OPTION_NON_VOLATILE,
46         &ulResult);
47     if (NT_SUCCESS(status)){
48         if (ulResult == REG_CREATED_NEW_KEY){
49             DbgPrint("Subregister item is created!\n");
50         }
51         else if (ulResult == REG_OPENED_EXISTING_KEY){
52             DbgPrint("Subregister item was created!\n");
53         }
54     }
55     ZwClose(hRegister);
56     ZwClose(hSubRegister);
57 }

会分别创建表项和子项:

用ZwCreateKey可以打开注册表,同样用ZwOpenKey也可以。只是ZwOpenKey在当没有这个表项的时候不会去创建,而是返回一个错误。

添加、修改注册表键值,代码如下:

 1 VOID SetRegisterTest(){
 2     UNICODE_STRING regUnicodeString;
 3     HANDLE hRegister;
 4     RtlInitUnicodeString(&regUnicodeString,
 5         MY_REG_SOFTWARE_KEY_NAME);
 6     OBJECT_ATTRIBUTES objectAttributes;
 7     InitializeObjectAttributes(&objectAttributes,
 8         &regUnicodeString,
 9         OBJ_CASE_INSENSITIVE,
10         NULL, NULL);
11     NTSTATUS status = ZwOpenKey(&hRegister,
12         KEY_ALL_ACCESS,
13         &objectAttributes);
14     if (NT_SUCCESS(status)){
15         DbgPrint("Add value!\n");
16     }
17 
18     //设置一个键名、键值、键类型
19     //******************************************************************************
20     UNICODE_STRING ValueName;
21     //设置键名
22     RtlInitUnicodeString(&ValueName,
23         L"DwordValue");
24     ULONG ulValue = 1000;//设置键值
25     ZwSetValueKey(hRegister, &ValueName, 0, REG_DWORD, &ulValue, sizeof(ulValue));
26     //******************************************************************************
27 
28 
29     RtlInitUnicodeString(&ValueName, L"SZValue");
30     WCHAR* strValue = L"hello world";
31     ZwSetValueKey(hRegister, &ValueName, 0, REG_SZ, strValue, (ULONG)(wcslen(strValue) * 2 + 2));
32 
33     RtlInitUnicodeString(&ValueName, L"BianryValue");
34     UCHAR Buffer[10];
35     RtlFillMemory(Buffer, sizeof(Buffer), 0x73);
36     ZwSetValueKey(hRegister, &ValueName, 0, REG_BINARY, Buffer, sizeof(Buffer));
37 
38     ZwClose(hRegister);
39 }

运行输出结果如下:

查询注册表,代码如下:

 1 VOID QueryRegisterTest(){
 2     UNICODE_STRING RegUnicodeString;
 3     HANDLE hRegister;
 4     RtlInitUnicodeString(&RegUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
 5     OBJECT_ATTRIBUTES objectAttributes;
 6     InitializeObjectAttributes(&objectAttributes,
 7         &RegUnicodeString,
 8         OBJ_CASE_INSENSITIVE,
 9         NULL, NULL);
10     NTSTATUS status = ZwOpenKey(&hRegister,
11         KEY_ALL_ACCESS,
12         &objectAttributes);
13     if (NT_SUCCESS(status)){
14         DbgPrint("Open register succeed!\n");
15     }
16 
17     UNICODE_STRING ValueName;
18     RtlInitUnicodeString(&ValueName, L"DwordValue");
19     ULONG ulSize;
20     //第一次查询,获得所要查询的数据的长度
21     status = ZwQueryValueKey(hRegister,
22         &ValueName,
23         KeyValuePartialInformation,
24         NULL, 0, &ulSize);
25     if (status == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0){
26         ZwClose(hRegister);
27         DbgPrint("Value name not found!\n");
28         return;
29     }
30     PKEY_VALUE_PARTIAL_INFORMATION pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)
31         ExAllocatePool(PagedPool, ulSize);
32     //开辟完堆空间之后,去获取内容
33     status = ZwQueryValueKey(hRegister, &ValueName, KeyValuePartialInformation,
34         pvpi, ulSize, &ulSize);
35     if (!NT_SUCCESS(status)){
36         ZwClose(hRegister);
37         DbgPrint("Query failed!\n");
38         return;
39     }
40     if (pvpi->Type == REG_DWORD&&pvpi->DataLength == sizeof(ULONG)){
41         PULONG pulValue = (PULONG)pvpi->Data;
42         DbgPrint("Query value:%d!\n", *pulValue);
43     }
44     ExFreePool(pvpi);
45     ZwClose(hRegister);
46 }

运行结果如下,可以看到查询结果:

 枚举子项,代码如下:

 1 VOID EnumSubkeyTest(){
 2     UNICODE_STRING regUnicodeString;
 3     HANDLE hRegister;
 4     RtlInitUnicodeString(&regUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
 5     OBJECT_ATTRIBUTES objectAttributes;
 6     InitializeObjectAttributes(&objectAttributes,
 7         &regUnicodeString,
 8         OBJ_CASE_INSENSITIVE,
 9         NULL, NULL);
10     NTSTATUS status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
11     if (NT_SUCCESS(status)){
12         DbgPrint("Open register succeed!\n");
13     }
14     ULONG ulSize;
15     //第一次查询获取结构体的大小
16     ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);
17     PKEY_FULL_INFORMATION pfi =
18         (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);
19     //第二次查询获取具体的结构体中的数据
20     ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);
21     for (ULONG i = 0; i < pfi->SubKeys; i++){
22 
23         ZwEnumerateKey(hRegister, i,
24             KeyBasicInformation,
25             NULL, 0, &ulSize);
26         PKEY_BASIC_INFORMATION pbi =
27             (PKEY_BASIC_INFORMATION)
28             ExAllocatePool(PagedPool, ulSize);
29         ZwEnumerateKey(hRegister, i,
30             KeyBasicInformation,
31             pbi, ulSize, &ulSize);
32         UNICODE_STRING uniKeyName;
33         uniKeyName.Length = uniKeyName.MaximumLength =
34             (USHORT)pbi->NameLength;
35         uniKeyName.Buffer = pbi->Name;
36         DbgPrint("The %d subkey is %wZ\n", i, &uniKeyName);
37         ExFreePool(pbi);
38     }
39     ExFreePool(pfi);
40     ZwClose(hRegister);
41 }

输出结果如下:

枚举子健,代码如下:

 1 VOID EnumValueKeyTest(){
 2     UNICODE_STRING regUnicodeString;
 3     HANDLE hRegister;
 4     RtlInitUnicodeString(&regUnicodeString, MY_REG_SOFTWARE_KEY_NAME);
 5     OBJECT_ATTRIBUTES objectAttributes;
 6     InitializeObjectAttributes(&objectAttributes,
 7         &regUnicodeString,
 8         OBJ_CASE_INSENSITIVE,
 9         NULL, NULL);
10     NTSTATUS status = ZwOpenKey(&hRegister,
11         KEY_ALL_ACCESS,
12         &objectAttributes);
13     if (NT_SUCCESS(status)){
14         DbgPrint("Open register succeed!\n");
15     }
16     ULONG ulSize;
17     ZwQueryKey(hRegister,
18         KeyFullInformation,
19         NULL, 0, &ulSize);
20     PKEY_FULL_INFORMATION pfi =
21         (PKEY_FULL_INFORMATION)
22         ExAllocatePool(PagedPool, ulSize);
23     ZwQueryKey(hRegister,
24         KeyFullInformation,
25         pfi, ulSize, &ulSize);
26     for (ULONG i = 0; i < pfi->Values; i++){
27         ZwEnumerateValueKey(hRegister, i,
28             KeyValueBasicInformation,
29             NULL, 0, &ulSize);
30         PKEY_VALUE_BASIC_INFORMATION pvbi =
31             (PKEY_VALUE_BASIC_INFORMATION)
32             ExAllocatePool(PagedPool, ulSize);
33         ZwEnumerateValueKey(hRegister, i,
34             KeyValueBasicInformation,
35             pvbi, ulSize, &ulSize);
36         UNICODE_STRING uniKeyName;
37         uniKeyName.Length =
38             uniKeyName.MaximumLength =
39             (USHORT)pvbi->NameLength;
40         uniKeyName.Buffer = pvbi->Name;
41         DbgPrint("The %d key value is %wZ", i, uniKeyName);
42         ExFreePool(pvbi);
43     }
44     ExFreePool(pfi);
45     ZwClose(hRegister);
46 }

运行结果如下:

 

posted @ 2016-05-24 17:50  _No.47  阅读(689)  评论(0编辑  收藏  举报