ELF文件格式
这一节文章的标题叫做<提取so文件的特征值>,在这里就不得不说ELF文件的格式. 因为像.o , .so, .exe 为后缀名的文件都是elf格式的文件. ELF 文件格式是一种二进制的文件.它被叫做可执行链接的格式(Executable and Linking Format).
ELF格式文件标准被选作为一种可移植的目标文件被分为三种类型:
- 可重定位文件(Relocatable File) (*.0) 其包含适用于与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据.
- 可执行文件(Executable File)(*.exe) 包含使用于执行的一个程序,此文件规定了exec()如何创建一个程序的映像.
- 共享目标文件(Shared Object File)(*.so)包含可在两种上下文链接的代码和数据.首先链接编辑器可以将它和其他的可重定位文件和共享文件一起处理
ELF的数据类型
ELF文件的头部结构
typedef struct{ Elf32_Word sh_name; //节区名,是节区头部字符串表节区(Section Header String Table Section)的索引。名字是一个 NULL 结尾的字符串。 Elf32_Word sh_type; //为节区类型 Elf32_Word sh_flags; //节区标志 Elf32_Addr sh_addr; //如果节区将出现在进程的内存映像中,此成员给出节区的第一个字节应处的位置。否则,此字段为 0。 Elf32_Off sh_offset; //此成员的取值给出节区的第一个字节与文件头之间的偏移。 Elf32_Word sh_size; //此 成 员 给 出 节 区 的 长 度 ( 字 节 数 )。 Elf32_Word sh_link; //此成员给出节区头部表索引链接。其具体的解释依赖于节区类型。 Elf32_Word sh_info; //此成员给出附加信息,其解释依赖于节区类型。 Elf32_Word sh_addralign; //某些节区带有地址对齐约束. Elf32_Word sh_entsize; //某些节区中包含固定大小的项目,如符号表。对于这类节区,此成员给出每个表项的长度字节数。 }Elf32_Shdr;
每次我看到ELF文件的时候,总会想到的东西就是虫子,因为它们都是一节一节的.(或许这个表述不准确) ELF文件包括了很多的节区(section),这些节区有的是系统预定好的,有些是用户通过.section命令自定义的.
在这里我们需要强调的是一些特殊节区, 这些节区是系统预定的,我们在这里要提一下我们之后需要的提取的节区的特征值
.dynamic 动态链接信息
.dynsym 此节区包含了动态链接符号表
.got 此节区包含了全局偏移表
.plt 过程链接表
.text 此节区包含了程序的可执行指令
如果你想要了解更多这方面的内容,你可以参考这篇文章:
elf文件格式总结
readelf工具
readelf是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用.在提取so文件我们也用到了这个工具.
你可以在这里下载到:http://download.csdn.net/detail/grace_0642/8562495
下面在这里简单介绍一下它的用法:
1.显示ELF Header文件头信息
readelf -h file
===================================
2. 查看文件的程序头表信息
readelf -I file
===================================
3. 显示文件的节信息
readelf -S file
====================================
4.显示 Dynamic Section 信息
readelf -d file
==================================
你还需要知道的事
1.awk的用法
你可以参考这篇文章,写的很好 链接:http://coolshell.cn/articles/9070.html
AWK 简明教程
代码
结构说明:
python脚本调用shell脚本.shell脚本调用readelf工具读取so文件内容信息, readelf工具和脚本放在相同的路径下.
python脚本代码:
''' @Author : Chicho @Date : 2014-12-5 @Function : elf parser @Running : pyhton ELF_Extract.py /path/to/so ''' import os import sys if (len(sys.argv)<2): print("*Usage : python ELF_Extract.py /path/to/so") else: path = sys.argv[1] fileList = os.listdir(path) ''' we will put the readelf file in the path of so files so that we can extract the features of ELF ''' for filename in fileList: portion = os.path.splitext(filename) # find the .so file if portion[1]==".so": os.system("./moreelf_finefeatures_extract.sh " + filename ) print "The end"
shell脚本:
#!/bin/bash INPUT=$1 if [ $# -lt 1 ]; then echo "Usage: $0 /path/to/libXXX.so" exit 1 fi READELF=./readelf entry_point_addr=$($READELF -h $INPUT| grep "Entry point address:" | egrep -o "0x[0-9A-Za-z]*") start_section_headers=$($READELF -h $INPUT | grep "Start of section headers:" | egrep -o "[0-9]*") num_programs=$($READELF -h $INPUT | grep "Number of program headers:" | egrep -o "[0-9]*") size_section_headers=$($READELF -h $INPUT | grep "Size of section headers:" | egrep -o "[0-9]*") num_section_headers=$($READELF -h $INPUT | grep "Number of section headers:" | egrep -o "[0-9]*") string_table_index=$($READELF -h $INPUT | grep "Section header string table index:" | egrep -o "[0-9]*") dynamic_section=$($READELF -d $INPUT | grep "Dynamic section at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") dynsym_entries=$($READELF -s $INPUT | grep "Symbol table '.dynsym' contains" | egrep -o "[0-9]*") num_rel_dyn=$($READELF -r $INPUT | grep "Relocation section '.rel.dyn' at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") num_rel_plt=$($READELF -r $INPUT | grep "Relocation section '.rel.plt' at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") echo $entry_point_addr $start_section_headers $num_programs $size_section_headers $num_section_headers $string_table_index $dynamic_section $dynsym_entries $num_rel_dyn $num_rel_plt $label>> more_finefeatures_result.txt
就比如说如果我们还想做点别的事情,比如说判断特定的so文件的特征值:
#!/bin/bash INPUT=$1 if [ $# -lt 1 ]; then echo "Usage: $0 /path/to/libXXX.so" exit 1 fi READELF=./readelf entry_point_addr=$($READELF -h $INPUT| grep "Entry point address:" | egrep -o "0x[0-9A-Za-z]*") start_section_headers=$($READELF -h $INPUT | grep "Start of section headers:" | egrep -o "[0-9]*") num_programs=$($READELF -h $INPUT | grep "Number of program headers:" | egrep -o "[0-9]*") size_section_headers=$($READELF -h $INPUT | grep "Size of section headers:" | egrep -o "[0-9]*") num_section_headers=$($READELF -h $INPUT | grep "Number of section headers:" | egrep -o "[0-9]*") string_table_index=$($READELF -h $INPUT | grep "Section header string table index:" | egrep -o "[0-9]*") dynamic_section=$($READELF -d $INPUT | grep "Dynamic section at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") dynsym_entries=$($READELF -s $INPUT | grep "Symbol table '.dynsym' contains" | egrep -o "[0-9]*") num_rel_dyn=$($READELF -r $INPUT | grep "Relocation section '.rel.dyn' at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") num_rel_plt=$($READELF -r $INPUT | grep "Relocation section '.rel.plt' at" | egrep -o "[0-9]* entries" | egrep -o "[0-9]*") if [[ "$1" =~ "libsecmain"* ]] then label="Bangcle1" elif [[ "$1" =~ "libsecexe"* ]] then label="Bangcle2" elif [[ "$1" =~ "libtup"* ]] then label="Tencent" elif [[ "$1" =~ "libprotectClass"* ]] then label="Qihoo" elif [[ "$1" =~ "libexecmain"* ]] then label="ijiami1" elif [[ "$1" =~ "libexec"* ]] then label="ijiami2" elif [[ "$1" =~ "libapkprotect"* ]] then label="APKProtect1" elif [[ "$1" =~ "libcube-jni"* ]] then label="APKProtect2" elif [[ "$1" =~ "libminimapv320"* ]] then label="APKProtect3" elif [[ "$1" =~ "libswiperctrl"* ]] then label="APKProtect4" else label="unknow" fi echo $entry_point_addr $start_section_headers $num_programs $size_section_headers $num_section_headers $string_table_index $dynamic_section $dynsym_entries $num_rel_dyn $num_rel_plt $label>> more_finefeatures_result.txt