UEFI 文件类型 .efi (二)

来源:互联网 发布:php 图片上传的原理 编辑:程序博客网 时间:2024/06/01 19:00

上一篇博客讲了一个例子关于在一个C 程序里如何动态去load 一个可执行文件,并且让这个文件能够跑起来,代码里有几处是hard code 写的,没有去根据读取的可执行文件类型去分析它。上篇也说了,如果那个例子理解透了,那么对于efi 文件加载和执行理解起来就不成问题了。

这篇博客介绍一下,efi 文件内容。其实不用去看代码,也不用怎么翻spec, 看看下面的几个图片,应该就会很清晰,efi 文件的重定位,装载,执行了。

举个具体例子看一下吧。我这边有一个build 好的efi driver, 文件格式呢是pe32。

先来看看这个driver 是怎么个结构,我们可以用Windows 下的命令dumpbin /ALL xxx.efi > xx.txt

FILE HEADER VALUES
14C machine (x86)
3 number of sections
0 time date stamp
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
2102 characteristics
Executable
32 bit word machine
DLL

OPTIONAL HEADER VALUES
10B magic # (PE32)
10.00 linker version
4DA0 size of code
4400 size of initialized data
0 size of uninitialized data
240 entry point (00000240)
240 base of code
4FE0 base of data
0 image base (00000000 to 000093DF)
20 section alignment
20 file alignment
0.00 operating system version
0.00 image version
0.00 subsystem version
0 Win32 version
93E0 size of image
240 size of headers
0 checksum
B subsystem (EFI Boot Service Driver)
0 DLL characteristics
0 size of stack reserve
0 size of stack commit
0 size of heap reserve
0 size of heap commit
0 loader flags
10 number of directories
0 [ 0] RVA [size] of Export Directory
0 [ 0] RVA [size] of Import Directory
0 [ 0] RVA [size] of Resource Directory
0 [ 0] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
8FA0 [ 428] RVA [size] of Base Relocation Directory
0 [ 0] RVA [size] of Debug Directory
0 [ 0] RVA [size] of Architecture Directory
0 [ 0] RVA [size] of Global Pointer Directory
0 [ 0] RVA [size] of Thread Storage Directory
0 [ 0] RVA [size] of Load Configuration Directory
0 [ 0] RVA [size] of Bound Import Directory
0 [ 0] RVA [size] of Import Address Table Directory
0 [ 0] RVA [size] of Delay Import Directory
0 [ 0] RVA [size] of COM Descriptor Directory
0 [ 0] RVA [size] of Reserved Directory

只是截取一部分,大概就这个样子,我们只关心加载和执行,所以其中

  1. entry point
  2. image base
  3. 重定向表

都在option header 里。所以无论我们的build tool 还是core 去分析这个driver 找到option header 就可以把需要的信息提取出来。提取出来,我们image 需要重定向,关于重定向之前也讲过,需要分析重定向表,好吧,看看重定向表的信息。

SECTION HEADER #3  .reloc name     428 virtual size    8FA0 virtual address (00008FA0 to 000093C7)     440 size of raw data    8FA0 file pointer to raw data (00008FA0 to 000093DF)       0 file pointer to relocation table       0 file pointer to line numbers       0 number of relocations       0 number of line numbers42000040 flags         Initialized Data         Discardable         Read OnlyRAW DATA #3  00008FA0: 00 00 00 00 4C 00 00 00 54 32 6F 32 80 32 85 32    00008FB0: A1 32 B6 33 CC 33 E2 33 F8 33 04 36 2C 36 36 38    00008FC0: 47 38 4D 38 59 38 9C 38 97 39 10 3A 37 3A 52 3A    00008FD0: 57 3A 09 3B 35 3B 95 3B 2D 3C 4C 3C 6B 3C 8A 3C   00008FE0: A9 3C 2B 3E 32 3E E6 3E 4B 3F 5D 3F 00 10 00 00    00008FF0: 68 00 00 00 87 33 D2 33 95 35 9B 35 DE 35 E4 35    00009000: 3A 36 40 36 BA 36 BF 36 12 37 17 37 63 37 69 37    00009010: 8D 37 92 37 AB 37 B1 37 C7 37 CD 37 EA 37 F0 37    00009020: 06 38 0C 38 22 38 28 38 36 38 3B 38 5B 38 61 38    00009030: 77 38 7D 38 91 38 97 38 AB 38 B1 38 CD 38 D5 38    00009040: 33 39 3A 39 BD 39 C3 39 82 3B 4B 3D 25 3F 44 3F    // 重定向表的解析  BASE RELOCATIONS #3       0 RVA,       4C SizeOfBlock     254  HIGHLOW            000051B0     26F  HIGHLOW            000070B8     280  HIGHLOW            00005020     285  HIGHLOW            000070BC     2A1  HIGHLOW            000070A0     3B6  HIGHLOW            000052A0     3CC  HIGHLOW            000052B0     3E2  HIGHLOW            000052C0     3F8  HIGHLOW            000052D0     604  HIGHLOW            00005010

我们也稍微简单分析一下这个可重定向表,我们可以从表头可以看到这个表载入内存大小是0x428, 并且virtual address 0x8FA0(Image base 0x0000),所以0x8FA0 也可以看成载入内存时候,可重定向表距离image base 偏移是0x8FA0。 OK 找到表了,接下来就是对表的分析了

00008FA0: 00 00 00 00 4C 00 00 00 54 32 6F 32 80 32 85 32

重定向表还是按照block 去划分,每个block 会有一个header ,里面有两个内容 1 UINT32 RVP, 2 UINT32 blocksize。 从上面的数据,我们可以得出 RVP 是 0x00000000, blocksize =0x4c ,然后每个可重定位项是16bits 高4位是类型,低12bit 是偏移。我们可以看到上面的 54 32 就会解析成,偏移是0x254, 类型是0x03(HIGHLOW)。这个0x254 需要加上所在Block 的 RVP, 意思就是0x254 + 0x000000 = 0x254,这个偏移地方需要修改,修改多大,我们的类型是0x03,就是32bit。一起看个图片就知道了。两张图一个是重定向后的(左),一个没有重定向(右)。
这里写图片描述

这里写图片描述

可以看到偏移0xF4 的位置被修改了,那是Image Base ,被修改成实际image 载入内存的地址。剩下的就是需要重定向位置,我们用可以看到上面需要重定向的位置,有0x254, 0x26F, 等等,我们对着图片看看,不一样的地方正好和这些重定向偏移的地址吻合。好了,重定向之后,我们就可以根据表头的Entry point 偏移找到入口地址,然后跳入这个image 里。

关于PE 结构,它有它方便的一面,也有复杂的一面,对于学习uefi 的同学,PE 结构,我们了解这么多,也可以了。其他方面关于导入表,导出表,动态延时绑定等等,有兴趣自己去找另外的资料研究学习。

看着简单吧,其实自己写还不一定能写好,因为也有很多细节问题,比如内存对齐等等,细节的地方只能自己去摸索了,别人讲太多都是记不住,程序员还是应该务实一点,写几段代码调试几遍。比只看不写强太多。

0 0
原创粉丝点击