概述:内核开发字符串使用
相关参考:
内核字符串
内核编程中主要使用的字符串有两种格式:
-
UNICODE_STRING
1 2 3 4 5 6 7 8 9 10 11
| typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; #ifdef MIDL_PASS [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer; #else _Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer; #endif } UNICODE_STRING; typedef UNICODE_STRING *PUNICODE_STRING; typedef const UNICODE_STRING *PCUNICODE_STRING;
|
-
ANSI_STRING
1 2 3 4 5 6 7 8 9 10
| typedef struct _STRING { USHORT Length; USHORT MaximumLength; #ifdef MIDL_PASS [size_is(MaximumLength), length_is(Length) ] #endif _Field_size_bytes_part_opt_(MaximumLength, Length) PCHAR Buffer; } STRING; typedef STRING *PSTRING; typedef STRING ANSI_STRING;
|
在 Windows 内核中,字符串的处理十分重要。稍有不慎就会造成系统蓝屏。因此,对于字符串的处理必须遵循严格的安全规则,以确保不会引发各种安全漏洞。
内核字符串初始化
内核开发模式下提供了多个 API 可以用于字符串初始化操作,常见的主要是:
RtlInitUnicodeString
RtlInitAnsiString
字符串转换
针对 ANSI 和 UNICODE 两种编码格式之间进行转换操作,主要的 API 是:
RtlUnicodeStringToAnsiString
RtlAnsiStringToUnicodeString
另外的就是可以使用 CHAR*、WCHAR* 来保存和操作字符串。
Demo1
需要注意的是,参考的教程直接修改内存的方式会崩溃蓝屏。修改常量区内存需要先修改内存属性才可以。这里我是在网上随便找了一个方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
#include <ntifs.h>
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriver) { DbgPrint("Bye, Driver\n");
return STATUS_SUCCESS; }
KIRQL WPOFFx64() { KIRQL irql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql; }
void WPONx64(KIRQL irql) { UINT64 cr0 = __readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); }
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgPrint("Hello World, Driver\n"); DbgPrint("PDRIVER_OBJECT-> [0x%08x]\n", pDriver); DbgPrint("PUNICODE_STRING->[%ws]\n", pReg->Buffer);
ANSI_STRING ansi; ANSI_STRING ansiDst = {0}; UNICODE_STRING unicode; UNICODE_STRING str;
char* chr = "Hello Kernel Test"; wchar_t* wchr = (WCHAR*)L"Hello Kernel Test";
RtlInitAnsiString(&ansi, chr); RtlInitUnicodeString(&unicode, wchr); RtlInitUnicodeString(&str, L"Hello Kernel Test");
#if 0 PMDL mdl = IoAllocateMdl(chr, strlen(chr) + 1, FALSE, FALSE, NULL); if (!mdl) { DbgPrint("Failed to allocate MDL.\n"); return STATUS_INSUFFICIENT_RESOURCES; }
MmBuildMdlForNonPagedPool(mdl);
PVOID baseAddress = MmGetSystemAddressForMdlSafe(mdl, MdlMappingNoExecute); if (!baseAddress) { DbgPrint("Failed to map MDL to system address space.\n"); IoFreeMdl(mdl); return STATUS_INSUFFICIENT_RESOURCES; }
NTSTATUS status = MmProtectMdlSystemAddress(mdl, PAGE_READWRITE); if (!NT_SUCCESS(status)) { DbgPrint("Failed to change memory protection: %x\n", status); IoFreeMdl(mdl); return status; } #endif
KIRQL irql = WPOFFx64(); chr[0] = 'h'; chr[6] = 'k';
WPONx64(irql);
DbgPrint("[*] 输出ANSI: %Z \n", &ansi); DbgPrint("[*] 输出WCHAR: %Z \n", &unicode); DbgPrint("[*] 输出字符串: %wZ \n", &str);
NTSTATUS flag = RtlUnicodeStringToAnsiString(&ansiDst, &unicode, TRUE); if (NT_SUCCESS(flag)) { DbgPrint("[*] RtlUnicodeStringToAnsiString Called Print: %Z", &ansiDst); }
pDriver->DriverUnload = UnloadDriver;
return STATUS_SUCCESS; }
|
输出:
Hello World, Driver
PDRIVER_OBJECT-> [0x0edcee30]
PUNICODE_STRING->[\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\KmdfString]
[*] 输出ANSI: hello kernel Test
[*] 输出WCHAR: H
[*] 输出字符串: Hello Kernel Test
[*] RtlUnicodeStringToAnsiString Called Print: Hello Kernel Test
Bye, Driver
字符串和数字之间的转换
Demo2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
#include <ntifs.h>
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriver) { DbgPrint("Bye, Driver\n");
return STATUS_SUCCESS; }
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgPrint("Hello World, Driver\n"); DbgPrint("PDRIVER_OBJECT-> [0x%08x]\n", pDriver); DbgPrint("PUNICODE_STRING->[%ws]\n", pReg->Buffer);
UNICODE_STRING unicode_buffer_source = { 0 }; UNICODE_STRING unicode_buffer_target = { 0 };
ULONG number; RtlInitUnicodeString(&unicode_buffer_source, L"100"); NTSTATUS flag = RtlUnicodeStringToInteger(&unicode_buffer_source, 10, &number);
if (NT_SUCCESS(flag)) { DbgPrint("[*] 字符串 -> 数字:%d \n", number); }
unicode_buffer_target.Buffer = (PWSTR)ExAllocatePool(PagedPool, 1024); unicode_buffer_target.MaximumLength = 1024;
flag = RtlIntegerToUnicodeString(number, 10, &unicode_buffer_target); if (NT_SUCCESS(flag)) { DbgPrint("[*] 数字 -> 字符串:%wZ \n", unicode_buffer_target); }
{ RtlFreeUnicodeString(&unicode_buffer_target); }
pDriver->DriverUnload = UnloadDriver; return STATUS_SUCCESS; }
|
输出:
Hello World, Driver
PDRIVER_OBJECT-> [0x0b68a570]
PUNICODE_STRING->[\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\KmdfString2]
字符串 -> 数字:100
数字 -> 字符串:100
Bye, Driver
字符串拷贝和比较
UNICODE_STRING 和 ANSI_STRING 都是结构体,因此在使用上可以直接通过申请内存的方式来指定字符串的大小。
RtlInitEmptyUnicodeString
RtlCopyUnicodeString
RtlAppendUnicodeToString
RtlEqualUnicodeString
Demo3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
#include <ntifs.h>
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriver) { DbgPrint("Bye, Driver\n");
return STATUS_SUCCESS; }
void StringCopyDemo() { UNICODE_STRING dst; WCHAR dst_buf[256] = { 0 }; NTSTATUS status;
UNICODE_STRING src = RTL_CONSTANT_STRING(L"Hello World!");
RtlInitEmptyUnicodeString(&dst, dst_buf, 256 * sizeof(WCHAR));
if (&dst) { RtlCopyUnicodeString(&dst, &src); }
status = RtlAppendUnicodeToString(&dst, L"KernelTest"); if (status == STATUS_SUCCESS) { DbgPrint("[*] 输出操作后的字符串:%wZ", &dst); } }
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) { DbgPrint("Hello World, Driver\n"); DbgPrint("PDRIVER_OBJECT-> [0x%08x]\n", pDriver); DbgPrint("PUNICODE_STRING->[%ws]\n", pReg->Buffer);
UNICODE_STRING unicode_buffer = { 0 }; UNICODE_STRING unicode_buffer_dst = { 0 }; wchar_t* wchar_string = L"Hello World! Kernel Test";
RtlInitUnicodeString(&unicode_buffer_dst, L"Hello World! Kernel Test");
unicode_buffer.MaximumLength = 1024;
unicode_buffer.Buffer = (PWSTR)ExAllocatePool(PagedPool, 1024);
unicode_buffer.Length = wcslen(wchar_string) * 2;
ASSERT(unicode_buffer.MaximumLength >= unicode_buffer.Length);
RtlCopyMemory(unicode_buffer.Buffer, wchar_string, unicode_buffer.Length);
unicode_buffer.Length = wcslen(wchar_string) * 2; DbgPrint("[*] 输出字符串:%wZ \n", unicode_buffer);
if (RtlEqualUnicodeString(&unicode_buffer, &unicode_buffer_dst, TRUE)) { DbgPrint("[*] 字符串相等"); } else { DbgPrint("[*] 字符串不相等"); }
ExFreePool(unicode_buffer.Buffer);
unicode_buffer.Buffer = NULL; unicode_buffer.MaximumLength = 0; unicode_buffer.Length = 0;
pDriver->DriverUnload = UnloadDriver;
return STATUS_SUCCESS; }
|
输出:
Hello World, Driver
PDRIVER_OBJECT-> [0x0fb6fa80]
PUNICODE_STRING->[\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\KmdfStringCopy]
[*] 输出字符串:Hello World! Kernel Test
[*] 字符串相等
Bye, Driver
大小写操作
相关API:
RtlUpcaseUnicodeString
RtlUpcaseUnicodeChar