驅動開發中使用安全字符串函數


一、前言

       大量的系統安全問題是由於薄弱的緩沖處理以及由此產生的緩沖區溢出造成的,而薄弱的緩沖區處理常常與字符串操作相關。c/c++語言運行庫提供的標准字符串操作函數(strcpy, strcat, sprintf等)不能阻止在超出字符串尾端的寫入。

       基於Windows XP SP1以及隨后的操作系統的Windows DDK版本提供了安全字符串函數(safe string functions)。這類函數被設計的目的是用來取代相同功能的c/c++標准函數和其它微軟提供的庫函數。這類函數具有以下特征:

  • 每個函數以目標緩沖區所占的字節大小作為其一個輸入參數,因此可以保證在寫入時不會超出緩沖區末端。
  • 每個函數的輸出字符串均以NULL結尾(null-terminate),即使該函數可能會對正確的結果進行截斷。
  • 所有函數均有返回值,類型為NTSTATUS,只有返回STATUS_SUCCESS時,操作結果才正確。
  • 每個函數均有兩種類型的版本,按字節或者按字符數。例如,RtlStringCbCatWRtlStringCchCatW
  • 每個函數均有支持雙字節的unicode字符(以W作為后綴)和單字節的ANSI字符(以A作為后綴)的版本。例如:RtlStringCbCatWRtlStringCbCatA
  • 大部分函數有提供擴展版本的函數(以Ex作為后綴),例如,RtlStringCbCatWRtlStringCbCatExW

二、如何在內核驅動代碼中引入安全字符串函數

    有兩種方式可以引入安全字符串函數:

l        以內聯的方式引入,包含在ntstrsafe.h中

l        在鏈接時以庫的方式引入

其中,如果代碼需要在系統為Windows XP及以后版本運行時,可以使用內聯的方式;如果代碼需要運行在早於Windows XP時,則必須使用鏈接庫的方式。

以內聯方式引入

只需包含頭文件即可

#include <ntstrsafe.h>

以鏈接庫的方式

  1. 在包含頭文件之前先定義宏

#define NTSTRSAFE_LIB

#include <ntstrsafe.h>

  1. 在項目的sources文件中,添加一TARGETLIBS條目如下: $(DDK_LIB_PATH)\ntstrsafe.lib.

在默認情況下,當引入了安全字符串函數后,那些被取代的c/c++運行庫函數將變得無效,編譯是會報錯,提示需要使用安全字符串函數。

    如果還希望繼續使用c/c++運行庫函數,即在使用安全字符串函數的時候,c/c++運行庫函數還可以繼續使用,則需要在包含ntstrsafe.h之前先定義宏NTSTRSAFE_NO_DEPRECATE

#define NTSTRSAFE_NO_DEPRECATE

The maximum number of characters that any ANSI or Unicode string can contain is STRSAFE_MAX_CCH. This constant is defined in ntstrsafe.h.

字符串最長長度為STRSAFE_MAX_CCH,該宏在ntstrsafe.h中定義。另外,如果一個字符串需要被轉換成UNICODE_STRING結構,則該字符串長度不能超過65535.

三、內核模式安全字符串函數概述

    下表概述了可以在內核驅動中使用的安全字符串函數,並指明了它們用來何種類型的c/c++運行庫函數。

說明:

函數名含有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

格式化輸出

sprintf
swprintf
_snprintf
_snwprintf

RtlStringCbVPrintf 
RtlStringCbVPrintfEx 
RtlStringCchVPrintf 
RtlStringCchVPrintfEx

可變格式化輸出

vsprintf
vswprintf
_vsnprintf
_vsnwprintf

各個函數的作用可以通過它所取代的c/c++函數可以大概看出,具體用法請查閱DDK幫助文檔。

  

驅動中使用的字符串操作函數 ,這里給出ANSI和UNICODE的對比

操作

ANSI串函數

Unicode串函數

Length

Strlen

wcslen

Concatenate

Strcat

strncat

Wcscat

wcsncat

RtlAppendUnicodeStringToString

RtlAppendUnicodeToString

Copy

Strcpy

strncpy

RtlCopyString

Wcscpy

wcsncpy

TrlCopyUnicodeString

Reverse

_strrev

_wcsrev

Compare

Strcmp

Strncmp

_stricmp

_strnicmp

RtlCompareString

RtlEqualString

Wcscmp

Wcsncmp

_wcsicmp

_wcsnicmp

RtlCompareUnicodeString

RtlEqualUnicodeString

RtlPrefixUnicodeString

Initialize

_strset

_strnset

RtlInitAnsiString

RtlInitString

_wcsnset

RtlInitUnicodeString

Search

Strchr

strrchr

strspn

strstr

Wcschr

wcsrchr

wcsspn

wcsstr

Upper/Lowercase

_strlwr

_strupr

RtlUpperString,

_wcslwr

_wcsupr

RtlUpcaseUnicodeString

Character

isdigit

islower

isprint

isspace

isupper

isxdigit

tolower

toupper

RtlUpperChar

Towolower

towupper

RtlUpcaseUnicodeString

Format

Sprintf

vsprintf

_snprintf

_vsnprintf

Swprintf

_snwprintf

String Conversion

Atoi

Atoll

_itoa

_itow

RtlIntegerToUnicodeString

RtlUnicodeStringToInteger

Type conversion

RtlAnsiStringToUnicodeString

RtlAnsiStringToUnicodeString

RtlUnicodeStringToAnsiString

Memory Release

RtlFreeAnsiString

RtlFreeUnicodeString

 Ansi轉換Unicode

   RtlAnsiStringToUnicodeString

Unicode轉換Ansi

  RtlUnicodeStringToAnsiString

    以上兩個函數第三個參數都為True時需要使用RtlFreeUnicodeString/RtlFreeAnsiString來釋放空間。我設置過False 但是測試時候 第一次可以 第二次就藍屏了。如果讀者知道為什么 可以在下方評論留言給我。謝謝

KdPrint輸出unicode_string類型字符串使用 %wZ

 

// convert the name to UNICODE_STRING
wchar_t name[100];
auto status =
RtlStringCchPrintfW(name, RTL_NUMBER_OF(name), L"%S", export_name);
if (!NT_SUCCESS(status)) {
return true;
}
UNICODE_STRING name_u = {};
RtlInitUnicodeString(&name_u, name);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM