看流星社区

 找回密码
 注册账号
查看: 2120|回复: 0

Unicode_String Ansi_String 内核字符串操作

[复制链接]

该用户从未签到

发表于 2017-6-1 13:34:18 | 显示全部楼层 |阅读模式
  1. typedef struct _UNICODE_STRING {
  2.   USHORT  Length;//字节数,不是字符数 一定要* sizeof(WCHAR)
  3.   USHORT  MaximumLength;//字节数,不是字符数 一定要* sizeof(WCHAR)
  4.   PWSTR  Buffer;//非零结尾,中间也可能含有零
  5. } UNICODE_STRING, *PUNICODE_STRING;
复制代码
//常用函数
RtlInitUnicodeString(&uStr1, str1);//注意 这个函数并不是将str1拷贝到uStr1.buffer 而是将buffer指向str1 所以如果这个buffer是程序员为它分配的 那么不能释放 也不能为它分配 一是BSOD 二是内存泄露
RtlCopyUnicodeString(&uStr1, &uStr2);//需要注意这里copy uStr1的buffer必须自己分配 如果后面跟着的是常量
RtlAppendUnicodeToString(&uStr1, str1);//注意 uStr1的buffer必须自己分配
RtlAppendUnicodeStringToString(&uStr1, &uStr2);//注意 uStr1的buffer必须自己分配
RtlCompareUnicodeString(&uStr1, &uStr2, TRUE/FALSE);//比较 TRUE 指定大小写
RtlAnsiStringToUnicodeString(&uStr1, &aStr1, TRUE/FALSE);// TRUE 指定buffer系统分配 如果是TRUE 则用后需要调用RtlFreeUnicodeString
RtlFreeUnicodeString(&uStr1);


这些函数调用时系统会自动检测是否超过buffer 相对来说安全一些
  1. #include <ntstrsafe.h>
  2. RtlUnicodeStringInit(&uStr1, str1);
  3. RtlUnicodeStringCopy(&uStr1, &uStr2);
  4. RtlUnicodeStringCat(&uStr1, &uStr2);
  5. #define NTSTRSAFE_UNICODE_STRING_MAX_CCH    (0xffff / sizeof(wchar_t))  (32767个字符)
复制代码


快速初始化一个UnicodeString字符串
  1. DECLARE_CONST_UNICODE_STRING(ustrTest,L”Hello, world!”);
  2. //这个等同于
  3. UNICODE_STRING ustrTest = {0};
  4. WCHAR *szHello = L”Hello, world!”;
  5. RtlInitUnicodeString(&ustrTest, szHello);
  6. //Length:wcslen(szHello)*sizeof(WCHAR)
  7. //MaximumLength:(wcslen(szHello)+1)*sizeof(WCHAR);
复制代码
初始化方式:栈上buffer
  1. UNICODE_STRING ustrTest = {0};
  2. WCHAR szHello[512] = L”Hello, world!”;
  3. //Length:wcslen(szHello)*sizeof(WCHAR)
  4. //MaximumLength:(wcslen(szHello)+1)*sizeof(WCHAR);
  5. RtlInitUnicodeString(&ustrTest, szHello);
复制代码
或者
  1. UNICODE_STRING ustrTest = {0};
  2. WCHAR szHello[512] = L”Hello, world!”;
  3. ustrTest.Buffer = szHello;
  4. ustrTest.Length = wcslen(L”hello,world!”)*sizeof(WCHAR);
  5. ustrTest.MaximumLength = sizeof(szHello);
复制代码
初始化方式:堆上buffer
  1. UNICODE_STRING ustrTest = {0};
  2. ULONG ulLength = (wcslen(L"Hello world") + 1)*sizeof(WCHAR);
  3. ustrTest.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH*sizeof(WCHAR), 'POCU');
  4. if (ustrTest.Buffer == NULL)
  5. {
  6.         return;
  7. }
  8. RtlZeroMemory(ustrTest.Buffer, MAX_PATH*sizeof(WCHAR));
  9. wcscpy(ustrTest.Buffer, L"Hello, world");//必须使用内存拷贝类函数
  10. ustrTest.Length = ulLength;
  11. ustrTest.MaximumLength = MAX_PATH*sizeof(WCHAR);
  12. DbgPrint("%wZ\n", &ustrTest);
  13. ExFreePool(ustrTest.Buffer);//这样释放就没有问题啦
