说我有一个C字符数组char buf[15]
。说变量int set_me = 0
的数据紧接在之后的位置char buf[15]
。如果我溢出buf
与串"aaabbbcccdddeee\xef\xbe\xad\xde"
,将set_me
的数据类型的变化从一个整数的字符阵列?
说我有一个C字符数组char buf[15]
。说变量int set_me = 0
的数据紧接在之后的位置char buf[15]
。如果我溢出buf
与串"aaabbbcccdddeee\xef\xbe\xad\xde"
,将set_me
的数据类型的变化从一个整数的字符阵列?
Answers:
没有。
变量的“数据类型”仅在源代码中相关(甚至在某些语言中也是如此)。它告诉编译器如何处理变量。
这些高级数据类型在已编译的(本机)代码中并不存在。它们会影响编译器生成的指令,但是指令本身并不关心数据是表示字符还是数字。
变量在硬件中不存在。在硬件中,您具有内存位置以及对其进行操作的指令。
变量可以看作是内存位置数据的视图 —如果斜视并看一下同一块内存(不同类型的不同变量引用同一位置),则相同的二进制值可能具有不同的含义。
例如,字节0x41可以解释为UTF-8编码字符A
。也可以将其解释为单字节整数65
。也可以将其解释为多字节整数或浮点数中的一个字节,或多字节字符编码中的一个字节。这可能是个问题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|
+-------------+--------------------------------------------------------+
您可以看到,int
现在0xEFBEADDE
假设使用大尾数系统2,它的内存位置包含其中。这是有符号的32位int -272716322
。现在,如果您将同一内存解释为一个无符号的int(uint
),它将4022250974
改为。对于内存中完全相同的数据,含义完全取决于您如何查看数据。
1有一些机制可以阻止您写入受保护的内存区域,并且如果尝试这样做,将使程序崩溃。
2 x86实际上是little-endian,这意味着您向后解释构成较大值的字节。因此,在x86上,您将拥有0xDEADBEEF
签名-559038737
或未签名的属性3735928559
。
0xdeadbeef
,在x86架构上,它将比其十进制形式占用更少的内存空间3735928559
?
0xDEADBEEF
以形式存储在内存中0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46
。
0xEFBEADDE
。也许改写一下。否则,这是一个绝妙的答案-我特别喜欢“观察”类比和“斜眼”的想法:)