objdump Command in Linux

Introduction to objdump

This hands-on lab introduces the Linux objdump command, a vital tool for system administrators and developers needing to dissect object file internals. You'll begin with the core purpose of objdump, then delve into its command syntax and options, culminating in a detailed analysis of objdump output from a basic C program. This tutorial hones fundamental skills applicable to scripting, programming, software debugging, and reverse engineering tasks performed by systemadmin and development teams.

Understanding the Role of the objdump Command

This section illuminates the function of the objdump command within the Linux environment. objdump serves as a robust utility for scrutinizing the makeup of object files – binary files containing compiled machine code and associated data.

A primary application of objdump is disassembling machine code, transforming binary instructions into a more easily interpreted, human-readable representation. This capability proves invaluable for deciphering program logic, pinpointing software bugs, and even conducting reverse engineering operations on software components.

To illustrate, we'll construct a straightforward C program and leverage objdump to dissect its contents.

Begin by generating a file named hello.c within the ~/project directory, populated with the subsequent code:

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

Subsequently, compile the C code utilizing the gcc compiler:

cd ~/project
gcc -o hello hello.c

Now, invoke the objdump command to scrutinize the hello executable:

objdump -d hello

Sample output:

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

As evidenced, objdump has disassembled the hello executable, displaying the underlying machine instructions the processor will execute. This level of detail facilitates understanding program behavior and diagnosing potential issues.

Next, we'll examine the command syntax and available options within objdump.

Dissecting objdump Syntax and Options

This segment explores the syntax and customizable options of the objdump command. Numerous options exist to fine-tune output and isolate specific information within the object file.

First, consider the fundamental structure of the objdump command:

objdump [options] file

Key objdump options include:

  • -d or --disassemble: Disassembles the executable code into assembly language.
  • -S or --source: Integrates source code alongside the disassembly for easier comprehension.
  • -t or --syms: Reveals the symbol table's contents, mapping names to addresses.
  • -x or --all-headers: Outputs all header information, offering a comprehensive file overview.
  • -h or --section-headers: Presents section headers, detailing file segmentation.

Apply these options to the hello executable created earlier:

## Display the disassembly with source code
objdump -dS hello

## Display the symbol table
objdump -t hello

## Display all available header information
objdump -x hello

Illustrative output:

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

This output exemplifies the disassembled code, accompanied by source lines. A powerful aid for detailed code analysis.

The next section provides an in-depth analysis of the objdump output when applied to our hello program.

Deep Dive: Analyzing objdump Output from a Simple C Program

In this concluding step, we perform an extensive analysis of objdump output specifically concerning the hello program.

Let's re-examine the disassembly output:

objdump -d hello

Representative output:

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

This output represents the disassembled main function. A breakdown of the instructions follows:

  1. f3 0f 1e fa: The endbr64 instruction, a security precaution against certain attacks.
  2. 55: push %rbp, storing the base pointer on the stack.
  3. 48 89 e5: mov %rsp,%rbp, setting the base pointer to the stack pointer.
  4. bf 00 00 00 00: mov $0x0,%edi, setting the first argument for the puts function.
  5. e8 85 fe ff ff: callq f20 <puts@plt>, calling the puts function to display "Hello, World!".
  6. b8 00 00 00 00: mov $0x0,%eax, setting the main function's return value to 0.
  7. 5d: pop %rbp, restoring the base pointer from the stack.
  8. c3: retq, returning from the main function.

By interpreting the disassembly output, you gain insights into the low-level workings of the hello program. This understanding is beneficial for debugging or reverse engineering.

Summary

This lab provided an introduction to the objdump command within Linux, highlighting its utility in analyzing object files. You constructed a simple C program, compiled it, and utilized objdump to disassemble its executable code, granting a peek into its low-level operations. Furthermore, the lab explored the syntax and options within objdump, facilitating the extraction of symbol tables and other file details. Ultimately, this lab equipped you with a fundamental understanding of employing objdump for executable file analysis on Linux, a valuable skill for any systemadmin working within the Linux ecosystem or developers debugging their applications.

400+ Linux Commands