上代码:
#include
#include
#include
int low(char str1[])
{
int i;
for (i=0;i<strlen(str1);i++)
{
if(str1[i]>='A'&&str1[i]<='Z')
{
str1[i]+=32;
}
}
return str1;
}
int raise(char str1[])
{
int i;
for (i=0;i<strlen(str1);i++)
{
if(str1[i]>='a'&&str1[i]<='z')
{
str1[i]-=32;
}
}
return str1;
}
int main()
{ //打印字符
int str=0;
int i=0;
for(str=0;str<128;str++)
{
printf("%c\t ",str);//ASCII码0-32字符显示是不整成的
}
//输入字母全部转换为小写或者大写
char str1[100]={0};
scanf("%s",&str1);
low(str1);
printf("%s\n",str1);
raise(str1);
printf("%s\n",str1);
//数字字符转换为int
/*atoi
C语言库函数名: atoi
功 能: 把字符串转换成整型数
函数说明: atoi()会扫描参数nptr字符串,检测到第一个数字或正负符号时开始做类型转换,之后检测到非数字或结束符 \0 时停止转换,返回整型数。
原型: int atoi(const char *nptr);
需要用到的头文件: #include */
int inumber=0;
char *chnumber="12345.67";
inumber=atoi(chnumber);
printf("string = %s integer = %d\n",chnumber,inumber);
//wctomb和mbtowc完成ansi与unicode相互转换,
//C 库函数 int wctomb(char *str, wchar_t wchar) 把宽字符 wchar 转换为它的多字节表示形式,并把它存储在 str 指向的字符数组的开头
//wctomb实现ansi向unicode转换
i=0;
wchar_t wc = L'a';
char *pmbnull = NULL;
char *pmb = (char *)malloc(sizeof( char ));
memset(pmb,0,NULL);
printf("要转换的宽字符:\n");
i = wctomb( pmb, wc );
printf("被转换的字符:%u\n", i);
printf("多字节字符:%.1s\n", pmb);
printf("当要转换的字符为 NULL 时尝试转换:\n");
i = wctomb( pmbnull, wc );
printf("被转换的字符:%u\n", i);
/* 不会输出任何值 */
printf("多字节字符:%.1s\n", pmbnull);
//mbtowc实现unicode向ansi转换
char *str3 = "这里是 runoob.com";
wchar_t mb[100];
int len;
len = mblen(NULL, MB_CUR_MAX);
mbtowc(mb, str3, len*strlen(str3) );
wprintf(L"%ls \n", mb ); //因为它要以多字节形式输出结果,这是一种二进制输出
free(pmb);
pmb=NULL;
return 0;
}
ZeroMemory 是memset 的一个宏接口
比memset 少一个参数
后面这两函数的代码是我抄的
直接看问题:
nt low(char str1[])
{
int i;
for (i=0;i<strlen(str1);i++)
{
if(str1[i]>='A'&&str1[i]<='Z')
{
str1[i]+=32;
}
}
return str1;
}
问题:
1、返回值类型不匹配,str1 char * 函数定义的是int
2、参数合法性没有检查。str1 如果是非法的呢
3、ansi可见字符的范围是多少,不可见字符的范围是多少,
代码中没有体现
4、单个字符转成数值的函数,是自己通过代码逻辑实现,
而不是调用atoi 实现。当然调接口也是一种方式
char '9'-->int 9
char 9的 ansi 是57 - 48 就等于9了
char* pmb = (char*)malloc(sizeof(char));
memset(pmb, 0, NULL);
问题:
1、malloc 的返回值,并没有检测有效性,直接使用
i = wctomb(pmb, wc);
问题:返回值接收了,但是并没有利用
所有的函数的返回值,都得正确处理
否则在代码层面你不知道函数是否执行成功
在R3层,代码错误不处理,也会有异常机制去处理,
所以看起来影响不太大,但如果是R0层的代码,
错误不处理,那后果只能是系统蓝屏
这是一个编码习惯,所以考核性的测试,这块是必须要考察的
用户层(R3)与驱动层(R0)
https://blog.csdn.net/qq_34479012/article/details/128892693
简单来说,R3层,权限小,错误处理机制完善,R0层,权限大,错误处理机制,几乎没有,所有R0层代码出错,系统就会崩溃
所有R0层的代码有三分之二以上,都在处理错误
因为,R3层和R0层,有内存交互,也就是说,R3层的接口,能影响到R0层的代码,那么就有概率产生R0层的代码攻击了
R3层漏洞,大多是在Windows窗体创建这块,含有就是各种图片处理接口上。攻击发起是R3层的,包括UAF,提权的,还有内存任意读写漏洞
C 库函数 int wctomb(char *str, wchar_t wchar)
把宽字符 wchar 转换为它的多字节表示形式
并把它存储在 str 指向的字符数组的开头
int wctomb(char *str, wchar_t wchar)
# str -- 一个指针,指向一个足以存储多字节字符的数组。
# wchar -- 类型为 wchar_t 的宽字符。
返回值
如果 str 不为 NULL,wctomb() 函数返回写入字节数组中的字节数
如果 wchar 不能被表示为一个多字节序列,则会返回 -1
如果 str 为 NULL,如果编码具有移位状态
则 wctomb() 函数返回非零,如果编码是无状态的,则返回零
https://www.runoob.com/cprogramming/c-function-wctomb.html
C 库函数 int mbtowc(whcar_t *pwc, const char *str, size_t n)
把一个多字节序列转换为一个宽字符
int mbtowc(whcar_t *pwc, const char *str, size_t n)
# pwc -- 指向类型为 wchar_t 对象的指针。
# str -- 指向多字节字符的第一个字节的指针。
# n -- 要被检查的最大字节数。
返回值
如果 str 不为 NULL,mbtowc() 函数返回 str 开始消耗的字节数
如果指向一个空字节,则返回 0,如果操作失败,则返回 -1
如果 str 为 NULL,如果编码具有移位状态
则 mbtowc() 函数返回非零,如果编码是无状态的,则返回零。
https://www.runoob.com/cprogramming/c-function-mbtowc.html
mbstowcs wcstombs这两函数
s结尾通常要安全些
字符到数值的转换
int getIntByChar(char intChar)
{
if (intChar < 48 || intChar > 57)
{
return -1;
}
return intChar - 48;
}
小组其他同学问题
char* getASCII()
{
char* ret = (PCHAR)malloc(128);
if (!ret)
{
return NULL;
}
for (size_t i = 0; i < 127; i++)
{
*(ret + i) = i + 1;
}
*(ret + 127) = '\0';
return ret;
}
这个函数设计,有些问题,申请内存和释放内存,
不再同一个函数层级,在开发层面看,容易忘记释放
参考windows 标准函数设计,要么就是申请好内存传进去,
函数只负责填写内存,要么就是所有的释放在函数内部完成
外层负责使用。
不规范的函数设计,也是漏洞挖掘者,最喜欢搞的一个点
ansi表,中各种类型字符的分类,在威胁检测中是有实际应用意义的
特别是,脚本类的威胁样本
通过不同类型的字符提取后,能得到一个特征信息相对稳定的检测平面
英文串每一个wchar是两个字节,第二个字节始终为00
wchar的结束符是两倍的\0
multichar 和 wchar 两种 串存储形式是程序中,常见的存储形式,
对于,进程空间中,经常需要暴力搜索某些串,除了,multichar 之外,还有wchar 别忘了
多字符(MultiChar)也就是ANSI编码的方式
https://www.cnblogs.com/gardenintheair/articles/4791677.html
在mbstowcs被调用,并且实际循环赋值内存
但是在重新运行的时候我发现它不仅仅是在mbstowcs被调用,
就连printf都会调用这个循环体,屏幕上每出现一个文字都会调用一遍这个循环
但是mbstowcs里面确实调用了这个循环并且赋值到了wchar_t的内存里面,所以我认为这也确实是mbstowcs的核心代码,根据我的部分猜测,应该是edx(或者在我的程序里面是rdx,重新编译太多次懒得改了)保存的是一张分页表,然后eax作为偏移量,在分页表前面的部分是ascii,往后的部分根据用户当前分页进行排序,比如windows下默认为gbk。
edx实际指向的地方,猜测这是一张gbk->utf-16的对应表
对于检查到是多字节的,会走入多字节处理,把表中读出的数据写入wchar_t(2字节),然后eax+2,对于单字节的,原样复制,第二个字节为00
因此如果mbstowcs遇到了多字节文本,会根据当前的locale读取不同的对应表,然后转换为utf-16
说明,printf内部是使用unicode进行处理的
不光是c库,windows,内部很多地址串,都默认使用unicode版本处理函数
multichar,版本接口,只是封了一个unicode转换函数而已,最后都走unicode,处理流程
用wprintf会加快效率,毕竟不用走一遍转换了
不过,你程序中的所有串,都得用widechar组织
内部也会走,multibytetowidechar
mbstowcs – ucrtbase._mbstowcs_l—MultiByteToWideChar
内部定义的宏
多字节字符的最大字符长度
C 库函数 int mblen(const char *str, size_t n) 返回参数 str 所指向的多字节字符的长度。
int mblen(const char *str, size_t n)
# str -- 指向多字节字符的第一个字节的指针。
# n -- 要检查的字符长度的最大字节数。
返回值
如果识别了一个非空宽字符,
mblen() 函数返回 str 开始的多字节序列解析的字节数。
如果识别了一个空宽字符,则返回 0。如果识别了一个无效的多字节序列
,或者不能解析一个完整的多字节字符,则返回 -1。
课外拓展:
函数mbstowcs,都是成对使用的
第一个,获取,目标串所需的内存,动态申请后,再次执行,接收转换后的结果。
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/mbstowcs-mbstowcs-l?view=msvc-170