• Home
  • TTP
  • Pages
  • p5.0_disasm.core // Binary Deconstruction: The Art of Disassembly

0x01: The Philosophy of Disassembly

Disassembly is the process of reversing the final stage of compilation. While the CPU sees a stream of high-speed electrical pulses (represented as Hex/Binary), the analyst needs to see intent.

In the world of the 0x10 Operator, disassembly is the only way to verify what a program actually does, regardless of what the documentation claims.

Critical Use Cases:

  • Malware Analysis: Determining if a binary is exfiltrating data or encrypting your disk.
  • Vulnerability Research: Identifying “Buffer Overflows” or “Use-After-Free” bugs by seeing exactly how the compiler allocated memory.
  • Exploit Development: Moving from a simple “crash” to a working “exploit” requires knowing the exact state of the registers and the stack at the moment of failure.

0x02: The Anatomy of an Instruction

When we disassemble a binary, we are looking for three pieces of information that make up an instruction:

  1. The Address (Offset): Where the instruction lives in memory.
  2. The Opcode (Machine Code): The raw bytes the CPU interprets.
  3. The Mnemonic (Assembly): The human-readable name for the action (e.g., MOV, PUSH, BL).

0x03: Tactical Tooling: objdump

While advanced analysts eventually move to heavy-duty GUIs like Ghidra or IDA Pro, the “First Response” tool is always objdump. It is fast, lightweight, and pre-installed on almost every Linux system.

By using the -c flag in GCC, we create an Object File (.o). This is vital because it strips away the noise of the C-Runtime and allows us to focus strictly on the code we wrote.

0x04: Analyzing the hello.o Trace

Look at the following trace generated from a simple write() function. This is your first look at the “Matrix”:

00000000 <main>:
   0: b580       push {r7, lr}          // Save the return address
   2: af00       add  r7, sp, #0        // Set up the local stack frame
   4: 2207       movs r2, #7            // Argument 3: String length (7)
   c: 2001       movs r0, #1            // Argument 1: File Descriptor (1 = stdout)
   e: f7ff fffe  bl   0 <write>         // Branch with Link: Call the write function

Intelligence Note: Notice how the arguments are loaded into registers (r0, r1, r2) before the bl (Branch with Link) instruction is called. In Reverse Engineering, seeing a bl or call instruction is your signal to look at the registers immediately preceding it to find the function’s parameters.


0x05: Interactive Lab (Disassembly Reconstruction)

In this lab, you must act as the “Human Disassembler.” Look at the raw machine code and identify the operation.

[DISASM_CORE_EXTRACTION_v5.0]

MISSION: Using the objdump logic from the briefing, identify the Mnemonic (the assembly command) represented by the hex code b580.

ADDR: 0x00000000
DATA: B5 80
MNEMONIC: [LOCKED]

0x06: Mission Task

Current Objective: Compile the hello.c program using gcc -c hello.c. Run objdump -d hello.o and look at the movs instructions.

The Challenge: Why does the compiler use movs instead of just mov? Search for the difference in the ARM instruction set documentation. This tiny detail (the “s” suffix) affects how the CPU’s Flags (Zero, Negative, Carry) are set, which is crucial for understanding conditional branches like jump if equal.


0x07: Advanced Disassembly & Logic Flow

When you run objdump -d, you are performing Static Analysis. You are looking at the instructions while they are “frozen.” To make this information useful, you need to reconstruct the logic that the programmer originally wrote in C.

1. The Function Prologue (The Handshake)

Every function starts with a sequence called the Prologue. Look at our hello.o output again: 0: b580 push {r7, lr}

  • r7: This is the Frame Pointer. It holds a reference to the start of the current function’s workspace.
  • lr (Link Register): This is the “Return Ticket.” It holds the address the CPU should jump back to once this function finishes. If a hacker overwrites this value on the stack, they can redirect the program to their own code. This is the foundation of Buffer Overflow Exploits.

2. PC-Relative Addressing (Finding Data)

