极客秀
搜索

C语言:你不知道的printf的奥秘(格式字符串攻击)

相信大家学习C语言的第一课就是Hello World!

printf("Hello World!");

printf是一种在C语言中用于格式化输出的函数。它是C标准库(stdio.h头文件中)提供的一部分。
是每一个学习C语言(除非你从C++开始学)肯定会接触的输出函数。在大部分教程中都会教大家printf函数是如何使用,举个例子。

int a = 50;printf("OutPut :%d",a);

这样子我们就可以把变量50给输出来啦。
老师肯定说过,printf的第一个参数是输出的语句,其中会有例如%d说明后面读取的第一个变量的类型是整型,同样的,我们可以输出多个不同类型的变量。

以下是一些常见的格式说明符:

  • %d: 用于输出整数。

  • %f: 用于输出浮点数。

  • %c: 用于输出字符。

  • %s: 用于输出字符串。


    // 使用多个格式说明符,输出多个变量    float b = 3.14;    char c = 'A';    // %f 表示输出一个浮点数,%c 表示输出一个字符    printf("Values: %d, %f, %cn", a, b, c);

可以使用一些修饰符来控制输出的宽度和精度。例如,%5d 表示输出的整数占五个字符宽度,%.2f 表示浮点数保留两位小数。


int number = 12345;float pi = 3.14159;printf("Number: %8dn", number);  // 输出宽度为8的整数printf("Pi: %.2fn", pi);         // 输出两位小数的浮点数

** 但是,不知道有多少朋友看过printf函数的原型呢?? **

int printf(const char *format, ...);

事实上,printf函数只有一个固定参数和…不固定数量的可变参数组成。
所以printf函数真正重要的参数就是第一个字符串,而且他的输入参数就是一个字符串!这意味着,我们可以用一个const char *
类型的字符串变量来作为它的参数。

那么接下来我们在做一个直观的测试!


#include <stdio.h>#include <string.h>  
int main() {    int A = 97;//97对应的ASCLL码是a    const char* s = "A = %drn";    char newString[20];  // 为了安全,选择足够大的字符数组  
    // 将 "printf " 复制到新的字符数组中    strcpy(newString, s);    //这里实际上是printf("A = %drn",A);    printf(newString, A);    strcpy(newString + 4, "%crn");    //这里实际上是printf("A = %crn",A);    printf(newString, A);  
    return 0;}

我们两次用字符串代替第一个参数,第一次字符串中设置%d让A输出整形91,第二次我们设置为%c,让其输出对应的ASCLL字符(‘a’)

所以由此可见printf的第一个参数可以以字符串变量作为参数传入。
但是这种方法是十分不安全的, 可能会导致安全漏洞,特别是当用户能够控制输入时。

如果用户可以控制格式化字符串,可能会引发一些安全问题,例如格式字符串攻击(Format String
Vulnerability)。攻击者可以通过在格式化字符串中插入特定格式说明符来读取或修改程序的内存,这是一种严重的安全风险。

为了防范这种攻击,我们通常建议使用安全的输入处理函数,如 printf 的安全版本 printf_s 或者更加安全的输入函数,比如
snprintf,它们提供了更多的控制和保护机制,避免了潜在的缓冲区溢出问题。

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容