#!/usr/bin/env ruby msfbase = __FILE__ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end $:.unshift(File.join(File.dirname(msfbase), 'lib')) $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] require 'rex/machparsey' require 'rex/machscan' require 'rex/arch/x86' require 'optparse' def opt2i(o) o.index("0x")==0 ? o.hex : o.to_i end opt = OptionParser.new opt.banner = "Usage: #{$PROGRAM_NAME} [mode] [targets]" opt.separator('') opt.separator('Modes:') worker = nil param = {} opt.on('-j', '--jump [regA,regB,regC]', 'Search for jump equivalent instructions') do |t| # take csv of register names (like eax,ebx) and convert # them to an array of register numbers regnums = t.split(',').collect { |o| begin Rex::Arch::X86.reg_number(o) rescue puts "Invalid register \"#{o}\"" exit(1) end } worker = Rex::MachScan::Scanner::JmpRegScanner param['args'] = regnums end opt.on('-p', '--poppopret', 'Search for pop+pop+ret combinations') do |t| worker = Rex::MachScan::Scanner::PopPopRetScanner param['args'] = t end opt.on('-r', '--regex [regex]', 'Search for regex match') do |t| worker = Rex::MachScan::Scanner::RegexScanner param['args'] = t end opt.separator('') opt.separator('Options:') opt.on('-A', '--after [bytes]', 'Number of bytes to show after match (-a/-b)') do |t| param['after'] = opt2i(t) end opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b)') do |t| param['before'] = opt2i(t) end opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase') do |t| param['imagebase'] = opt2i(t) 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 (! worker) puts opt exit(1) end ARGV.each do |file| param['file'] = file begin mach = Rex::MachParsey::Mach.new_from_file(file, true) o = worker.new(mach) o.scan(param) mach.close rescue Rex::MachParsey::MachHeaderError $stderr.puts("File is not a Mach-O binary, trying Fat..\n") fat = Rex::MachParsey::Fat.new_from_file(file, true) o = worker.new(fat) o.scan(param) fat.close rescue Errno::ENOENT $stderr.puts("File does not exist: #{file}") next end end