Linux objdump 命令实战示例

LinuxBeginner
立即练习

介绍

在本实验中,你将学习如何使用 Linux 的 objdump 命令,这是一个用于分析目标文件内容的强大工具。你将首先了解 objdump 命令的用途,然后探索其基本语法和选项,最后分析 objdump 在一个简单 C 程序上的输出。本实验涵盖了脚本和编程领域的基本技能,所获得的知识可以应用于各种软件开发和调试任务。

Linux 命令速查表

理解 objdump 命令的用途

在这一步中,你将学习 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 命令的基本语法:

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 可执行文件的反汇编代码,包括与机器指令混合的源代码。这对于从底层理解程序的工作原理非常有用。

在下一步中,你将更详细地分析 objdumphello 程序上的输出。

分析 objdump 在简单 C 程序上的输出

在这最后一步中,你将更详细地分析 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 函数的机器指令。让我们逐条分析这些指令:

  1. f3 0f 1e fa:这是 endbr64 指令,是一种安全特性,用于防止某些类型的攻击。
  2. 55:这是 push %rbp 指令,将基指针寄存器保存到栈中。
  3. 48 89 e5:这是 mov %rsp,%rbp 指令,将基指针设置为当前栈指针。
  4. bf 00 00 00 00:这是 mov $0x0,%edi 指令,将 puts 函数调用的第一个参数(文件描述符)设置为 0。
  5. e8 85 fe ff ff:这是 callq f20 <puts@plt> 指令,调用 puts 函数以打印 "Hello, World!" 消息。
  6. b8 00 00 00 00:这是 mov $0x0,%eax 指令,将 main 函数的返回值设置为 0。
  7. 5d:这是 pop %rbp 指令,从栈中恢复基指针。
  8. c3:这是 retq 指令,从 main 函数返回。

通过理解反汇编输出,你可以更深入地了解 hello 程序在底层的运行方式。这对于调试问题或逆向工程软件尤其有用。

总结

在本实验中,你首先了解了 Linux 中 objdump 命令的用途,这是一个用于分析目标文件内容的强大工具。你创建了一个简单的 C 程序,编译它,然后使用 objdump 反汇编可执行文件中的机器代码,从而能够从底层理解程序的运行方式。接着,你探索了 objdump 命令的基本语法和选项,这些选项可用于从目标文件中提取各种类型的信息,例如符号表、重定位信息等。通过本实验,你已经掌握了如何使用 objdump 分析 Linux 系统上可执行文件的内容。

Linux 命令速查表