第五章 Linux二进制分析
第三题:分析lvl3文件
$ readelf -h lvl3
ELF Header:
Magic: 7f 45 4c 46 02 01 01 0b 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: Novell - Modesto
ABI Version: 0
Type: EXEC (Executable file)
Machine: Motorola Coldfire
Version: 0x1
Entry point address: 0x4005d0
Start of program headers: 4022250974 (bytes into file)
Start of section headers: 4480 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
readelf: Error: Reading 0x1f8 bytes extends past end of file for program headers
OS/ABI和Machine是一个没见过的类型,程序头的位置明显有问题。
使用010 Editor修改一下程序:
修改前:
修改后:
$ readelf -h lvl3
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4005d0
Start of program headers: 64 (bytes into file)
Start of section headers: 4480 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
尝试运行:
$ ./lvl3
0e2ada7381d04d4d2ed31be82b121aa3 ./lvl3
$ ltrace -i ./lvl3
[0x4005f9] __libc_start_main(0x400550, 1, 0x7fff4cb74e98, 0x4006d0 <unfinished ...>
[0x40058c] __strcat_chk(0x7fff4cb74990, 0x400754, 1024, 0) = 0x7fff4cb74990
[0x4005a2] __strncat_chk(0x7fff4cb74990, 0x7fff4cb7539d, 1016, 1024) = 0x7fff4cb74990
[0x4005aa] system("md5sum ./lvl3"0e2ada7381d04d4d2ed31be82b121aa3 ./lvl3
<no return ...>
[0x7f914a66d730] --- SIGCHLD (Child exited) ---
[0x4005aa] <... system resumed> ) = 0
[0xffffffffffffffff] +++ exited (status 0) +++
$ md5sum ./lvl3
0e2ada7381d04d4d2ed31be82b121aa3 ./lvl3
程序执行的输出为该程序的md5散列,但是0e2ada7381d04d4d2ed31be82b121aa3并不是flag
$ readelf -S lvl3
......
[12] .plt PROGBITS 00000000004004e0 000004e0
0000000000000060 0000000000000010 AX 0 0 16
[13] .plt.got PROGBITS 0000000000400540 00000540
0000000000000008 0000000000000000 AX 0 0 8
[14] .text NOBITS 0000000000400550 00000550
00000000000001f2 0000000000000000 AX 0 0 16
[15] .fini PROGBITS 0000000000400744 00000744
0000000000000009 0000000000000000 AX 0 0 4
[16] .rodata PROGBITS 0000000000400750 00000750
000000000000000c 0000000000000000 A 0 0 4
......
注意到.text节的类型是NOBITS,这显然不合适,正常情况下其类型应该为PROGBITS
.text节的位置=4480+14*64=5376=0x1500
将0x1504处的08修改为01,即将.text的类型修改为PROGBITS。
$ md5sum ./lvl3
3a5c381e40d2fffd95ba4452a0fb4a40 ./lvl3
$ ./oracle 3a5c381e40d2fffd95ba4452a0fb4a40
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Level 3 completed, unlocked lvl4 |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Run oracle with -h to show a hint
补充
对于上述lvl3的.text节头,其内容如下:
readelf的结果为:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[14] .text PROGBITS 0000000000400550 00000550
00000000000001f2 0000000000000000 AX 0 0 16
可以从中看到对应的关系。
以下是一些常见的节类型及其相应的编码:
NULL
(0x00):表示一个无效的节头。通常不包含实际数据,只是一个占位符。PROGBITS
(0x01):包含可执行程序或数据的实际位。SYMTAB
(0x02):包含符号表,用于存储程序中的符号信息。STRTAB
(0x03):包含字符串表,用于存储字符串,如符号名称。STRTAB
(0x04):包含重定位表,用于重定位信息。HASHTAB
(0x05):包含哈希表,用于加速符号查找。DYNAMIC
(0x06):包含动态链接信息,如共享库的依赖关系。NOTE
(0x07):包含备注信息,通常用于存储与程序或库相关的附加信息。NOBITS
(0x08):类似于PROGBITS
,但不占用实际的文件空间,通常用于未初始化的数据段。REL
(0x09):包含重定位信息,但是重定位信息存储在一个独立的重定位节中。SHLIB
(0x0A):保留,不再使用。DYNSYM
(0x0B):包含动态符号表,与SYMTAB
不同,用于动态链接。INIT_ARRAY
(0x0E):包含初始化函数指针数组,用于在程序启动时执行初始化操作。FINI_ARRAY
(0x0F):包含终结函数指针数组,用于在程序结束时执行清理操作。PREINIT_ARRAY
(0x10):包含预初始化函数指针数组,用于在主函数之前执行初始化操作。GROUP
(0x11):用于将多个节组合到一个组中,通常用于支持特殊链接选项。
这些是一些常见的ELF节类型,每种类型都有其特定的用途和语义。请注意,ELF规范还可以允许用户定义的自定义节类型。不同的操作系统和工具链可能会使用不同的自定义类型。在使用readelf
等工具时,您可以查看特定ELF文件的节类型以了解其结构和内容。