翼度科技»论坛 云主机 LINUX 查看内容

Linux 可执行文件瘦身指令 strip 使用示例

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/lJ8vj-FszEoplMVcmT0I0w

在 Linux 系统下开发软件,输出的可执行文件可大可小,运行环境如果是在服务器那么可能资源比较充足,但如果是在嵌入式环境,那么存储资源是寸土必争的。所以会有对可执行文件进行瘦身的需求,比如使用指令 strip。
关于 strip 的操作,有人戏称是“脱衣服”,我这里的描述不会这么赤裸裸,改成“瘦身”。
在 man 手册里,strip 的说明是:
discard symbols from object files
意思就是把文件内的符号信息移除,这样文件的大小就降下来了,同时不影响可执行文件被运行。另外,把可执行文件内的部分信息移除有助于防止被逆向工程破解。
strip 命令格式如下:
strip [options] filename ...
下面我通过几个例子来说明如何使用这个命令:
巧妇难为无米之炊,所以需要先准备一个可执行文件 test,生成可执行文件的源文件 test.cpp 如下:
  1. #include<stdio.h>
  2. class test{
  3. };
  4. int main(void)
  5. {
  6.     printf("sizeof(class test)=%d\n", (int)sizeof(test));
  7.     return 0;
  8. }
复制代码
移除所有符号信息

先来看看可执行文件的内部符号信息,通过命令 readelf 读取
  1. $ readelf -s test
复制代码
  1. Symbol table '.dynsym' contains 7 entries:
  2.    Num:    Value          Size Type    Bind   Vis      Ndx Name
  3.      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
  4.      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
  5.      2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
  6.      3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
  7.      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
  8.      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
  9.      6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)
  10. Symbol table '.symtab' contains 63 entries:
  11.    Num:    Value          Size Type    Bind   Vis      Ndx Name
  12.      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
  13.      1: 0000000000000238     0 SECTION LOCAL  DEFAULT    1
  14.      2: 0000000000000254     0 SECTION LOCAL  DEFAULT    2
  15.      3: 0000000000000274     0 SECTION LOCAL  DEFAULT    3
  16.      4: 0000000000000298     0 SECTION LOCAL  DEFAULT    4
  17.      5: 00000000000002b8     0 SECTION LOCAL  DEFAULT    5
  18.      6: 0000000000000360     0 SECTION LOCAL  DEFAULT    6
  19.      7: 00000000000003e4     0 SECTION LOCAL  DEFAULT    7
  20.      8: 00000000000003f8     0 SECTION LOCAL  DEFAULT    8
  21.      9: 0000000000000418     0 SECTION LOCAL  DEFAULT    9
  22.     10: 00000000000004d8     0 SECTION LOCAL  DEFAULT   10
  23.     11: 00000000000004f0     0 SECTION LOCAL  DEFAULT   11
  24.     12: 0000000000000510     0 SECTION LOCAL  DEFAULT   12
  25.     13: 0000000000000530     0 SECTION LOCAL  DEFAULT   13
  26.     14: 0000000000000540     0 SECTION LOCAL  DEFAULT   14
  27.     15: 00000000000006e4     0 SECTION LOCAL  DEFAULT   15
  28.     16: 00000000000006f0     0 SECTION LOCAL  DEFAULT   16
  29.     17: 000000000000070c     0 SECTION LOCAL  DEFAULT   17
  30.     18: 0000000000000748     0 SECTION LOCAL  DEFAULT   18
  31.     19: 0000000000200db8     0 SECTION LOCAL  DEFAULT   19
  32.     20: 0000000000200dc0     0 SECTION LOCAL  DEFAULT   20
  33.     21: 0000000000200dc8     0 SECTION LOCAL  DEFAULT   21
  34.     22: 0000000000200fb8     0 SECTION LOCAL  DEFAULT   22
  35.     23: 0000000000201000     0 SECTION LOCAL  DEFAULT   23
  36.     24: 0000000000201010     0 SECTION LOCAL  DEFAULT   24
  37.     25: 0000000000000000     0 SECTION LOCAL  DEFAULT   25
  38.     26: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
  39.     27: 0000000000000570     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
  40.     28: 00000000000005b0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
  41.     29: 0000000000000600     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
  42.     30: 0000000000201010     1 OBJECT  LOCAL  DEFAULT   24 completed.7698
  43.     31: 0000000000200dc0     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin
  44.     32: 0000000000000640     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
  45.     33: 0000000000200db8     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_
  46.     34: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
  47.     35: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
  48.     36: 000000000000084c     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
  49.     37: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
  50.     38: 0000000000200dc0     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
  51.     39: 0000000000200dc8     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
  52.     40: 0000000000200db8     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
  53.     41: 000000000000070c     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
  54.     42: 0000000000200fb8     0 OBJECT  LOCAL  DEFAULT   22 _GLOBAL_OFFSET_TABLE_
  55.     43: 00000000000006e0     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
  56.     44: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
  57.     45: 0000000000201000     0 NOTYPE  WEAK   DEFAULT   23 data_start
  58.     46: 0000000000201010     0 NOTYPE  GLOBAL DEFAULT   23 _edata
  59.     47: 00000000000006e4     0 FUNC    GLOBAL DEFAULT   15 _fini
  60.     48: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
  61.     49: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
  62.     50: 0000000000201000     0 NOTYPE  GLOBAL DEFAULT   23 __data_start
  63.     51: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
  64.     52: 0000000000201008     0 OBJECT  GLOBAL HIDDEN    23 __dso_handle
  65.     53: 00000000000006f0     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
  66.     54: 0000000000000670   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
  67.     55: 0000000000201018     0 NOTYPE  GLOBAL DEFAULT   24 _end
  68.     56: 0000000000000540    43 FUNC    GLOBAL DEFAULT   14 _start
  69.     57: 0000000000201010     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
  70.     58: 000000000000064a    33 FUNC    GLOBAL DEFAULT   14 main
  71.     59: 0000000000201010     0 OBJECT  GLOBAL HIDDEN    23 __TMC_END__
  72.     60: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
  73.     61: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@@GLIBC_2.2
  74.     62: 00000000000004f0     0 FUNC    GLOBAL DEFAULT   11 _init
