C-%x格式说明符


77

我有一个小问题。我知道%x格式说明符可用于在格式字符串攻击中从堆栈中读取值。

我发现以下代码:

%08x%08x%08x%08x

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


1
字段宽度为8个字符,较短的数字以前导零开头以匹配字段宽度,例如000007ac0005ceef
赫里斯托·伊利耶夫

2
这是在说什么功能?您说的是“读取值”,但所有答案似乎都假定printf()正在使用。
放松

1
@unwind好点。我们都为printf写作。
Grijesh Chauhan

1
傻我 是的,我指的是在printf函数中使用此代码。
马修,

Answers:


138

分解:

  • 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

1
@Matthew您也应该尝试%-8x和资本X。并观察效果
Grijesh Chauhan

1
即使80都是数字(因此是英语中语法的相同部分),它们也是printf格式语法的不同部分。0是一个“标记”和8是“宽度”(其可以是一个参数<ε (no input)><d (any number greater than 0)>* (a literal asterisk))。肯定是非直觉的API!但是,您能说什么呢……所有这些都是老式的C语言,其中的内存是如此宝贵,以至于您想在程序中保存尽可能多的字符-考虑到他们所面临的限制,我同意他们的决定!
阿里·斯威德勒

1
我确实认为这是一个有趣的问题。您将如何重新设计printf语法?我喜欢%用作转义字符,它对字符串格式是如此独特且利基。我认为修饰符应该附加而不是前置-这样,您就可以从左到右阅读它。有点像%<specifier>[%f<flags>][%-w<width>.<precision>]%,而不是%[flags][width][.precision][length]specifier。我%在每个字段之间都选择了一个,以及要关闭的字段(因此您仍然可以执行%x%x-%x %% x%),并允许使用多字符说明符
Ari Sweedler

5

%08x 意味着每个数字应至少打印8个字符宽,并用零填充所有缺失的数字,例如对于'1'输出将为 00000001


2

指定要显示的位数。

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



2

您提到的针对printf的格式字符串攻击并非特定于“%x”格式-在任何情况下,如果printf的格式化参数比传递的变量多,它将从堆栈中读取不属于它的值。例如,您将在%d中遇到相同的问题。当您希望将这些值视为十六进制时,%x很有用。

如前面的答案所述,%08x将产生一个8位数的十六进制数字,并用前面的零填充。

在printf的代码示例中使用格式,不带其他参数:

printf ("%08x %08x %08x %08x");

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.