raw binary文件探秘

版权声明:本文没有任何版权限制,任何人可以以任何方式使用本文。 https://blog.csdn.net/crazycoder8848/article/details/70768684
Linux下的目标文件、动态库文件、可执行文件,其格式为elf格式。
elf文件是有结构的文件,其内部有丰富的信息,例如,可能包含了可执行文件的入口地址,各个节的起始地址,可重定位信息,还可能包含指令与代码行的对应关系(用于调试)。
内核则利用elf文件中的相关信息,加载运行可执行文件。
然而内核映像,u-boot映像这些特殊的文件,则是raw_binary文件。这当然有他的原因。
以u-boot为例,cpu通电后,就开始执行指令。而首先要执行的就是u-boot中的指令。然而cpu不具备解析elf文件的能力,他只知道执行指令。因此,只好给他一块纯粹的机器码让他跑。
因此,u-boot映像就做成了raw_binary文件。
raw_binary文件是没有任何结构的,其内容就是赤裸裸的代码与数据的组合体。
因此,不具备可解析性。


下面以一个简单的小例子,来看看raw_binary文件的面貌。

raw_binary.c是个简单的小程序,其内容如下:

char the_data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char bss_data1[3], bss_data2[4];

/* 为了初始化bss节,这里借助链接脚本中创建的两个符号,以得到bss节的地址区间 */
extern char __bss_start[], __bss_end[];
void init_bss_area();

void my_test_func()
{
    /* 为了能以raw binary形式运行,程序自己实现对bss节的清零 */
    init_bss_area(); 
    
    the_data[1]++;
    
    while (1)
    {
        asm volatile ("nop");
    }
}

void init_bss_area()
{
    int i, len = __bss_end - __bss_start;
    for (i=0; i<len; i++)
        __bss_start[i] = 0;
}

我们通过如下命令将上述代码编译成一个可执行文件。

[root@localhost raw_binary]# gcc -O2 -c raw_binary.c  -o  raw_binary.o
[root@localhost raw_binary]# ld -T raw_binary.lds raw_binary.o  -o raw_binary.exe

注意,上述编译过程中,我们用到了一个链接脚本raw_binary.lds。其内容如下:

ENTRY(my_test_func)
SECTIONS
{
    /* 这里设置代码段从2M开始 */
    . = 0x200000;
    .text :      
    {
        *(.text)
    }
    
    /* 我们让数据段的虚拟地址空间开始于8字节对齐的地方 */
    . = ALIGN(8);
    .data :
    {
        *(.data)
    }

    __bss_start = .; /* 创建一个符号,以方便C代码得到bss起始地址 */
    .bss : 
    {
        *(.bss)
    }
    __bss_end = .; /* 创建一个符号,以方便C代码得到bss结束地址 */
}

之所以这样做,是为了生成一个内容非常简单的可执行文件,以便于看清raw_binary文件的面貌。通过本方法生成的这个可执行程序与一般的可执行程序不大一样,他的入口是my_test_func,并且他不链接任何C库的东西。虽然他与别的程序不大一样,但从内核的角度或elf可执行文件的角度来看,并没有什么特殊的地方。因为他同样由多个section构成,同样完成了重定位,同样具有一个入口。 而站在这个角度上来看,一般的普通可执行程序也都是这样的。

另外,此程序为了在raw binary形式下也能运行,通过一些技巧自己初始化了bss段。

下面运行这个小程序,看看效果。由于没有链接C库,因此不方便打印信息。

只好通过ps简单看看他的存在。从命令输出可以看出,此程序是可以跑起来的。最后我们通过kill命令终止了此程序。

[root@localhost raw_binary]# ./raw_binary.exe &
[1] 2205
[root@localhost raw_binary]# ps -ef | grep -v grep | grep raw_binary
root      2205  1605 98 23:14 pts/0    00:00:36 ./raw_binary.exe
[root@localhost raw_binary]# kill -9 2205

下面我们将此可执行程序通过如下命令转换为raw_binary文件。

objcopy -O binary raw_binary.exe  raw_binary.rb

好了,看看转换得到的raw_binary.rb文件的内容吧:

b8 a7 00 20 00 31 d2 2d a0 00 20 00 85 c0 7e 0e 
c6 82 a0 00 20 00 00 83 c2 01 39 c2 75 f2 80 05 
99 00 20 00 01 8d 76 00 90 eb fd 90 8d 74 26 00 
ba a7 00 20 00 31 c0 81 ea a0 00 20 00 85 d2 7e 
15 8d b4 26 00 00 00 00 c6 80 a0 00 20 00 00 83 
c0 01 39 d0 75 f2 f3 c3 14 00 00 00 00 00 00 00 
01 7a 52 00 01 7c 08 01 1b 0c 04 04 88 01 00 00 
10 00 00 00 1c 00 00 00 88 ff ff ff 2b 00 00 00 
00 00 00 00 10 00 00 00 30 00 00 00 a4 ff ff ff 
28 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 

从上面的显示,很难看出raw binary文件的内容。不过我们通过以下objdump输出的raw_binary.exe的内容,就能看出端倪了:

raw_binary.bin文件的内容,就是.text、.eh_frame(是个没起作用的节)、.data这三个section的内容拼接到一块组成的。并且,其内容就是赤裸裸的节的内容,没有任何描述信息。

这三个节在elf文件中,处于一片连续的地址空间中。因此,如果可执行文件raw_binary.exe被加载执行,这三个节是位于一片连续的虚拟地址空间中的。

