Android中ELF文件结构浅析(二)

一、程序头表(program_header_table)

        一个可执行文件或共享目标文件的程序头表(program header table)是一个数组,数组中的每一个元素称为“程序头(program header)”,每一个程序头描述了一个“段(segment)”或者一块用于准备执行程序的信息。

        在elf header中e_phentsize 和 e_phnum 成员指定了程序头的大小和数量。

        每个segment的结构如下:

struct Elf64_Phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  Elf64_Off p_offset;
  Elf64_Addr p_vaddr;
  Elf64_Addr p_paddr;
  Elf64_Xword p_filesz;
  Elf64_Xword p_memsz;
  Elf64_Xword p_align;
};

1.  p_type

        描述的段的类型。

#define	PT_NULL		0
#define PT_LOAD		1
#define PT_DYNAMIC	2
#define PT_INTERP	3
#define PT_NOTE		4
#define PT_SHLIB	5
#define PT_PHDR		6
#define PT_TLS		7
#define	PT_NUM		8
#define PT_LOOS		0x60000000
#define PT_GNU_EH_FRAME	0x6474e550
#define PT_GNU_STACK	0x6474e551
#define PT_GNU_RELRO	0x6474e552
#define PT_GNU_PROPERTY	0x6474e553
#define PT_LOSUNW	0x6ffffffa
#define PT_SUNWBSS	0x6ffffffa
#define PT_SUNWSTACK	0x6ffffffb
#define PT_HISUNW	0x6fffffff
#define PT_HIOS		0x6fffffff
#define PT_LOPROC	0x70000000
#define PT_HIPROC	0x7fffffff

        结尾案例会说其中一部分。 

2.   p_flags

        此数据成员给出了本段内容的权限。

标志权限实际权限
PF_None0
PF_Exec1可执行可读,可执行
PF_Write2可写可读,可写,写执行
PF_Write_Exec3可写,可执行可读,可写,写执行
PF_Read4可读可读,可执行
PF_Read_Exec5可读,可执行可读,可执行
PF_Read_Write6可读,可写可读,可写,写执行
PF_Read_Write_Exec7可读,可写,写执行可读,可写,写执行

        对上表总结一下,有两条:

        1、可读与可执行是通用的,有其中一个就等于也有了另一个

        2、可写权限是最高权限,可以覆盖另外两个,有了可写权限,所有权限就都有了

 3.  p_offset

         段(segment)内容的开始位置相对于文件开头的偏移量,在010Edit解析后如下所示

        其中(p_offset)为0x0

4.  p_vaddr

        此数据成员给出本段内容的开始位置在进程空间中的虚拟地址。

        听着感觉要长脑子了,小案例来喽~

 

可以看到在文件中的位置是0x3C78

但是在内存中时,对于so基址的偏移是0x4C78。

5.  p_paddr

       一般与p_vaddr的值相同,貌似无用。

6.  p_filesz

        此数据成员给出本段内容在文件中的大小,单位是字节。

        p_offset 偏移后的位置 加上 p_filesz 就是本segment 在文件中的内容

7.  p_memsz

        此数据成员给出本段内容在内存中的大小,单位是字节。

         在内存中 p_vaddr 对于基址偏移后的位置 加上 p_memsz 就是本segment 在内存中的内容

8.   p_align

        对于可装载的段来说,其 p_vaddr 和 p_offset 的值至少要向内存页面大小对齐。

        此数据成员指明本段内容如何在内存和文件中对齐。

        如果该值为 0 或 1,表明没有对齐要求;

        否则,p_align 应该是一个正整数,并且是 2 的幂次数。p_vaddr 和 p_offset 在对 p_align 取模后应该相等。

         

0x3C78 % 0x1000 (4096) =  C78

0x4C78 % 0x1000 (4096) =  C78

二、总结分析

        

         根据上一篇的 elf header 分析,我们知道program header table 的起始位置是 0x40,其中每个表项的大小相同。

        上图黑色背景的内容是和蓝色背景的内容都是程序头表的表项。

