《编译系统-自底向上研究方法》ELF段表 - 弦外之音

/ 0评 / 0

《编译系统-自底向上研究方法》ELF头部 ,之前这篇文章讲解了 ELF 的头部,头部有几个段表的字段,当时没有仔细讲解。

1,e_shoff ,段表的指针,也就是段表在 main 文件的偏移值。

2,e_shensize,段表中单个段的大小。

3,e_shnum,段表中 段的数量。



再次用 xelfviewer 打开 main 文件,如下:

注意看上图用 红笔 圈出来的字段,这些都是 16 进制的。可以看到 e_shoff 的值是 0x1948 ,也就是 6472 ,所以 main 文件 从第6472 字节开始就是 段表的内容,因为一个段大小是 0x40 字节,所以 第 6472 ~ 6536 字节是第一个段的内容,第 6537 ~ 6660 字节是第二个段的内容,以此类推。一共有 e_shnum (28)个段。

段其实是一个 Elf64_Shdr 结构体定义的,在在 /usr/include/elf.h 文件里面,如下:

typedef struct
{
  Elf64_Word    sh_name;        /* Section name (string tbl index) */
  Elf64_Word    sh_type;        /* Section type */
  Elf64_Xword   sh_flags;       /* Section flags */
  Elf64_Addr    sh_addr;        /* Section virtual addr at execution */
  Elf64_Off sh_offset;      /* Section file offset */
  Elf64_Xword   sh_size;        /* Section size in bytes */
  Elf64_Word    sh_link;        /* Link to another section */
  Elf64_Word    sh_info;        /* Additional section information */
  Elf64_Xword   sh_addralign;       /* Section alignment */
  Elf64_Xword   sh_entsize;     /* Entry size if section holds table */
} Elf64_Shdr;

Elf64_Shdr 这个结构体就是 0x40 字节大小。


下面就 从 第 6472 字节开始分析 段表的各个段的内容。还是用 xelfviewer,版本是0.04,直接点击左边的 Sections 选项即可,Sections 就是 段,如下图:

从上图可以看到,中间这个表格的列就是按照 Elf64_Shdr 结构体解析出来的。不过要注意一下 底部的 十六进制 ,我用红笔圈出来的,这个不是 Elf64_Shdr 结构体 对应的十六进制。而是 段 对应的 value,可以看到第二个段的 sh_addr 是 0x238 ,低下 的也是从 0x238 位置开始的内容。这个等下会详细讲解。

现在先来验证一个问题,之前说 段表是 从 main文件的 第 0x1948 字节 开始解析的,用 notepad++ 来看看是不是,如下图:

从上图可以看到,xelfviewernotepad++ 两个软件的数据都能对得上,证明之前的说法没有问题。段表确实是 从0x1948 开始解析的。


段表的第一个段,通常是空,也就是全都是 0 ,不用管他。从第二个段开始分析,第二个段的 sh_name 字段是 1b,这个 1b 是什么东西呢?实际上,这也是一个偏移值,通过偏移找到真正的字符串,而不是把字符串直接存在 sh_name 字段。

那这个 1b 是哪个地方的偏移呢?在 ELF 头部,之前有个字段没有讲,就是 e_shstrndx 字段,全称 Section header string table index,翻译是 段字符串表的索引值,他的值是 0x1b ,也就是 27 ,这是一个下标值。之前说过 段表里面有 28个段,所以 字符串表 就是 最后一个段,如下图:

注意看上图的段,他的 sh_offset 是 0x1848 ,这个段的 value 是 从 main 文件的 第 0x1848 字节开始的。所以 第二个段的 sh_name 就是 0x1848 + 0x1b 等于 0x1863 的位置,直接用 notepad++ 查看这个位置的数据,如下:

可以看到,这个位置,就是 interp 字符串。字符串以 00 结尾的。xelfviewer 为了方便查看,倒数第二列的 Name 就是这样解析显示出来的。


讲解到这里,是时候画一张数据结构体,首先是 头部Elf64_Ehdr 指出 段表的开始位置,字符串段 的下标。然后段表里面包含各个段,段里还有一个 sh_offset 指针,指向真正的value位置。


本文只讲了 段结构体 Elf64_Shdrsh_namesh_offset,其他字段,读者自行百度搜索关键词,或者阅读 《程序员的自我修养》第3,4章节即可。


由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1,QQ:2338195090。

发表回复

您的电子邮箱地址不会被公开。