avatar

内存中操作字符串

内存中操作字符串

字符串本质上就是一段内存

CHAR* (字符指针类型) WCHAR* (wchar_t所能表示的字符数远超char型)ANSI_STRING UNICODE_STRING

ANSI_STRING可以看成是CHAR* 的安全性扩展,UNICODE_STRING 可以看成是 WCHAR* 的安全性扩展,CHAR* ,可以理解成 CHAR 数组,本 质上来说是一个地址,它的有效长度是多少?不知道。字符串有多长?不清楚,遇到\0 就 当成是字符串的结尾。综上所述,CHAR* 的安全性是非常糟糕的,如果内核使用 CHAR* 作为 主要字符串,那么会非常不稳定

WCHAR* 和 CHAR类似,和 CHAR的唯一不同在于一个 WCHAR 占 2 个字节,而一个 CHAR 只占 1 个字节。所以,WCHAR*的安全性也是非常糟糕 的。微软为了安全性着想,推出了这两种字符串的扩展集,ANSI_STRING和UNICODE_STRING。 ANSI_STRING 和 UNICODE_STRING 都是结构体,定义如下:

ANSI_STRING UNICODE_STRING
typedef struct _ANSI_STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } ANSI_STRING, *PANSI_STRING; tyoedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWCHAR Buffer; } UNICODE_STRING, *PUNICODE_STRING;

它们的第一和第二个成员分别代表字符串的长 度和内存的有效长度,比如 BUFFER 的长度是 260 字节,而 BUFFER 只是一个单词”FUCK”, 则 ANSI_STRING 的 Length=4、MaximumLength=260;UNICODE_STRING 的 Length=8、 MaximumLength=260,,CHAR * 和 WCHAR * 都是以 0 结尾的(CHAR* 以 1 个 \0 结尾,WCHAR*以 2 个\0 结尾),但 ANSI_STRING 和 UNICODE_STRING 不一定以 0 结 尾。因为有了长度的说明,就不需要用特殊标识符来表示结尾了。有些自以为是的人直接把 ANSI_STRING 或 UNICODE_STRING 的 BUFFER 当作字符串用,是不对的

在内核里,大部分的 C 语言字符串函数都是可以用的,无论是宽版的还是窄版的。比如 内核里可以照样使用 strcpy 和 wcscpy,但某些字符串函数签名可能要加上一个下划线。比 如 strlwr 要写成_strlwr。ANSI_STRING 和 UNICODE_STRING 有一套专门的字符串函数

查看:http://msdn.microsoft.com/en-us/library/windows/hardware/ff563638(v=vs.85).aspx

1.字符串初始化、2.字符串拷贝、3.字符串比较、4.字符串变大写、5.字符串与整型相 互转化、6. ANSI_STRING 字符串与 UNICODE_STRING 字符串相互转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <ntddk.h>
#include <intrin.h >
//1.字符串初始化
VOID StringInitTest()
{
//(1)用RtlInitAnsiString初始化字符串
{
ANSI_STRING AnsiString1;
CHAR* string1 = "hello";
//初始化ANSI_STRING字符串
RtlInitAnsiString(&AnsiString1, string1);
DbgPrint("AnsiString1:%Z\n", &AnsiString1);//打印hello
/*string1[0] = 'H';
string1[1] = 'E';
string1[2] = 'L';
string1[3] = 'L';
string1[4] = 'O';*/
//改变string1,AnsiString1同样会导致变化
DbgPrint("AnsiString1:%Z\n", &AnsiString1);//打印HELLO
}
//(2)程序员自己初始化字符串
{
#define BUFFER_SIZE 1024
UNICODE_STRING UnicodeString1 = { 0 };
WCHAR* wideString = L"hello";
//设置缓冲区大小
UnicodeString1.MaximumLength = BUFFER_SIZE;
//分配内存
UnicodeString1.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
//设置字符长度,因为是宽字符,所以是字符长度的2倍
UnicodeString1.Length = 2 * wcslen(wideString);
//保证缓冲区足够大,否则程序终止
ASSERT(UnicodeString1.MaximumLength >= UnicodeString1.Length);
//内存拷贝,
RtlCopyMemory(UnicodeString1.Buffer, wideString, UnicodeString1.Length);
//设置字符长度
UnicodeString1.Length = 2 * wcslen(wideString);
DbgPrint("UnicodeString:%wZ\n", &UnicodeString1);
//清理内存
ExFreePool(UnicodeString1.Buffer);
UnicodeString1.Buffer = NULL;
UnicodeString1.Length = UnicodeString1.MaximumLength = 0;
}
}

//2.字符串拷贝
VOID StringCopyTest()
{
UNICODE_STRING UnicodeString1;
UNICODE_STRING UnicodeString2 = { 0 };
//初始化UnicodeString1
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
//初始化UnicodeString2
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
UnicodeString2.MaximumLength = BUFFER_SIZE;
//将初始化UnicodeString2拷贝到UnicodeString1
RtlCopyUnicodeString(&UnicodeString2, &UnicodeString1);
//分别显示UnicodeString1和UnicodeString2
DbgPrint("UnicodeString1:%wZ\n", &UnicodeString1);
DbgPrint("UnicodeString2:%wZ\n", &UnicodeString2);
//销毁UnicodeString2(UnicodeString1不用销毁)
RtlFreeUnicodeString(&UnicodeString2);
}

//3.字符串比较
VOID StringCompareTest()
{
UNICODE_STRING UnicodeString1;
UNICODE_STRING UnicodeString2;
//初始化UnicodeString1
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
//初始化UnicodeString2
RtlInitUnicodeString(&UnicodeString1, L"Hello");
if (RtlEqualUnicodeString(&UnicodeString1, &UnicodeString2, TRUE))
DbgPrint("UnicodeString1 and UnicodeString2 are equal\n");
else
DbgPrint("UnicodeString1 and UnicodeString2 are NOT equal\n");
}

