Rtl开头函数(Ntddk.h 以及Ntstrsafe.h)
大量的系统安全问题是由于薄弱的缓冲处理以及由此产生的缓冲区溢出造成的,而薄弱的缓冲区处理常常与字符串操作相关。c/c++语言运行库提供的标准字符串操作函数(strcpy, strcat, sprintf等)不能阻止在超出字符串尾端的写入。
基于Windows XP SP1以及随后的操作系统的Windows DDK版本提供了安全字符串函数(safe string functions)。这类函数被设计的目的是用来取代相同功能的c/c++标准函数和其它微软提供的库函数。这类函数具有以下特征:
- 每个函数以目标缓冲区所占的字节大小作为其一个输入参数,因此可以保证在写入时不会超出缓冲区末端。
- 每个函数的输出字符串均以NULL结尾(null-terminate),即使该函数可能会对正确的结果进行截断。
- 所有函数均有返回值,类型为NTSTATUS,只有返回STATUS_SUCCESS时,操作结果才正确。
- 每个函数均有两种类型的版本,按字节或者按字符数。例如,RtlStringCbCatW和RtlStringCchCatW。
- 每个函数均有支持双字节的unicode字符(以W作为后缀)和单字节的ANSI字符(以A作为后缀)的版本。例如:RtlStringCbCatW和RtlStringCbCatA。
- 大部分函数有提供扩展版本的函数(以Ex作为后缀),例如,RtlStringCbCatW和RtlStringCbCatExW。
-
函数名
作用
取代
RtlStringCbCat
RtlStringCbCatEx
RtlStringCchCat
RtlStringCchCatEx将源字符串连接到目的字符串的末尾
strcat
wcscatRtlStringCbCatN
RtlStringCbCatNEx
RtlStringCchCatN
RtlStringCchCatNEx将源字符串指定数目的字符连接到目的字符串的末尾
strncat
wcsncatRtlStringCbCopy
RtlStringCbCopyEx
RtlStringCchCopy
RtlStringCchCopyEx将源字符串拷贝到目的字符串
strcpy
wcscpyRtlStringCbCopyN
RtlStringCbCopyNEx
RtlStringCchCopyN
RtlStringCchCopyNEx将源字符串指定数目的字符拷贝到目的字符串
strncpy
wcsncpyRtlStringCbLength
RtlStringCchLength确定字符串的长度
strlen
wcslenRtlStringCbPrintf
RtlStringCbPrintfEx
RtlStringCchPrintf
RtlStringCchPrintfEx格式化输出
sprintf
swprintf
_snprintf
_snwprintfRtlStringCbVPrintf
RtlStringCbVPrintfEx
RtlStringCchVPrintf
RtlStringCchVPrintfEx可变格式化输出
vsprintf
vswprintf
_vsnprintf
_vsnwprint
1.判断从字符串开头到Len长度的子串是否存在
1.1以下是自己实现的普通R3代码(C字符串实现)
char* strinstr(const char *Str, int Len, const char *SubStr)
{
if (Str == NULL || SubStr == NULL || Len == 0)
return NULL;
char *cp = (char*)Str;
char *s1, *s2;
int m = 0, n = 0;
if (!*SubStr)
return ((char*)Str);
while (m < Len)
{
if (*cp == 0)
break;
s1 = cp;
s2 = (char*)SubStr;
n = 0;
while (m + n < Len && *s1 && *s2)
{
char ch1 = *s1, ch2 = *s2;
if ((*s1) >= 'A' && (*s1) <= 'Z')
ch1 = (char)tolower(*s1);
if ((*s2) >= 'A' && (*s2) <= 'Z')
ch2 = (char)tolower(*s2);
if (ch1 == ch2)
{
s1++;
s2++;
n++;
}
else
{
break;
}
}
if (!*s2)
return cp;
cp++;
m++;
}
return NULL;
}
WCHAR* wcsinstr(const WCHAR *Str, int Len, const WCHAR *SubStr)
{
if (Str == NULL || SubStr == NULL || Len == 0)
return NULL;
WCHAR *cp = (WCHAR*)Str;
WCHAR *s1, *s2;
int m = 0, n = 0;
if (!*SubStr)
return ((WCHAR*)Str);
while (m < Len)
{
if (*cp == 0)
break;
s1 = cp;
s2 = (WCHAR*)SubStr;
n = 0;
while (m + n < Len && *s1 && *s2)
{
WCHAR ch1 = *s1, ch2 = *s2;
if ((*s1) >= 'A' && (*s1) <= 'Z')
ch1 = towlower(*s1);
if ((*s2) >= 'A' && (*s2) <= 'Z')
ch2 = towlower(*s2);
if (ch1 == ch2)
{
s1++;
s2++;
n++;
}
else
{
break;
}
}
if (!*s2)
return cp;
cp++;
m++;
}
return NULL;
}
1.2 使用系统函数实现(StrStrIA、StrStrNIW)
//判断是否是子串
char* strinstr(const char *Str, int Len, const char *SubStr)
{
int length = 0;
char* res;
if (Str == NULL || SubStr == NULL || Len == 0)
return NULL;
char* cp = const_cast<char*>(Str);
res = StrStrIA(cp, SubStr);
if ((int)(res - Str) > Len)
return NULL;
return res;
}
WCHAR* wcsinstr(const WCHAR *Str, int Len, const WCHAR *SubStr)
{
if (Str == NULL || SubStr == NULL || Len == 0)
return NULL;
return StrStrNIW(Str,SubStr,len);
}
2.比较字符串
2.1使用C语言函数实现比较两个字符串
int strincmp(const char *Str1, int BufferSize, const char *Str2)
{
if (Str1 == NULL || Str2 == NULL || BufferSize == 0)
return 3;
int i = 0;
while (i < BufferSize)
{
if (Str1[i] == 0)
break;
i++;
}
int Len = min(i, BufferSize);
for (i = 0; i < Len; i++)
{
if (Str1[i] == 0 && Str2[i] == 0)
return 0;
char ch1 = 0, ch2 = 0;
if (Str1[i] >= 'A' && Str1[i] <= 'Z')
ch1 = (char)Str1[i] + 'a' - 'A';
else
ch1 = (char)Str1[i];
if (Str2[i] >= 'A' && Str2[i] <= 'Z')
ch2 = (char)Str2[i] + 'a' - 'A';
else
ch2 = (char)Str2[i];
if (ch1 > ch2)
{
return 1;
}
else if (ch1 < ch2)
{
return -1;
}
}
if (Str2[i] != 0)
return -1;
return 0;
}
int wcsincmp(const WCHAR *Str1, int BufferSizeInCh, const WCHAR *Str2)
{
if (Str1 == NULL || Str2 == NULL || BufferSizeInCh == 0)
return 3;
int i = 0;
while (i < BufferSizeInCh)
{
if (Str1[i] == 0)
break;
i++;
}
int Len = min(i, BufferSizeInCh);
for (i = 0; i < Len; i++)
{
if (Str1[i] == 0 && Str2[i] == 0)
return 0;
char ch1 = 0, ch2 = 0;
if (Str1[i] >= 'A' && Str1[i] <= 'Z')
ch1 = (char)Str1[i] + 'a' - 'A';
else
ch1 = (char)Str1[i];
if (Str2[i] >= 'A' && Str2[i] <= 'Z')
ch2 = (char)Str2[i] + 'a' - 'A';
else
ch2 = (char)Str2[i];
if (ch1 > ch2)
{
return 1;
}
else if (ch1 < ch2)
{
return -1;
}
}
if (Str2[i] != 0)
return -1;
return 0;
}
2.2 使用Rtl类型函数比较两个字符串(RtlCompareString和RtlCompareUnicodeString)
int strincmp(const char *Str1, int BufferSize, const char *Str2)
{
if (Str1 == NULL || Str2 == NULL || BufferSize == 0)
return 3;
STRING s1 = { 0 };
STRING s2 = { 0 };
s1.Buffer = (char*)Str1;s1.Length = sizeof(s1);s1.MaximumLength = BufferSize;
s2.Buffer = (char*)Str2;s2.Length = sizeof(s2);s2.MaximumLength = BufferSize;
if (RtlCompareString(&s1, &s2, TRUE) == 0)
return 0;
else if (RtlCompareString(&s1, &s2, TRUE) > 0)
return 1;
else return -1;
}
int wcsincmp(PCWSTR Str1, int BufferSizeInCh, PCWSTR Str2)
{
PUNICODE_STRING PS1;
PUNICODE_STRING PS2;
if (RtlUnicodeStringInit(PS1, Str1) == STATUS_SUCCESS && RtlUnicodeStringInit(PS2, Str2) == STATUS_SUCCESS)
{
if (RtlCompareUnicodeString(PS1, PS2, TRUE) == 0)
return 0;
else if (RtlCompareUnicodeString(PS1, PS2, TRUE) > 0)
return 1;
else return -1;
}
else
return 3;
}
3.计算字符串长度
3.1 普通实现
int strnlen_safe(const char *Str, int MaxLen)
{
if (Str == NULL || MaxLen <= 0)
return 0;
int i = 0;
while (i < MaxLen)
{
if (Str[i] == 0)
break;
i++;
}
return i;
}
int wcsnlen_safe(const WCHAR *Str, int MaxLen)
{
if (Str == NULL || MaxLen <= 0)
return 0;
int i = 0;
while (i < MaxLen)
{
if (Str[i] == 0)
break;
i++;
}
return i;
}
3.2 Rtl函数实现(RtlStringCchLengthA和RtlStringCchLengthW)
int strnlen_safe(const char *Str, int MaxLen)
{
size_t reslen = 0;
if (Str == NULL || MaxLen <= 0)
return 0;
if (MaxLen > NTSTRSAFE_MAX_CCH)
return -1;
RtlStringCchLengthA(Str, MaxLen, &reslen);
return reslen;
}
int wcsnlen_safe(const WCHAR *Str, int MaxLen)
{
size_t reslen;
if (Str == NULL || MaxLen <= 0)
return 0;
if (MaxLen > NTSTRSAFE_MAX_CCH)
return -1;
RtlStringCchLengthW(Str, MaxLen, &reslen);
return reslen;
}
4计算某个字符的个数
计算某个字符的个数,不涉及缓冲区大小 所以不存在安全问题,普通实现即可
//计算某个字符的个数,不涉及缓冲区大小 所以不存在安全问题,没找到Rtl类型函数
int wcsncount(const WCHAR *Str, int MaxLen, const WCHAR ch)
{
if (Str == NULL || MaxLen == 0)
return 0;
int count = 0;
int i = 0;
while (i < MaxLen)
{
if (Str[i] == '\0')
break;
if(Str[i] == ch)
count++;
i++;
}
return count;
}
5.另外Rtl