全局const vs #define。从安全角度来看哪个更好?

时间:2013-07-03 06:35:34

标签: c macros constants buffer-overflow

使用#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?

我自己没有尝试过十六进制编辑,因为我没有任何想法如何破译这些十六进制值!我也找不到任何可靠的教程。

4 个答案:

答案 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)

我认为这是一回事,一旦你可以编辑二进制文件,我可以修改这些值。