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:
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:
[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:
-
Immediate operand:
Operand is a literal value.
-
Register operand:
Operand is a register.
-
Memory operand:
Operand is a memory location calculated as
EBX + 0x04. -
Scaled index:
Operand uses a scaling factor (e.g., for arrays).
Ghidra example:
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.