使用内核驱动Rtl函数实现更为安全的字符串处理

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时,操作结果才正确。
  • 每个函数均有两种类型的版本,按字节或者按字符数。例如,RtlStringCbCatWRtlStringCchCatW
  • 每个函数均有支持双字节的unicode字符(以W作为后缀)和单字节的ANSI字符(以A作为后缀)的版本。例如:RtlStringCbCatWRtlStringCbCatA
  • 大部分函数有提供扩展版本的函数(以Ex作为后缀),例如,RtlStringCbCatWRtlStringCbCatExW
  • 函数名

    作用

    取代

    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
    _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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值