Skip to content

x86 Instruction Set

Malware analysis often requires disassembling x86 binaries to understand malicious behavior. The x86 instruction set forms the foundation of this process, with opcodes, registers, and memory addressing modes enabling reverse engineers to trace execution flows, extract data, and identify evasion techniques. Ghidra’s disassembler provides visibility into these low-level constructs, making them critical for analyzing malware that leverages x86-specific patterns.


x86 Opcodes: The Language of Instructions

Opcodes are the binary codes that specify operations like arithmetic, control flow, and memory access. They vary in length (1–3 bytes) and depend on the instruction’s operands. For example:
- 0x8B (MOV register from memory)
- 0xEB (JMP short relative)
- 0x90 (NOP, no operation)

Common opcode categories:
- Data transfer: MOV, PUSH, POP
- Arithmetic/logic: ADD, SUB, XOR
- Control flow: JMP, CALL, RET
- System calls: INT, SYSCALL

Example:

; Ghidra disassembly snippet
0x00401000  8B 0D 00 00 00 00   MOV EAX, [0x00401000]
Here, 0x8B is the opcode for MOV, and the subsequent bytes specify the memory operand.

Ghidra tip: Use View > Display Options > Show Opcodes to inspect raw opcode bytes in the disassembly view.


x8, x16, and x32 Registers: Tracking Data Flow

x86 processors use registers for fast data manipulation. Key registers include:

Register Size Purpose
EAX/AX/AL 32/16/8 bits Accumulator for arithmetic operations
EBX/BX/BL 32/16/8 bits Base pointer for memory addressing
ESP/SP 32/16 bits Stack pointer
EBP 32 bits Frame pointer for stack frames
EIP/IP 32/16 bits Instruction pointer (program counter)

64-bit note: In x64 mode, registers are extended to 64 bits (e.g., RAX, RBX). However, many malware samples still use 32-bit registers for compatibility or obfuscation.

Example:

; Ghidra disassembly
0x00401000  8B 45 FC           MOV EAX, [EBP-0x04]
This instruction moves the value at [EBP-0x04] (a local variable) into EAX.

Ghidra tip: Use View > Register View to monitor register values during analysis.


Memory Addressing Modes: Navigating the Address Space

x86 instructions use complex memory addressing modes to access operands. Common forms include:

  1. Immediate operand:

    MOV EAX, 0x12345678
    
    Operand is a literal value.

  2. Register operand:

    MOV EAX, EBX
    
    Operand is a register.

  3. Memory operand:

    MOV EAX, [EBX+0x04]
    
    Operand is a memory location calculated as EBX + 0x04.

  4. Scaled index:

    MOV EAX, [EBX+ECX*4]
    
    Operand uses a scaling factor (e.g., for arrays).

Ghidra example:

# Ghidra command to analyze memory access patterns
analyze -p x86 -o 0x00401000 -s 0x100
This command analyzes a 256-byte memory region starting at 0x00401000.


Key takeaways

  • Opcodes define the instruction set, and Ghidra’s disassembly reveals their structure.
  • Registers track critical data and control flow, making them essential for debugging.
  • Memory addressing modes enable indirect access to data, a common technique in malware for obfuscation.
  • Mastery of these concepts allows analysts to dissect malicious code at the machine code level.