1.   program_table_element[0] (可加载段)

        

         在这个元素中的p_type 类型为 PT_LOAD

        此类型表明本程序头指向一个可装载的段。

        段的内容会被从文件中拷贝到内存中。如前所述,段在文件中的大小是 p_filesz,在内存中的大小是p_memsz。如果 p_memsz 大于 p_filesz,在内存中多出的存储空间应填 0 补充。

        也就是说,段在内存中可以比在文件中占用空间更大;而相反,p_filesz永远不应该比 p_memsz 大,因为这样的话,内存中就将无法完整地映射段的内容。在程序头表中,所有 PT_LOAD 类型的程序头按照 p_vaddr 的值做升序排列。 

        从(p_offset)0x0的位置开始加载31C8(12744)个字节 加载进内存。此内存页的权限为 可读,可执行。  当p_vadder 不为 0 时情况如下;

2.  program_table_element[1] (可加载段)

         从(p_offset)0x3C78的位置开始加载3C8(968)个字节 加载进内存 对于 so基地址 加上 4C78偏移的位置。此内存页的权限为 可读,可写,可执行。

        p_data 是圈出来的段的内容。 

        此段也是init_array。

3.  program_table_element[2] (动态段)

        p_type 类型为 PT_DYNAMIC。

        如果一个目标文件参与动态连接的话,它的程序头表中一定会包含一个类型为PT_DYNAMIC 的表项,其所对应的段称为动态段(dynamic segment),段的名字为.dynamic。

        动态段的作用是提供动态连接器所需要的信息,比如依赖于哪些共享目标文件、动态连接符号表的位置、动态连接重定位表的位置等等。

        它包含一个由 如下结构体组成的数组。

typedef struct {
  Elf64_Sxword d_tag;
  union {
      Elf64_Xword d_val;
      Elf64_Addr d_ptr;
  } d_un;
} Elf64_Dyn;

对于每一个这种类型的目标项,d_tag 控制着对 d_un 的解析。

截取了一部分tags

tags[13] 的type是 DT_STRTAB 也就是字符串表所在的地址。

d_ptr 是 0x978

tags[14] 的type是 DT_SYMTAB 也就是符号表所在的地址

d_ptr 是 0x480

tags[16] 的type是 DT_SYMENT 也就是每个符号表条目的大小

d_val 是 24 

3.  tag type

名称
DT_NULL0Terminating entry.
DT_NEEDED1所需共享库的字符串表偏移量
DT_PLTRELSZ2PLT重定位的总大小(以字节为单位)
DT_PLTGOT3

                        处理器相关地址

