类型
windows 内核有四种字符串类型
- CHAR
- WCHAR
- UNICODE_STRING
- ANSI_STRING
CHAR 和WCHAR是以NULL结尾的字符串类型,UNICODE_STRING和ANSI_STRING是字符串结构体
除此之外,还可以使用一些C语言的字符串函数 ,如: strstr(),strlen(),strcpy(),
UNICODE_STRING
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
#else // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PWCH Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
UNICODE_STRING 包含3个成员
- Length:Buffer成员指向的buffer 占用了多少给字节,
- 等于字符长度乘以字符数,单位为字节
- Length 不代表字符串有多少个字符
- MaximumLength:字符缓冲区分配的内存字节数。
- Buffer:指向WCHAR(宽字符)的指针
初始化UNICODE_STRING
使用 RTL_CONSANT_STRING 的宏初始化
UNICODE_STRING string = RTL_CONSTANT_STRING(L"hello driver\r\n");
DbgPrint("%wZ",&string);
DbgPrint() 函数 使用 “%wZ” 来指明打印内容为UNICODE_SSTRING,函数需要传递一个UNICODE_STRING类型的指针
RtlInitUnicodeString
UNICODE_STRING string2 = { 0 };
RtlInitUnicodeString(&string2,L"hello driver2\r\n");
DbgPrint("%wZ",&string2);
需要先将 UNICODE_STRING结构体赋值为0,再用函数初始化
手动初始化
UNICODE_STRING string3;
WCHAR strbuffer[120] = {0};
string3.Buffer = strbuffer;
string3.MaximumLength = sizeof(WCHAR) * 120;
string3.Length = wcslen(L"hello driver3\r\n") * sizeof(WCHAR);
wcscpy(string3.Buffer,L"hello driver3\r\n");
DbgPrint("%wZ",&string3);
不过要注意的是strcpy 只能操作以null结尾的字符串
完整代码
#include <ntddk.h>
VOID Unload(IN PDRIVER_OBJECT DriverObject) {
DbgPrint("driver unload\r\n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegisteryPath) {
DriverObject->DriverUnload = Unload;
UNICODE_STRING string1 = RTL_CONSTANT_STRING(L"hello driver1\r\n");
DbgPrint("%wZ",&string1);
UNICODE_STRING string2 = { 0 };
RtlInitUnicodeString(&string2,L"hello driver2\r\n");
DbgPrint("%wZ",&string2);
UNICODE_STRING string3;
WCHAR strbuffer[120] = {0};
string3.Buffer = strbuffer;
string3.MaximumLength = sizeof(WCHAR) * 120;
string3.Length = wcslen(L"hello driver3\r\n") * sizeof(WCHAR);
wcscpy(string3.Buffer,L"hello driver3\r\n");
DbgPrint("%wZ",&string3);
return STATUS_SUCCESS;
}
ANSI_STRING
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength), length_is(Length) ]
#endif // MIDL_PASS
_Field_size_bytes_part_opt_(MaximumLength, Length) PCHAR Buffer;
} STRING;
typedef STRING *PSTRING;
typedef STRING ANSI_STRING;
和 UNICODE_STRING有相同的结构体,但是buffer指向的是一个asiic 字符串,一个字节一个字符。
这意味着 Length 表示这个字符串有多少个字符
字符串操作
复制
WCHAR strbuf[60] = { 0 };
UNICODE_STRING sourecstring = RTL_CONSTANT_STRING(L"hello driver \r\n");
UNICODE_STRING deststring = { 0 };
deststring.Buffer = strbuf;
deststring.Length = deststring.MaximumLength = 60;
RtlCopyUnicodeString(&deststring,&sourecstring);
DbgPrint("%wZ",&deststring);
字符串转为大写
- 使用RtlUpcaseUnicodeString 函数来转换
- 此函数不会改变原来的字符,而会将转换后的字符串写入新的缓冲区
- 第三个参数为 true ,函数会为我们申请新缓冲区
使用完后需要用 RtlFreeUnicodeString 来释放内存
UNICODE_STRING sourecstring = RTL_CONSTANT_STRING(L"hello driver \r\n");
UNICODE_STRING deststring = { 0 };
RtlUpcaseUnicodeString(&deststring, &sourecstring, TRUE);
DbgPrint("%wZ",&deststring);
RtlFreeUnicodeString(&deststring);
将unicode 转为ansi 字符
与上一个函数一样,不过要注意
- 函数会返回一个NT_STATUS 的状态码,返回false 代表转换是失败
- 使用后需要释放内存
- DbgPrint 需要改为 “ Z” ```c UNICODE_STRING sourecstring = RTL_CONSTANT_STRING(L”hello driver \r\n”); ANSI_STRING deststring = { 0 }; NTSTATUS status;
status =RtlUnicodeStringToAnsiString(&deststring, &sourecstring, TRUE);
if (NT_SUCCESS(status))
{
DbgPrint("%Z",&deststring);
RtlFreeAnsiString(&deststring);
}
<a name="U01LC"></a>
## 比较字符串
```c
UNICODE_STRING sourecstring = RTL_CONSTANT_STRING(L"hello driver");
UNICODE_STRING deststring = RTL_CONSTANT_STRING(L"hrllo");
if (RtlEqualUnicodeString(&sourecstring,&deststring,TRUE))
{
DbgPrint("two string are equals\r\n");
}
else
{
DbgPrint("two string are not equal\r\n");
}
RtlEqualUnicodeString 最后一个参数是 是否大小写敏感
相等返回true,不相等返回false
字符串copy
UNICODE_STRING sourecstring = RTL_CONSTANT_STRING(L"hello driver");
WCHAR string[50] = { 0 };
wcsncpy(string, sourecstring.Buffer, sourecstring.Length);
DbgPrint("string is :%ws",string);
因为unicode_string 不是以null 结尾的,所以直接使用wcscpy 会有风险,我们要使用wscncpy 指定copy大小
字符串长度
PWCHAR string = L"hello driver";
ULONG length;
length = wcsnlen(string, 50);
if (length==50)
{
//do something
}
DbgPrint("length is :%d",length);
wcslen 是以null 为结尾统计的,如果字符串后门没有null ,会一直统计下去
我们需要wcsnlen 来代替wcslen,函数指定最大统计数