msfbinscan - a tool which merges all the functionality of msf*scan into a single tool
git-svn-id: file:///home/svn/framework3/trunk@12855 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
65cdcd67cc
commit
c97476eb54
|
@ -0,0 +1,278 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# $Id$
|
||||
# $Revision$
|
||||
#
|
||||
|
||||
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 'metasm'
|
||||
require 'rex/elfparsey'
|
||||
require 'rex/elfscan'
|
||||
require 'rex/machparsey'
|
||||
require 'rex/machscan'
|
||||
require 'rex/peparsey'
|
||||
require 'rex/pescan'
|
||||
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] <options> [targets]"
|
||||
opt.separator('')
|
||||
opt.separator('Modes:')
|
||||
|
||||
worker = nil
|
||||
param = {}
|
||||
files = []
|
||||
mode = ""
|
||||
|
||||
opt.on('-j', '--jump [regA,regB,regC]', 'Search for jump equivalent instructions [PE|ELF|MACHO]') do |t|
|
||||
# take csv of register names (like eax,ebx) and convert
|
||||
# them to an array of register numbers
|
||||
mode = "jump"
|
||||
regnums = t.split(',').collect { |o|
|
||||
begin
|
||||
Rex::Arch::X86.reg_number(o)
|
||||
rescue
|
||||
puts "Invalid register \"#{o}\""
|
||||
exit(1)
|
||||
end
|
||||
}
|
||||
param['args'] = regnums
|
||||
end
|
||||
|
||||
opt.on('-p', '--poppopret', 'Search for pop+pop+ret combinations [PE|ELF|MACHO]') do |t|
|
||||
mode = "pop"
|
||||
param['args'] = t
|
||||
end
|
||||
|
||||
opt.on('-r', '--regex [regex]', 'Search for regex match [PE|ELF|MACHO]') do |t|
|
||||
mode = "regex"
|
||||
param['args'] = t
|
||||
end
|
||||
|
||||
opt.on('-a', '--analyze-address [address]', 'Display the code at the specified address [PE|ELF]') do |t|
|
||||
mode = "analyze-address"
|
||||
param['args'] = opt2i(t)
|
||||
end
|
||||
|
||||
opt.on('-b', '--analyze-offset [offset]', 'Display the code at the specified offset [PE|ELF]') do |t|
|
||||
mode = "analyze-offset"
|
||||
param['args'] = opt2i(t)
|
||||
end
|
||||
|
||||
opt.on('-f', '--fingerprint', 'Attempt to identify the packer/compiler [PE]') do |t|
|
||||
mode = "fingerprint"
|
||||
param['database'] = File.join(File.dirname(msfbase), 'data', 'msfpescan', 'identify.txt')
|
||||
end
|
||||
|
||||
opt.on('-i', '--info', 'Display detailed information about the image [PE]') do |t|
|
||||
mode = "info"
|
||||
end
|
||||
|
||||
opt.on('-R', '--ripper [directory]', 'Rip all module resources to disk [PE]') do |t|
|
||||
mode = "ripper"
|
||||
param['dir'] = t
|
||||
end
|
||||
|
||||
opt.on('--context-map [directory]', 'Generate context-map files [PE]') do |t|
|
||||
mode = "context"
|
||||
param['dir'] = t
|
||||
end
|
||||
|
||||
opt.separator('')
|
||||
opt.separator('Options:')
|
||||
|
||||
opt.on('-A', '--after [bytes]', 'Number of bytes to show after match (-a/-b) [PE|ELF|MACHO]') do |t|
|
||||
param['after'] = opt2i(t)
|
||||
end
|
||||
|
||||
opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b) [PE|ELF|MACHO]') do |t|
|
||||
param['before'] = opt2i(t)
|
||||
end
|
||||
|
||||
opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase [PE|ELF|MACHO]') do |t|
|
||||
param['imagebase'] = opt2i(t)
|
||||
end
|
||||
|
||||
opt.on('-D', '--disasm', 'Disassemble the bytes at this address [PE]') do |t|
|
||||
param['disasm'] = true
|
||||
end
|
||||
|
||||
opt.on('-F', '--filter-addresses [regex]', 'Filter addresses based on a regular expression [PE]') do |t|
|
||||
param['filteraddr'] = 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
|
||||
|
||||
# check if the file is a directory if it is collect all the entries
|
||||
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
|
||||
|
||||
# we need to do some work to figure out the file format
|
||||
files.each do |file|
|
||||
param['file'] = file
|
||||
|
||||
bin = Metasm::AutoExe.decode_file(file) if not file.empty?
|
||||
|
||||
if bin.kind_of?(Metasm::PE)
|
||||
case mode
|
||||
when "jump"
|
||||
worker = Rex::PeScan::Scanner::JmpRegScanner
|
||||
when "pop"
|
||||
worker = Rex::PeScan::Scanner::PopPopRetScanner
|
||||
when "regex"
|
||||
worker = Rex::PeScan::Scanner::RegexScanner
|
||||
when "analyze-address"
|
||||
worker = Rex::PeScan::Search::DumpRVA
|
||||
when "analyze-offset"
|
||||
worker = Rex::PeScan::Search::DumpOffset
|
||||
when "fingerprint"
|
||||
worker = Rex::PeScan::Analyze::Fingerprint
|
||||
when "info"
|
||||
worker = Rex::PeScan::Analyze::Information
|
||||
when "ripper"
|
||||
worker = Rex::PeScan::Analyze::Ripper
|
||||
when "context"
|
||||
worker = Rex::PeScan::Analyze::ContextMapDumper
|
||||
else
|
||||
$stderr.puts("Mode unsupported by file format")
|
||||
end
|
||||
|
||||
pe_klass = Rex::PeParsey::Pe
|
||||
begin
|
||||
pe = pe_klass.new_from_file(file, true)
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue Rex::PeParsey::FileHeaderError
|
||||
next if $!.message == "Couldn't find the PE magic!"
|
||||
raise $!
|
||||
rescue Errno::ENOENT
|
||||
$stdout.puts("File does not exist: #{file}")
|
||||
next
|
||||
rescue ::Rex::PeParsey::SkipError
|
||||
next
|
||||
rescue ::Exception => e
|
||||
$stdout.puts "[#{file}] #{e.class}: #{e}"
|
||||
next
|
||||
end
|
||||
|
||||
if (param['imagebase'])
|
||||
pe.image_base = param['imagebase'];
|
||||
end
|
||||
|
||||
o = worker.new(pe)
|
||||
o.scan(param)
|
||||
|
||||
pe.close
|
||||
|
||||
elsif bin.kind_of?(Metasm::ELF)
|
||||
case mode
|
||||
when "jump"
|
||||
worker = Rex::ElfScan::Scanner::JmpRegScanner
|
||||
when "pop"
|
||||
worker = Rex::Elfscan::Scanner::PopPopRetScanner
|
||||
when "regex"
|
||||
worker = Rex::ElfScan::Scanner::RegexScanner
|
||||
when "analyze-address"
|
||||
worker = Rex::ElfScan::Search::DumpRVA
|
||||
when "analyze-offset"
|
||||
worker = Rex::ElfScan::Search::DumpOffset
|
||||
else
|
||||
$stderr.puts("Mode unsupported by file format")
|
||||
end
|
||||
|
||||
begin
|
||||
elf = Rex::ElfParsey::Elf.new_from_file(file, true)
|
||||
rescue Rex::ElfParsey::ElfHeaderError
|
||||
if $!.message == 'Invalid magic number'
|
||||
$stderr.puts("Skipping #{file}: #{$!}")
|
||||
next
|
||||
end
|
||||
raise $!
|
||||
rescue Errno::ENOENT
|
||||
$stderr.puts("File does not exist: #{file}")
|
||||
next
|
||||
end
|
||||
|
||||
if (param['imagebase'])
|
||||
elf.base_addr = param['imagebase'];
|
||||
end
|
||||
|
||||
o = worker.new(elf)
|
||||
o.scan(param)
|
||||
|
||||
elf.close
|
||||
|
||||
elsif bin.kind_of?(Metasm::MachO)
|
||||
case mode
|
||||
when "jump"
|
||||
worker = Rex::MachScan::Scanner::JmpRegScanner
|
||||
when "pop"
|
||||
worker = Rex::MachScan::Scanner::PopPopRetScanner
|
||||
when "regex"
|
||||
worker = Rex::MachScan::Scanner::RegexScanner
|
||||
else
|
||||
$stderr.puts("Mode unsupported by file format")
|
||||
end
|
||||
|
||||
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")
|
||||
begin
|
||||
fat = Rex::MachParsey::Fat.new_from_file(file, true)
|
||||
o = worker.new(fat)
|
||||
o.scan(param)
|
||||
fat.close
|
||||
rescue
|
||||
$stderr.puts("Error: " + $!.to_s)
|
||||
$stderr.puts("Skipping #{file}")
|
||||
end
|
||||
rescue Errno::ENOENT
|
||||
$stderr.puts("File does not exist: #{file}")
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
if not worker
|
||||
$stderr.puts("Unsupported file format")
|
||||
$stderr.puts("Skipping #{file}")
|
||||
next
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue