登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 27|回复: 0

Win64驱动开发教程06-内核里操作字符串

[复制链接]

79

主题

2

回帖

104

积分

网站编辑

积分
104
发表于 3 天前 | 显示全部楼层 |阅读模式
本帖最后由 天行健 于 2025-1-21 21:33 编辑

字符串本质上就是一段内存,之所以和内存使用分开讲,是因为内核里的字符串太有花样了,细数下来竟然有 4 种字符串!这四种字符串,分别是:CHAR*、WCHAR*、ANSI_STRING、UNICODE_STRING。当然,内核里使用频率最多的是 UNICODE_STRING,其次是 WCHAR*,再次是 CHAR*,而ANSI_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 都是结构体,定义如下:
  1. ypedef struct _ANSI_STRING {
  2. USHORT Length;
  3. USHORT MaximumLength;
  4. PCHAR Buffer;
  5. } ANSI_STRING, *PANSI_STRING;

  6. typedef struct _UNICODE_STRING {
  7. USHORT Length;
  8. USHORT MaximumLength;
  9. PWCHAR Buffer;
  10. } UNICODE_STRING, *PUNICODE_STRING;
复制代码


可以看到,ANSI_STRING 和 UNICODE_STRING 的结构体大小是一样的,唯一不同在于第三个成员,他们分别对应 CHAR*和 WCHAR*。它们的第一和第二个成员分别代表字符串的长度和内存的有效长度。比如 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),如果需要查询怎么使用,就用浏览器打开,搜索 AnsiString 或者 UnicodeString,并点击进去查看说明即可。关于CHAR*和 WCHAR*的字符串操作就不讲了,不懂的请看任意的 C 语言教程。下面举几个关于 UNICODE_STRING 的例子。
1.字符串初始化、2.字符串拷贝、3.字符串比较、4.字符串变大写、5.字符串与整型相互转化、6. ANSI_STRING 字符串与 UNICODE_STRING 字符串相互转换。
  1. //1.字符串初始化
  2. VOID StringInitTest()
  3. {
  4. //(1)用 RtlInitAnsiString 初始化字符串
  5. ANSI_STRING AnsiString1;
  6. CHAR * string1= "hello";
  7. //初始化 ANSI_STRING 字符串
  8. RtlInitAnsiString(&AnsiString1,string1);
  9. KdPrint(("AnsiString1:%Z\n",&AnsiString1));//打印 hello
  10. string1[0]='H';
  11. string1[1]='E';
  12. string1[2]='L';
  13. string1[3]='L';
  14. string1[4]='O';
  15. //改变 string1,AnsiString1 同样会导致变化
  16. KdPrint(("AnsiString1:%Z\n",&AnsiString1));//打印 HELLO
  17. //(2)程序员自己初始化字符串
  18. #define BUFFER_SIZE 1024
  19. UNICODE_STRING UnicodeString1 = {0};
  20. //设置缓冲区大小
  21. UnicodeString1.MaximumLength = BUFFER_SIZE;
  22. //分配内存
  23. UnicodeString1.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
  24. WCHAR* wideString = L"hello";
  25. //设置字符长度,因为是宽字符,所以是字符长度的 2 倍
  26. UnicodeString1.Length = 2*wcslen(wideString);
  27. //保证缓冲区足够大,否则程序终止
  28. ASSERT(UnicodeString1.MaximumLength>=UnicodeString1.Length);
  29. //内存拷贝,
  30. RtlCopyMemory(UnicodeString1.Buffer,wideString,UnicodeString1.Length);
  31. //设置字符长度
  32. UnicodeString1.Length = 2*wcslen(wideString);
  33. KdPrint(("UnicodeString:%wZ\n",&UnicodeString1));
  34. //清理内存
  35. ExFreePool(UnicodeString1.Buffer);
  36. UnicodeString1.Buffer = NULL;
  37. UnicodeString1.Length = UnicodeString1.MaximumLength = 0;
  38. }
复制代码
  1. //2.字符串拷贝
  2. VOID StringCopyTest()
  3. {
  4. //初始化 UnicodeString1
  5. UNICODE_STRING UnicodeString1;
  6. RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  7. //初始化 UnicodeString2
  8. UNICODE_STRING UnicodeString2={0};
  9. UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
  10. UnicodeString2.MaximumLength = BUFFER_SIZE;
  11. //将初始化 UnicodeString2 拷贝到 UnicodeString1
  12. RtlCopyUnicodeString(&UnicodeString2,&UnicodeString1);
  13. //分别显示 UnicodeString1 和 UnicodeString2
  14. KdPrint(("UnicodeString1:%wZ\n",&UnicodeString1));
  15. KdPrint(("UnicodeString2:%wZ\n",&UnicodeString2));
  16. //销毁 UnicodeString2
  17. //注意!!UnicodeString1 不用销毁
  18. RtlFreeUnicodeString(&UnicodeString2);
  19. }
复制代码
  1. //3.字符串比较
  2. VOID StringCompareTest()
  3. {
  4. //初始化 UnicodeString1
  5. UNICODE_STRING UnicodeString1;
  6. RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  7. //初始化 UnicodeString2
  8. UNICODE_STRING UnicodeString2;
  9. RtlInitUnicodeString(&UnicodeString1,L"Hello");
  10. if (RtlEqualUnicodeString(&UnicodeString1,&UnicodeString2,TRUE))
  11. KdPrint(("UnicodeString1 and UnicodeString2 are equal\n"));
  12. else
  13. KdPrint(("UnicodeString1 and UnicodeString2 are NOT equal\n"));
  14. }
