使用安全字符串函数

 

在驱动程序中帮助防止缓冲区溢出,使用安全字符串函数

内核模式驱动程序中的缓冲区溢出增加了可能导致系统崩溃的缺陷和内存池破坏风险,也增加了攻击者可以利用的安全漏洞。字符串处理操作是缓冲区溢出的常见根源,大部分是由于 C/C++ 语言运行时库提供的标准字符串处理函数(strcatstrcpysprintf 等)不会阻止超出缓冲区结尾的写入操作。

使用内核模式安全字符串函数而不是标准字符串处理函数来消除驱动程序中许多潜在的缓冲区溢出。内核模式安全字符串函数在 Ntstrsafe.h 中定义;在 Windows XP SP1 和更高版本的 Windows 的 Windows DDK 中提供了此头文件和关联的库 (Ntstrsafe.lib)。(用户模式应用程序中对应的安全字符串函数集合在 Strsafe.h 中定义。关于这些函数的更多信息,请参见 Platform SDK。)

内核模式安全字符串函数将目标缓冲区的大小作为输入参数,来确保函数的写入操作不会超过缓冲区结尾。这些函数还用 null 终结符终止所有输出字符串,以避免丢失的 null 终结符导致的问题。为了使得检查返回值更简加单和一致,所有的安全字符串函数都返回只有一个可能的成功码的 NTSTATUS 值 (STATUS_SUCCESS)。

每个内核模式安全字符串都可以在字节计数和字符计数版本(RtlStringCbXxxRtlStringCchXxx)以及双字节 Unicode 字符和单字节 ANSI 字符版本(RtlStringXxxWRtlStringXxxA)中使用,这使得处理混合 Unicode 和 ANSI 的字符串更容易。大部分函数也可以在提供了高级功能的扩展版本 (RtlStringXxxEx) 中使用,例如填充 null 终结符之后的目标缓冲区。

应该做什么?

如果驱动程序将只在 Windows XP 和更高版本的 Windows 上运行,那么只需在代码包含 Ntstrsafe.h。Ntstrsafe.h 是一个单独的头文件,它依赖于从 Ntoskrnl.exe 导出的实现,该可执行文件仅在 Windows XP 和更高版本的 Windows 上可用。

如果驱动程序必须在 Windows 2000 和早期版本上运行,那么您必须显式地链接到 Ntstrsafe.lib,它包含所需导出的实现:

1.

在包含 ntstrsafe.h 之前定义 NTSTRSAFE_LIB,如下所示。
#define NTSTRSAFE_LIB #include <ntstrsafe.h>

2.

在项目的 sources 文件中,添加一个 #(DDK_LIB_PATH)/ntstrsafe.lib 的 TARGETLIBS 条目。

将 Ntstrsafe.h 的包含指令放在其他头文件的包含指令之后。Ntstrsafe.h 中的函数取代了 C/C++ 语言运行时库函数,因此调用那些函数的任何一个都会导致编译器错误。如果其他头文件提供了引用运行时库函数的代码,那么仍会发生编译器错误。

如果必须在代码中同时使用 C/C++ 语言运行时库函数和安全字符串函数,那么在 Ntstrsafe.h 的包含指令之前包含下面一行:
#define NTSTRSAFE_NO_DEPRECATE

可以通过定义下列语句之一(但不是同时定义两者)来使得只有字节计数或只有字符计数版本的安全字符串函数可用:
#define NTSTRSAFE_NO_CCH_FUNCTIONS #define NTSTRSAFE_NO_CB_FUNCTIONS

必须显式调用 Unicode (W) 或 ANSI (A) 版本的内核模式安全字符串函数(如下面的例子中所示)。与 Strsafe.h 中定义的用户模式安全字符串函数不同,无法隐藏内核模式安全字符串函数的 Unicode 或 ANSI 版本。

 

例子:使用 RtlStringCbVPrintfA 代替 _vsnprintf
Windows DDK 中的 Toaster 例子在其 ToasterDebugPrint 函数中使用安全字符串函数 RtlStringCbVPrintfA 代替 _vsnprintfRtlStringCbVPrintfA 创建一个字节计数的 ANSI 文本字符串和以 null 结尾的消息(如果它比缓冲区长)。要使 _vsnprintf 具有相当的安全性,则需要更多大量的错误处理。

//%winddk%/src/general/toaster/func/featured1/toaster.c //See sample code for complete comments 
VOID ToasterDebugPrint( IN ULONG   DebugPrintLevel, IN PCCHAR  DebugMessage, ...)
{
  #define    TEMP_BUFFER_SIZE        1024
  va_list    list;
  UCHAR      debugMessageBuffer[TEMP_BUFFER_SIZE];
  NTSTATUS   status;
 
  va_start(list, DebugMessage);
  if (DebugMessage)
  {
    //Use safe string function instead of _vsnprintf
    status = RtlStringCbVPrintfA(debugMessageBuffer, sizeof(debugMessageBuffer), DebugMessage, list);
    if(!NT_SUCCESS(status))
    {
      KdPrint ((_DRIVER_NAME_":RtlStringCbVPrintfA failed %x/n", status));
      return;
    }
   
    if (DebugPrintLevel <= DebugLevel)
    {
      KdPrint ((_DRIVER_NAME_":%s", debugMessageBuffer));
    }
  }
  va_end(list);
  return;
}

更多信息:

Windows Driver Kit
使用安全字符串函数

MSDN 库
使用 Strsafe.h 函数
Writing Secure Code(第二版),Michael Howard 和 David LeBlanc 编写,(ISBN 0-7356-1722-8)
Chapter 5, Public Enemy #1: The Buffer Overrun

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值