64位内核第七讲.内核中字符串编程注意事项

本文详细介绍了Windows内核中UNICODE_STRING结构体的使用方法,包括初始化、拷贝、拼接和格式化输出等操作。同时,文章还探讨了在栈、全局和堆上初始化UNICODE_STRING的不同方式及其注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存中字符串编程

一丶UNICODE_STRING讲解

1.1简介

在内核中.我们的字符有 char类型的.也有wchar_t类型的.分别是宽字符
跟窄字符.但是这种都不建议使用了.而内核提供了两个新的结构体让我们使用
分别别:
UNICODE_STRING
ANSI_STRING

随便哪个结构体进行简介.

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

内核中的UNICODE_STRING其实是个结构体.
简介一下:
参数一: 字符串的字节数.不带\0结尾的字节数. 注意是字节
参数二: Buffer的最大字节数.如果Buffer存储字符串.那么字节数就是
wcslen(Buffer)+sizeof(wchar_t)也就是说说带\0结尾.
参数三: Buffer缓冲区.存放字符串的指针.

1.2字符串的操作函数

既然有了这些结构体.那么就会有相应的提供操作字符串的函数.
如我们在WDK文档查询这个结构体的时候.
下面就会有个 See Also告诉我们字符串操作相关的一系列函数.

函数名作用
RtlUnicodeStringInit安全的初始化UNICODE_STRING.不安全的有RtlinitUnicodeString.安全的动词放后面
RtlStringCbCopyUnicodeString将UNICODE_STRING按照字节大小,拷贝到一个wchar_t的缓冲区中
RtlUnicodeStringCat拼接一个UNICODE_STRIGN
RtlUnicodeStringCatString将UNICODE_STRING 拼接一个PCTSTR的字符串.
RtlUnicodeStringCbCatN都是传入两个UNICODE_STRING结构体.多了一个参数.这个参数指定你要拼接的字节数进行拼接.不用完整拼接了.

具体函数查询WDK帮助文档即可.

1.3UNICODE_STRING的使用

说的UNICODE_STRING的使用.这里需要注意一下.

1.3.1 在栈上初始化一个Buffer
UNICODE_STRING TestUCString = [0];
WCHAR wzData[0x100] = L"Hello World""

RtlInitUnicodeString(&TetUCString,wzData);

这样初始化的方式.是将UNICODE_STRING的 Buffer指针指向栈内存.

伪代码:
Buffer = wzData;
最重要的一点就是此时你可以使用Rtl拷贝函数对这个UNICODE_STRING进行操作了.
因为内存是有的.

RtlUnicodeStringCopyString是可以对这个内存进行拷贝的.

1.3.2 全局初始化
UNICODE_STRING ustr;
RtlUnicodeStringInit(&ustr,L"HelloWorld");

此时的UNICODE_STRING里面的Buffer指针是指向全局常量区的 HelloWorld的.所以此时你使用拷贝函数就会出错.很可能就会蓝屏

1.3.3堆上初始化一个缓冲区.

UNICODE_STRING ustr = {0};
ULONG length = (wcslen(L"HelloWorld") + ) * sizeof(WCHAR);
ustr.Buffer = ExAllocatePoolWithTag(PagedPool,MAX_PATH 8 sizeof(WCHAR),"niBI");

if (ustr.Buffer == NULL)
    return ;

清空缓存
RtlZeroMemory(ustr.Buffer,MAX_PATH *sizeof(WCHAR));

wcscpy(ustr.Buffer,L"HelloWorld");
ustr.length = length;
ustr.Maximumlength = MAX_PATH * sizeof(WCHAR);

DbgPrint("%wZ",&ustr);
ExFreePool(ustr.Buffer); 

上面的UNICODE_STRING 的Buffer指向一个堆内存.这个内存是我们分配的.

二丶内核中其它常用字符串函数的使用

2.1初始化UNICODE_STRING

初始化一个 UNICODE_STRING 字符串