复制代码
下个这个演示了UnicodeString的一个蓝屏
  1. UNICODE_STRING ustrTest = {0};
  2. ustrTest.Buffer = ExAllocatePoolWithTag(PagedPool,
  3.                 (wcslen(L"Nice to meet u") + 1)*sizeof(WCHAR), 'POCU');
  4. if (ustrTest.Buffer == NULL)
  5. {
  6.         return;
  7. }
  8. RtlZeroMemory(ustrTest.Buffer, (wcslen(L"Hello, world") + 1)*sizeof(WCHAR));
  9. RtlInitUnicodeString(&ustrTest, L”Hello, world”);//这个时候userTest.buffer指向了hello wolrd的地址 导致了内存泄露 在下面调用ExFree的时候还会蓝屏
  10. DbgPrint("%wZ\n", & ustrTest);
  11. ExFreePool(ustrTest.Buffer); //蓝屏 释放常量区内存
复制代码
UNICODE_STRING常见问题
计算length的时候,少了*sizeof(WCHAR)
计算字符数的时候,少了/sizeof(WCHAR)
使用了wcscmp/wcscpy等函数操作
更长远的说,缓冲大小长度问题,就是驱动容易出错的问题
WCHAR wszPath[MAX_PATH];
MAX_PATH? MAX_PATH 在windows上是260 在linux是256
sizeof(wszPath)或者MAX_PATH*sizeof(WCHAR) 这才是字符长度
MAX_PATH*2? 也是可以的


使用Copy Append时目标的buffer不是自行分配的 必定失败 如下:
  1.         RtlInitUnicodeString(&uStr1, L"hello"); //直接将L"hello"字符串的指针赋给了uStr.Buffer;
  2.         RtlInitUnicodeString(&uStr2, L"Goodbye");
  3.         DbgPrint("%ws\n", L"hello world");
  4.         DbgPrint("uStr1=%wZ\n", &uStr1);
  5.         DbgPrint("uStr2=%wZ\n", &uStr2);
  6.         RtlInitAnsiString(&aStr1, "Ansi to unicode");
  7.         DbgPrint("aStr1=%Z\n", &aStr1);
  8.         RtlCopyUnicodeString(&uStr3, &uStr1);
  9.         DbgPrint("uStr3=%wZ\n", &uStr3);//失败
  10.         RtlAppendUnicodeToString(&uStr1, L"world");
  11.         DbgPrint("uStr1=%wZ\n", &uStr1);//失败
  12.         RtlAppendUnicodeStringToString(&uStr1, &uStr2);
  13.         DbgPrint("uStr1=%wZ\n", &uStr1);//失败
复制代码

缓冲大小的判断
//处理应用层的read()函数
  1. NTSTATUS DispatchRead (
  2.     IN PDEVICE_OBJECT        pDevObj,
  3.     IN PIRP        pIrp)
  4. {
  5.         NTSTATUS         status = STATUS_SUCCESS;
  6.         PVOID         userBuffer = NULL;
  7.         ULONG         xferSize = 0;
  8.         //获取IRP堆栈的当前位置
  9.         PIO_STACK_LOCATION pIrpStack =
  10.                 IoGetCurrentIrpStackLocation( pIrp );
  11.         //获取传输的字节数和缓冲
  12.         xferSize = pIrpStack->Parameters.Read.Length;
  13.         userBuffer = pIrp->AssociatedIrp.SystemBuffer;       
  14.         //从驱动中读数据
  15.         RtlCopyMemory( userBuffer, L"Hello, world",
  16.             xferSize );
  17.         //填写IRP中的完成状态,结束IRP操作,不向下层发送
  18.         pIrp->IoStatus.Status = status;
  19.         pIrp->IoStatus.Information = xferSize;
  20.         IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  21.         return status;
  22. }
复制代码


字符串本质上就是一段内存,之所以和内存使用分开讲,是因为内核里的字符串太有花
样了,细数下来竟然有 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. typedef 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,并点击进去查
看说明即可。


