#define
:#include <stdio.h>
#define CONSTANT "Constant"
int main(void)
{
char buf[32];
strcpy(buf, CONSTANT);
return 0;
}
const
:#include <stdio.h>
const char *constant = "Constant";
int main(void)
{
char buf[32];
strcpy(buf, constant);
return 0;
}
现在假设有人设法对生成的二进制文件进行十六进制编辑。他/她可以编辑全局常量以导致缓冲区溢出,从而执行任意代码。
我的问题是,这种十六进制编辑是否可以使用#define
s?
我自己没有尝试过十六进制编辑,因为我没有任何想法如何破译这些十六进制值!我也找不到任何可靠的教程。
答案 0 :(得分:2)
两者都不安全。有一次,两个字符串都必须存储在可执行文件中。
此外,如果用户要编辑二进制文件,我认为他们根本不打算溢出你的字符串 - 他们只是直接编辑二进制代码。
$ cat test.c
#include <stdio.h>
#if TEST == 0
#define str "Hello World\n"
int main() {
puts(str);
return 0;
}
#else
const char *str = "Hello World\n";
int main() {
puts(str);
return 0;
}
#endif
$ gcc test.c -Wall -DTEST=0 -o test0
$ gcc test.c -Wall -DTEST=1 -o test1
$ grep "Hello World" test0
Binary file test0 matches
$ grep "Hello World" test1
Binary file test1 matches
答案 1 :(得分:1)
如果名称将被多次使用,则应该使用全局常量数组:
const char constant[] = "Constant";
它占用的空间更少 - 数组名称是指针,但它不存储在内存中。相比之下,在const char *constant = "Constant";
版本中,您既有存储指针(可以修改)又有字符串值。如果名称仅使用一次,您可能决定将字符串直接写为代码中的文字,或者您可以使用数组或#define
机制。
即使您使用#define
,用户也可以“生成”十六进制编辑生成的二进制文件,就像任何其他机制一样。使用的符号没有提供额外的保护。
答案 2 :(得分:1)
完全一样。唯一的区别是使用#define字符串将获得编译器自动分配的内部名称,C程序无法访问该内部名称。
如果使用选项-save-temps -fverbose-asm编译程序,则可以看到它。这将留下预处理器结果和汇编程序。您将看到,在这两种情况下都将声明字符串,其中一个标签为const *
,另一个标签为生成名称。
答案 3 :(得分:0)
我认为这是一回事,一旦你可以编辑二进制文件,我可以修改这些值。