Notice this line in the disassembly: 6: 4b04 ldr r3, [pc, #16]

In ARM architecture, the PC (Program Counter) points to the instruction currently being executed. The code is saying: “Go 16 bytes forward from where we are right now and grab the data there.” This is how the program finds the “Hello!” string. The string isn’t “in” the code; it’s tucked away in a data section, and the code uses the PC as a GPS to find it.

3. The Branch with Link (bl)

e: f7ff fffe bl 0 <write>

The bl instruction is a “Call.” It does two things:

  1. It jumps to the write function.
  2. It saves the current address into the Link Register (lr) so the program knows how to come back.

0x08: Tactical Intelligence Extraction

In high-level C, you write: write(1, "Hello!", 7);. In Disassembly, you must track where those three arguments (1, address, and 7) go.

C ArgumentARM RegisterDisassembly Line
1 (File Descriptor)r0c: 2001 movs r0, #1
"Hello!" (Buffer)r1a: 4619 mov r1, r3 (r3 held the address)
7 (Count)r24: 2207 movs r2, #7

0x09: Interactive Lab (Logic Reconstruction)

You have intercepted a mystery binary. Your mission is to determine what value is being passed as the Length of the string by analyzing the raw hex.

[CRITICAL_LOGIC_CHECK_v5.0]
0: 2101 movs r1, #1
2: 2005 movs r0, #5
4: 1c02 adds r2, r0, r1

MISSION: Calculate the final value stored in register R2 after execution.

0x10: The “Pro” Disassembler Overview

While objdump is our primary scout, for complex missions, we use tools that can graph the logic flow:

  • Ghidra (NSA): Excellent for “Decompilation” (turning assembly back into C-like code).
  • IDA Pro: The gold standard for commercial malware analysis.
  • Binary Ninja: Known for its clean UI and powerful “Intermediate Language” (IL) which simplifies complex assembly.

As we move into the next lectures, we will begin using these tools to map out large, “stripped” binaries where we don’t even have function names to guide us.


Mission Task

Current Objective: Re-run objdump -d hello.o. Look for the 18: 0000000c .word 0x0000000c at the end.

Challenge: This is a Literal Pool. The instruction at offset 6 used the Program Counter to find this value. Can you calculate why the offset is #16? (Hint: In ARM, the PC is often 2 instructions ahead of the one being executed).

This is p5.1_disasm.summary // The Operator’s Synthesis.

To achieve the rank of 0x11 (Master Analyst), you must be able to look at a wall of hexadecimal noise and instantly see the high-level logic. This lecture serves as a “Combat Review” of everything we have covered regarding disassembly, from raw opcodes to register tracking.


0x11: The Disassembly Masterclass

Disassembly is the bridge between the Physical Layer (machine code) and the Logical Layer (source code). By now, you should recognize that every binary follows a predictable pattern dictated by the compiler and the CPU architecture.

I. The Physical Signature (The Bytes)

Every instruction starts as a specific hex value. When you see B5 80, your brain should immediately translate that to PUSH {R7, LR}.

  • Pro Tip: In ARM Thumb mode (32-bit), instructions are often 2 bytes. In A64 (64-bit), they are strictly 4 bytes. Knowing the “width” of your instructions prevents you from getting lost in the offsets.

II. The Structural Blueprint (The Sections)

We don’t just find code anywhere. A well-formed ELF binary organizes its intel into compartments:

  • .text: The armory where the actual instructions (MOV, ADD, BL) are stored.
  • .rodata: The archive where static strings (“Hello World”) live.
  • .data: The workbench for variables that change during execution.

III. The Data Flow (The Calling Convention)

This is where most analysts fail. You must remember the Standard Handshake:

  1. R0-R3 / X0-X7: These are the “Input Slots.” Before a function is called, the arguments are placed here.
  2. BL (Branch with Link): The jump happens.
  3. R0 / X0: After the function returns, the “Result” is placed back in the first register.

0x12: Tactical Error Resolution (The “Why” Behind the Error)

In your last mission, many of you encountered “Logic Divergence.” Let’s analyze why those errors happen and how to resolve them.

Scenario: ADDS R2, R0, R1 where R0=5 and R1=1.

  • Error: “I thought the answer was 1.”
    • Reason: You focused on the last register loaded (R1) and forgot that ADDS is an arithmetic operation, not a move.
    • Resolution: Always look for the Mnemonic. If it’s ADD, SUB, or MUL, you are performing math, not just storage.
  • Error: “I thought the answer was 5.”
    • Reason: You identified the source register (R0) but ignored the secondary operand.
    • Resolution: ARM instructions often use Three-Operand Syntax: DESTINATION, OPERAND1, OPERAND2. The first register is where the result goes; the next two are the ingredients.
  • Error: “The Hex says 0xA, so I wrote 10.”
    • Reason: This is correct, but if the lab asks for Hex and you give Decimal (or vice versa), the system will flag a mismatch.
    • Resolution: Radix Literacy. Always check your prefixes. 10 ≠ 0x10 (which is 16).

0x13: Interactive Lab (Final Synthesis Check)

This is the final gate. You must analyze this three-line trace and provide the final state of the registers.

[SYNTHESIS_GATE_V5.1]
0: 200A movs r0, #10
2: 2102 movs r1, #2
4: fb00 f201 mul r2, r0, r1
FINAL VALUE OF R2 (DECIMAL)

0x14: The Road Ahead

You have mastered the Static deconstruction of a binary. You can read the code while it sleeps. In the next phase, we wake it up. We will move into Dynamic Analysis, where we use debuggers to watch these registers change in real-time.

Mission Task:

Use objdump -S on a binary you compiled with debugging symbols (gcc -g). This flag interweaves your C source code with the Disassembly. This is the “God View” of reverse engineering. Study how a single line of C (like x = a * b) often results in 3 or 4 lines of Assembly.