下面的来直张帆的书
下面举几个关于 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. }
  39. //2.字符串拷贝
  40. VOID StringCopyTest()
  41. {
  42.         //初始化 UnicodeString1
  43.         UNICODE_STRING UnicodeString1;
  44.         RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  45.         //初始化 UnicodeString2
  46.         UNICODE_STRING UnicodeString2={0};
  47.         UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
  48.         UnicodeString2.MaximumLength = BUFFER_SIZE;
  49.         //将初始化 UnicodeString2 拷贝到 UnicodeString1
  50.         RtlCopyUnicodeString(&UnicodeString2,&UnicodeString1);
  51.         //分别显示 UnicodeString1 和 UnicodeString2
  52.         KdPrint(("UnicodeString1:%wZ\n",&UnicodeString1));
  53.         KdPrint(("UnicodeString2:%wZ\n",&UnicodeString2));
  54.         //销毁 UnicodeString2
  55.         //注意!!UnicodeString1 不用销毁
  56.         RtlFreeUnicodeString(&UnicodeString2);
  57. }
  58. //3.字符串比较
  59. VOID StringCompareTest()
  60. {
  61.         //初始化 UnicodeString1
  62.         UNICODE_STRING UnicodeString1;
  63.         RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  64.         //初始化 UnicodeString2
  65.         UNICODE_STRING UnicodeString2;
  66.         RtlInitUnicodeString(&UnicodeString1,L"Hello");
  67.         if (RtlEqualUnicodeString(&UnicodeString1,&UnicodeString2,TRUE))
  68.                 KdPrint(("UnicodeString1 and UnicodeString2 are equal\n"));
  69.         else
  70.                 KdPrint(("UnicodeString1 and UnicodeString2 are NOT equal\n"));
  71. }
  72. //4.字符串变大写
  73. VOID StringToUpperTest()
  74. {
  75.         //初始化 UnicodeString1
  76.         UNICODE_STRING UnicodeString1;
  77.         UNICODE_STRING UnicodeString2;
  78.         RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  79.         //变化前
  80.         DbgPrint("UnicodeString1:%wZ\n",&UnicodeString1);
  81.         //变大写
  82.         RtlUpcaseUnicodeString(&UnicodeString2,&UnicodeString1,TRUE);
  83.         //变化后
  84.         DbgPrint("UnicodeString2:%wZ\n",&UnicodeString2);
  85.         //销毁 UnicodeString2(UnicodeString1 不用销毁)
  86.         RtlFreeUnicodeString(&UnicodeString2);
  87. }
  88. //5.字符串与整型相互转化
  89. VOID StringToIntegerTest()
  90. {
  91.         //(1)字符串转换成数字
  92.         //初始化 UnicodeString1
  93.         UNICODE_STRING UnicodeString1;
  94.         RtlInitUnicodeString(&UnicodeString1,L"-100");
  95.         ULONG lNumber;
  96.         NTSTATUS nStatus = RtlUnicodeStringToInteger(&UnicodeString1,10,&lNumber);
  97.         if ( NT_SUCCESS(nStatus))
  98.         {
  99.                 KdPrint(("Conver to integer succussfully!\n"));
  100.                 KdPrint(("Result:%d\n",lNumber));
  101.         }
  102.         else
  103.         {
  104.                 KdPrint(("Conver to integer unsuccessfully!\n"));
  105.        
  106.         }
  107.         //(2)数字转换成字符串
  108.         //初始化 UnicodeString2
  109.         UNICODE_STRING UnicodeString2={0};
  110.         UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
  111.         UnicodeString2.MaximumLength = BUFFER_SIZE;
  112.         nStatus = RtlIntegerToUnicodeString(200,10,&UnicodeString2);
  113.         if ( NT_SUCCESS(nStatus))
  114.         {
  115.                 KdPrint(("Conver to string succussfully!\n"));
  116.                 KdPrint(("Result:%wZ\n",&UnicodeString2));
  117.         }
  118.         else
  119.         {
  120.                 KdPrint(("Conver to string unsuccessfully!\n"));
  121.         }
  122.         //销毁 UnicodeString2
  123.         //注意!!UnicodeString1 不用销毁
  124.         RtlFreeUnicodeString(&UnicodeString2);
  125. }
  126. //6. ANSI_STRING 字符串与 UNICODE_STRING 字符串相互转换
  127. VOID StringConverTest()
  128. {
  129.         //(1)将 UNICODE_STRING 字符串转换成 ANSI_STRING 字符串
  130.         //初始化 UnicodeString1
  131.         UNICODE_STRING UnicodeString1;
  132.         RtlInitUnicodeString(&UnicodeString1,L"Hello World");
  133.         ANSI_STRING AnsiString1;
  134.         NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString1,&UnicodeString1,TRUE);
  135.         if ( NT_SUCCESS(nStatus))
  136.         {
  137.                 KdPrint(("Conver succussfully!\n"));
  138.                 KdPrint(("Result:%Z\n",&AnsiString1));
  139.         }
  140.         else
  141.         {
  142.                         KdPrint(("Conver unsuccessfully!\n"));
  143.         }
  144.         //销毁 AnsiString1
  145.         RtlFreeAnsiString(&AnsiString1);
  146.         //(2)将 ANSI_STRING 字符串转换成 UNICODE_STRING 字符串
  147.         //初始化 AnsiString2
  148.         ANSI_STRING AnsiString2;
  149.         RtlInitString(&AnsiString2,"Hello World");
  150.         UNICODE_STRING UnicodeString2;
  151.         nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2,&AnsiString2,TRUE);
  152.         if ( NT_SUCCESS(nStatus))
  153.         {
  154.                 KdPrint(("Conver succussfully!\n"));
  155.                 KdPrint(("Result:%wZ\n",&UnicodeString2));
  156.         }
  157.         else
  158.         {
  159.                 KdPrint(("Conver unsuccessfully!\n"));
  160.         }
  161.         //销毁 UnicodeString2
  162.         RtlFreeUnicodeString(&UnicodeString2);
  163. }
