《Windows驱动开发技术详解》之Windows内核函数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《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,
230);
24if (NT_SUCCESS(status)){
25 DbgPrint("Create file succeed!\n");
26 }
27else{
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,
230);
24
25if (NT_SUCCESS(status)){
26 DbgPrint("Create file succeed!\n");
27 }
28else{
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,
230);
24
25if (NT_SUCCESS(status)){
26 DbgPrint("Create file succeed!\n");
27 }
28else{
29 DbgPrint("Create file failed!\n");
30 }
31 FILE_STANDARD_INFORMATION fsi;
32 status = ZwQueryInformationFile(hfile, &iostatus, &fsi,
33sizeof(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", rmation);
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,
170, NULL,
18 REG_OPTION_NON_VOLATILE,
19 &ulResult);
20if (NT_SUCCESS(status)){
21if (ulResult == REG_CREATED_NEW_KEY){
22 DbgPrint("Register item is created!\n");
23 }
24else 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,
440, NULL,
45 REG_OPTION_NON_VOLATILE,
46 &ulResult);
47if (NT_SUCCESS(status)){
48if (ulResult == REG_CREATED_NEW_KEY){
49 DbgPrint("Subregister item is created!\n");
50 }
51else 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(®UnicodeString,
5 MY_REG_SOFTWARE_KEY_NAME);
6 OBJECT_ATTRIBUTES objectAttributes;
7 InitializeObjectAttributes(&objectAttributes,
8 ®UnicodeString,
9 OBJ_CASE_INSENSITIVE,
10 NULL, NULL);
11 NTSTATUS status = ZwOpenKey(&hRegister,
12 KEY_ALL_ACCESS,
13 &objectAttributes);
14if (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);
13if (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);
25if (status == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0){
26 ZwClose(hRegister);
27 DbgPrint("Value name not found!\n");
28return;
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);
35if (!NT_SUCCESS(status)){
36 ZwClose(hRegister);
37 DbgPrint("Query failed!\n");
38return;
39 }
40if (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(®UnicodeString, MY_REG_SOFTWARE_KEY_NAME);
5 OBJECT_ATTRIBUTES objectAttributes;
6 InitializeObjectAttributes(&objectAttributes,
7 ®UnicodeString,
8 OBJ_CASE_INSENSITIVE,
9 NULL, NULL);
10 NTSTATUS status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);
11if (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);
21for (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(®UnicodeString, MY_REG_SOFTWARE_KEY_NAME);
5 OBJECT_ATTRIBUTES objectAttributes;
6 InitializeObjectAttributes(&objectAttributes,
7 ®UnicodeString,
8 OBJ_CASE_INSENSITIVE,
9 NULL, NULL);
10 NTSTATUS status = ZwOpenKey(&hRegister,
11 KEY_ALL_ACCESS,
12 &objectAttributes);
13if (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);
26for (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 }
运⾏结果如下:。