复制代码
  1. //4.字符串变大写
  2. VOID StringToUpperTest()
  3. {
  4. //初始化 UnicodeString1
  5. UNICODE_STRING UnicodeString1;
  6. UNICODE_STRING UnicodeString2;
  7. RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  8. //变化前
  9. DbgPrint("UnicodeString1:%wZ\n",&UnicodeString1);
  10. //变大写
  11. RtlUpcaseUnicodeString(&UnicodeString2,&UnicodeString1,TRUE);
  12. //变化后
  13. DbgPrint("UnicodeString2:%wZ\n",&UnicodeString2);
  14. //销毁 UnicodeString2(UnicodeString1 不用销毁)
  15. RtlFreeUnicodeString(&UnicodeString2);
  16. }
复制代码
  1. //5.字符串与整型相互转化
  2. VOID StringToIntegerTest()
  3. {
  4. //(1)字符串转换成数字
  5. //初始化 UnicodeString1
  6. UNICODE_STRING UnicodeString1;
  7. RtlInitUnicodeString(&UnicodeString1,L"-100");
  8. ULONG lNumber;
  9. NTSTATUS nStatus = RtlUnicodeStringToInteger(&UnicodeString1,10,&lNumber);
  10. if ( NT_SUCCESS(nStatus))
  11. {
  12. KdPrint(("Conver to integer succussfully!\n"));
  13. KdPrint(("Result:%d\n",lNumber));
  14. }
  15. else
  16. {
  17. KdPrint(("Conver to integer unsuccessfully!\n"));
  18. }
  19. //(2)数字转换成字符串
  20. //初始化 UnicodeString2
  21. UNICODE_STRING UnicodeString2={0};
  22. UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
  23. UnicodeString2.MaximumLength = BUFFER_SIZE;
  24. nStatus = RtlIntegerToUnicodeString(200,10,&UnicodeString2);
  25. if ( NT_SUCCESS(nStatus))
  26. {
  27. KdPrint(("Conver to string succussfully!\n"));
  28. KdPrint(("Result:%wZ\n",&UnicodeString2));
  29. }
  30. else
  31. {
  32. KdPrint(("Conver to string unsuccessfully!\n"));
  33. }
  34. //销毁 UnicodeString2
  35. //注意!!UnicodeString1 不用销毁
  36. RtlFreeUnicodeString(&UnicodeString2);
  37. }
复制代码
  1. //6. ANSI_STRING 字符串与 UNICODE_STRING 字符串相互转换
  2. VOID StringConverTest()
  3. {
  4. //(1)将 UNICODE_STRING 字符串转换成 ANSI_STRING 字符串
  5. //初始化 UnicodeString1
  6. UNICODE_STRING UnicodeString1;
  7. RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  8. ANSI_STRING AnsiString1;
  9. NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString1,&UnicodeString1,TRUE);
  10. if ( NT_SUCCESS(nStatus))
  11. {
  12. KdPrint(("Conver succussfully!\n"));
  13. KdPrint(("Result:%Z\n",&AnsiString1));
  14. }
  15. else
  16. {
  17. KdPrint(("Conver unsuccessfully!\n"));
  18. }
  19. //销毁 AnsiString1
  20. RtlFreeAnsiString(&AnsiString1);
  21. //(2)将 ANSI_STRING 字符串转换成 UNICODE_STRING 字符串
  22. //初始化 AnsiString2
  23. ANSI_STRING AnsiString2;
  24. RtlInitString(&AnsiString2,"Hello World");
  25. UNICODE_STRING UnicodeString2;
  26. nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2,&AnsiString2,TRUE);
  27. if ( NT_SUCCESS(nStatus))
  28. {
  29. KdPrint(("Conver succussfully!\n"));
  30. KdPrint(("Result:%wZ\n",&UnicodeString2));
  31. }
  32. else
  33. {
  34. KdPrint(("Conver unsuccessfully!\n"));
  35. }
  36. //销毁 UnicodeString2
  37. RtlFreeUnicodeString(&UnicodeString2);
  38. }
复制代码
  1. //UNICODE_STRINGz 转换为 CHAR*
  2. //输入 UNICODE_STRING 的指针,输出窄字符串,BUFFER 需要已经分配好空间
  3. VOID UnicodeToChar(PUNICODE_STRING dst, char *src)
  4. {
  5. ANSI_STRING string;
  6. RtlUnicodeStringToAnsiString(&string,dst, TRUE);
  7. strcpy(src,string.Buffer);
  8. RtlFreeAnsiString(&string);
  9. }
复制代码
  1. //WCHAR*转换为 CHAR*
  2. //输入宽字符串首地址,输出窄字符串,BUFFER 需要已经分配好空间
  3. VOID WcharToChar(PWCHAR src, PCHAR dst)
  4. {
  5. UNICODE_STRING uString;
  6. ANSI_STRING aString;
  7. RtlInitUnicodeString(&uString,src);
  8. RtlUnicodeStringToAnsiString(&aString,&uString,TRUE);
  9. strcpy(dst,aString.Buffer);
  10. RtlFreeAnsiString(&aString);
  11. }
复制代码
  1. //CHAR*转 WCHAR*
  2. //输入窄字符串首地址,输出宽字符串,BUFFER 需要已经分配好空间
  3. VOID CharToWchar(PCHAR src, PWCHAR dst)
  4. {
  5. UNICODE_STRING uString;
  6. ANSI_STRING aString;
  7. RtlInitAnsiString(&aString,src);
  8. RtlAnsiStringToUnicodeString(&uString,&aString,TRUE);
  9. wcscpy(dst,uString.Buffer);
  10. RtlFreeUnicodeString(&uString);
  11. }
复制代码




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-1-24 19:38 , Processed in 0.054538 second(s), 26 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表