复制代码

下面三个来自TA
  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. }
  10. //WCHAR*转换为 CHAR*
  11. //输入宽字符串首地址,输出窄字符串,BUFFER 需要已经分配好空间
  12. VOID WcharToChar(PWCHAR src, PCHAR dst)
  13. {
  14.         UNICODE_STRING uString;
  15.         ANSI_STRING aString;
  16.         RtlInitUnicodeString(&uString,src);
  17.         RtlUnicodeStringToAnsiString(&aString,&uString,TRUE);
  18.         strcpy(dst,aString.Buffer);
  19.         RtlFreeAnsiString(&aString);
  20. }
  21. //CHAR*转 WCHAR*
  22. //输入窄字符串首地址,输出宽字符串,BUFFER 需要已经分配好空间
  23. VOID CharToWchar(PCHAR src, PWCHAR dst)
  24. {
  25.         UNICODE_STRING uString;
  26.         ANSI_STRING aString;
  27.         RtlInitAnsiString(&aString,src);
  28.         RtlAnsiStringToUnicodeString(&uString,&aString,TRUE);
  29.         wcscpy(dst,uString.Buffer);
  30.         RtlFreeUnicodeString(&uString);
  31. }
复制代码


CharToUnicode(CHAR*转 UNICODE_STRING)函数怎么写?


//待定
  1. VOID CharToUnicode(PCHAR src,PUNICODE_STRING dst)
  2. {
  3.         ANSI_STRING aString;
  4.         RtlInitAnsiString(&aString,src);
  5.         RtlAnsiStringToUnicodeString(dst,&aString,FALSE);
  6. }
复制代码


下面还有用于安全开发的,转来的

