有趣的二进制转储可执行文件

时间:2014-03-16 14:20:30

标签: c linux binary bin

出于某种原因,我在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

2 个答案:

答案 0 :(得分:2)

当您将程序编译为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位数字,这意味着在这一特定部分中有很多零。

答案 1 :(得分:1)

这不是一个编程问题,但不过......

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

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

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