class Ronin::ASM::Program

Represents a full Assembly program.

Constants

PARSERS

The Assembly Parsers

SYNTAX

Supported Assembly Syntaxs

Attributes

allocated_registers[R]

The registers used by the program

arch[R]

The targeted architecture

instructions[R]

The instructions of the program

os[R]

The targeted Operating System

registers[R]

The registers available to the program

@return [Hash{Symbol => Register}]

The names and registers.
syscalls[R]

The syscalls available to the program

@return [Hash{Symbol => Integer}]

The syscall names and numbers.
word_size[R]

The default word size

Public Class Methods

new(options={},&block) click to toggle source

Initializes a new Assembly Program.

@param [Hash] options

Additional options.

@option options [String, Symbol] :arch (:x86)

The Architecture to target.

@option options [String, Symbol] :os

The Operating System to target.

@option options [Hash{Symbol => Object}] :define

Constants to define in the program.

@yield []

The given block will be evaluated within the program.

@example

Program.new(arch: :amd64) do
  push  rax
  push  rbx

  mov   rsp,     rax
  mov   rax[8],  rbx
end
# File lib/ronin/asm/program.rb, line 105
def initialize(options={},&block)
  @arch = options.fetch(:arch,:x86).to_sym

  arch = Archs.const_get(@arch.to_s.upcase)

  @word_size = arch::WORD_SIZE
  @registers = arch::REGISTERS

  extend Archs.const_get(@arch.to_s.upcase)

  @syscalls = {}

  if options.has_key?(:os)
    @os       = options[:os].to_s
    @syscalls = OS::SYSCALLS[@os][@arch]

    extend OS.const_get(@os)
  end

  if options[:define]
    options[:define].each do |name,value|
      instance_variable_set("@#{name}",value)
    end
  end

  @allocated_registers = []
  @instructions = []

  instance_eval(&block) if block
end

Public Instance Methods

assemble(output,options={}) click to toggle source

Assembles the program.

@param [String] output

The path for the assembled program.

@param [Hash] options

Additional options.

@option options [Symbol, String] :syntax (:intel)

The syntax to compile the program to.

@option options [Symbol] :format (:bin)

The format of the assembled executable. May be one of:

* `:dbg` - Trace of all info passed to object format module.
* `:bin` - Flat format binary.
* `:dosexe` - DOS .EXE format binary.
* `:elf` - ELF.
* `:elf32` - ELF (32-bit).
* `:elf64` - ELF (64-bit).
* `:coff` - COFF (DJGPP).
* `:macho` - Mac OS X ABI Mach-O File Format.
* `:macho32` - Mac OS X ABI Mach-O File Format (32-bit).
* `:macho64` - Mac OS X ABI Mach-O File Format (64-bit).
* `:rdf` - Relocatable Dynamic Object File Format (RDOFF) v2.0.
* `:win32` - Win32.
* `:win64` / `:x64` - Win64.
* `:xdf` - Extended Dynamic Object.

@return [String]

The path to the assembled program.
# File lib/ronin/asm/program.rb, line 453
def assemble(output,options={})
  syntax  = options.fetch(:syntax,:intel)
  format  = options.fetch(:format,:bin)
  parser  = PARSERS[syntax]

  source = Tempfile.new(['ronin-asm', '.s'])
  source.write(to_asm(syntax))
  source.close

  YASM::Program.assemble(
    file:          source.path,
    parser:        PARSERS[syntax],
    target:        @arch,
    output_format: format,
    output:        output
  )

  return output
end
byte(op) click to toggle source

Creates an operand of size 1 (byte).

@param [MemoryOperand, Integer] op

The value of the operand.

@return [MemoryOperand, ImmediateOperand]

The new operand value.
# File lib/ronin/asm/program.rb, line 202
def byte(op)
  case op
  when MemoryOperand
    MemoryOperand.new(op.base,op.offset,op.index,op.scale,1)
  else
    ImmediateOperand.new(op,1)
  end
end
critical(*regs,&block) click to toggle source

Defines a critical region, where the specified Registers should be saved and then reloaded.

@param [Array<Symbol>] regs

The registers to save and reload.

@yield []

The given block will be evaluated after the registers
have been saved.
# File lib/ronin/asm/program.rb, line 385
def critical(*regs,&block)
  regs.each { |name| register_save(name) }

  instance_eval(&block)

  regs.reverse_each { |name| register_load(name) }
end
dword(op) click to toggle source

Creates a operand of size 4 (bytes).

@param [MemoryOperand, Integer] op

The value of the operand.

@return [ImmediateOperand]

The new operand value.
# File lib/ronin/asm/program.rb, line 238
def dword(op)
  case op
  when MemoryOperand
    MemoryOperand.new(op.base,op.offset,op.index,op.scale,4)
  else
    ImmediateOperand.new(op,4)
  end
end
eval(&block) click to toggle source

Evaluates code within the Program.

@yield []

The code to evaluate.
# File lib/ronin/asm/program.rb, line 399
def eval(&block)
  instance_eval(&block)
end
instruction(name,*operands) click to toggle source

