【问题标题】:Interesting binary dump of executable file有趣的可执行文件二进制转储
【发布时间】:2014-03-16 14:20:30
【问题描述】:

出于某种原因,我用 C 语言编写了一个简单的程序来输出给定输入的二进制表示:

int main()
{
  char c;
  while(read(0,&c,1) > 0)
    {
      unsigned char cmp = 128;
      while(cmp)
        {
          if(c & cmp)
            write(1,"1",1);
          else
            write(1,"0",1);
          cmp >>= 1;
        }
    }

  return 0;
}

编译后:

$ gcc bindump.c -o bindump

我做了简单的测试来检查程序是否能够打印二进制:

$ cat bindump | ./bindump | fold -b100 | nl

输出如下:http://pastebin.com/u7SasKDJ

我怀疑输出看起来像随机的 1 和 0 序列。然而,部分输出似乎更有趣。例如,看看第 171 行和第 357 行之间的输出。我想知道 为什么与可执行文件的其他部分相比有很多零

我的架构是:

$ lscpu

Architecture:          i686
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    2
Core(s) per socket:    2
Socket(s):             1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 28
Stepping:              10
CPU MHz:               1000.000
BogoMIPS:              3325.21
Virtualization:        VT-x
L1d cache:             24K
L1i cache:             32K
L2 cache:              512K

【问题讨论】:

    标签: c linux binary bin


    【解决方案1】:

    当您在 Linux(和许多其他 unix 系统)上将程序编译为可执行文件时,它会以 ELF 格式编写。 ELF 格式有许多部分,您可以使用 readelf 或 objdump 检查它们:

    readelf -a bindump | less
    

    例如.text段包含CPU指令,.data全局变量,.bss未初始化的全局变量(在ELF文件本身中实际上是空的,但在程序执行时在主存中创建) 、.plt.got是跳转表、调试信息等。

    顺便说一句。使用 hexdump 检查文件的二进制内容要方便得多:

    hexdump -C bindata | less
    

    您可以看到从偏移量 0x850 开始(大约在您的转储中的第 171 行)有很多零,您还可以在右侧看到 ASCII 表示。

    让我们看看在 0x850 和 0x1160 之间哪些部分对应于您感兴趣的块(Off 字段 - 文件中的偏移量在这里很重要):

    > readelf -a bindata
    ...
    Section Headers:
    [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
    ...
    [28] .shstrtab         STRTAB          00000000 00074c 000106 00      0   0  1
    [29] .symtab           SYMTAB          00000000 000d2c 000440 10     30  45  4
    ...
    

    您可以使用 -x 检查单个部分的内容:

    > readelf -x .symtab bindump | less
    0x00000000 00000000 00000000 00000000 00000000 ................
    0x00000010 00000000 34810408 00000000 03000100 ....4...........
    0x00000020 00000000 48810408 00000000 03000200 ....H...........
    0x00000030 00000000 68810408 00000000 03000300 ....h...........
    0x00000040 00000000 8c810408 00000000 03000400 ................
    0x00000050 00000000 b8810408 00000000 03000500 ................
    0x00000060 00000000 d8810408 00000000 03000600 ................
    

    你会看到有很多零。该部分由定义符号的 18 字节值(= -x 输出中的一行)组成。从readelf -a 你可以看到它有 68 个条目,其中前 27 个(不包括第一个)是 SECTION 类型:

    Symbol table '.symtab' contains 68 entries:
       Num:    Value  Size Type    Bind   Vis      Ndx Name
         0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 08048134     0 SECTION LOCAL  DEFAULT    1 
         2: 08048148     0 SECTION LOCAL  DEFAULT    2 
         3: 08048168     0 SECTION LOCAL  DEFAULT    3 
         4: 0804818c     0 SECTION LOCAL  DEFAULT    4 
         ...
    

    根据specification(第1-18页),每个条目的格式如下:

    typedef struct {
        Elf32_Word st_name;
        Elf32_Addr st_value;
        Elf32_Word st_size;
        unsigned char st_info;
        unsigned char st_other;
        Elf32_Half st_shndx;
    } Elf32_Sym;
    

    这里没有过多的细节,我认为这里重要的是 st_name 和 st_size 对于这些 SECTION 条目都是零。两者都是 32 位数字,这意味着在这个特定部分中有很多零。

    【讨论】:

      【解决方案2】:

      这不是一个真正的编程问题,但是......

      二进制文件通常由不同的部分组成:代码、数据、调试信息等。由于这些部分的内容因类型而异,我非常希望它们看起来不同。

      即符号表由二进制中的地址偏移量组成。如果我正确阅读了您的lspci,那么您使用的是 32 位系统。这意味着每个偏移量都有四个字节,并且给定程序的大小,在大多数情况下,其中两个字节将为零。而且这样的效果还有很多。

      你没有strip你的程序,这意味着二进制文件中仍然存在大量信息(符号表等)。尝试剥离二进制文件并再次查看。

      【讨论】:

      • 我使用 -s 选项执行了条带:pastebin.com/EYvswHrC 似乎还有很多零的大部分。您可能是对的,这与冗余有关。我会检查一下。
      猜你喜欢
      • 2018-04-17
      • 2013-12-02
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多