zoukankan      html  css  js  c++  java
  • linux实践之ELF文件分析

    linux实践之ELF文件分析

    下面开始elf文件的分析。

    我们首先编写一个简单的C代码。

    编译链接生成可执行文件。

    首先,查看scn15elf.o文件的详细信息。

    16进制形式查看scn15elf.o文件。

     

    查看scn15elf.o中各个段和符号表的信息。

    各个段的详细信息如下。

     

    符号表的信息如下:

     

    使用readelf命令查看各个段的详细信息:

     

    段表信息如下:

     

    符号表信息如下:

     

    下面让我们开始分析文件头吧!

    由于我的虚拟机是32位的,我下面就主要以32位的系统进行分析,就不比较32位机和64位机的区别了。

    32位系统elf头文件的定义。

     

    从上图中,我们可知,elf文件头在32位系统中,占52个字节。(16+2+2+4+4+4+4+4+2+2+2+2+2+2=52)转换为16进制表示为0x34个字节。

     

    由于该虚拟机处理器使用小端法表示数据。

     

    分析elf文件头

    第一行:

    e_ident16个字节表示为“7f45 4c46 0101 0100 0000 0000 0000 0000”,其中“7f45 4c46”表示“ELF”的ASCII码表。“0101”中前一个“01”表示是32位的机器,后一个“01”表示使用的是小端法。“0100”中的“01”表示的是版本号是01。剩下的0为默认填充。

    第二行:

    e_type2个字节表示,为“0001”,表示是一个重定向文件。

    e_machine2个字节表示,为“0003”,表示Inter 80386的处理器体系结构(32位)

    e_version4个字节表示,为“0000 0001”,表示的是当前版本。

    e_entry4个字节表示,为“0000 0000 ”表示没有入口点。

    e_phoff4个字节表示,为“0000 0000”表示没有程序头表。

    第三行:

    e_shoff4个字节表示,为“0000 0228”表示段表的偏移地址。

    e_flags4个字节表示,为“0000 0000”表示未知处理器特定标志。

    e_ehsize2个字节表示,为“0034”表示elf文件头大小。

    e_phentsize2个字节表示,为“0000”,因为重定位文件没有程序头表。

    e_phnum2个字节表示,为“0000”,因为重定位文件没有程序头表。

    e_shentsize2个字节表示,为“0028”,表示段头大小为“0x28”字节,即为40个字节(由此知道section header table里面每一个table的大小为40个字节)。

    第四行:

    e_shnum2个字节表示,为“000d”,表示段表入口有13个,这里可以知道,段有13

    e_shstrndx2个字节表示,为“000a”,表示段名串表在段表中的索引,(符号表的信息在段表的索引号是10)。

    自己手工分析完后,可以和“readelf”指令读出的数据进行比较。

     

    分析段表:

     

    首先我们根据刚刚在elf文件头中读到的段表偏移,找到段表的起始,我们可以看到偏移为“0x228”。从上图中段表的数据结构中可以看出,段表占40个字节(4*10=40字节即“0x28个字节”),这个结果和我们从elf文件头中读到的结果一致。

     

    由于第一个段中有一部分数据没有读出来,所以我们以第二个段(偏移为0x0000268~0x00002a7)为例分析:

    sh_name4个字节表示,为“0000 001f”,该值代表section header string table中的索引。

    sh_type 4个字节表示,为“0000 0001”,表示该段的类型是“SHT_PROGBITS”。

    sh_flags 4个字节表示,为“0000 0006”,指示该section在进程执行时的特性。其中最低位如果为1 表示此节在进程执行过程中可写,次低位为1表示此节的内容加载时要读到内存中去,第三低位为1表示这个节中的数据是可执行的机器指令。这里表明该节在进程执行过程中不可写,在内容加载时要读到内存中去,该节数据是可执行的机器指令。

    sh_addr 4个字节表示,为“0000 0000”,表示该节在进程中的起始地址为“0x0000 0000”。

    sh_offset4个字节表示,为“0000 0034”表示该节在整个文件中的起始偏移量为“0x34”。

    sh_size4个字节表示,为“0000 002e”,表示该节的字节大小为2e

    sh_link4个字节表示,为“0000 0000”,表示没有和该节相关联的节。

    sh_info4个字节表示,为“0000 0000”表示没有文件信息

    sh_addralign4个字节表示,为“0000 0001”,该值用于表示地址对齐信息,值为1时表示不用地址对齐。

    sh_entsize4个字节表示,为“0000 0000”,对特定节(动态符号)才有意义,这里没有意义。

    总结:从section header table找到各个section头的信息,还是很简单的。

    只要知道其序列号(第几个节)。寻找偏移“0x228+i个节*0x28”即可。

    通过从section header table中读到的信息,我们来找一找这个字段的内容。

    经分析知,该节内容起始,距文件头0x34的位置,内容大小为0x2e个字节。

     

    如图所示,该节的内容即为图中高亮的部分。我们反汇编一下scn15elf.o文件,结果为

     

    对比发现两个结果是一致的。

    分析各个section。(.text .strtab .symtab .rodata

     

    .text

    分析见上一步的例子,已经分析完了。

    .strtab

    .strtab中存放的是符号的名字(符号表示一个固定的内存地址)。

    计算该节的偏移=0x228+12*0x28=0x408

     

    sh_name4个字节表示,为“0000 0009”,该值代表section header string table中的索引。即.strtab节。

    sh_type 4个字节表示,为“0000 0003”,表示该段的类型是“SHT_STRTAB”。

    sh_flags 4个字节表示,为“0000 0000”,指示该section在进程执行时的特性。表明该节在进程执行过程中不可写,在内容加载时不需要读到内存中去,该节数据不是可执行的机器指令。

    sh_addr 4个字节表示,为“0000 0000”,表示该节在进程中的起始地址为“0x0000 0000”。

    sh_offset4个字节表示,为“0000 00198”表示该节在整个文件中的起始偏移量为“0x198”。

    sh_size4个字节表示,为“0000 0016”,表示该节的字节大小为16

    sh_link4个字节表示,为“0000 0000”,表示没有和该节相关联的节。

    sh_info4个字节表示,为“0000 0000”表示没有文件信息

    sh_addralign4个字节表示,为“0000 0001”,该值用于表示地址对齐信息,值为1时表示不用地址对齐。

    sh_entsize4个字节表示,为“0000 0000”,对特定节(动态符号)才有意义,这里没有意义。

    总结上面的分析是,该节距离文件头偏移为0x198,内容大小为0x16

     

    .symtab

    该节中存放着所有section中定义的符号名字。描述了.strtab中的符号在“内存”中对应的“内存地址”。这里的“内存地址”指的是偏移量,不是真的内存地址。

    计算该节的偏移=0x228+11*0x28=0x3E0

     

    sh_name4个字节表示,为“0000 0001”,该值代表section header string table中的索引。即.symtab节。

    sh_type 4个字节表示,为“0000 0002”,表示该段的类型是“SHT_STRTAB”。

    sh_flags 4个字节表示,为“0000 0000”,指示该section在进程执行时的特性。表明该节在进程执行过程中不可写,在内容加载时不需要读到内存中去,该节数据不是可执行的机器指令。

    sh_addr 4个字节表示,为“0000 0000”,表示该节在进程中的起始地址为“0x0000 0000”。

    sh_offset4个字节表示,为“0000 00e8”表示该节在整个文件中的起始偏移量为“0xe8”。

    sh_size4个字节表示,为“0000 00b0”,表示该节的字节大小为16

    sh_link4个字节表示,为“0000 000c”,表示没有和该节相关联的节。

    sh_info4个字节表示,为“0000 0009”表示没有文件信息

    sh_addralign4个字节表示,为“0000 0004”,该值用于表示地址对齐信息,值为4时表示需要地址对齐。

    sh_entsize4个字节表示,为“0000 0010”,表示字节大小。

    总结上面的分析是,该节距离文件头偏移为0xe8,内容大小为0xb0

     

    对比符号表里的内容。

     

    .rodata

    rodata的意义同样明显,ro代表read only,即只读数据(const)。关于rodata类型的数据,要注意以下几点:
    1常量不一定就放在rodata里,有的立即数直接编码在指令里,存放在代码段(.text)中。
    对于字符串常量,编译器会自动去掉重复的字符串,保证一个字符串在一个可执行文件(EXE/SO)中只存在一份拷贝。
    2rodata是在多个进程间是共享的,这可以提高空间利用率。
    3有的嵌入式系统中,rodata放在ROM(norflash)里,运行时直接读取ROM内存,无需要加载到RAM内存中。
    4在嵌入式linux系统中,通过一种叫作XIP(就地执行)的技术,也可以直接读取,而无需要加载到RAM内存中。

    计算该节的偏移=0x228+5*0x28=0x2F0

     

    sh_name4个字节表示,为“0000 030”,该值代表section header string table中的索引。即.rodata节。

    sh_type 4个字节表示,为“0000 0001”,表示该段的类型是“SHT_STRTAB”。

    sh_flags 4个字节表示,为“0000 0002”,指示该section在进程执行时的特性。表明该节在进程执行过程中不可写,在内容加载时不需要读到内存中去,该节数据不是可执行的机器指令。

    sh_addr 4个字节表示,为“0000 0000”,表示该节在进程中的起始地址为“0x0000 0000”。

    sh_offset4个字节表示,为“0000 0062”表示该节在整个文件中的起始偏移量为“0x62”。

    sh_size4个字节表示,为“0000 0013”,表示该节的字节大小为13

    sh_link4个字节表示,为“0000 0000”,表示没有和该节相关联的节。

    sh_info4个字节表示,为“0000 0000”表示没有文件信息

    sh_addralign4个字节表示,为“0000 0001”,该值用于表示地址对齐信息,值为1时表示不用地址对齐。

    sh_entsize4个字节表示,为“0000 0000”,对特定节(动态符号)才有意义,这里没有意义。

    总结上面的分析是,该节距离文件头偏移为0x62,内容大小为0x13

     

    参考资料

    1、 浅谈Linux的可执行文件格式ELF

    http://blog.chinaunix.net/uid-9068997-id-2010376.html

  • 相关阅读:
    Effective C# 学习笔记(三十五) 了解PLINQ如何实现并行算法
    Effective C# 学习笔记(三十八)理解Dynamic的得与失
    转单例的分析
    获取系统当前音量 和 监听系统音量 ios
    (转) iphone开发资源汇总
    xcode show line numbers
    为了编程方便的效率宏定义的一些代码
    ios6下cocos2d & ipad 调用摄像头报错问题 (在竖屏情况下调用Camera 会导致转屏)
    转KVC
    不记住的
  • 原文地址:https://www.cnblogs.com/java-stx/p/5551160.html
Copyright © 2011-2022 走看看