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

标签 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

最佳答案

当您在 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 之间您感兴趣的 block (字段 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;

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

关于c - 有趣的可执行文件二进制转储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22438057/

相关文章:

linux - 我应该使用哪个工具从字符串中提取数据?

linux - Shell - 如何在消息中的某个点找到一个词

MySQL 内存使用率增长到 100%

c 二进制文件大于源文件

c - 需要帮助解决 C 指针链表赋值问题

比较opencv中灰度图像的直方图

c - 如何使用 GDB 在给定函数的范围内声明变量?

vim - 如何使用vim自定义缩进文件?

python - 如何在 Python 中解码二进制编码的邮件消息?

c - 从多个文件读取到一个结构