Windows 内核字符串

UNICODE_STRING 结构

Unicode 字符串的结构定义如下

typedef struct _UNICODE_STRING {
    USHORT Length;            // 字符串长度(Byte)
    USHORT MaxiumLength;    // 字符缓冲区长度(Byte)
    PWSTR Buffer;            // 字符串缓冲区
} UNICODE_STRING, *PUNICODE_STRING

需要注意的是 UNICODE_STRING 结构中的缓冲区 Buffer 并不一定保证是以 '\0' 空字符结束的,所以最好不要使用传统的字符串函数对其进行操作

内核字符串相关的 API

这里笔者写出一些常用的内核字符串的 API,关于字符串的初始化、拷贝、连接(追加)和格式化输出。

字符串的初始化

  • RTL_CONSTANT_STRING 宏
    此宏用于根据显式指定的字符串来初始化一个 UNICODE_STRING 字符串
#include <ntdef.h>
UNICODE_STRING str = RTL_CONSTANT_STRING(L"this is my string");

需要注意的是 RTL_CONSTANT_STRING 宏只能用于 UNICODE_STRING 结构变量的定义式。

  • RtlInitUnicodeString 函数
    此函数用于根据显式指定的字符串来初始化一个 UNICODE_STRING 字符串
UNICODE_STRING str;
RtlInitUnicodeString(&str, L"this is my string");
  • RtlInitEmptyString 函数
    此函数用于根据指定的缓冲区空间来初始化一个 UNICODE_STRING 空字符串,与前两者不同之处在于,此函数将需要分配额外的内存缓冲区空间(在栈上或者在堆上)
UNICODE_STRING str;
WCHAR buff[256];    // 定义缓冲区空间,256 * sizeof(WCHAR) 共 512 字节

// 使用自定义的缓冲区空间 buff 来初始化字符串 str,第三个参数即缓冲区空间大小(字节数)
RtlInitEmptyString(&str, buff, 256 * sizeof(WCHAR));

字符串的拷贝

  • RtlCopyUnicodeString 函数
    此函数用于将源字符串拷贝至目标字符串(当然,这里说的是深拷贝)
UNICODE_STRING dest_str;
WCHAR dest_buff[256];    // 定义缓冲区空间,256 * sizeof(WCHAR) 共 512 字节

// 用显式指定的字符串来初始化源字符串
UNICODE_STRING src_str = RTL_CONSTANT_STRING(L"this is source string");

// 把目标字符串初始化为缓冲区为 dest_buff 的空字符串,大小为 256 * sizeof(WCHAR)
RtlInitEmptyString(&dest_str, dest_buff, 256 * sizeof(WCHAR));
RtlCopyUnicodeString(&dest_str, &src_str); // 字符串拷贝

需要注意的是,使用 RtlCopyUnicodeString 函数拷贝字符串的时候,如果目标字符串的缓冲区最大长度小于源字符串的长度,拷贝时字符串将被截短,这取决于目标字符串的缓冲区最大长度。

字符串的连接(追加)

  • RtlAppendUnicodeToString 函数
    此函数用于将显式指定的字符串追加到目标 UNICODE_STRING 字符串的末尾,在如下示例代码中,dest_str 是 UNICODE_STRING 结构,函数第二个参数即显式指定的源字符串
NTSTATUS status; // NTSTATUS 枚举

// 如果成功,将返回 STATUS_SUCCESS,缓冲区不够则返回 STATUS_BUFFER_TOO_SMALL
status = RtlAppendUnicodeToString(&dest_str, L"this is a string which you want to append");
  • RtlAppendUnicodeStringToString 函数
    此函数用于将源 UNICODE_STRING 字符串追加到目标 UNICODE_STRING 字符串的末尾,在如下示例代码中,dest_str 与 src_str 都是 UNICODE_STRING 结构
NTSTATUS status; // NTSTATUS 枚举

// 如果成功,将返回 STATUS_SUCCESS,缓冲区不够则返回 STATUS_BUFFER_TOO_SMALL
status = RtlAppendUnicodeToString(&dest_str, &src_str);

字符串的格式化输出

  • RtlStringCbPrintfW 函数
#include <ntstrsafe.h>

// 暂且把缓冲区定义在栈中
WCHAR dest_buff[512] = { 0 };
UNICODE_STRING dest;
NTSTATUS status;        // NTSTATUS 枚举

/* ...... */

// 字符串初始化为指定缓冲区为 buff 的空字符串,缓冲区长度为 512 * sizeof(WCHAR)
RtlInitEmptyString(&dest, dest_buff, 512 * sizeof(WCHAR));

// 调用 RtlStringCbPrintfW 函数进行字符串格式化输出,其中 filepath 是个 UNICODE_STRING 结构
// 使用格式化符 %wZ 可以直接打印出 UNICODE_STRING 结构的字符串
status = RtlStringCbPrintfW(dest.Buffer, 512 * sizeof(WCHAR), 
                         L"file path = %wZ, file size = %d \r\n", 
                         &file_path, file_size);

// 这里调用 wcslen 函数没有问题,因为 RtlStringCbPrintfW 打印的字符串以 '\0' 结束
dest.Length = wcslen(dest.Buffer) * sizeof(WCHAR); // 字节数

RtlStringCbPrintfW 函数需要包含 ntstrsafe.h 头文件,链接的时候需要链接库 ntsafestr.lib。如果在目标缓冲区空间不足的情况下,此函数将对字符串进行截短,并返回 STATUS_BUFFER_OVERFLOW。

📅 更新时间:2019/05/24 Friday 07:56

🖊️ 本文由 Alone Café 创作,如果您觉得本文让您有所收获,请随意赞赏 🥺
⚖️ 本文以 CC BY-NC-SA 4.0,即《署名-非商业性使用-相同方式共享 4.0 国际许可协议》进行许可
👨‍⚖️ 本站所发表的文章除注明转载或出处外,均为本站作者原创或翻译,转载前请务必署名并遵守上述协议
🔗 原文链接:https://alone.cafe/2019/05/windows内核字符串
📅 最后更新:2019年05月24日 Friday 07:56

评论

Your browser is out of date!

Update your browser to view this website correctly. Update my browser now

×