【问题标题】:Regarding `sprintf` and `nm` [closed]关于 `sprintf` 和 `nm` [关闭]
【发布时间】:2021-04-20 04:28:31
【问题描述】:

考虑以下程序:

#include <stdio.h>

int main(void)
{
    char c[10] = "hello!";
    char d[10] = {'\0'};

    sprintf (d, "%s", c);
    return printf("%s\n", d);
}

使用gcc -Wall -pedantic a.c(CentOS 上的GCC 4.8.5)编译后,当我在可执行文件上运行nm 时,我可以看到strcpy 被列为未定义符号:

 nm a.out | grep strcpy
                 U strcpy@@GLIBC_2.2.5

strcpy 是如何以及为什么出现在图片中的?如果我在 GCC 8.3.0 上编译相同的程序,strcpy 符号在nm 的输出中找不到。此外,在 GCC 4.8.5 上,如果我在 % 符号 sprintf (d, " %s", c) 之前添加一个空格,则 sprintf 调用不会替换为 strcpy

使用-S 开关和gcc 生成的汇编代码支持这些发现。有人可以帮我理解这里发生了什么吗?

客户审核可执行文件,如果他们发现对strcpy 的调用,将引发危险信号。我只是想了解为什么sprintf 调用被strcpy 取代。

【问题讨论】:

  • 也许编译器将对sprintf() 的调用优化为strcpy(d, c) — 达到相同的结果。查看汇编器——使用 GCC 的 -S 选项; source.c 的输出文件应该是 source.s
  • 降级编译器比升级编译器更有可能奏效。旧版本可能不会进行这种优化。较新的版本几乎可以肯定。还要考虑抑制优化-O0 是否有帮助——它可能会,也可能不会。
  • 使用memcpy,或者写一个循环,或者sprintf(d, "%.*s", (int)sizeof(d) - 1, c);,或者...
  • @babon 当然你必须这样做。这是一个安全审计。否则这只是老笑话Problem: "Evidence of hydraulic leak on right main landing gear." Solution: "Evidence removed."的编程等价物
  • 我不明白为什么如果客户对strcpy 有问题,他们不会对sprintf 有问题提供他们都可能遭受同样的失败。您是说 sprintf 的 所有用法 已经经过专门审核,以确保内容适合目标缓冲区?你真的应该考虑edit提出你的问题。

标签: c gcc compilation strcpy nm


【解决方案1】:

我的要求是strcpy 不应出现在nm 返回的符号列表中。

为什么?

但是在 Linux/x86-64 上使用GCC 10,您可以拥有自己的static inline 变体strcpy,也许使用一些extended asm 指令(也许是一些REP STOS...)

您还可以使用自己的GCC plugin 改进 GCC。

你也可以静态链接你的可执行文件,编译并链接到gcc -O2 -flto -Wall,然后使用strip(1)

strcpy 是怎么出现在这里的?

编译你的a.cusinggcc -fverbose-asm -Wall -Wextra -O3 -fdump-tree-all -S a.c,通过查看许多a.c.*转储文件和a.s文件,你将了解编译器做了什么。

允许编译器优化printf(有一个__builtin_printf....)。通过阅读n1570 或一些更新的 C 标准进行检查。

请注意,像 BINSEC 这样的二进制分析工具会“找到”与 strcpy 等效的代码

所以你的要求不合理,你应该解释一下

如果你需要一些code obfuscation(我认为大多数时候这是错误的),你最好使用更复杂的技术......例如在运行时使用GNU lightningasmjit 生成机器代码。

另一种可能的方法(由我的 manydl.c 程序说明)是在运行时生成一些混淆的 C 代码,将其编译为插件,然后使用 dlopen(3) 加载生成的插件。

要提高 C 源代码的安全性、安全性或可靠性,请使用 code reviews,遵循 MISRA C 等指南,考虑使用 Frama-C 等静态分析框架或Clang static analyzer(或者,在 2021 年春季,bismonthis DRAFT 报告中描述)。在许多情况中,使用snprintfstrcpy 是安全的(在某些情况下,可以“证明”如此;注意Rice's theorem) .为了增加对生成的可执行文件的信心,请考虑使用 CompCert 作为您的 C 编译器。

PS。如果您需要保护您的代码(C 源代码或生成的 executable),您应该请求您的律师帮助编写保护它的法律合同。

【讨论】:

  • 首先,我之前没有投反对票。谢谢回答我的问题。我遇到的问题是客户对提供的可执行文件进行了一些审核,一旦他们找到strcpy,他们就会发出危险信号。 strcpy 电话被替换为内部更安全的替代方案,现在我发现我也必须更换 sprintf 电话。我只是想了解为什么 sprintf 在 GCC 4.8 上转换为 strcpy。谢谢。
  • 是的。我认为您应该与您的客户进行讨论,而不是更改您的源代码。还要注意sprintf 的源代码在GNU libc 内部,优化过程的源代码在GCC 内部。 两者都是免费软件,您可以研究它们的源代码并进行改进
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多