DT_HASH4符号哈希表的地址
DT_STRTAB5字符串表的地址
DT_SYMTAB6符号表的地址
DT_RELA7ElfNN_Rela 重定位的地址
DT_RELASZ8ElfNN_Rela 重定位的总大小
DT_RELAENT9每个 ElfNN_Rela 重定位项的大小
DT_STRSZ10字符串表的总大小
DT_SYMENT11每个符号表项的大小
DT_INIT12init函数的地址
DT_FINI13fini函数的地址
DT_SONAME14以空字符结尾的字符串的 DT_STRTAB 字符串表偏移,用于标识共享目标文件的名称。
DT_RPATH15以空字符结尾的库搜索路径字符串的 DT_STRTAB 字符串表偏移。此元素的用途已被 DT_RUNPATH 取代。
DT_SYMBOLIC16表示目标文件包含在其链接编辑过程中应用的符号绑定。
DT_REL17与 DT_RELA 类似,但其表中包含隐式加数。此元素要求同时存在 DT_RELSZ 和 DT_RELENT 元素。
DT_RELSZ18DT_REL 重定位表的总大小
DT_RELENT19DT_REL 重定位项的大小
DT_PLTREL20表示过程链接表指向的重定位项的类型(DT_REL 或 DT_RELA)。过程链接表中的所有重定位都必须使用相同的重定位项。此元素要求同时存在 DT_JMPREL 元素
DT_DEBUG21用于调试
DT_TEXTREL22表示一个或多个重定位项可能会要求修改非可写段,并且运行时链接程序可以相应地进行准备
DT_JMPREL23与过程链接表单独关联的重定位项的地址,此元素要求同时存在 DT_PLTRELSZ 和 DT_PLTREL 元素
DT_BIND_NOW24表示在将控制权返回给程序之前,必须处理此目标文件的所有重定位项
DT_INIT_ARRAY25init_array函数的指针数组的地址,此元素要求同时存在 DT_INIT_ARRAYSZ 元素
DT_FINI_ARRAY26fini_array函数的指针数组的地址,此元素要求同时存在 DT_FINI_ARRAYSZ 元素
DT_INIT_ARRAYSZ  27DT_INIT_ARRAY 数组的总大小
DT_FINI_ARRAYSZ28DT_FINI_ARRAY 数组的总大小
DT_RUNPATH29以空字符结尾的库搜索路径字符串的 DT_STRTAB 字符串表偏移
DT_FLAGS30特定于此目标文件的标志值。
DT_MAXPOSTAGS34正动态数组标记值的数量
DT_RELRSZ35ElfNN_Relr 重定位的总大小
DT_RELR36ElfNN_Relr 重定位的地址
DT_RELRENT37每个 ElfNN_Relr 重定位的大小
DT_LOOS0x6000000d此范围内包含的值(包括这两个值)保留用于特定于操作系统的语义
DT_SUNW_AUXILIARY0x6000000d以空字符结尾的字符串的 DT_STRTAB 字符串表偏移,用于逐符号指定一个或多个辅助 filtee
DT_SUNW_RTLDINF0x6000000e保留供运行时链接程序内部使用
DT_SUNW_FILTER0x6000000f符号过滤器名称,以空字符结尾的字符串的 DT_STRTAB 字符串表偏移,用于逐符号指定一个或多个标准 filtee
DT_SUNW_CAP0x60000010功能节的地址
DT_SUNW_ASLR0x60000023ASLR控制
DT_HIOS0x6ffff000特定于操作系统

  • 32
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ELF (Executable and Linkable Format) 文件是可执行文件或共享库的格式。它包含了可执行代码和元数据(如符号表,程序头部等),但不包含汇编代码。要查看汇编代码,可以使用反汇编工具,如objdump来反编译ELF文件的二进制代码。 ### 回答2: 是的,elf文件可以看到汇编二进制。ELF(可执行与可链接格式,Executable and Linkable Format)是一种常见的二进制文件格式,用于存储可执行文件、目标文件、共享库和核心转储文件等。 通过使用相关工具,如反汇编工具,我们可以将ELF文件的机器指令转换为汇编指令。反汇编是一种将二进制代码转换为可读性更高的汇编代码的过程。它允许我们分析和理解程序的逻辑和执行流程。 在反汇编过程,我们可以看到程序使用的各种指令、寄存器的操作、内存地址的引用等。这有助于我们理解程序的实际执行过程,并可以用于调试、性能分析、逆向工程等目的。 需要注意的是,ELF文件可能包含很多节(sections),而不仅仅是代码节。除了代码节(.text节)之外,还有数据节、符号表节、重定位节等。这些节包含了程序的各个部分和相关信息。因此,在查看ELF文件的汇编二进制时,我们需要关注并选择适当的节来分析。 ### 回答3: elf文件是一种可执行文件格式,它包含了程序的二进制机器代码、数据和其他用于执行程序的信息。所以通过查看elf文件的二进制内容,我们可以间接地看到一部分汇编代码。 具体地说,elf文件是由不同的节(section)组成的,每个节都有不同的作用和内容。其包含了.text节,它存储了程序的二进制机器代码,也就是汇编指令的二进制表示。通过查看.text节的内容,我们可以间接地了解到程序的汇编指令。 然而,直接从elf文件提取汇编代码是非常困难和复杂的,因为elf文件的二进制机器代码是经过编译和链接处理的,其还包含了许多与具体平台相关的信息和修饰。如果想要完整地查看汇编代码,最好的方法是使用专门的反汇编工具,将elf文件转换为可读的汇编代码。 总而言之,从elf文件的二进制内容可以间接看到一部分汇编代码,但如果需要获取完整的汇编代码,最好使用反汇编工具进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值