目录
预备学习——Linux实践:ELF文件格式分析
一、概述
1.ELF全称Executable and Linkable Format,可执行连接格式,ELF格式的文件用于存储Linux程序。ELF文件(目标文件)格式主要有三种:
- 可重定向文件(Relocatable file):文件保存着代码和适当的数据,用来和其他的目标文件一起来创建一个可执行文件或者是一个共享目标文件(目标文件或者静态库文件,即Linux通常后缀为.a和.o的文件)。
- 可执行文件(Executable file):文件保存着一个用来执行的程序(例如bash,gcc等)。
- 共享目标文件:动态库文件(Linux下后缀为.so的文件)。文件保存着代码和合适的数据(这些数据是在连接时候被连接器ld和运行时动态连接器使用的)。
二、分析ELF文件头(ELF header)
- 在终端输入
cd /usr/include
进入include目录后查看elf.h文件,查看ELF的文件头ELF Header的定义。
(这里以64位的为例,64位和32位的都可以查看到)
关于其长度信息:
插入图片elf5.pdf
可以看到32位与64位的部分长度不同,要根据具体文件具体判断。 - 写一个小程序并编译,生成hello可执行文件
使用readelf -a hello
命令,得到ELF Header头文件的信息。 - 通过上图信息,可以得出Elf Header的Size为64bytes,所以可以使用hexdump工具将头文件的16进制表打开。
使用hexdump -x hello -n 52
命令查看hello文件头的16进制表(前52bytes),对格式进行分析。 - 第一行
- 对应e_ident[EI_NIDENT]。实际表示内为7f454c46020100010000000000000000,前四个字节7f454c46(0x45,0x4c,0x46是'e','l','f'对应的ascii编码)是一个魔数,表示这是一个ELF对象。
- 接下来的一个字节02表示是一个64位对象,接下来的一个字节01表示是小端法表示,再接下来的一个字节01表示文件头版本。剩下的都默认为0。
- 第二行
- e_type(2字节)值为0003(不确定写得对不对),表示是一个共享目标文件。
- e_machine(2字节)值为003e(不确定写得对不对),表示是Advanced Micro Devices X86-64架构。
- e_version(4字节)值为00010000(不确定写得对不对),表示是当前版本。
- e_entry(8字节)值为1050000000000000(不确定写得对不对),表示入口点地址。
- 第三行
- e_phoff(8字节)值为0040000000000000(不确定写得对不对),表示程序头表的偏移地址。
- e_shoff(8字节)值为3960000000000000不确定写得对不对),表示段表的偏移地址。
- 第四行
- e_flags(4字节)值为00000000(不确定写得对不对),表示未知处理器特定标志#define EF_SH_UNKNOWN 0x0。
- e_ehsize(2字节)值为0040(不确定写得对不对),表示.elf文件头大小为00 40(64个字节)。
- e_phentsize(2字节)值为0038(不确定写得对不对),表示一个程序头表中的入口的长度。
- e_phnum(2字节)值为000b(不确定写得对不对),表示程序头表中的入口数目。
- e_shentsize(2字节)值为0040(64字节)(不确定写得对不对),表示section header table中每个header的大小。
- e_shnum(2字节)值为001e(不确定写得对不对),表示段表入口有30个(不确定),即段表有13段。
- e_shstrndx(2字节)值为001d(不确定写得对不对),表示段表字符串在段表中的索引号。为29(不确定)。
本部分最大的问题是怎么划分哪几位代表什么。经过一番波折找到了64位和32位占字节不一的问题,但是小端法是否反序读,高位0是否省略等问题还是不清楚。参考了多位学长学姐的博客,格式各有不同,最终没有搞明白这一点。我采用的方法是全都没有反序,按照终端显示的顺序来读。
三、通过文件头找到section header table,理解其内容
file elf文件的名字
显示生成的目标文件hello的类型- hello是一个可执行文件,输入
ls -l hello
查看hello的大小 - 如上图,hello大小为16608字节。输入
hexdump -x hello
用16进制的数字显示hello的内容。(其中,第二列是16进制表示的偏移地址) - 输入
objdump -x hello
来显示hello中各个段以及符号表的相关信息。 - 输入
readelf -a hello
来查看各个段信息。- ELF文件头信息:
- 段表Section header table:
- 符号表Symbol table:
- ELF文件头信息:
四、通过section header table找到各section
在一个ELF文件中有一个section header table,通过它我们可以定位到所有的section,而ELF header中的e_shoff变量就是保存section header table入口对文件头的偏移量。而每个section都会对应一个section header,所以只要在section header table中找到每个section header,就可以通过section header找到你想要的section。
下面以可执行文件hello为例,以保存代码段的section为例来讲解读取某个section的过程。
使用gedit /usr/include/elf.h
查看Section header的结构体。
由上面分析可知,section header table中的每个section header所占的size均为64字节,ELF header得到了e_shoff变量的值为0x0000000000006039(不确定对不对),也就是table入口的偏移量,通过看e_shnum的值为0x001e,表示段表入口有30个。
所以从0x0000000000003960(不确定对不对)开始有30个段,每个段占64字节大小,输入hexdump hello
查看。
- 第一个段:全为0,不表示任何段。
- 第二个段:
- sh_name(4字节)的值为001b0000表示该段名称在.shstrtab中偏移量,为.inter段。
- sh_type(4字节)的值为00010000表示这个段拥有程序所定义的信息,其格式和含义完全由该程序确定,这里表示PROGBITS。
- sh_flags(8字节)的值为0002000000000000表示alloc和execute。
- sh_addr(8字节)的值为02a8000000000000表示section在内存中的虚拟地址。
- sh_offset(8字节)的值为02a8000000000000(000002a8)表示section与文件头之间的偏移。
- sh_size(8字节)的值为001c000000000000表示文件里面section占用的大小。
- sh_link(4字节)的值为00000000,表示没有链接信息。
- sh_info(4字节)的值为00000000,表示没有辅助信息。
- sh_addralign(8字节)的值为0001000000000000,表示字节对齐长度。
- sh_entsize(8字节)的值为0000000000000000,表示没有入口。
- 第三个段:
- 段名:note.ABI-tag
- 类型:NOTE
- 标志:(不知道)
- 相对文件头偏移:000002c4
- 占用大小:00000020(不确定)
- 第四个段
- 段名:.note-gnu.build-i
- 类型:NOTE
- 标志:(不知道)
- 相对文件头偏移:000002e4
- 占用大小:00000024(不确定)
···
···
- 第三十个段:
正式开始
题目链接:
catalyst-system
无能瞎搞
1.预备了这么久真是没想到..一开始下载下来是个文本文件,但是打开是乱码。
用16进制方式打开后发现开头是.ELF,于是去搜索了,并且按照预备知识学习了一下。
向下划发现这里还有很多有趣的东西
还比如flag
用户名和密码
还有这里很像刚才学的.shstrtab,也像flag的格式
2.啥也不会的我使用预备里学到的指令readelf来查看
发现是一个可执行文件。
3.搜索学习了Linux执行可执行文件的方法,先用chmod -x catalyst.txt
给执行权限,然后./catalyst.txt
执行。
Wow,好酷
4.刚才预备里学了一个objdump
是反汇编的命令,尝试一下。
以上我做的这些花里胡哨的东西可以用下图总结
嗯,没有什么用。所以接下来直接寻找write up照着做吧。(顺便这时候我知道了catalyst是催化剂的意思,好浪漫啊。)
IDA启动
值得一提的是,刚刚在执行此文件时很慢,一直卡在“Loading”那里,没有显示出所有我们在16进制中看到的提示字符串“Username:”。
由于以下题解本人还没看懂,暂时止步于此(。。。)(而且已经第四周了。。)