Class: OneGadget::Emulators::X86

Inherits:
Processor show all
Defined in:
lib/one_gadget/emulators/x86.rb

Overview

Super class for amd64 and i386 processor.

Direct Known Subclasses

Amd64, I386

Constant Summary collapse

JCC =

x86 conditional-jump mnemonics mapped to shared Conditional::RELATION predicates (x86's adapter table, as ArmFamily::COND is for arm/aarch64).

{
  'je' => :eq, 'jz' => :eq, 'jne' => :ne, 'jnz' => :ne,
  'jb' => :ult, 'jc' => :ult, 'jnae' => :ult, 'jae' => :uge, 'jnb' => :uge, 'jnc' => :uge,
  'ja' => :ugt, 'jnbe' => :ugt, 'jbe' => :ule, 'jna' => :ule,
  'jl' => :slt, 'jnge' => :slt, 'jge' => :sge, 'jnl' => :sge,
  'jg' => :sgt, 'jnle' => :sgt, 'jle' => :sle, 'jng' => :sle,
  'js' => :slt, 'jns' => :sge
}.freeze
COMPARES =

x86 flag-setting compare mnemonics mapped to the ALU op whose result their flags reflect (see Conditional::COMPARE_OPS). test is a bitwise AND, cmp a subtraction.

{ 'cmp' => :sub, 'test' => :and }.freeze
SEGMENT_OPERAND =

A segment-prefixed operand reads thread-local storage, which isn't modelled (nor is its counterpart on the other arches -- aarch64's mrs tpidr_el0 and arm's mrc p15 are unsupported instructions, so those paths already abort). Every gadget observed behind one tests errno == ENOEXEC on glibc's execvpe path -- a value the caller would have to have arranged beforehand, since the gadget is entered after the execve that would set it -- so modelling this only produces gadgets that all but never apply. Worth revisiting if a libc is found reaching a terminal call under a condition that commonly holds, e.g. errno != <some error>.

Examples:

cmp DWORD PTR fs:[r14], 0x8 -- errno == ENOEXEC

/\b(?:fs|gs|ds|es|ss|cs):/

Constants inherited from Processor

Processor::ADDRESS_TYPES, Processor::CLOBBERED, Processor::NULLABLE_REQUIREMENTS, Processor::POINTER_REQUIREMENTS, Processor::TERMINAL_CALL_RE

Constants included from Conditional

Conditional::COMPARE_OPS, Conditional::NEGATE, Conditional::RELATION

Instance Attribute Summary

Attributes inherited from Processor

#bp, #pc, #refused_line, #registers, #sp

Instance Method Summary collapse

Methods inherited from Processor

#address_deref0?, #argument, bits, #bp_based_stack, #closed_fds, #constraint_key, #constraints, #drop_implied_nonzero, #drop_restated_null, #get_corresponding_stack, instruction_table, line_memo, #parse, #process, #reach_terminal_call, #render_constraint, #resolve_address, #setup_frame_pointer, #sp_based_stack, #terminal_call?

Methods included from Conditional

#branch_on_bit, #branch_on_compare, #branch_on_zero, #comparisons_on, #handle_compare, #mnemonic, #operand_str, #record_compare, #resolve_pending_branch, #satisfiable?, #value_str

Constructor Details

#initialize(registers, sp, bp, pc) ⇒ X86

Constructor for a x86 processor.



13
14
15
16
17
# File 'lib/one_gadget/emulators/x86.rb', line 13

def initialize(registers, sp, bp, pc)
  super(registers, sp)
  @pc = pc
  setup_frame_pointer(bp)
end

Instance Method Details

#instructionsArray<Instruction>

Supported instruction set.

Returns:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/one_gadget/emulators/x86.rb', line 67

def instructions
  [
    Instruction.new('add', 2),
    Instruction.new('and', 2),
    Instruction.new('call', 1),
    Instruction.new('endbr32', -1),
    Instruction.new('endbr64', -1),
    Instruction.new('jmp', 1),
    Instruction.new('lea', 2),
    Instruction.new('mov', 2),
    Instruction.new('movsxd', 2),
    Instruction.new('nop', -1),
    Instruction.new('push', 1),
    Instruction.new('sub', 2),
    Instruction.new('xchg', 2),
    Instruction.new('xor', 2),
    Instruction.new('movq', 2),
    Instruction.new('movaps', 2),
    Instruction.new('movhps', 2),
    Instruction.new('punpcklqdq', 2)
  ]
end

#process!(cmd) ⇒ Boolean

Process one command. Will raise exceptions when encounter unhandled instruction.

Parameters:

  • cmd (String)

    One line from result of objdump.

Returns:

  • (Boolean)

    If successfully processed.



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/one_gadget/emulators/x86.rb', line 25

def process!(cmd)
  cmd = concretize_rip(cmd)
  resolve_pending_branch(cmd)
  mnem = mnemonic(cmd)
  return handle_compare(COMPARES[mnem], cmd) if COMPARES.key?(mnem)
  return handle_branch(mnem, cmd) != :fail if branch_mnem?(mnem)

  inst, args = parse(cmd)
  sym = :"inst_#{inst.inst}"
  __send__(sym, *args) != :fail
end