复制代码
用 strip 加上 -s 把所有符号信息移除,然后再次读取文件信息看看
  1. $ strip -s test
  2. $ readelf -s test
复制代码
  1. Symbol table '.dynsym' contains 7 entries:
  2.    Num:    Value          Size Type    Bind   Vis      Ndx Name
  3.      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
  4.      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
  5.      2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
  6.      3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
  7.      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
  8.      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
  9.      6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)
复制代码
从上面的输出可以看到文件内的符号信息已被移除。但是 .dynsym 和 .dynstr 表信息还是存在的,这两个表信息是用于动态链接库链接使用,所以执行 strip -s 后,不影响动态链接库的使用。
移除调试信息

如果仅仅需要移除调试信息,那么可以使用选项 --strip-debug
  1. strip --strip-debug test
复制代码
然后对比一下读出来的符号信息,发现瘦身后文件信息缺失了下面的内容
  1.     ...
  2.     26: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
  3.     ...
  4.     34: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
  5.     35: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
  6.     ...
复制代码
移除特定的字段信息

有些情况下,我们需要对特定的字段头信息移除,那么可以使用选项 -R
先来读取一下未经瘦身的可执行文件的字段头信息
  1. $ readelf -S test
复制代码
  1. There are 29 section headers, starting at offset 0x18b8:
  2. Section Headers:
  3.   [Nr] Name              Type             Address           Offset
  4.        Size              EntSize          Flags  Link  Info  Align
  5.   [ 0]                   NULL             0000000000000000  00000000
  6.        0000000000000000  0000000000000000           0     0     0
  7.   [ 1] .interp           PROGBITS         0000000000000238  00000238
  8.        000000000000001c  0000000000000000   A       0     0     1
  9.   [ 2] .note.ABI-tag     NOTE             0000000000000254  00000254
  10.        0000000000000020  0000000000000000   A       0     0     4
  11.   [ 3] .note.gnu.build-i NOTE             0000000000000274  00000274
  12.        0000000000000024  0000000000000000   A       0     0     4
  13.   [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298
  14.        000000000000001c  0000000000000000   A       5     0     8
  15.   [ 5] .dynsym           DYNSYM           00000000000002b8  000002b8
  16.        00000000000000a8  0000000000000018   A       6     1     8
  17.   [ 6] .dynstr           STRTAB           0000000000000360  00000360
  18.        0000000000000084  0000000000000000   A       0     0     1
  19.   [ 7] .gnu.version      VERSYM           00000000000003e4  000003e4
  20.        000000000000000e  0000000000000002   A       5     0     2
  21.   [ 8] .gnu.version_r    VERNEED          00000000000003f8  000003f8
  22.        0000000000000020  0000000000000000   A       6     1     8
  23.   [ 9] .rela.dyn         RELA             0000000000000418  00000418
  24.        00000000000000c0  0000000000000018   A       5     0     8
  25.   [10] .rela.plt         RELA             00000000000004d8  000004d8
  26.        0000000000000018  0000000000000018  AI       5    22     8
  27.   [11] .init             PROGBITS         00000000000004f0  000004f0
  28.        0000000000000017  0000000000000000  AX       0     0     4
  29.   [12] .plt              PROGBITS         0000000000000510  00000510
  30.        0000000000000020  0000000000000010  AX       0     0     16
  31.   [13] .plt.got          PROGBITS         0000000000000530  00000530
  32.        0000000000000008  0000000000000008  AX       0     0     8
  33.   [14] .text             PROGBITS         0000000000000540  00000540
  34.        00000000000001a2  0000000000000000  AX       0     0     16
  35.   [15] .fini             PROGBITS         00000000000006e4  000006e4
  36.        0000000000000009  0000000000000000  AX       0     0     4
  37.   [16] .rodata           PROGBITS         00000000000006f0  000006f0
  38.        000000000000001b  0000000000000000   A       0     0     4
  39.   [17] .eh_frame_hdr     PROGBITS         000000000000070c  0000070c
  40.        000000000000003c  0000000000000000   A       0     0     4
  41.   [18] .eh_frame         PROGBITS         0000000000000748  00000748
  42.        0000000000000108  0000000000000000   A       0     0     8
  43.   [19] .init_array       INIT_ARRAY       0000000000200db8  00000db8
  44.        0000000000000008  0000000000000008  WA       0     0     8
  45.   [20] .fini_array       FINI_ARRAY       0000000000200dc0  00000dc0
  46.        0000000000000008  0000000000000008  WA       0     0     8
  47.   [21] .dynamic          DYNAMIC          0000000000200dc8  00000dc8
  48.        00000000000001f0  0000000000000010  WA       6     0     8
  49.   [22] .got              PROGBITS         0000000000200fb8  00000fb8
  50.        0000000000000048  0000000000000008  WA       0     0     8
  51.   [23] .data             PROGBITS         0000000000201000  00001000
  52.        0000000000000010  0000000000000000  WA       0     0     8
  53.   [24] .bss              NOBITS           0000000000201010  00001010
  54.        0000000000000008  0000000000000000  WA       0     0     1
  55.   [25] .comment          PROGBITS         0000000000000000  00001010
  56.        0000000000000029  0000000000000001  MS       0     0     1
  57.   [26] .symtab           SYMTAB           0000000000000000  00001040
  58.        0000000000000588  0000000000000018          27    39     8
  59.   [27] .strtab           STRTAB           0000000000000000  000015c8
  60.        00000000000001f2  0000000000000000           0     0     1
  61.   [28] .shstrtab         STRTAB           0000000000000000  000017ba
  62.        00000000000000fe  0000000000000000           0     0     1
  63. Key to Flags:
  64.   W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  65.   L (link order), O (extra OS processing required), G (group), T (TLS),
  66.   C (compressed), x (unknown), o (OS specific), E (exclude),
  67.   l (large), p (processor specific)
复制代码
假如需要移除字段头 .gnu.version 的信息,那么执行
  1. $ strip -R .gnu.version test
复制代码
再次使用 readelf -S 读文件信息可以发现指定的信息已被移除。
移除重定位时不需要的符号信息

如果需要移除重定位时不需要的符号信息,那么可以使用选项 --strip-unneeded
  1. $ strip --strip-unneeded test
复制代码
比如需要对静态链接库文件瘦身时,这个选项不影响静态库的链接使用。
瘦身时保留部分符号信息

某些情况下,对可执行文件瘦身不是一刀切的,还可能需要对部分符号信息网开一面,可以使用选项 -K
  1. $ strip -s -Kframe_dummy test
复制代码
  1. $ readelf -s test Symbol table '.dynsym' contains 7 entries:
  2.    Num:    Value          Size Type    Bind   Vis      Ndx Name
  3.      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
  4.      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
  5.      2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
  6.      3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
  7.      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
  8.      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
  9.      6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)Symbol table '.symtab' contains 27 entries:   Num:    Value          Size Type    Bind   Vis      Ndx Name    ...     1: 0000000000000640     0 FUNC    LOCAL  DEFAULT   14 frame_dummy    ...
