3.31~4.3

学习ansi表,编程实现:打印输出所有可见字符和非可见字符,实现大小字母转换,实现数字字符char转换为int,在代码中使用wctomb和mbtowc完成ansi与unicode相互转换,调试bin,观察这两个函数内部实现。

上代码:

#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 就等于9char* pmb = (char*)malloc(sizeof(char));
memset(pmb, 0, NULL);
问题:
1、malloc 的返回值,并没有检测有效性,直接使用

i = wctomb(pmb, wc);
问题:返回值接收了,但是并没有利用
所有的函数的返回值,都得正确处理
否则在代码层面你不知道函数是否执行成功
在R3层,代码错误不处理,也会有异常机制去处理,
所以看起来影响不太大,但如果是R0层的代码,
错误不处理,那后果只能是系统蓝屏
这是一个编码习惯,所以考核性的测试,这块是必须要考察的

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,提权的,还有内存任意读写漏洞

wctomb和mbtowc

C 库函数 int wctomb(char *str, wchar_t wchar) 
把宽字符 wchar 转换为它的多字节表示形式
并把它存储在 str 指向的字符数组的开头
int wctomb(char *str, wchar_t wchar)
   # str -- 一个指针,指向一个足以存储多字节字符的数组。
   # wchar -- 类型为 wchar_t 的宽字符。
返回值
如果 str 不为 NULLwctomb() 函数返回写入字节数组中的字节数
如果 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 不为 NULLmbtowc() 函数返回 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表,中各种类型字符的分类,在威胁检测中是有实际应用意义的
特别是,脚本类的威胁样本
通过不同类型的字符提取后,能得到一个特征信息相对稳定的检测平面

Multichar 和 wchar 在内存中的存储形式是什么样的(简单说就是一个相同的 英文串,在multichar 的内存形式和wchar 的内存形式上的异同)

英文串每一个wchar是两个字节,第二个字节始终为00
wchar的结束符是两倍的\0

multichar 和 wchar 两种 串存储形式是程序中,常见的存储形式,
对于,进程空间中,经常需要暴力搜索某些串,除了,multichar 之外,还有wchar 别忘了
多字符(MultiChar)也就是ANSI编码的方式
https://www.cnblogs.com/gardenintheair/articles/4791677.html

小组同学提出的猜想

3.31~4.3_第1张图片在mbstowcs被调用,并且实际循环赋值内存
但是在重新运行的时候我发现它不仅仅是在mbstowcs被调用,
就连printf都会调用这个循环体,屏幕上每出现一个文字都会调用一遍这个循环
但是mbstowcs里面确实调用了这个循环并且赋值到了wchar_t的内存里面,所以我认为这也确实是mbstowcs的核心代码,根据我的部分猜测,应该是edx(或者在我的程序里面是rdx,重新编译太多次懒得改了)保存的是一张分页表,然后eax作为偏移量,在分页表前面的部分是ascii,往后的部分根据用户当前分页进行排序,比如windows下默认为gbk。
edx实际指向的地方,猜测这是一张gbk->utf-16的对应表
3.31~4.3_第2张图片对于检查到是多字节的,会走入多字节处理,把表中读出的数据写入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

MB_CUR_MAX是什么

内部定义的宏
多字节字符的最大字符长度

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

你可能感兴趣的:(上课内容,学习)