无论是内核还是应用层变成,字符串都是最基本的数据结构。 而在内核中字符串给封装了。
封装成了UNICODE_STRING 和 ASCII_STRING。
看下这两个结构
typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWCH Buffer; } UNICODE_STRING;
本质是一个结构体, 这里请注意Buffer指向的字符串。而这个字符串可能并不是以 ‘\0’ 结尾的。
因为前两个字段已经在控制他的字符串长度了。
第二点需要注意的是 Buffer是一个指针。它可以指向一个缓冲区 这个缓冲区可以是你在栈上定义的缓冲区, 也可以是一个常量字符串缓冲区。 也可以是你申请内存后给定的一个堆内存的缓冲区。
默认他只是一个指针,请不要直接对他进行内存拷贝。
例如如下会出现bug的例子
UNICODE_STRING uabc; memcpy(uabc.buffer,xxx,10); //uabc.buffer 未初始化,不知道是指向哪里。有可能是0 给0拷贝就崩溃 例子2 wchat a[10] = L"xxx...."; RtlInitUnicodeString(&uabc,a); //这里实际上uabc.buffer = a 所以buffer的缓冲只有10越界也会崩溃
ASCII_STRING 同理 不在赘述
字符串初始化函数
函数 | 作用 | IRQL级别 |
---|---|---|
VOID RtlInitUnicodeString(PUNICODE_STRING Dest,PCWSTR Src) | 将Src指向的字符串赋值给dest | 如果Dst指向的内存是非分页内存,那么此函数可以工作在IRQL <= DISPATCH_LEVEL下,否则只能工作在<= APC_LEVEL |
例子:
UNICODE_STRING uTest; RtlInitUnicodeString(&uTest,L"HelloWorld"); DbgPrint("初始化的UTest = : %wZ \r\n", uTest);
本质上就是操作 utest.Buffer = L"HelloWorld"
其他常用的UnicodeString的方法如下:
RtlInitEmptyUnicodeString(); //初始化空的UNICODE_STRING RtlCompareUnicodeString(); //比较UNICODE_STRING RtlAppendUnicodeStringToString();//拼接UNICODE_STRING RtlCopyUnicodeString(); //拷贝 RtlEqualUnicodeString(); RtlInt64ToUnicodeString();
关于UNICODE_String 有更加安全的函数,那就是头文件 <ntstrsafe.h> 里面。
其中
RtlUnicodeStringxxxxx 前缀开始的是对UNICODE_STRING操作的
RtlStringxxx 前缀开始的是对 宽字符操作的。 比如 拷贝UNICODE_STRING的值到宽字符指针指向的内存中
其它还有就是字符串拼接等函数。 具体看下MSDN
MSDN_Kern API详解
这里额外提一下 对于UNICODE_STRING的格式化函数。 相当于 sprintf 或者wprintf
RtlUnicodeStringPrintf()
最重要的一点是 拷贝的函数 只能在 PASSIVE_LEVEL下使用
RtlUnicodeStringCopyString()