0x00 read()
函数原型
1 | #include <unistd.h> |
fd:文件描述符;fd为0从键盘读取
buf:指定的缓冲区,即指针,指向一段内存单元;
nbyte:要读入文件指定的字节数;
功能
read()会把参数fd所指的文件传送nbyte个字节到buf指针所指的内存中。若参数nbyte为0,则read()不会有作用并返回0。
返回值
成功时,read返回实际所读的字节数,如果返回的值是0,表示已经读到文件的结束了.
小于0表示出现了错误.如果错误为EINTR说明读是由中断引起的, 如果是ECONNREST表示网络连接出了问题.
0x01 write()
函数原型
1 | #include <unistd.h> |
fd:文件描述符;fd为1输出到显示器
buf:指定的缓冲区,即指针,指向一段内存单元;
nbyte:要写入文件指定的字节数;
功能
write()会把参数buf 所指的内存写入nbytes 个字节到参数fd 所指的文件内. 当然, 文件读写位置也会随之移动.
返回值
如果顺利write()会返回实际写入的字节数.
当有错误发生时则返回-1, 错误代码存入errno 中.
错误代码:
- EINTR 此调用被信号所中断.
- EAGAIN 当使用不可阻断I/O 时 (O_NONBLOCK), 若无数据可读取则返回此值.
- EADF 参数fd 非有效的文件描述词, 或该文件已关闭
0x02 gets()
函数原型
1 | # include <stdio.h> |
功能
gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。
注意
使用 gets() 时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了
gets() 时有空格也可以直接输入,但是 gets() 有一个非常大的缺陷,即它不检查预留存储区是否能够容纳实际输入的数据,换句话说,如果输入的字符数目大于数组的长度,gets 无法检测到这个问题,就会发生内存越界。
0x03 strcpy()和memcpy()和strncpy()
函数原型
1 | char* strcpy(char* dest, const char* src) |
dest:指向用于存储复制内容的目标数组。
src:要复制的字符串。
count:要读入文件指定的字节数;
注意
- strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符’\0’。
- 复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
- 复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符”\0”才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
- 用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
- strncpy函数,只是将src的前n个字符复制到dest的前n个字符,不自动添加’\0’。如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节
0x04 printf()和scanf()
scanf函数
scanf(“%d %d”,&a,&b);
遇到空格(0x20)停止读取
printf函数
printf(“%s”, i);
输出直到\x00
格式化字符串漏洞
通常来说,我们会使用printf([格式化字符串],参数)的形式来进行调用,例如1
2char s[20] = “Hello world!\n”;
printf(“%s”, s);
然而,有时候为了省事也会写成1
2char s[20] = “Hello world!\n”;
printf(s);
事实上,这是一种非常危险的写法。由于printf函数族的设计缺陷,当其第一个参数可被控制时,攻击者将有机会对任意内存地址进行读写操作。