缓冲区溢出是否会改变它正在覆盖的变量的数据类型?

Dar*_*ger 8 memory buffer

假设我有一个 C 字符数组char buf[15]。假设变量int set_me = 0将其数据直接存储在char buf[15]. 如果我溢出buf与串"aaabbbcccdddeee\xef\xbe\xad\xde",将set_me的数据类型的变化从一个整数的字符阵列?

Bob*_*Bob 33

不。

变量的“数据类型”仅与源代码相关(甚至仅与某些语言相关)。它告诉编译器如何处理变量。

这些高级数据类型在编译(本机)代码中不存在。它们会影响编译器生成的指令,但指令本身并不关心数据是表示字符还是数字。


硬件中不存在变量。在硬件中,您有内存位置和对它们进行操作的指令。

一个变量可以被看作是一个内存位置的数据视图——如果你眯着眼睛看同一个内存略有不同(不同类型的不同变量引用同一位置),相同的二进制值可能有不同的含义.

例如,字节 0x41 可以解释为 UTF-8 编码的字符A。它也可以解释为单字节整数65。它也可以解释为多字节整数或浮点数中的一个字节,或多字节字符编码中的一个字节。它可能是 bitset 0b1000001。全部来自同一内存位置中的同一字节。在 C 语言中,您可以通过强制转换为这些不同的类型来看到这种效果。

当您遇到“缓冲区溢出”时,您所做的事情超出了您的编译器或语言的预期范围。但是,就硬件而言1,您正在将字节(无论是单个还是多个)写入内存位置。内存位置没有“类型”。事实上,硬件甚至不知道任何特定的字节集在您的代码中构成一个数组或缓冲区。

无论您下次在代码中的何处访问该内存位置,指令都将按照最初定义的方式运行。例如,如果他们在那里期待一个数字,他们会像处理数字一样处理任何字节的数据。


要使用您的示例,假设您int是一个有符号的 4 字节(32 位)整数:

+-------------+--------------------------------------------+-----------+
| Source code |                  char[15]                  |    int    |
+-------------+--------------------------------------------------------+
| Memory      |61|61|61|62|62|62|63|63|63|64|64|64|65|65|65|EF|BE|AD|DE|
+-------------+--------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

您可以看到int的内存位置现在包含0xEFBEADDE,假设是大端系统2。这是有符号的 32 位 int -272716322。现在,如果您将相同的内存解释为 unsigned int ( uint),则4022250974相反。对于内存中完全相同的数据,其含义完全取决于您如何查看它。


1有一些机制会阻止您写入受保护的内存区域,并且如果您尝试这样做会使您的程序崩溃。

2 x86 实际上是 little-endian,这意味着您可以向后解释构成较大值的字节。因此,在 x86 上,您将改为使用0xDEADBEEFSigned-559038737或 unsigned 3735928559

  • @DarienSpringer 换句话说,一个数字无论在什么基数中都是相同的数字。十六进制是查看二进制的一种方便(紧凑)的方式。在物理上,它是二进制的。人类喜欢十进制,所以我们更经常将数字显示为十进制。但是在我们到达显示步骤之前,所有数值运算(加、减、乘等)都对内存中的相同二进制数据起作用。 (5认同)
  • @DarienSpringer 两者都占用 4 字节的内存——它们是相同的 4 字节序列。它们在内存中是相同的。如果需要,您可以将其全部视为内存中的基数 2(二进制)。然后,当您显示它们时(转换为字符串用于输出),您可以选择要显示的基数——十六进制是基数 16,十进制是基数 10。字符串表示存储在不同的内存位置,可以使用不同的数量内存(因为每个字符都是一个单独的字节)。*string* `0xDEADBEEF` 在内存中存储为 `0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46`。 (2认同)