剥离二进制文件后的调试部分
Posted
技术标签:
【中文标题】剥离二进制文件后的调试部分【英文标题】:Debug sections after binary is stripped 【发布时间】:2016-03-25 22:49:11 【问题描述】:我在 linux 上构建了我的应用程序(c/c++)并使用“strip”命令将其剥离。 我认为如果不提供任何选项,它将从原始二进制文件中删除所有调试信息。 我使用以下内容进行了剥离:
strip my_app -o $odir/my_app_stripped (where $odir is preconfigured location)
但是,当我执行以下操作时:
objdump -h my_app_stripped
它给了我以下输出:
my_app_stripped: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000002c 00048154 00048154 00000154 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 00048180 00048180 00000180 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .hash 00067dcc 000481a0 000481a0 000001a0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .dynsym 0011f6e0 000aff6c 000aff6c 00067f6c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynstr 00488e4c 001cf64c 001cf64c 0018764c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .gnu.version 00023edc 00658498 00658498 00610498 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version_r 00000290 0067c374 0067c374 00634374 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .rel.dyn 00006860 0067c604 0067c604 00634604 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.plt 00003768 00682e64 00682e64 0063ae64 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .init 00000017 006865cc 006865cc 0063e5cc 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
10 .plt 00006ee0 006865e4 006865e4 0063e5e4 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .text 01120918 0068d4d0 0068d4d0 006454d0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 BINK 00018d20 017addf0 017addf0 01765df0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 BINK32 00001350 017c6b10 017c6b10 0177eb10 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 BINK16 00001008 017c7e60 017c7e60 0177fe60 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 BINKP8 000008fb 017c8e70 017c8e70 01780e70 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
16 BINKY16 000008e1 017c9770 017c9770 01781770 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
17 BINKY12 000001b0 017ca060 017ca060 01782060 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
18 .fini 0000001a 017ca210 017ca210 01782210 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
19 .rodata 00164204 017ca240 017ca240 01782240 2**6
CONTENTS, ALLOC, LOAD, READONLY, DATA
20 .debug$S 000010f8 0192e444 0192e444 018e6444 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
21 BINKCONST 00004e40 0192f540 0192f540 018e7540 2**6
CONTENTS, ALLOC, LOAD, READONLY, DATA
22 .debug$F 00000250 01934380 01934380 018ec380 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
23 .rdata 00000080 019345d0 019345d0 018ec5d0 2**4
CONTENTS, ALLOC, LOAD, READONLY, DATA
24 .eh_frame_hdr 0004765c 01934650 01934650 018ec650 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
25 .eh_frame 00128fec 0197bcac 0197bcac 01933cac 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
26 .gcc_except_table 000aaaf1 01aa4c98 01aa4c98 01a5cc98 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
27 .tbss 00000004 01b5078c 01b5078c 01b0778c 2**2
ALLOC, THREAD_LOCAL
28 .ctors 000004f4 01b5078c 01b5078c 01b0778c 2**2
CONTENTS, ALLOC, LOAD, DATA
29 .dtors 000004d0 01b50c80 01b50c80 01b07c80 2**2
CONTENTS, ALLOC, LOAD, DATA
30 .jcr 00000004 01b51150 01b51150 01b08150 2**2
CONTENTS, ALLOC, LOAD, DATA
31 .data.rel.ro 00012160 01b51160 01b51160 01b08160 2**5
CONTENTS, ALLOC, LOAD, DATA
32 .dynamic 00000240 01b632c0 01b632c0 01b1a2c0 2**2
CONTENTS, ALLOC, LOAD, DATA
33 .got 00002e6c 01b63500 01b63500 01b1a500 2**2
CONTENTS, ALLOC, LOAD, DATA
34 .data 000481a8 01b66380 01b66380 01b1d380 2**5
CONTENTS, ALLOC, LOAD, DATA
35 .got.plt 00001bc0 01bae528 01bae528 01b65528 2**2
CONTENTS, ALLOC, LOAD, DATA
36 BINKDATA 00002de0 01bb0100 01bb0100 01b67100 2**5
CONTENTS, ALLOC, LOAD, DATA
37 .bss 0046f8e8 01bb2ee0 01bb2ee0 01b69ee0 2**5
ALLOC
38 BINKBSS 000067a0 020227e0 020227e0 01b69ee0 2**5
ALLOC
39 .comment 00002d95 00000000 00000000 01b69ee0 2**0
CONTENTS, READONLY
40 .drectve 0000005d 00000000 00000000 01b6cc75 2**0
CONTENTS, READONLY
那么,如果调试被全部删除,那么“.debug$S”和“.debug$F”是什么部分?
【问题讨论】:
【参考方案1】:尽管它们的名称这些部分不是调试部分,至少根据它们的标志不是。您会注意到它们具有相同的标志CONTENTS, ALLOC, LOAD, READONLY, DATA
,与可执行文件中的许多其他部分(如.rodata
)相同。这些标志表示该部分旨在加载到内存中并用作数据。 strip
命令无法知道这些部分是否不必要。丢弃.rodata
部分会破坏您的程序,导致它在每次运行时崩溃。 strip
命令不知道丢弃 .debug$F
和 .debug$S
部分不会做同样的事情。
请注意,您通常不会在 ELF 可执行文件中找到名为 .debug$F
和 debug$S
的部分。通常在 ELF 文件中使用的 DWARF 调试信息存储在名称以 .debug_
而不是 .debug$
开头的部分中。他们还设置了DEBUGGING
标志(但没有设置LOAD
标志),因此strip
知道他们正在调试部分并且应该并且可以删除它。具有这些名称的部分通常只能在 Microsoft 编译器生成的 PECOFF 文件中看到。它们包含 Microsoft 专有格式的调试信息。
如果您可以确定这些部分不包含有用的信息并且想要删除它们,您应该在链接之前将它们从目标文件中删除。由于它们已加载到内存中,因此在链接后完全删除它们可能为时已晚。您可以使用objcopy -R ".debug$*" foo.o foo-stripped.o
之类的命令,然后使用foo-stripped.o
而不是foo.o
链接。
您可能还想从可执行文件中删除.comment
和.directve
部分,因为这些部分可能不是必需的。特别是.directve
是另一个您通常不会在 ELF 文件中看到的 PECOFF 部分。
【讨论】:
感谢您的回答。但是,当您说“.debug$S/F”和“.directive”是由微软创建的 PECOFF 格式部分时,我不明白。但我在 linux 上工作并使用 gcc/g++,那么这些是如何创建的呢? @Monku GCC/G++ 永远不会在任何平台上创建.debug$
部分,除非你明确告诉它创建一个这样的部分并准确告诉它要放入什么(例如 @987654342 @)。它仅在 Windows PECOFF 目标上创建 .directive
部分。因此,要么您链接到由 Microsoft 编译器创建的目标文件,要么您的代码在某处明确告诉 GCC 创建这些部分。创建地图文件可以帮助您确定哪个。将 -Wl,-Map=my_app.map
传递给用于创建可执行文件的 GCC 命令。以上是关于剥离二进制文件后的调试部分的主要内容,如果未能解决你的问题,请参考以下文章