Windows驱动
+ -

UNICODE_STRING的初始化

2021-07-01 188 0

从UNICODE_STRING结构体的三个成员可以看到,其包含的是字符串的指针,字符串的实际长度和字符串指针的内存空间长。
学过C语言的我们都知道,要对一个指针的内存进行赋值,就必须确定这个指针指向的内存空间可用,否则会导致内存使用异常。在应用层中会导致应用程序异常,而在驱动中会导致蓝屏。
我们们这里使用以下的代码是完全错误的,内核会立刻崩溃:

    #define MYSTRING L"www.pnpon.com"
    UNICODE_STRING str;
    wcscpy(str.Buffer,MYSTRING);
    str.Length = str.MaximumLength = wcslen(MYSTRING) * sizeof(WCHAR);

上面的这段代码相当于定义了一个指针,但并没有对这个指针进行初所以系统会使用默认的值进行填充。str.Buffer只是一个未初始化的指针。它并没有指向有意义的空间。

Rlease/Free编译环境下为NULL,所以wcscpy其实是对NULL地址复制数据。

其相当于我们在应用层如下的代码:

#define MYSTRING L"www.pnpon.com"
char * pBuffer;
wcscpy(str.Buffer,MYSTRING);

pBuffer并未始始化,所以对其指向的内存赋值会引起内存写异常。

手动初始化UNICODE_STRING

以下的方法是正确初始化UNICODE_STRING:

#define MYSTRING L"www.pnpon.com"
    // 先定义后,再定义空间
UNICODE_STRING str;
str.Buffer = MYSTRING;
str.Length = str.MaximumLength = wcslen(MYSTRING) * sizeof(WCHAR);

在上面的代码中,指针Buffer进行了初始化赋值,这个指针指向的全局常量地址空间,所以这一段地址空间只能读,不可写。
如果我们强行对其地址修改,会触发系统的异常,导致蓝屏。

下在我们来使用另一种方式来初始化UNICODE_STRING。

UNICODE_STRING str = { 
    sizeof(L"www.pnpon.com") – sizeof((L"www.pnpon.com")[0]),
    sizeof(L"www.pnpon.com"),
    L"www.pnpon.com"};

上面一段代码相当于分别对结构体的三个变量进行初始化:
对于UNICODE_STRING的Length,相当于

str.Length = sizeof(L"www.pnpon.com") – sizeof((L"www.pnpon.com")[0]);
  • sizeof(L”www.pnpon.com”) 计算该字符串所占的内存空间,这里包括L’\0’。
  • sizeof((L”www.pnpon.com”)[0])相当于取的是这个字符串的第一个字符长度,这里因为宽字节,所以是2,两者相减,就计算出了字符串的长度。这里看到确实是以字节为单位计算的,而不是以宽字节的长度为单位的。

而对于UNIOCDE_STRING的MaximumLength成同,则直接使用sizeof计算其所占内存空间。所以这里也就包括了L’\0’2个字节的长度。

对于UNIOCDE_STRING的Buffer成员,直接使用常量地址空间的地址赋值。


使用RtlInitUnicodeString和RTL_CONSTANT_STRING初始化字符串

通过上面的代码看到,要初始化一个UNICODE_STRING,简直不要太复杂,而且很容易由于书写错误引起错误而导致蓝屏。
这里就不得不说一下微软简易太贴心了,它把以上的代码封装成了一个宏RTL_CONSTANT_STRING,我们可以直接使用这个宏来初始化常量字符串。

#define RTL_CONSTANT_STRING(s) \
{ \
    sizeof( s ) - sizeof( (s)[0] ), \
    sizeof( s ) / sizeof(_RTL_CONSTANT_STRING_type_check(s)), \
    _RTL_CONSTANT_STRING_remove_const_macro(s) \
}

所以上面的代码可以简化为:

#include <ntdef.h>
UNICODE_STRING str = RTL_CONSTANT_STRING(L"www.pnpon.com");

要使用宏RTL_CONSTANT_STRING,必须包括头文件ntdef.h,因为这个宏是在ntdef.h头文件中定义的。

这里我们再介绍一个函数可以使用RtlInitUnicodeString函数,这个函数可以随时初始化一个字符串。

这只能在定义这个字符串的时候使用。为了随时初始化一个字符串,可以使用RtlInitUnicodeString。示例如下:

UNICODE_STRING str;
RtlInitUnicodeString(&str,L"www.pnpon.com");
...
//可以再次初始化
RtlInitUnicodeString(&str,L"pnpon内核开发");

关于ANSI_STRING

ANSI_STRING字符串也有相对应的宏和初始函数,分别为RTL_CONSTANT_STRING和RtlInitString。

    ANSI_STRING str = RTL_CONSTANT_STRING("www.pnpon.com");
    RtlInitAnsiString(&str, "www.pnpon.com");

用本小节的方法初始化的字符串,不用担心内存释放方面的问题。因为我们并没有分配任何内存,因为这些内存都是使用的是常量地址空间。

0 篇笔记 写笔记

UNICODE_STRING的初始化
UNICODE_STRING结构体的三个成员可以看到,其包含的是字符串的指针,字符串的实际长度和字符串指针的内存空间长。学过C语言的我们都知道,要对一个指针的内存进行赋值,就必须确定这个指针指向的内存空间可用,否则会导致内存使用异常。在应用层中会导致应用程序异常,而在驱动中会导致蓝屏。我们们这里使......
字符串UNICODE_STRING
在Windows下编程,根据字符串的使用分为UNICODE编程和我们平常使用的多字节编程。我们开发Windows驱动使用的是C语言。在C语言中定义的字符串是以为结尾表示一个字符串的结束。 char* pStr="www.pnpon.com";// ansi字符串 ......
UNICODE_STRING的拼接
像普通的字符串使用strcat一样,UNICODE_STRING也支持拼接功能。UNICODE_STRING的拼接按源字符的类型分为以下几中:RtlAppendUnicodeToString拼接将一个宽字节接接到UNICODE_STRING中。这里使用RtlAppendUnicodeToStrin......
UNICODE_STRING的打印
字符串的连接另一种常见的情况是字符串和数字的组合。有时数字需要被转换为字符串。有时需要把若干个数字和字符串混合组合起来。这往往用于打印日志的时候。日志中可能含有文件名、时间、和行号,以及其他的信息。熟悉C语言的读者会使用sprintf。这个函数的宽字符版本为swprintf。该函数在驱动开发中依然......
UNICODE_STRING的拷贝复制
由于UNICODE_STRING和ANSI_STRING字符串是一个结构体,所以UNICODE_STRING和ANSI_STRING字符串的拷贝就不能使用wcscpy和strcpy来进行拷贝了。微软的WDK中提供了专门的函数RtlCopyUnicodeString和RtlCopyString来进行U......
Windows内核STRING转UNICODE
VOIDConvertToUnicodeString( IN CHAR * Buffer, IN ULONG ResultBufferLength, IN ULONG ResultBufferOffset, OUT LPWSTR ResultBuffer, ......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!