0

使用#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;
}

现在假设有人设法对生成的二进制文件进行十六进制编辑。他/她可以编辑全局常量以导致缓冲区溢出,从而执行任意代码。

我的问题是,这种十六进制编辑可以用#defines 吗?

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

4

4 回答 4

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
于 2013-07-03T06:44:42.717 回答
1

如果名称将被多次使用,您可能应该使用全局常量数组:

const char constant[] = "Constant";

它占用的空间更少——数组名是一个指针,但它不存储在内存中。相比之下,在该const char *constant = "Constant";版本中,您同时拥有一个存储的指针(可以修改)和字符串值。如果名称只使用一次,您可能决定将字符串直接写为代码中的文字,或者您可以使用数组或#define机制。

即使您使用#define,用户也可以像任何其他机制一样“十六进制编辑”生成的二进制文件。使用的符号没有提供额外的保护。

于 2013-07-03T06:41:22.893 回答
1

完全一样。唯一的区别是使用#define 字符串将获得一个由编译器自动分配的内部名称,C 程序无法访问该名称。

如果您使用选项 -save-temps -fverbose-asm 编译程序,您可以看到它。这将留下预处理器结果和汇编程序。您将看到在这两种情况下都将声明字符串,其中一种带有您的标签,const *另一种带有生成的名称。

于 2013-07-03T06:52:09.047 回答
0

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

于 2013-07-03T06:44:04.677 回答