介绍
在本实验中,你将学习如何使用 Linux 的 objdump 命令,这是一个用于分析目标文件内容的强大工具。你将首先了解 objdump 命令的用途,然后探索其基本语法和选项,最后分析 objdump 在一个简单 C 程序上的输出。本实验涵盖了脚本和编程领域的基本技能,所获得的知识可以应用于各种软件开发和调试任务。
在本实验中,你将学习如何使用 Linux 的 objdump 命令,这是一个用于分析目标文件内容的强大工具。你将首先了解 objdump 命令的用途,然后探索其基本语法和选项,最后分析 objdump 在一个简单 C 程序上的输出。本实验涵盖了脚本和编程领域的基本技能,所获得的知识可以应用于各种软件开发和调试任务。
在这一步中,你将学习 Linux 中 objdump 命令的用途。objdump 命令是一个强大的工具,用于分析目标文件的内容,这些文件是包含机器代码和其他信息的二进制文件。
objdump 命令可以用于反汇编目标文件中的机器代码,这意味着它可以将二进制指令转换为人类可读的格式。这对于理解程序的工作原理、调试问题,甚至逆向工程软件都非常有用。
让我们从创建一个简单的 C 程序开始,并使用 objdump 分析其内容。
首先,在 ~/project 目录下创建一个名为 hello.c 的新文件,内容如下:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
接下来,使用 gcc 编译器编译该程序:
cd ~/project
gcc -o hello hello.c
现在,让我们使用 objdump 命令分析 hello 可执行文件的内容:
objdump -d hello
示例输出:
hello: file format elf64-x86-64
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax ## 3fe8 <__gmon_start__>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 callq *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 retq
objdump 命令反汇编了 hello 可执行文件中的机器代码,显示了程序运行时处理器将执行的低级指令。这对于理解程序的工作原理和调试问题非常有用。
在下一步中,你将探索 objdump 命令的基本语法和选项。
在这一步中,你将探索 objdump 命令的基本语法和选项。objdump 命令提供了多种选项,允许你自定义输出并从目标文件中提取特定信息。
让我们首先回顾 objdump 命令的基本语法:
objdump [options] file
以下是 objdump 命令的一些常用选项:
-d 或 --disassemble:反汇编可执行代码。-S 或 --source:将源代码与反汇编代码混合显示。-t 或 --syms:显示符号表的内容。-x 或 --all-headers:显示所有可用的头信息。-h 或 --section-headers:显示节头(section headers)的内容。让我们尝试使用这些选项来分析上一步中创建的 hello 可执行文件:
## 显示反汇编代码及源代码
objdump -dS hello
## 显示符号表
objdump -t hello
## 显示所有可用的头信息
objdump -x hello
示例输出:
hello: file format elf64-x86-64
Disassembly of section .text:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax ## 3fe8 <__gmon_start__>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 callq *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 retq
0000000000001020 <__libc_csu_init>:
1020: f3 0f 1e fa endbr64
1024: 41 57 push %r15
1026: 4c 8d 3d 93 2c 00 00 lea 0x2c93(%rip),%r15 ## 3cc0 <__frame_dummy_init_array_entry>
102d: 41 56 push %r14
102f: 49 89 e6 mov %rsp,%r14
1032: 41 55 push %r13
1034: 41 54 push %r12
1036: 4c 8d 25 83 2c 00 00 lea 0x2c83(%rip),%r12 ## 3cc0 <__frame_dummy_init_array_entry>
103d: 55 push %rbp
103e: 48 8d 2d 83 2c 00 00 lea 0x2c83(%rip),%rbp ## 3cc8 <__do_global_dtors_aux_fini_array_entry>
1045: 53 push %rbx
1046: 4c 29 e5 sub %r12,%rbp
1049: 48 83 ec 08 sub $0x8,%rsp
104d: e8 ae fe ff ff callq f00 <_init>
1052: 48 c1 fd 03 sar $0x3,%rbp
1056: 74 1f je 1077 <__libc_csu_init+0x57>
1058: 31 db xor %ebx,%ebx
105a: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
105f: 4c 89 f2 mov %r14,%rdx
1062: 4c 89 ee mov %r13,%rsi
1065: 44 89 e7 mov %r12d,%edi
1068: 41 ff 14 df callq *(%r15,%rbx,8)
106c: 48 83 c3 01 add $0x1,%rbx
1070: 48 39 dd cmp %rbx,%rbp
1073: 75 ea jne 105f <__libc_csu_init+0x3f>
1075: 48 83 c4 08 add $0x8,%rsp
1079: 5b pop %rbx
107a: 5d pop %rbp
107b: 41 5c pop %r12
107d: 41 5d pop %r13
107f: 41 5e pop %r14
1081: 41 5f pop %r15
1083: c3 retq
0000000000001084 <__libc_csu_fini>:
1084: f3 0f 1e fa endbr64
1088: c3 retq
0000000000001089 <main>:
1089: f3 0f 1e fa endbr64
108d: 55 push %rbp
108e: 48 89 e5 mov %rsp,%rbp
1091: bf 00 00 00 00 mov $0x0,%edi
1096: e8 85 fe ff ff callq f20 <puts@plt>
109b: b8 00 00 00 00 mov $0x0,%eax
10a0: 5d pop %rbp
10a1: c3 retq
10a2: 66 2e 0f 1f 84 00 00 00 00 00 nopw %cs:0x0(%rax,%rax,1)
10ac: 0f 1f 40 00 nopl 0x0(%rax)
Disassembly of section .fini:
00000000000010b0 <_fini>:
10b0: f3 0f 1e fa endbr64
10b4: 48 83 ec 08 sub $0x8,%rsp
10b8: 48 83 c4 08 add $0x8,%rsp
10bc: c3 retq
输出显示了 hello 可执行文件的反汇编代码,包括与机器指令混合的源代码。这对于从底层理解程序的工作原理非常有用。
在下一步中,你将更详细地分析 objdump 在 hello 程序上的输出。
在这最后一步中,你将更详细地分析 objdump 命令的输出,重点关注我们之前创建的 hello 程序。
让我们首先仔细查看反汇编输出:
objdump -d hello
示例输出:
hello: file format elf64-x86-64
Disassembly of section .text:
0000000000001089 <main>:
1089: f3 0f 1e fa endbr64
108d: 55 push %rbp
108e: 48 89 e5 mov %rsp,%rbp
1091: bf 00 00 00 00 mov $0x0,%edi
1096: e8 85 fe ff ff callq f20 <puts@plt>
109b: b8 00 00 00 00 mov $0x0,%eax
10a0: 5d pop %rbp
10a1: c3 retq
反汇编输出显示了构成 hello 程序 main 函数的机器指令。让我们逐条分析这些指令:
f3 0f 1e fa:这是 endbr64 指令,是一种安全特性,用于防止某些类型的攻击。55:这是 push %rbp 指令,将基指针寄存器保存到栈中。48 89 e5:这是 mov %rsp,%rbp 指令,将基指针设置为当前栈指针。bf 00 00 00 00:这是 mov $0x0,%edi 指令,将 puts 函数调用的第一个参数(文件描述符)设置为 0。e8 85 fe ff ff:这是 callq f20 <puts@plt> 指令,调用 puts 函数以打印 "Hello, World!" 消息。b8 00 00 00 00:这是 mov $0x0,%eax 指令,将 main 函数的返回值设置为 0。5d:这是 pop %rbp 指令,从栈中恢复基指针。c3:这是 retq 指令,从 main 函数返回。通过理解反汇编输出,你可以更深入地了解 hello 程序在底层的运行方式。这对于调试问题或逆向工程软件尤其有用。
在本实验中,你首先了解了 Linux 中 objdump 命令的用途,这是一个用于分析目标文件内容的强大工具。你创建了一个简单的 C 程序,编译它,然后使用 objdump 反汇编可执行文件中的机器代码,从而能够从底层理解程序的运行方式。接着,你探索了 objdump 命令的基本语法和选项,这些选项可用于从目标文件中提取各种类型的信息,例如符号表、重定位信息等。通过本实验,你已经掌握了如何使用 objdump 分析 Linux 系统上可执行文件的内容。