2006-04-15 22:26:41 +02:00
|
|
|
#!/usr/bin/env ruby
|
|
|
|
|
2006-07-31 17:36:08 +02:00
|
|
|
msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
|
|
|
$:.unshift(File.join(File.dirname(msfbase), 'lib'))
|
2008-02-02 22:29:46 +01:00
|
|
|
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
2006-04-15 22:26:41 +02:00
|
|
|
|
|
|
|
require 'rex/peparsey'
|
2006-04-16 03:56:17 +02:00
|
|
|
require 'rex/pescan'
|
2006-04-15 22:26:41 +02:00
|
|
|
require 'rex/arch/x86'
|
|
|
|
require 'optparse'
|
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
def opt2i(o)
|
|
|
|
o.index("0x")==0 ? o.hex : o.to_i
|
|
|
|
end
|
|
|
|
|
2006-05-01 20:51:20 +02:00
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
#
|
|
|
|
# Right now this program is a bit shakey...
|
|
|
|
#
|
|
|
|
# - It tries to error on the side of caution, so it will try for a
|
|
|
|
# false negative vs a false positive.
|
|
|
|
# - It doesn't account for the entire PE image neccesairly
|
|
|
|
# - It wouldn't find hits that overlap sections
|
|
|
|
# - etc etc
|
|
|
|
#
|
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt = OptionParser.new
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt.banner = "Usage: #{$PROGRAM_NAME} [mode] <options> [targets]"
|
|
|
|
opt.separator('')
|
|
|
|
opt.separator('Modes:')
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
worker = nil
|
|
|
|
param = {}
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
pe_klass = Rex::PeParsey::Pe
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
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| Rex::Arch::X86.reg_number(o) }
|
|
|
|
worker = Rex::PeScan::Scanner::JmpRegScanner
|
|
|
|
param['args'] = regnums
|
2006-04-15 22:26:41 +02:00
|
|
|
end
|
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt.on('-p', '--poppopret', 'Search for pop+pop+ret combinations') do |t|
|
|
|
|
worker = Rex::PeScan::Scanner::PopPopRetScanner
|
|
|
|
param['args'] = t
|
|
|
|
end
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt.on('-r', '--regex [regex]', 'Search for regex match') do |t|
|
|
|
|
worker = Rex::PeScan::Scanner::RegexScanner
|
|
|
|
param['args'] = t
|
2006-04-15 22:26:41 +02:00
|
|
|
end
|
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt.on('-a', '--analyze-address [address]', 'Display the code at the specified address') do |t|
|
|
|
|
worker = Rex::PeScan::Search::DumpRVA
|
|
|
|
param['args'] = opt2i(t)
|
|
|
|
end
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
opt.on('-b', '--analyze-offset [offset]', 'Display the code at the specified offset') do |t|
|
|
|
|
worker = Rex::PeScan::Search::DumpOffset
|
|
|
|
param['args'] = opt2i(t)
|
|
|
|
end
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
opt.on('-f', '--fingerprint', 'Attempt to identify the packer/compiler') do |t|
|
|
|
|
worker = Rex::PeScan::Analyze::Fingerprint
|
2008-08-26 23:26:24 +02:00
|
|
|
param['database'] = File.join(File.dirname(msfbase), 'data', 'msfpescan', 'identify.txt')
|
2006-04-16 03:56:17 +02:00
|
|
|
end
|
2006-04-15 22:26:41 +02:00
|
|
|
|
2007-07-06 07:14:05 +02:00
|
|
|
opt.on('-i', '--info', 'Display detailed information about the image') do |t|
|
|
|
|
worker = Rex::PeScan::Analyze::Information
|
2007-07-09 20:17:04 +02:00
|
|
|
end
|
|
|
|
|
2007-07-25 18:26:52 +02:00
|
|
|
opt.on('-R', '--ripper [directory]', 'Rip all module resources to disk ') do |t|
|
2007-07-09 20:17:04 +02:00
|
|
|
worker = Rex::PeScan::Analyze::Ripper
|
|
|
|
param['dir'] = t
|
2007-07-06 07:14:05 +02:00
|
|
|
end
|
|
|
|
|
2007-10-18 18:55:23 +02:00
|
|
|
opt.on('--context-map [directory]', 'Generate context-map files') do |t|
|
|
|
|
worker = Rex::PeScan::Analyze::ContextMapDumper
|
|
|
|
param['dir'] = t
|
|
|
|
end
|
2007-07-06 07:14:05 +02:00
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
opt.separator('')
|
|
|
|
opt.separator('Options:')
|
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
opt.on('-M', '--memdump', 'The targets are memdump.exe directories') do |t|
|
|
|
|
pe_klass = Rex::PeParsey::PeMemDump
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
opt.on('-A', '--after [bytes]', 'Number of bytes to show after match (-a/-b)') do |t|
|
2006-04-16 03:56:17 +02:00
|
|
|
param['after'] = opt2i(t)
|
2006-04-15 22:26:41 +02:00
|
|
|
end
|
2006-04-16 03:56:17 +02:00
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b)') do |t|
|
2006-04-16 03:56:17 +02:00
|
|
|
param['before'] = opt2i(t)
|
2006-04-15 22:26:41 +02:00
|
|
|
end
|
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
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
|
|
|
|
end
|
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
opt.parse!
|
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
if (! worker)
|
|
|
|
puts opt
|
|
|
|
exit(0)
|
|
|
|
end
|
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
ARGV.each do |file|
|
2006-04-16 06:41:54 +02:00
|
|
|
|
|
|
|
param['file'] = file
|
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
begin
|
|
|
|
pe = pe_klass.new_from_file(file, true)
|
|
|
|
rescue Rex::PeParsey::FileHeaderError
|
|
|
|
next if $!.message == "Couldn't find the PE magic!"
|
|
|
|
raise $!
|
2007-01-16 18:09:41 +01:00
|
|
|
rescue Errno::ENOENT
|
|
|
|
$stderr.puts("File does not exist: #{file}")
|
|
|
|
next
|
2006-04-15 22:26:41 +02:00
|
|
|
end
|
2006-04-16 03:56:17 +02:00
|
|
|
|
2006-04-16 06:41:54 +02:00
|
|
|
if (param['imagebase'])
|
|
|
|
pe.image_base = param['imagebase'];
|
|
|
|
end
|
2007-10-18 18:55:23 +02:00
|
|
|
|
2006-04-16 03:56:17 +02:00
|
|
|
o = worker.new(pe)
|
|
|
|
o.scan(param)
|
|
|
|
|
2006-04-15 22:26:41 +02:00
|
|
|
pe.close
|
|
|
|
|
|
|
|
end
|