Adds a new instruction to the program.

@param [String, Symbol] name

@param [Array] operands

@return [Instruction]

The newly created instruction.
# File lib/ronin/asm/program.rb, line 186
def instruction(name,*operands)
  insn = Instruction.new(name.to_sym,operands)

  @instructions << insn
  return insn
end
interrupt(number) click to toggle source

Generic method for generating the instruction for causing an interrupt.

@param [Integer] number

The interrupt number to call.

@abstract

# File lib/ronin/asm/program.rb, line 294
def interrupt(number)
end
label(name,&block) click to toggle source

Adds a label to the program.

@param [Symbol, String] name

The name of the label.

@yield []

The given block will be evaluated after the label has been
added.

@return [Symbol]

The label name.
# File lib/ronin/asm/program.rb, line 278
def label(name,&block)
  name = name.to_sym

  @instructions << name
  instance_eval(&block)
  return name
end
qword(op) click to toggle source

Creates a operand of size 8 (bytes).

@param [MemoryOperand, Integer] op

The value of the operand.

@return [MemoryOperand, ImmediateOperand]

The new operand.
# File lib/ronin/asm/program.rb, line 256
def qword(op)
  case op
  when MemoryOperand
    MemoryOperand.new(op.base,op.offset,op.index,op.scale,8)
  else
    ImmediateOperand.new(op,8)
  end
end
register(name) click to toggle source

Accesses a register.

@param [String, Symbol] name

The name of the register.

@return [Register]

The register.

@raise [ArgumentError]

The register could not be found.
# File lib/ronin/asm/program.rb, line 161
def register(name)
  name = name.to_sym

  unless register?(name)
    raise(ArgumentError,"unknown register: #{name}")
  end

  unless @allocated_registers.include?(name)
    # mark the register as being used, when it was first accessed
    @allocated_registers << name
  end

  return @registers[name]
end
register?(name) click to toggle source

Determines if a register exists.

@param [Symbol] name

The name of the register.

@return [Boolean]

Specifies whether the register exists.
# File lib/ronin/asm/program.rb, line 145
def register?(name)
  @registers.has_key?(name.to_sym)
end
register_clear(name) click to toggle source

Generic method for clearing a register.

@param [Symbol] name

The name of the reigster.

@abstract

# File lib/ronin/asm/program.rb, line 335
def register_clear(name)
end
register_load(name) click to toggle source

Generic method for loading a register.

@param [Symbol] name

The name of the reigster.

@abstract

# File lib/ronin/asm/program.rb, line 371
def register_load(name)
end
register_save(name) click to toggle source

Generic method for saving a register.

@param [Symbol] name

The name of the reigster.

@abstract

# File lib/ronin/asm/program.rb, line 360
def register_save(name)
end
register_set(name,value) click to toggle source

Generic method for setting a register.

@param [Symbol] name

The name of the reigster.

@param [Register, Immediate, Integer] value

The new value for the register.

@abstract

# File lib/ronin/asm/program.rb, line 349
def register_set(name,value)
end
stack_pop(name) click to toggle source

Generic method for popping off the stack.

@param [Symbol] name

The name of the reigster.

@abstract

# File lib/ronin/asm/program.rb, line 324
def stack_pop(name)
end
stack_push(value) click to toggle source

Generic method for pushing onto the stack.

@param [Register, Integer] value

The value to push.

@abstract

# File lib/ronin/asm/program.rb, line 313
def stack_push(value)
end
syscall() click to toggle source

Generic method for generating the instruction for invoking a syscall.

@abstract

# File lib/ronin/asm/program.rb, line 302
def syscall
end
to_asm(syntax=:intel) click to toggle source

Converts the program to Assembly Source Code.

@param [Symbol] syntax

The syntax to compile the program to.
# File lib/ronin/asm/program.rb, line 409
def to_asm(syntax=:intel)
  SYNTAX[syntax].emit_program(self)
end
to_s() click to toggle source

@see to_s

# File lib/ronin/asm/program.rb, line 416
def to_s
  to_asm
end
word(op) click to toggle source

Creates a operand of size 2 (bytes).

@param [MemoryOperand, Integer] op

The value of the operand.

@return [MemoryOperand, ImmediateOperand]

The new operand value.
# File lib/ronin/asm/program.rb, line 220
def word(op)
  case op
  when MemoryOperand
    MemoryOperand.new(op.base,op.offset,op.index,op.scale,2)
  else
    ImmediateOperand.new(op,2)
  end
end

Protected Instance Methods

method_missing(name,*arguments,&block) click to toggle source

Allows adding unknown instructions to the program.

@param [Symbol] name

The name of the instruction.

@param [Array] arguments

Additional operands.
Calls superclass method
# File lib/ronin/asm/program.rb, line 487
def method_missing(name,*arguments,&block)
  if (block && arguments.empty?)
    label(name,&block)
  elsif block.nil?
    if (arguments.empty? && register?(name))
      register(name)
    else
      instruction(name,*arguments)
    end
  else
    super(name,*arguments,&block)
  end
end