一、前言
??????
大量的系統(tǒng)安全問題是由于薄弱的緩沖處理以及由此產(chǎn)生的緩沖區(qū)溢出造成的,而薄弱的緩沖區(qū)處理常常與字符串操作相關(guān)。
c/c++
語言運(yùn)行庫提供的標(biāo)準(zhǔn)字符串操作函數(shù)(
strcpy, strcat, sprintf
等)不能阻止在超出字符串尾端的寫入。
??????
基于
Windows XP SP1
以及隨后的操作系統(tǒng)的
Windows DDK
版本提供了安全字符串函數(shù)(
safe string functions
)。這類函數(shù)被設(shè)計(jì)的目的是用來取代相同功能的
c/c++
標(biāo)準(zhǔn)函數(shù)和其它微軟提供的庫函數(shù)。這類函數(shù)具有以下特征:
-
每個(gè)函數(shù)以目標(biāo)緩沖區(qū)所占的字節(jié)大小作為其一個(gè)輸入?yún)?shù),因此可以保證在寫入時(shí)不會超出緩沖區(qū)末端。
-
每個(gè)函數(shù)的輸出字符串均以NULL結(jié)尾(null-terminate),即使該函數(shù)可能會對正確的結(jié)果進(jìn)行截?cái)唷?span lang="EN-US">
-
所有函數(shù)均有返回值,類型為NTSTATUS,只有返回STATUS_SUCCESS時(shí),操作結(jié)果才正確。
-
每個(gè)函數(shù)均有兩種類型的版本,按字節(jié)或者按字符數(shù)。例如,RtlStringCbCatW和RtlStringCchCatW。
-
每個(gè)函數(shù)均有支持雙字節(jié)的unicode字符(以W作為后綴)和單字節(jié)的ANSI字符(以A作為后綴)的版本。例如:RtlStringCbCatW和RtlStringCbCatA。
-
大部分函數(shù)有提供擴(kuò)展版本的函數(shù)(以Ex作為后綴),例如,RtlStringCbCatW和RtlStringCbCatExW。
二、如何在內(nèi)核驅(qū)動(dòng)代碼中引入安全字符串函數(shù)
???
有兩種方式可以引入安全字符串函數(shù):
l???????
以內(nèi)聯(lián)的方式引入,包含在ntstrsafe.h中
l???????
在鏈接時(shí)以庫的方式引入
其中,如果代碼需要在系統(tǒng)為Windows XP及以后版本運(yùn)行時(shí),可以使用內(nèi)聯(lián)的方式;如果代碼需要運(yùn)行在早于Windows XP時(shí),則必須使用鏈接庫的方式。
以內(nèi)聯(lián)方式引入
只需包含頭文件即可
#include?<ntstrsafe.h>
以鏈接庫的方式
-
在包含頭文件之前先定義宏
#define?NTSTRSAFE_LIB
#include?<ntstrsafe.h>
-
在項(xiàng)目的sources文件中,添加一TARGETLIBS條目如下: $(DDK_LIB_PATH)\ntstrsafe.lib.
在默認(rèn)情況下,當(dāng)引入了安全字符串函數(shù)后,那些被取代的c/c++運(yùn)行庫函數(shù)將變得無效,編譯是會報(bào)錯(cuò),提示需要使用安全字符串函數(shù)。
???
如果還希望繼續(xù)使用c/c++運(yùn)行庫函數(shù),即在使用安全字符串函數(shù)的時(shí)候,c/c++運(yùn)行庫函數(shù)還可以繼續(xù)使用,則需要在包含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中定義。另外,如果一個(gè)字符串需要被轉(zhuǎn)換成UNICODE_STRING結(jié)構(gòu),則該字符串長度不能超過65535.
三、內(nèi)核模式安全字符串函數(shù)概述
???
下表概述了可以在內(nèi)核驅(qū)動(dòng)中使用的安全字符串函數(shù),并指明了它們用來何種類型的c/c++運(yùn)行庫函數(shù)。
說明:
函數(shù)名含有Cb的是以字節(jié)數(shù)為單位,含有Cch的是以字符數(shù)為單位。
函數(shù)名
|
作用
|
取代
|
RtlStringCbCat
RtlStringCbCatEx
RtlStringCchCat
RtlStringCchCatEx
|
將源字符串連接到目的字符串的末尾
|
strcat
wcscat
|
RtlStringCbCatN RtlStringCbCatNEx RtlStringCchCatN RtlStringCchCatNEx
|
將源字符串指定數(shù)目的字符連接到目的字符串的末尾
|
strncat
wcsncat
|
RtlStringCbCopy RtlStringCbCopyEx RtlStringCchCopy RtlStringCchCopyEx
|
將源字符串拷貝到目的字符串
|
strcpy wcscpy
|
RtlStringCbCopyN RtlStringCbCopyNEx RtlStringCchCopyN RtlStringCchCopyNEx
|
將源字符串指定數(shù)目的字符拷貝到目的字符串
|
strncpy wcsncpy
|
RtlStringCbLength RtlStringCchLength
|
確定字符串的長度
|
strlen wcslen
|
RtlStringCbPrintf RtlStringCbPrintfEx RtlStringCchPrintf RtlStringCchPrintfEx
|
格式化輸出
|
sprintf swprintf _snprintf _snwprintf
|
RtlStringCbVPrintf RtlStringCbVPrintfEx RtlStringCchVPrintf RtlStringCchVPrintfEx
|
可變格式化輸出
|
vsprintf vswprintf _vsnprintf _vsnwprintf
|
各個(gè)函數(shù)的作用可以通過它所取代的c/c++函數(shù)可以大概看出,具體用法請查閱DDK幫助文檔。