d33*_*tah 2 linux elf low-level
我正在分析这个小小的 ELF 文件:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
00000020 40 00 00 00 00 00 00 00 98 00 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 40 00 03 00 02 00 |....@.8...@.....|
00000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 |..@.......@.....|
00000060 7e 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 |~.......~.......|
00000070 00 00 20 00 00 00 00 00 31 c0 ff c0 cd 80 00 2e |.. .....1.......|
00000080 73 68 73 74 72 74 61 62 00 2e 74 65 78 74 00 00 |shstrtab..text..|
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000d0 00 00 00 00 00 00 00 00 0b 00 00 00 01 00 00 00 |................|
000000e0 06 00 00 00 00 00 00 00 78 00 40 00 00 00 00 00 |........x.@.....|
000000f0 78 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |x...............|
00000100 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000110 00 00 00 00 00 00 00 00 01 00 00 00 03 00 00 00 |................|
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000130 7e 00 00 00 00 00 00 00 11 00 00 00 00 00 00 00 |~...............|
00000140 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000150 00 00 00 00 00 00 00 00 |........|
00000158
Run Code Online (Sandbox Code Playgroud)
我找到了有关 ELF 头文件和程序头文件的文档并解码了这两个文件,但是我在解码之后的内容时遇到了问题(以 开头31 c0 ff c0 cd 80 00 2e)。从“shstrtab”文本来看,我正在查看节表,但这是什么31 c0 ff c0 cd 80 00 2e意思?这部分记录在哪里?
OK,根据header的前16个字节的信息来看:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
E L F | | '--- Pudding :) ---'
| '--- Little-endian (ELFDATA2LSB)
'------ 64-bit (ELFCLASS64)
Run Code Online (Sandbox Code Playgroud)
我们正在处理一个64 位 ELF,带有多字节数字的小端编码。所以ELF 头是十六进制编辑器中的前 4 行。我们对它最后两行的这些字段感兴趣:
Prog Hdr Tab offset Sect Hdr Tab offset
.----------^----------. .----------^----------.
00000020 40 00 00 00 00 00 00 00 98 00 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 01 00 40 00 03 00 02 00 |....@.8...@.....|
'-.-' '-.-' '-.-' '-.-' '-.-'
PHT entry size ---' | | | '-- Sect names in #2
PHT num entries ----------' | '-- SHT num entries
'-------- SHT entry size
Run Code Online (Sandbox Code Playgroud)
所以我们知道程序头表从0x40文件中的偏移量开始(在这个头之后)并且包含1大小0x38(56 字节)的条目。所以它以偏移量结束0x40 + 1*0x38 = 0x78(这是这个表之后的第一个字节,这也是你的“神秘数据”开始的地方,所以请记住这一点)。
在节头表开始于偏移0x98文件中,并包含3尺寸的表项0x40(64个字节),即,在SHT每个条目发生在十六进制编辑器连续4行,并且整个表是3*4 = 12这样的行,所以该偏移0x158是第一此表后的字节。但这只是文件的结尾,所以在 SHT 之后没有更多内容。
索引处的 SHT 条目2(第三个=最后一个)应该是一个包含各部分名称的字符串表。
现在让我们看看这些部分,好吗?
让我们从第 2 部分开始,因为它应该包含带有所有部分名称的字符串表,因此它将在进一步分析中非常有用。这是它的标题(表中的最后一个):
Name index Type=SHT_STRTAB (bingo!)
Flags .----^----. .----^----.
00000118 .----------^----------. 01 00 00 00 03 00 00 00 |........|
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000130 7e 00 00 00 00 00 00 00 11 00 00 00 00 00 00 00 |~...............|
'----------.----------' '----------.----------'
Starting offset Size
00000140 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000150 00 00 00 00 00 00 00 00 |........|
00000158
Run Code Online (Sandbox Code Playgroud)
所以这确实是一个字符串表(0x03 = SHT_STRTAB)。它从0x7E文件中的偏移量开始,并采用0x11( 17) 个连续字节。因此,字符串表之后的第一个字节是0x8F. 该字节不是任何部分(垃圾)的一部分。
字符串表
所以让我们看看包含字符串表的部分中有什么,以便我们可以命名我们的部分:
0000007E 00 2e |..|
00000080 73 68 73 74 72 74 61 62 00 2e 74 65 78 74 00 |shstrtab..text.|
0000008F
Run Code Online (Sandbox Code Playgroud)
这是字符串表,地址相对于它的开头:
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00: 00 2E 73 68 73 74 72 74 61 62 00 2e 74 65 78 74
10: 00
Run Code Online (Sandbox Code Playgroud)
或在 ASCII 中相同,空字符标记为?:
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00: ? . s h s t r t a b ? . t e x t
10: ?
Run Code Online (Sandbox Code Playgroud)
所以我们只有 3 个完整的字符串,具有以下相对偏移量:
00: "" (Just the empty string)
01: ".shstrtab" (Name for this section)
0B: ".text" (Name for the section that contains the executable code)
Run Code Online (Sandbox Code Playgroud)
(但请记住,如果这些部分具有共同的结尾,则这些部分也可以寻址这些字符串中的子字符串。)
我们现在可以验证这个部分(#2)确实被命名了.shstrtab:它的名字索引0x01毕竟是,不是吗?;)
现在让我们拆开第 1 节的标题:
Name index Type=SHT_PROGBITS
Flags .----^----. .----^----.
000000d8 .----------^----------. 0b 00 00 00 01 00 00 00 |........|
000000e0 06 00 00 00 00 00 00 00 78 00 40 00 00 00 00 00 |........x.@.....|
000000f0 78 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 |x...............|
'----------.----------' '----------.----------'
Starting offset Size
00000100 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000110 00 00 00 00 00 00 00 00 |........|
00000118
Run Code Online (Sandbox Code Playgroud)
所以这个部分被命名.text(注意名称 index 0x0B)并且它是 type SHT_PROGBITS,所以它包含一些程序定义的数据;在这种情况下的可执行代码。它从0x78文件中的偏移量开始并取下一个6字节,因此该部分之后的第一个字节位于偏移量处0x7E(字符串表开始的位置)。这是它的内容:
00000070 31 c0 ff c0 cd 80 |1.....|
0000007E
Run Code Online (Sandbox Code Playgroud)
可是等等!还记得你的“神秘数据”是从哪里开始的吗?是的!是0x78偏移量!:) 所以这个“神秘数据”实际上是你的可执行有效载荷 :) 在将它解码为 Intel x86-64 操作码后,我们得到了这个小程序:
31 C0 xor %eax,%eax ; Clear the EAX register to 0 (the short way).
FF C0 inc %eax ; Increase the EAX, so now it contains 1.
CD 80 int $0x80 ; Interrupt 0x80 is the system call on Linux.
Run Code Online (Sandbox Code Playgroud)
这基本上等同于exit(0)在 C 中调用;) 因为系统调用中断需要 EAX 中的操作编号,在这种情况下是sys_exit(操作编号 1)。
所以,是的,谜团解开了 :) 但无论如何让我们继续,学习更多的东西,这样我们就会找出这段代码将在内存中加载的位置。
最后是#0 部分。它缺少某些部分,但我认为它都是0s,因为毕竟第一部分始终是 NULL 部分。这是它的(屠宰的)标题:
00000098 00 00 00 00 00 00 00 00 | ........|
*
000000d0 00 00 00 00 00 00 00 00
Run Code Online (Sandbox Code Playgroud)
但这对我们没有用。这里没什么有趣的。
剩下要解码的最后一件事是程序头表,根据来自 ELF 头的信息,它从偏移量开始0x40并获取56字节,它之后的第一个字节位于偏移量处0x78。这是转储:
Type=PHT_EXEC Flags=RX Starting offset in file
.----^----. .----^----. .----------^----------.
00000040 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 40 00 00 00 00 00 00 00 40 00 00 00 00 00 |..@.......@.....|
'----------.----------' '----------.----------'
Virtual address Physical address
Size in file Size in memory
.----------^----------. .----------^----------.
00000060 7e 00 00 00 00 00 00 00 7e 00 00 00 00 00 00 00 |~.......~.......|
00000070 00 00 20 00 00 00 00 00
00000078 '----------.----------'
Alignment
Run Code Online (Sandbox Code Playgroud)
所以它说我们将文件的第一个126( 0x7E) 字节加载到一个相同大小的内存段中,并且该内存段应该从虚拟地址开始0x400000。我们的代码从0x78文件中的偏移量和偏移量之后的第一个字节开始0x7E,所以它基本上加载文件的整个开头,将 ELF 头和程序头表加载到内存中,以及我们的可执行负载在结束,然后停止加载,忽略文件的其余部分。
因此,如果文件的开头在 address 加载0x400000,并且我们的程序从它的开头开始120( 0x78) 个字节,它将位于0x400078内存中的地址:>
现在让我们看看在我们的程序的 ELF 头文件中指定了什么入口点:
Executable x86-64 Version=1 Program's entry point
.-^-. .-^-. .----^----. .----------^----------.
00000010 02 00 3e 00 01 00 00 00 78 00 40 00 00 00 00 00 |..>.....x.@.....|
Run Code Online (Sandbox Code Playgroud)
答对了!:> 它是0x400078,所以它指向我们在内存映像中的一小段代码的开头。
这就是全部,伙计们!;)
| 归档时间: |
|
| 查看次数: |
2125 次 |
| 最近记录: |