由于raw_binary文件,是按节的地址由低至高,将3个节的内容拼接到一块的,因此在raw_binary文件中,三个节的内容在文件中也是连续的。

同理,如果在cpu刚启动时,将此raw binary文件的内容拷贝到内存的0x200000物理地址处,那么三个节的内容将位于一片连续的物理地址区间中。

然后如果再跳转到0x200000处执行,那么这个raw binary映像就能跑起来了。

并且程序对变量的访问也将是正常的,因为从objdump输出可以看出,重定位是成功的。
因为the_data的地址是0x200038,而my_test_func函数的指令addb   $0x1,0x200039

正是在执行“the_data[1]++;”。

bss初始化代码也是正确的,他正是在对 0x2000a0~0x2000a7地址区间的内存做清零操作。

[root@localhost raw_binary]# objdump -D raw_binary.exe 

raw_binary.exe:     file format elf32-i386


Disassembly of section .text:

00200000 <my_test_func>:
  200000:       b8 a7 00 20 00          mov    $0x2000a7,%eax
  200005:       31 d2                   xor    %edx,%edx
  200007:       2d a0 00 20 00          sub    $0x2000a0,%eax
  20000c:       85 c0                   test   %eax,%eax
  20000e:       7e 0e                   jle    20001e <my_test_func+0x1e>
  200010:       c6 82 a0 00 20 00 00    movb   $0x0,0x2000a0(%edx)
  200017:       83 c2 01                add    $0x1,%edx
  20001a:       39 c2                   cmp    %eax,%edx
  20001c:       75 f2                   jne    200010 <my_test_func+0x10>
  20001e:       80 05 99 00 20 00 01    addb   $0x1,0x200099
  200025:       8d 76 00                lea    0x0(%esi),%esi
  200028:       90                      nop
  200029:       eb fd                   jmp    200028 <my_test_func+0x28>
  20002b:       90                      nop
  20002c:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi

00200030 <init_bss_area>:
  200030:       ba a7 00 20 00          mov    $0x2000a7,%edx
  200035:       31 c0                   xor    %eax,%eax
  200037:       81 ea a0 00 20 00       sub    $0x2000a0,%edx
  20003d:       85 d2                   test   %edx,%edx
  20003f:       7e 15                   jle    200056 <init_bss_area+0x26>
  200041:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi
  200048:       c6 80 a0 00 20 00 00    movb   $0x0,0x2000a0(%eax)
  20004f:       83 c0 01                add    $0x1,%eax
  200052:       39 d0                   cmp    %edx,%eax
  200054:       75 f2                   jne    200048 <init_bss_area+0x18>
  200056:       f3 c3                   repz ret 

Disassembly of section .eh_frame:

00200058 <.eh_frame>:
  200058:       14 00                   adc    $0x0,%al
  20005a:       00 00                   add    %al,(%eax)
  20005c:       00 00                   add    %al,(%eax)
  20005e:       00 00                   add    %al,(%eax)
  200060:       01 7a 52                add    %edi,0x52(%edx)
  200063:       00 01                   add    %al,(%ecx)
  200065:       7c 08                   jl     20006f <init_bss_area+0x3f>
  200067:       01 1b                   add    %ebx,(%ebx)
  200069:       0c 04                   or     $0x4,%al
  20006b:       04 88                   add    $0x88,%al
  20006d:       01 00                   add    %eax,(%eax)
  20006f:       00 10                   add    %dl,(%eax)
  200071:       00 00                   add    %al,(%eax)
  200073:       00 1c 00                add    %bl,(%eax,%eax,1)
  200076:       00 00                   add    %al,(%eax)
  200078:       88 ff                   mov    %bh,%bh
  20007a:       ff                      (bad)  
  20007b:       ff 2b                   ljmp   *(%ebx)
  20007d:       00 00                   add    %al,(%eax)
  20007f:       00 00                   add    %al,(%eax)
  200081:       00 00                   add    %al,(%eax)
  200083:       00 10                   add    %dl,(%eax)
  200085:       00 00                   add    %al,(%eax)
  200087:       00 30                   add    %dh,(%eax)
  200089:       00 00                   add    %al,(%eax)
  20008b:       00 a4 ff ff ff 28 00    add    %ah,0x28ffff(%edi,%edi,8)
  200092:       00 00                   add    %al,(%eax)
  200094:       00 00                   add    %al,(%eax)
        ...

Disassembly of section .data:

00200098 <the_data>:
  200098:       01 02                   add    %eax,(%edx)
  20009a:       03                      .byte 0x3
  20009b:       04 05                   add    $0x5,%al
  20009d:       06                      push   %es
  20009e:       07                      pop    %es
  20009f:       08                      .byte 0x8

Disassembly of section .bss:

002000a0 <bss_data2>:
  2000a0:       00 00                   add    %al,(%eax)
        ...

002000a4 <bss_data1>:
  2000a4:       00 00                   add    %al,(%eax)
        ...

Disassembly of section .comment:

00000000 <.comment>:
   0:   47                      inc    %edi
   1:   43                      inc    %ebx
   2:   43                      inc    %ebx
   3:   3a 20                   cmp    (%eax),%ah
   5:   28 47 4e                sub    %al,0x4e(%edi)
   8:   55                      push   %ebp
   9:   29 20                   sub    %esp,(%eax)
   b:   34 2e                   xor    $0x2e,%al
   d:   38 2e                   cmp    %ch,(%esi)
   f:   32 00                   xor    (%eax),%al
[root@localhost raw_binary]# 


没有更多推荐了,返回首页