复制代码
可见跟在 -K 选项后指定的符号被保留了下来,没有被一起移除。
另外,在同一个 strip 命令中 -K 选项可以同时多次使用。
移除特定的符号信息

如果仅仅需要对特定的符号信息进行移除,其它符号信息保留,那么可以使用选项 -N
假设可执行文件未经任何瘦身操作,然后执行下面的指令
$ strip -Nframe_dummy test
执行上面的指令后,再使用 readelf -s 读取符号信息,可以发现跟在 -N 选项后的符号已被移除。
另存文件

在移除相关信息后,希望保留原有可执行文件的内部信息不变,并且将瘦身后的文件另存为新文件,那么可以使用选项 -o
  1. $ strip -s -otest_striped test
复制代码
输出瘦身文件后,使用 readelf -s 分别读取文件 test_striped 和 test,对比可见文件 test 的符号信息没有变化,而文件 test_striped 已移除符号信息。
保留原有访问和修改时间

当有需要保留原有的访问和修改时间信息时,可以使用选项 -p
假设可执行文件未曾被瘦身过,用 stat 看看文件的详细状态
  1. $ stat test
复制代码
  1.   File: test
  2.   Size: 8304              Blocks: 24         IO Block: 4096   regular file
  3. Device: 801h/2049d        Inode: 803646      Links: 1
  4. Access: (0775/-rwxrwxr-x)  Uid: ( 1000/      if)   Gid: ( 1000/      if)
  5. Access: 2023-06-26 21:02:49.274028914 +0800
  6. Modify: 2023-06-26 21:02:49.274028914 +0800
  7. Change: 2023-06-26 21:02:49.274028914 +0800
  8. Birth: -