一、前言
大量的系统安全问题是由于薄弱的缓冲处理以及由此产生的缓冲区溢出造成的,而薄弱的缓冲区处理常常与字符串操作相关。c/c++语言运行库提供的标准字符串操作函数(strcpy, strcat, sprintf等)不能阻止在超出字符串尾端的写入。
基于Windows XP SP1以及随后的操作系统的Windows DDK版本提供了安全字符串函数(<em>safe string functions</em>)。这类函数被设计的目的是用来取代相同功能的c/c&#43;&#43;标准函数和其它微软提供的库函数。这类函数具有以下特征:
<ul type="disc" style="color:rgb(75,75,75)">
每个函数以目标缓冲区所占的字节大小作为其一个输入参数,因此可以保证在写入时不会超出缓冲区末端。每个函数的输出字符串均以NULL结尾(null-terminate),即使该函数可能会对正确的结果进行截断。所有函数均有返回&#20540;,类型为NTSTATUS,只有返回STATUS_SUCCESS时,操作结果才正确。每个函数均有两种类型的版本,按字节或者按字符数。例如,RtlStringCbCatW和RtlStringCchCatW。每个函数均有支持双字节的unicode字符(以W作为后缀)和单字节的ANSI字符(以A作为后缀)的版本。例如:RtlStringCbCatW和RtlStringCbCatA。大部分函数有提供扩展版本的函数(以Ex作为后缀),例如,RtlStringCbCatW和RtlStringCbCatExW。
二、如何在内核驱动代码中引入安全字符串函数
有两种方式可以引入安全字符串函数:
l以内联的方式引入,包含在ntstrsafe.h中
l在链接时以库的方式引入
其中,如果代码需要在系统为Windows XP及以后版本运行时,可以使用内联的方式;如果代码需要运行在早于Windows XP时,则必须使用链接库的方式。
以内联方式引入
只需包含头文件即可
#include&lt;ntstrsafe.h&gt;
以链接库的方式
<ol type="1" style="color:rgb(75,75,75)">
在包含头文件之前先定义宏</ol>
#defineNTSTRSAFE_LIB
#include&lt;ntstrsafe.h&gt;
<ol type="1" start="2" style="color:rgb(75,75,75)">
在项目的sources文件中,添加一TARGETLIBS条目如下:$(DDK_LIB_PATH)\ntstrsafe.lib.</ol>
在默认情况下,当引入了安全字符串函数后,那些被取代的c/c&#43;&#43;运行库函数将变得无效,编译是会报错,提示需要使用安全字符串函数。
如果还希望继续使用c/c&#43;&#43;运行库函数,即在使用安全字符串函数的时候,c/c&#43;&#43;运行库函数还可以继续使用,则需要在包含<em>ntstrsafe.h</em>之前先定义宏NTSTRSAFE_NO_DEPRECATE
#defineNTSTRSAFE_NO_DEPRECATE
The maximum number of characters that any ANSI or Unicode string can contain is STRSAFE_MAX_CCH. This constant is defined in<em>ntstrsafe.h</em>.
字符串最长长度为STRSAFE_MAX_CCH,该宏在<em>ntstrsafe.h</em>中定义。另外,如果一个字符串需要被转换成UNICODE_STRING结构,则该字符串长度不能超过65535.
三、内核模式安全字符串函数概述
下表概述了可以在内核驱动中使用的安全字符串函数,并指明了它们用来何种类型的c/c&#43;&#43;运行库函数。
说明:
函数名含有Cb的是以字节数为单位,含有Cch的是以字符数为单位。




函数名


作用


取代




RtlStringCbCat
RtlStringCbCatEx
RtlStringCchCat
RtlStringCchCatEx


将源字符串连接到目的字符串的末尾


strcat
wcscat




RtlStringCbCatN
RtlStringCbCatNEx
RtlStringCchCatN
RtlStringCchCatNEx


将源字符串指定数目的字符连接到目的字符串的末尾


strncat
wcsncat




RtlStringCbCopy
RtlStringCbCopyEx
RtlStringCchCopy
RtlStringCchCopyEx


将源字符串拷贝到目的字符串


strcpy
wcscpy




RtlStringCbCopyN
RtlStringCbCopyNEx
RtlStringCchCopyN
RtlStringCchCopyNEx


将源字符串指定数目的字符拷贝到目的字符串


strncpy
wcsncpy




RtlStringCbLength
RtlStringCchLength


确定字符串的长度


strlen
wcslen




RtlStringCbPrintf
RtlStringCbPrintfEx
RtlStringCchPrintf
RtlStringCchPrintfEx


&#26684;式化输出


sprintf
swprintf
_snprintf
_snwprintf




RtlStringCbVPrintf
RtlStringCbVPrintfEx
RtlStringCchVPrintf
RtlStringCchVPrintfEx


可变&#26684;式化输出


vsprintf
vswprintf
_vsnprintf
_vsnwprintf




各个函数的作用可以通过它所取代的c/c&#43;&#43;函数可以大概看出,具体用法请查阅DDK帮助文档。
http://www.cppblog.com/aurain/archive/2009/09/27/97363.html
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 17:43

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

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