Skip to content
This repository
branch: unstable
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 175 lines (139 sloc) 4.322 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
#!/usr/bin/env ruby
# -*- coding: binary -*-
#
# $Id$
#
# This tool will collect, export, and import ROP gadgets
# from various file formats (PE, ELF, Macho)
# $Revision$
#

msfbase = __FILE__
while File.symlink?(msfbase)
  msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
end

$:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
require 'fastlib'
require 'msfenv'



$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']

require 'rex'
require 'rex/ropbuilder'
require 'rex/ui/text/output/stdio'
require 'rex/ui/text/color'
require 'optparse'

def opt2i(o)
  o.index("0x")==0 ? o.hex : o.to_i
end

opts = {}
color = true

opt = OptionParser.new
opt.banner = "Usage #{$PROGRAM_NAME} <option> [targets]"
opt.separator('')
opt.separator('Options:')

opt.on('-d', '--depth [size]', 'Number of maximum bytes to backwards disassemble from return instructions') do |d|
  opts[:depth] = opt2i(d)
end

opt.on('-s', '--search [regex]', 'Search for gadgets matching a regex, match intel syntax or raw bytes') do |regex|
  opts[:pattern] = regex
end

opt.on('-n', '--nocolor', 'Disable color. Useful for piping to other tools like the less and more commands') do
  color = false
end

opt.on('-x', '--export [filename]', 'Export gadgets to CSV format') do |csv|
  opts[:export] = csv
end

opt.on('-i', '--import [filename]', 'Import gadgets from previous collections') do |csv|
  opts[:import] = csv
end

opt.on('-v', '--verbose', 'Output very verbosely') do
  opts[:verbose] = true
end

opt.on_tail('-h', '--help', 'Show this message') do
  puts opt
  exit(1)
end

begin
  opt.parse!
rescue OptionParser::InvalidOption
  puts "Invalid option, try -h for usage"
  exit(1)
end

if opts.empty? and (ARGV.empty? or ARGV.nil?)
  puts "no options"
  puts opt
  exit(1)
end

# set defaults
opts[:depth] ||= 5

gadgets = []

if opts[:import].nil?
  files = []
  ARGV.each do |file|
    if(File.directory?(file))
      dir = Dir.open(file)
      dir.entries.each do |ent|
        path = File.join(file, ent)
        next if not File.file?(path)
        files << File.join(path)
      end
    else
      files << file
    end
  end
  
  ropbuilder = Rex::RopBuilder::RopCollect.new

  files.each do |file|
    ret, retn = []
    ropbuilder = Rex::RopBuilder::RopCollect.new(file)
    ropbuilder.print_msg("Collecting gadgets from %bld%cya#{file}%clr\n", color)
    retn = ropbuilder.collect(opts[:depth], "\xc2") # retn
    ret = ropbuilder.collect(opts[:depth], "\xc3") # ret
    ropbuilder.print_msg("Found %grn#{ret.count + retn.count}%clr gadgets\n\n", color)

    # compile a list of all gadgets from all files
    ret.each do |gadget|
      gadgets << gadget
      if opts[:verbose]
        ropbuilder.print_msg("#{gadget[:file]} gadget: %bld%grn#{gadget[:address]}%clr\n", color)
        ropbuilder.print_msg("#{gadget[:disasm]}\n", color)
      end
    end

    retn.each do |gadget|
      gadgets << gadget
      if opts[:verbose]
        ropbuilder.print_msg("#{gadget[:file]} gadget: %bld%grn#{gadget[:address]}%clr\n", color)
        ropbuilder.print_msg("#{gadget[:disasm]}\n", color)
      end
    end
    
  end

  ropbuilder.print_msg("Found %bld%grn#{gadgets.count}%clr gadgets total\n\n", color)
end

if opts[:import]

  ropbuilder = Rex::RopBuilder::RopCollect.new()
  ropbuilder.print_msg("Importing gadgets from %bld%cya#{opts[:import]}\n", color)
  gadgets = ropbuilder.import(opts[:import])

  gadgets.each do |gadget|
    ropbuilder.print_msg("gadget: %bld%cya#{gadget[:address]}%clr\n", color)
    ropbuilder.print_msg(gadget[:disasm] + "\n", color)
  end

  ropbuilder.print_msg("Imported %grn#{gadgets.count}%clr gadgets\n", color)
end

if opts[:pattern]
  matches = ropbuilder.pattern_search(opts[:pattern])
  if opts[:verbose]
    ropbuilder.print_msg("Found %grn#{matches.count}%clr matches\n", color)
  end
end

if opts[:export]
  ropbuilder.print_msg("Exporting %grn#{gadgets.count}%clr gadgets to %bld%cya#{opts[:export]}%clr\n", color)
  csv = ropbuilder.to_csv(gadgets)

  if csv.nil?
    exit(1)
  end

  begin
    fd = File.new(opts[:export], 'w')
    fd.puts csv
    fd.close
  rescue
    puts "Error writing #{opts[:export]} file"
    exit(1)
  end
  ropbuilder.print_msg("%bld%redSuccess!%clr gadgets exported to %bld%cya#{opts[:export]}%clr\n", color)
end
Something went wrong with that request. Please try again.