复制代码
然后执行 strip 命令,并且尝试保留原有的访问和修改时间信息
  1. $ strip -s -p test
复制代码
再看看文件的详细状态
  1. $ stat test
  2.   File: test
  3.   Size: 6120              Blocks: 16         IO Block: 4096   regular file
  4. Device: 801h/2049d        Inode: 803647      Links: 1
  5. Access: (0775/-rwxrwxr-x)  Uid: ( 1000/      if)   Gid: ( 1000/      if)
  6. Access: 2023-06-26 21:02:49.000000000 +0800
  7. Modify: 2023-06-26 21:02:49.000000000 +0800
  8. Change: 2023-06-26 21:10:53.991892402 +0800
  9. Birth: -
复制代码
可见,原有的访问和修改时间信息得以保留,保留到秒单位。
从文件读取选项内容

在运维过程中,为了方便不同配置的灵活切换,往往会把参数配置等存储在文件中,不同的需求对求不同配置文件。
strip 命令同样支持从文件中读取配置选项,格式如
  1. $ strip @filename
复制代码
文件 filename 中保存有文本形式的参数选项等。比如
  1. $ echo "-s test" > options.txt
  2. $ strip @options.txt
复制代码
效果等同于
  1. $ strip -s test
复制代码
输出详细过程

在执行 strip 命令的过程中可以同时输出详细信息,使用选线 -v
  1. $ strip -v -s test
  2. copy from `test' [elf64-x86-64] to `stPp23jj' [elf64-x86-64]
复制代码
来源:https://www.cnblogs.com/englyf/p/17510353.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具