3.4 字符串操作
无论是应用层编程还是内核层编程,字符串都是最基本的数据结构,在应用层编程中,开发者所使用的字符串类型主要是Unicode与Ascii,在内核编程中,大部分情况下使用Unicode,但与应用层不同的是,内核层编程一般不直接使用WCHAR类型的Unicode字符串,而是使用UNICODE_STRING类型来表示Unicode,关于UNICODE_STRING类型,本书已经在第1章中进行了介绍。
再次提醒读者,UNICODE_STRING结构体内的Buffer指针所指向的字符串缓冲区的字符串结尾不一定包含'\0',开发者应该根据UNICODE_STRING结构体中的Length成员来确定字符串长度。不依赖'\0'作为结束标志将更为安全,可以较好地防止由缓冲区溢出后覆盖掉'\0'而导致的访问违例,这也是内核选用UNICODE_STRING而非WCHAR的原因。
下面介绍UNICODE_STRING的常用操作,首先介绍UNICODE_STRING的初始化,常用的初始化函数为RtlInitUnicodeString,这个函数的作用是把一个以'\0'结尾的WCHAR类型的Unicode字符串初始化成UNICODE_STRING类型的字符串。函数原型如下:
RtlInitUnicodeString函数有两个参数,第一个参数为返回类型,表示需要初始化的UNICODE_STRING结构体,第二个参数为传入参数,表示被用来初始化DestinationString的常量WCHAR*类型字符串,这个字符串以'\0'为结束符。如果DestinationString指向的内存为非分页内存,那么RtlInitUnicodeString可以工作在IRQL<= DISPATCH_LEVEL下,否则只能工作在IRQL<=APC_LEVEL下;下面是使用一个RtlInitUnicodeString的例子:
代码首先定义了一个uFirstString结构体,然后使用RtlInitUnicodeString函数把字符串L"Hello Kernel\n"初始化到uFirstString结构体中,最后通过DbgPrint打印uFirstString。
RtlInitUnicodeString函数的使用非常简单,但需要注意的是,RtlInitUnicodeString函数并没有为uFirstString.Buffer申请内存,而是令uFirstString.Buffer指向字符串L"Hello Kernel\n"的首地址,所以开发者使用RtlInitUnicodeString初始化DestinationString后,在使用DestinationString期间,必须保证SourceString有效,请看下面的代码:
由于uFirstString.Buffer指向的是str地址,所以str元素值的改变也影响着uFirstString的值。
下面为读者介绍UNICODE_STRING的拷贝操作,拷贝操作可以使用RtlUnicodeStringCopyString函数,原型如下:
RtlUnicodeStringCopyString函数把以'\0'结尾的字符串pszSrc拷贝到DestinationString中。虽然这个函数的功能看起来与前面的RtlInitUnicodeString函数功能类似,但是两者存在本质上的区别:RtlInitUnicodeString函数内部只是简单地使DestinationString.Buffer指向函数的第二个参数SourceString,没有任何的拷贝操作,而RtlUnicodeStringCopyString会把函数第二个参数pszSrc字符串拷贝到DestinationString所指向的内存中。下面给出一个RtlUnicodeStringCopyString的使用例子:
代码中首先使用RtlInitEmptyUnicodeString初始化一个空的UNICODE_STRING,然后通过RtlUnicodeStringCopyString函数,把字符串L"Hello Kernel\n"拷贝到uFirstString中,最后使用DbgPrint打印。
使用RtlUnicodeStringCopyString函数还必须添加相应的头文件“Ntstrsafe.h”,否则编译会报错,另外还需要添加引入库Ntstrsafe.lib文件,开发者可以在Sources文件中添加一行:TARGETLIBS = $(DDK_LIB_PATH)\ntstrsafe.lib。
RtlUnicodeStringCopyString函数的返回值为NTSTATUS类型,读者会在后面发现,大多数内核API的返回值都为NTSTATUS类型,RtlUnicodeStringCopyString函数成功返回STATUS_SUCCESS。
最后一点是关于RtlUnicodeStringCopyString函数的IRQL,这个函数只能在PASSIVE_LEVEL下使用,请读者注意。
上面介绍的是字符串最基本的操作,除此之外,系统还提供了其他功能强大的字符串操作函数,这些函数在用法上与上面的函数大同小异,本章不一一讲解,请读者自行查阅WDK帮助文档。