//4.字符串变大写
VOID StringToUpperTest()
{
//初始化UnicodeString1
UNICODE_STRING UnicodeString1;
UNICODE_STRING UnicodeString2;
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
//变化前
DbgPrint("UnicodeString1:%wZ\n", &UnicodeString1);
//变大写
RtlUpcaseUnicodeString(&UnicodeString2, &UnicodeString1, TRUE);
//变化后
DbgPrint("UnicodeString2:%wZ\n", &UnicodeString2);
//销毁UnicodeString2(UnicodeString1不用销毁)
RtlFreeUnicodeString(&UnicodeString2);
}

//5.字符串与整型相互转化
VOID StringToIntegerTest()
{
//(1)字符串转换成数字
{
UNICODE_STRING UnicodeString1;
ULONG lNumber;
NTSTATUS nStatus;
//初始化UnicodeString1
RtlInitUnicodeString(&UnicodeString1, L"-100");
nStatus = RtlUnicodeStringToInteger(&UnicodeString1, 10, &lNumber);
if (NT_SUCCESS(nStatus))
{
DbgPrint("Conver to integer succussfully!\n");
DbgPrint("Result:%d\n", lNumber);
}
else
{
DbgPrint("Conver to integer unsuccessfully!\n");
}
}
//(2)数字转换成字符串
{
NTSTATUS nStatus;
UNICODE_STRING UnicodeString2 = { 0 };
//初始化UnicodeString2
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
UnicodeString2.MaximumLength = BUFFER_SIZE;
nStatus = RtlIntegerToUnicodeString(200, 10, &UnicodeString2);
if (NT_SUCCESS(nStatus))
{
DbgPrint("Conver to string succussfully!\n");
DbgPrint("Result:%wZ\n", &UnicodeString2);
}
else
{
DbgPrint("Conver to string unsuccessfully!\n");
}
//销毁UnicodeString2
//注意!!UnicodeString1不用销毁
RtlFreeUnicodeString(&UnicodeString2);
}
}

//6. ANSI_STRING字符串与UNICODE_STRING字符串相互转换
VOID StringConverTest()
{
//(1)将UNICODE_STRING字符串转换成ANSI_STRING字符串
UNICODE_STRING UnicodeString1;
ANSI_STRING AnsiString1;
NTSTATUS nStatus;
//初始化UnicodeString1
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
nStatus = RtlUnicodeStringToAnsiString(&AnsiString1, &UnicodeString1, TRUE);
if (NT_SUCCESS(nStatus))
{
DbgPrint("Conver succussfully!\n");
DbgPrint("Result:%Z\n", &AnsiString1);
}
else
{
DbgPrint("Conver unsuccessfully!\n");
}
//销毁AnsiString1
RtlFreeAnsiString(&AnsiString1);
//(2)将ANSI_STRING字符串转换成UNICODE_STRING字符串
{
ANSI_STRING AnsiString2;
UNICODE_STRING UnicodeString2;
NTSTATUS nStatus;
//初始化AnsiString2
RtlInitString(&AnsiString2, "Hello World");
nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2, &AnsiString2, TRUE);
if (NT_SUCCESS(nStatus))
{
DbgPrint("Conver succussfully!\n");
DbgPrint("Result:%wZ\n", &UnicodeString2);
}
else
{
DbgPrint("Conver unsuccessfully!\n");
}
//销毁UnicodeString2
RtlFreeUnicodeString(&UnicodeString2);
}
}

//UNICODE_STRINGz转换为CHAR*
//输入UNICODE_STRING的指针,输出窄字符串,BUFFER需要已经分配好空间
VOID UnicodeToChar(PUNICODE_STRING dst, char* src)
{
ANSI_STRING string;
RtlUnicodeStringToAnsiString(&string, dst, TRUE);
strcpy(src, string.Buffer);
RtlFreeAnsiString(&string);
}
//WCHAR*转换为CHAR*
//输入宽字符串首地址,输出窄字符串,BUFFER需要已经分配好空间
VOID WcharToChar(PWCHAR src, PCHAR dst)
{
UNICODE_STRING uString;
ANSI_STRING aString;
RtlInitUnicodeString(&uString, src);
RtlUnicodeStringToAnsiString(&aString, &uString, TRUE);
strcpy(dst, aString.Buffer);
RtlFreeAnsiString(&aString);
}
//CHAR*转WCHAR*
//输入窄字符串首地址,输出宽字符串,BUFFER需要已经分配好空间
VOID CharToWchar(PCHAR src, PWCHAR dst)
{
UNICODE_STRING uString;
ANSI_STRING aString;
RtlInitAnsiString(&aString, src);
RtlAnsiStringToUnicodeString(&uString, &aString, TRUE);
wcscpy(dst, uString.Buffer);
RtlFreeUnicodeString(&uString);
}


VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint("[MyDriver]Unloaded...\n");
return;
}

/*KIRQL WPOFFx64()
{
//KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);//将值Data写入 CR0 寄存器
_disable();//禁用中断
return 0;
}*/

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
//WPOFFx64();
DriverObject->DriverUnload = DriverUnload;
DbgPrint("[MyDriver]Loaded...\n");
StringInitTest();
StringCopyTest();
StringCompareTest();
StringToUpperTest();
StringToIntegerTest();
StringConverTest();
return STATUS_SUCCESS;
}

image-20200305223419119

Author: L0x1c
Link: https://l0x1c.github.io/2020/04/26/2020-3-05/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