class Rex::RopBuilder::RopCollect

Public Class Methods

new(file="") click to toggle source
Calls superclass method Rex::RopBuilder::RopBase::new
# File lib/rex/ropbuilder/rop.rb, line 90
def initialize(file="")
  @stdio = Rex::Ui::Text::Output::Stdio.new
  @file = file if not file.empty?
  @bin = Metasm::AutoExe.decode_file(file) if not file.empty?
  @disassembler = @bin.disassembler if not @bin.nil?
  if @disassembler
    @disassembler.cpu = Metasm::Ia32.new('386_common')
  end
  super()
end

Public Instance Methods

collect(depth, pattern) click to toggle source
# File lib/rex/ropbuilder/rop.rb, line 101
def collect(depth, pattern)
  matches = []
  gadgets = []

  # find matches by scanning for the pattern
  matches = @disassembler.pattern_scan(pattern)
  if @bin.kind_of?(Metasm::PE)
    @bin.sections.each do |section|
      next if section.characteristics.include? 'MEM_EXECUTE'
      # delete matches if the address is outside the virtual address space
      matches.delete_if do |ea|
        va = section.virtaddr + @bin.optheader.image_base
        ea >= va and ea < va + section.virtsize
      end
    end
  elsif @bin.kind_of?(Metasm::ELF)
    @bin.segments.each do |seg|
      next if seg.flags.include? 'X'
      matches.delete_if do |ea|
        ea >= seg.vaddr and ea < seg.vaddr + seg.memsz
      end
    end
  elsif @bin.kind_of?(Metasm::MachO)
    @bin.segments.each do |seg|
      next if seg.initprot.include? 'EXECUTE'
      matches.delete_if do |ea|
        ea >= seg.virtaddr and ea < seg.virtaddr + seg.filesize
      end
    end
  end

  gadgets = process_gadgets(matches, depth)
  gadgets.each do |gadget|
    @gadgets << gadget
  end
  gadgets
end
color_pattern(gadget, disasm, addrs, p) click to toggle source
# File lib/rex/ropbuilder/rop.rb, line 164
def color_pattern(gadget, disasm, addrs, p)
  idx = disasm.index(p)
  if idx.nil?
    print_msg(gadget[:disasm])
    return
  end

  disasm = disasm.insert(idx, "%bld%grn")

  asm = ""
  cnt = 0
  colors = false
  disasm.each_line do |line|
    # if we find this then we are in the matching area
    if line.index(/\%bld\%grn/)
      colors = true
    end
    asm << "%clr" + addrs[cnt] + "\t"

    # color the remaining parts of the gadget
    if colors and line.index("%bld%grn").nil?
      asm << "%bld%grn" + line
    else
      asm << line
    end

    cnt += 1
  end
  asm << "%clr\n"
  print_msg(asm)
end
process_gadgets(rets, num) click to toggle source
# File lib/rex/ropbuilder/rop.rb, line 196
def process_gadgets(rets, num)
  ret     = {}
  gadgets = []
  tmp     = []
  rets.each do |ea|
    insn = @disassembler.disassemble_instruction(ea)
    next if not insn

    xtra = insn.bin_length

    num.downto(0) do |x|
      addr = ea - x

      # get the disassembled instruction at this address
      di = @disassembler.disassemble_instruction(addr)

      # skip invalid instructions
      next if not di
      next if di.opcode.props[:setip]
      next if di.opcode.props[:stopexec]

      # get raw bytes
      buf = @disassembler.read_raw_data(addr, x + xtra)


      # make sure disassembling forward leads to our instruction
      next if not ends_with_addr(buf, addr, ea)

      dasm = ""
      while addr <= ea
        di = @disassembler.disassemble_instruction(addr)
        dasm << ("0x%08x:\t" % addr) + di.instruction.to_s + "\n"
        addr = addr + di.bin_length
      end

      if not tmp.include?(ea)
        tmp << ea
      else
        next
      end

      # otherwise, we create a new tailchunk and add it to the list
      ret = {:file => @file, :address => ("0x%08x" % (ea - x)), :raw => buf, :disasm => dasm}
      gadgets << ret
    end
  end
  gadgets
end

Private Instance Methods

ends_with_addr(raw, base, addr) click to toggle source
# File lib/rex/ropbuilder/rop.rb, line 246
def ends_with_addr(raw, base, addr)
  dasm2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
  offset = 0
  while ((di = dasm2.disassemble_instruction(offset)))
    return true if (base + offset) == addr
    return false if di.opcode.props[:setip]
    return false if di.opcode.props[:stopexec]
    offset = di.next_addr
  end
  false
end
raw_instructions(raw) click to toggle source
# File lib/rex/ropbuilder/rop.rb, line 258
def raw_instructions(raw)
  insns = []
  d2 = Metasm::Shellcode.decode(raw, @disassembler.cpu).disassembler
  addr = 0
  while ((di = d2.disassemble_instruction(addr)))
    insns << di.instruction
    addr = di.next_addr
  end
  insns
end