C语言中的%x格式说明符

100
我是一名有用的助手,可以为您翻译文本。
我有一个小问题。我知道%x格式说明符可以用于在格式字符串攻击中从堆栈中读取值。
我找到了以下代码:
%08x%08x%08x%08x

08是什么意思?它到底在做什么?谢谢:)


2
字段宽度为8个字符,较短的数字前缀加上前导零以匹配字段宽度,例如000007ac0005ceef - Hristo Iliev
2
这里是在谈论哪个函数?你说“读取值”,但所有的答案似乎都假定使用了printf() - unwind
1
@unwind 很好的观点。我们都在为 printf 写作。 - Grijesh Chauhan
1
我太傻了。是的,我指的是在printf函数中使用此代码。 - Matthew
5个回答

167

解析:

  • 8 表示你想显示 8 位数字
  • 0 表示你想在前面加上 0 而不是空格
  • x 表示你要以小写十六进制打印。

快速示例(感谢 Grijesh Chauhan):

#include <stdio.h>
int main() {
    int data = 29;
    printf("%x\n", data);    // just print data
    printf("%0x\n", data);   // just print data ('0' on its own has no effect)
    printf("%8x\n", data);   // print in 8 width and pad with blank spaces
    printf("%08x\n", data);  // print in 8 width and pad with 0's

    return 0;
}

输出:

1d
1d
      1d
0000001d

此处的http://www.cplusplus.com/reference/cstdio/printf/是参考文献,可供查阅。请前往该链接查看相关内容。

9
添加了一个例子,希望你喜欢。如果不喜欢,你可以回到你的版本。 - Grijesh Chauhan
2
@Matthew,你也应该尝试一下%-8x和大写的X,并观察效果。 - Grijesh Chauhan
1
尽管80都是数字(因此在英语语法中是相同的部分),但它们是printf格式语法的不同部分。0是一个“标志”,而8是“宽度”的参数(可以是<ε(没有输入)><d(任何大于0的数字)>*(字面上的星号))。这绝对是一个非直观的API!但你能说什么呢...那是旧式C语言的所有东西,当时内存非常宝贵,你想要在程序中尽可能地节省字符 - 鉴于他们所面临的限制,我同意他们的决定! - Ari Sweedler
1
我认为这是一个有趣的问题值得思考。你会如何重新设计printf语法?我喜欢使用作为转义字符,它在字符串格式化时非常独特和专业。我认为修饰符应该是添加而不是放在前面,这样你就可以从左到右阅读它。类似于%<specifier> [%f<flags>] [%-w<width>.<precision>]%,而不是%[flags] [width] [.precision] [length] specifier。我选择每个字段之间使用以及一个关闭符号(所以你仍然可以做到%x%x - %x%%x)并允许多字符规范。 - Ari Sweedler

8

%08x 表示每个数字输出的最小宽度为8个字符,缺失的数字将用0填充,例如对于'1'的输出将是00000001


4
你所提到的针对printf的格式字符串攻击并不仅限于“%x”格式——在任何printf具有比传递变量更多的格式化参数的情况下,它都会从堆栈中读取不属于它的值。例如,您使用%d也会遇到相同的问题。 %x在您想要将这些值作为十六进制查看时非常有用。
如前面的回答所解释的那样,%08x将产生一个8位数的十六进制数字,并在前面填充零。
在您的代码示例中,如果没有其他参数,则使用printf中的格式化:
printf ("%08x %08x %08x %08x");

将从堆栈中获取4个参数,并将它们显示为8位填充的十六进制数字。


2

这指定了要显示的数字位数。

整数值或*,用于指定最小字段宽度。如果需要,在右对齐时会在左侧填充空格字符(默认情况下),在左对齐时会在右侧填充。当使用*时,宽度由额外的int类型参数指定。如果参数的值为负,则结果带有-标志并具有正字段宽度。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接