是否可以隐藏使用哪个编译器的详细信息?

逆向工程 反编译 编译器 C
2021-06-27 07:39:22

编译器将系统信息添加到编译时创建的输出/目标文件中。

  • 是否有任何编译器选项可以阻止添加此信息?
  • 是否可以完全删除编译器签名,以便检测使用的编译器很难/不可能?
4个回答

我在这里的答案特定于常见的 C/C++ 编译器,但答案背后的原则可以推广到其他场景。

编译器的差异表现在很多方面,其中一些非常微妙。如果严格来说是可执行标头中的属性问题,那么我们可以很容易地想象重写所述标头。但是,每个编译器都有自己独特的生成代码风格(这取决于优化级别)。每个编译器都有自己的默认标准库(通常包括指示字符串),以及可执行文件入口点的不同默认样板代码。还有其他差异,例如:在一个编译器中使用的优化在另一个编译器中未使用;默认调用约定可能不同;为函数序言生成的代码在 gcc 和 MSVC 上明显不同(例如);不同的编译器对于异常处理有不同的代码序列和数据结构;还有更多的例子。

回答您的第一个问题:不,我认为流行编译器没有任何编译器选项可以阻止它添加其编译器工件。

@Syzygy 的回答探讨了其中的部分问题:编译器有时会生成非常不同的指令。

更重要的是,了解不同编译器留下工件可以帮助您帮助区分使用的编译器。例如,想象一下使用 mingw 编译您的 Windows 可执行文件,然后向其中添加一个 RICH 标头。这是一个人为的例子,但是通过将 MSVC 编译器的这个工件添加到 mingw 输出可能会混淆一些自动化工具。

之前的许多答案都指出这是不可能的,因为编译器总是会留下工件。我决定使用 Linux 上的程序做一个小案例研究,尽管这个想法是可以转移的。

例如,我创建了一个小“Hello World!” C中的文件:

#include <stdio.h>

int main(void) {
    puts("Hello World!");
    return 0;
}

然后我编译它并用于hexdump -C结果。以下除了非常清楚地标识了编译器!

00001020  47 43 43 3a 20 28 55 62  75 6e 74 75 2f 4c 69 6e  |GCC: (Ubuntu/Lin|
00001030  61 72 6f 20 34 2e 36 2e  33 2d 31 75 62 75 6e 74  |aro 4.6.3-1ubunt|
00001040  75 35 29 20 34 2e 36 2e  33 00 00 2e 73 79 6d 74  |u5) 4.6.3...symt|
00001050  61 62 00 2e 73 74 72 74  61 62 00 2e 73 68 73 74  |ab..strtab..shst|
00001060  72 74 61 62 00 2e 69 6e  74 65 72 70 00 2e 6e 6f  |rtab..interp..no|
00001070  74 65 2e 41 42 49 2d 74  61 67 00 2e 6e 6f 74 65  |te.ABI-tag..note|
00001080  2e 67 6e 75 2e 62 75 69  6c 64 2d 69 64 00 2e 67  |.gnu.build-id..g|
00001090  6e 75 2e 68 61 73 68 00  2e 64 79 6e 73 79 6d 00  |nu.hash..dynsym.|
000010a0  2e 64 79 6e 73 74 72 00  2e 67 6e 75 2e 76 65 72  |.dynstr..gnu.ver|
000010b0  73 69 6f 6e 00 2e 67 6e  75 2e 76 65 72 73 69 6f  |sion..gnu.versio|
000010c0  6e 5f 72 00 2e 72 65 6c  61 2e 64 79 6e 00 2e 72  |n_r..rela.dyn..r|
000010d0  65 6c 61 2e 70 6c 74 00  2e 69 6e 69 74 00 2e 74  |ela.plt..init..t|
000010e0  65 78 74 00 2e 66 69 6e  69 00 2e 72 6f 64 61 74  |ext..fini..rodat|
000010f0  61 00 2e 65 68 5f 66 72  61 6d 65 5f 68 64 72 00  |a..eh_frame_hdr.|
00001100  2e 65 68 5f 66 72 61 6d  65 00 2e 63 74 6f 72 73  |.eh_frame..ctors|
00001110  00 2e 64 74 6f 72 73 00  2e 6a 63 72 00 2e 64 79  |..dtors..jcr..dy|
00001120  6e 61 6d 69 63 00 2e 67  6f 74 00 2e 67 6f 74 2e  |namic..got..got.|
00001130  70 6c 74 00 2e 64 61 74  61 00 2e 62 73 73 00 2e  |plt..data..bss..|
00001140  63 6f 6d 6d 65 6e 74 00  00 00 00 00 00 00 00 00  |comment.........|