UNICODE_STRING str;
RtlInitUnicodeString(&str,L"111");
RtlUnicodeStringInit(&str,L"111");

两种方法都可以,第二种是安全函数. 需要包含头文件 "ntstrsafe.h"

2.2拷贝字符串UNICODE_STRING

拷贝字符串分为你给不给UNICODE_STRING 分配内存跟不分配内存的拷贝.

不分配内存使用栈内存的分配

UNICODE_STRING str;

UNICODE_STRING dst;
UNICODE_STRING src = RTL_CONSTANT_STRING(L"HelloWorld");
wchar_t wzBuffer[512] = { 0 };

RtlInitEmptyUnicodeString(&dst, wzBuffer,512 * sizeof(WCHAR));
RtlCopyUnicodeString(&dst, &src);//将src UNICODE_STRING拷贝到dst
//RtlUnicodeStringcbCopyN();//这是将缓冲区拷贝给UNICODE_STRING的. 而不是U拷贝给U

上边两个遇到的定义分别都有源码,如下


char _RTL_CONSTANT_STRING_type_check(const void *s);
#define _RTL_CONSTANT_STRING_remove_const_macro(s) (s)
#endif
#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) \
}
这个其实就像相当于将一个WCHAR *给UNICODE_STRING

wrk的定义

#define RtlInitEmptyUnicodeString(_ucStr,_buf,_bufSize) \
    ((_ucStr)->Buffer = (_buf), \
     (_ucStr)->Length = 0, \
     (_ucStr)->MaximumLength = (USHORT)(_bufSize))
这个其实就是将缓冲区的地址,给UNICODE_STRING中的buff.并且长度置为0.
这里会有坑.虽然你的 u.buffer = wszBuffer.但是length=0;所以你拷贝的时候很可能会蓝屏.或者拷贝失败.原因就是长度为0.你拷贝一个东西也会去判断它的长度把.

2.3 字符串的拼接

字符串的拼接也是很常用的.
windows内核中提供了几个 Rtl函数供我们使用.


RtlAppenUnicodeToString();
RtlAppendUnicodeStringToString();
两个用法都是一样唯一不同就是第二个参数. 
函数1,是直接拼接一个 PWSTR字符串.也就是宽字符
函数2:是拼接一个UNICODE_STRING
    UNICODE_STRING dst;
    UNICODE_STRING src = RTL_CONSTANT_STRING(L"HelloWorld");
    wchar_t wzBuffer[512] = { 0 };

    RtlInitEmptyUnicodeString(&dst, wzBuffer,512 * sizeof(WCHAR));
    RtlCopyUnicodeString(&dst, &src);//将src UNICODE_STRING拷贝到dst

    RtlAppendUnicodeToString(&dst, L"123");
    RtlAppendUnicodeStringToString(&dst, &src);

2.4 字符串的格式化输出

在C/C++下.我们常用的格式化字符串是 sprintf swprintf wsprintf...
在内核中依然可以使用.但是windows内核为我们提供了Rtl函数所以可以不用它了.

如下:

RtlStringCbPrintW()

用法:


UNICODE_STRING dst;
UNICODE_STRING src = RTL_CONSTANT_STRING(L"HelloWorld");
char szbuffer[] = "111";
wchar_t wzBuffer[512] = { 0 };

RtlInitEmptyUnicodeString(&dst, wzBuffer,512 * sizeof(WCHAR));
RtlCopyUnicodeString(&dst, &src);//将src UNICODE_STRING拷贝到dst

RtlStringCbPrintfW(dst.Buffer,512*sizeof(WCHAR), L"%wZ %ws %s", &src, src.Buffer, szbuffer);

使用这个函数要注意返回值,如果超过缓冲区则会输出 STATUS_BUFFER_OVERFLOW

%wZ 输出UNICODE_STRING 字符
%ws 输出0结尾的宽字符
%s 输出0结尾的Ansi字符.

转载于:https://www.cnblogs.com/iBinary/p/10990678.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值