运行strip -R .comment部分有帮助,并完全删除了对 GCC 的明确提及,但仍然有一些明显的迹象:

00000260  47 4e 55 00 00 00 00 00  02 00 00 00 06 00 00 00  |GNU.............|
00000270  18 00 00 00 04 00 00 00  14 00 00 00 03 00 00 00  |................|
00000280  47 4e 55 00 5f 8a 1b 97  01 5a ac d7 93 fb 96 29  |GNU._....Z.....)|
* * *
00000310  00 00 00 00 00 00 00 00  00 5f 5f 67 6d 6f 6e 5f  |.........__gmon_|
00000320  73 74 61 72 74 5f 5f 00  6c 69 62 63 2e 73 6f 2e  |start__.libc.so.|
00000330  36 00 70 75 74 73 00 5f  5f 6c 69 62 63 5f 73 74  |6.puts.__libc_st|
00000340  61 72 74 5f 6d 61 69 6e  00 47 4c 49 42 43 5f 32  |art_main.GLIBC_2|
00000350  2e 32 2e 35 00 00 00 00  02 00 02 00 00 00 00 00  |.2.5............|
* * *
00001020  00 2e 73 68 73 74 72 74  61 62 00 2e 69 6e 74 65  |..shstrtab..inte|
00001030  72 70 00 2e 6e 6f 74 65  2e 41 42 49 2d 74 61 67  |rp..note.ABI-tag|
00001040  00 2e 6e 6f 74 65 2e 67  6e 75 2e 62 75 69 6c 64  |..note.gnu.build|
00001050  2d 69 64 00 2e 67 6e 75  2e 68 61 73 68 00 2e 64  |-id..gnu.hash..d|
00001060  79 6e 73 79 6d 00 2e 64  79 6e 73 74 72 00 2e 67  |ynsym..dynstr..g|
00001070  6e 75 2e 76 65 72 73 69  6f 6e 00 2e 67 6e 75 2e  |nu.version..gnu.|
00001080  76 65 72 73 69 6f 6e 5f  72 00 2e 72 65 6c 61 2e  |version_r..rela.|
00001090  64 79 6e 00 2e 72 65 6c  61 2e 70 6c 74 00 2e 69  |dyn..rela.plt..i|
000010a0  6e 69 74 00 2e 74 65 78  74 00 2e 66 69 6e 69 00  |nit..text..fini.|
000010b0  2e 72 6f 64 61 74 61 00  2e 65 68 5f 66 72 61 6d  |.rodata..eh_fram|
000010c0  65 5f 68 64 72 00 2e 65  68 5f 66 72 61 6d 65 00  |e_hdr..eh_frame.|
000010d0  2e 63 74 6f 72 73 00 2e  64 74 6f 72 73 00 2e 6a  |.ctors..dtors..j|
000010e0  63 72 00 2e 64 79 6e 61  6d 69 63 00 2e 67 6f 74  |cr..dynamic..got|
000010f0  00 2e 67 6f 74 2e 70 6c  74 00 2e 64 61 74 61 00  |..got.plt..data.|
00001100  2e 62 73 73 00 00 00 00  00 00 00 00 00 00 00 00  |.bss............|

我决定看看如果我用空字节替换这段代码的最后一部分会发生什么。该程序仍然运行良好,但这降低了对其他操作系统的可移植性。

如果您尝试GNU用另一个编译器替换,例如clang,它仍然可以正常工作。虽然它可能会使逆向工程师感到困惑,但它肯定不难注意到。

最后,我试着看看如果我删除任何痕迹会发生什么GLIBC......

./a.out: ./a.out: no version information available (required by ./a.out)
./a.out: relocation error: ./a.out: symbol , version  not defined in file  with link time reference

简短的回答:没有。我不知道任何具有“隐身模式”开关的编译器,如果它有最终结果,IMO 只是同一编译器的另一个签名。

正如@omghai2u 建议您可以手动修改二进制文件并针对自动化工具对其进行测试,但我认为这不会有太大帮助。

更好的方法可能是使用 exe packer/protector虽然一个有经验的 RE 大概可以拆开它,但它仍然意味着很多工作和知识。所以至少这是第一道防线。