mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-10-29 18:07:27 +01:00
Land #6446, Cleanup pattern_create/pattern_offset and document options
This commit is contained in:
commit
057c25e188
@ -1,28 +1,79 @@
|
||||
#!/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.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
||||
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
||||
$LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
||||
|
||||
require 'msfenv'
|
||||
require 'msf/core'
|
||||
require 'msf/base'
|
||||
require 'rex/text'
|
||||
require 'optparse'
|
||||
|
||||
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
||||
module PatternCreate
|
||||
class OptsConsole
|
||||
def self.parse(args)
|
||||
options = {}
|
||||
parser = OptionParser.new do |opt|
|
||||
opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -l 50 -s ABC,def,123\nAd1Ad2Ad3Ae1Ae2Ae3Af1Af2Af3Bd1Bd2Bd3Be1Be2Be3Bf1Bf"
|
||||
opt.separator ''
|
||||
opt.separator 'Options:'
|
||||
opt.on('-l', '--length <length>', Integer, "The length of the pattern") do |len|
|
||||
options[:length] = len
|
||||
end
|
||||
|
||||
require 'rex'
|
||||
opt.on('-s', '--sets <ABC,def,123>', Array, "Custom Pattern Sets") do |sets|
|
||||
options[:sets] = sets
|
||||
end
|
||||
|
||||
if (!(length = ARGV.shift))
|
||||
$stderr.puts("Usage: #{File.basename($0)} length [set a] [set b] [set c]\n")
|
||||
exit
|
||||
opt.on_tail('-h', '--help', 'Show this message') do
|
||||
$stdout.puts opt
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
parser.parse!(args)
|
||||
|
||||
if options.empty?
|
||||
raise OptionParser::MissingArgument, 'No options set, try -h for usage'
|
||||
elsif options[:length].blank? && options[:sets]
|
||||
raise OptionParser::MissingArgument, '-l <length> is required'
|
||||
end
|
||||
|
||||
options[:sets] = nil unless options[:sets]
|
||||
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
class Driver
|
||||
def initialize
|
||||
begin
|
||||
@opts = OptsConsole.parse(ARGV)
|
||||
rescue OptionParser::ParseError => e
|
||||
$stderr.puts "[x] #{e.message}"
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
pattern = Rex::Text.pattern_create(@opts[:length], @opts[:sets])
|
||||
puts pattern
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# If the user supplied custom sets, use those. Otherwise, use the default
|
||||
# sets.
|
||||
sets = ARGV.length > 0 ? ARGV : Rex::Text::DefaultPatternSets
|
||||
|
||||
puts Rex::Text.pattern_create(length.to_i, sets)
|
||||
if __FILE__ == $PROGRAM_NAME
|
||||
driver = PatternCreate::Driver.new
|
||||
begin
|
||||
driver.run
|
||||
rescue ::StandardError => e
|
||||
elog("#{e.class}: #{e.message}\n#{e.backtrace * "\n"}")
|
||||
$stderr.puts "[x] #{e.class}: #{e.message}"
|
||||
$stderr.puts "[*] If necessary, please refer to framework.log for more details."
|
||||
end
|
||||
end
|
||||
|
@ -1,123 +1,147 @@
|
||||
#!/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.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
||||
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
||||
$LOAD_PATH.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
||||
|
||||
require 'msfenv'
|
||||
require 'msf/core'
|
||||
require 'msf/base'
|
||||
require 'rex/text'
|
||||
require 'optparse'
|
||||
|
||||
$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
|
||||
module PatternOffset
|
||||
class OptsConsole
|
||||
def self.parse(args)
|
||||
options = {}
|
||||
parser = OptionParser.new do |opt|
|
||||
opt.banner = "Usage: #{__FILE__} [options]\nExample: #{__FILE__} -q Aa3A|0x39634138|0xFFFF4138\n[*] Exact match at offset 9"
|
||||
opt.separator ''
|
||||
opt.separator 'Options:'
|
||||
|
||||
require 'rex'
|
||||
opt.on('-q', '--query Aa0A', String, "Query to Locate") do |query|
|
||||
options[:query] = query
|
||||
end
|
||||
|
||||
if ARGV.length < 1
|
||||
$stderr.puts("Usage: #{File.basename($0)} <search item> <length of buffer>")
|
||||
$stderr.puts("Default length of buffer if none is inserted: 8192")
|
||||
$stderr.puts("This buffer is generated by pattern_create() in the Rex library automatically")
|
||||
exit
|
||||
end
|
||||
opt.on('-l', '--length <length>', Integer, "The length of the pattern") do |len|
|
||||
options[:length] = len
|
||||
end
|
||||
|
||||
value = ARGV.shift
|
||||
len = ARGV.shift || 8192
|
||||
opt.on('-s', '--sets <ABC,def,123>', Array, "Custom Pattern Sets") do |sets|
|
||||
options[:sets] = sets
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Examples:
|
||||
|
||||
$ ./tools/pattern_create.rb 128
|
||||
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae
|
||||
|
||||
$ ./tools/pattern_offset.rb 8Ac9
|
||||
[*] Exact match at offset 86
|
||||
|
||||
$ ./tools/pattern_offset.rb 39634138
|
||||
[*] Exact match at offset 86
|
||||
|
||||
$ ./tools/pattern_offset.rb 0x39634138
|
||||
[*] Exact match at offset 86
|
||||
|
||||
$ ./tools/pattern_offset.rb 0x396341FF
|
||||
[*] No exact matches, looking for likely candidates...
|
||||
[+] Possible match at offset 86 (adjusted [ little-endian: 199 | big-endian: 18996934 ] ) byte offset 0
|
||||
|
||||
$ ./tools/pattern_offset.rb 0x3963FFFF
|
||||
[*] No exact matches, looking for likely candidates...
|
||||
[+] Possible match at offset 86 (adjusted [ little-endian: 48839 | big-endian: 19045574 ] )
|
||||
[ snip ]
|
||||
|
||||
$ ./tools/pattern_offset.rb 0xFFFF4138
|
||||
[*] No exact matches, looking for likely candidates...
|
||||
[+] Possible match at offset 26 (adjusted [ little-endian: 3332243456 | big-endian: 3351109631 ] )
|
||||
[+] Possible match at offset 56 (adjusted [ little-endian: 3332177920 | big-endian: 3351109375 ] )
|
||||
[+] Possible match at offset 86 (adjusted [ little-endian: 3332112384 | big-endian: 3351109119 ] )
|
||||
[ snip ]
|
||||
|
||||
=end
|
||||
|
||||
|
||||
|
||||
# The normal format is a full hexadecimal value: 0x41424344
|
||||
if (value.length >= 8 and value.hex > 0)
|
||||
value = value.hex
|
||||
# However, you can also specify a four-byte string
|
||||
elsif (value.length == 4)
|
||||
value = value.unpack("V").first
|
||||
else
|
||||
# Or even a hex value that isn't 8 bytes long
|
||||
value = value.to_i(16)
|
||||
end
|
||||
|
||||
buffer = Rex::Text.pattern_create(len.to_i)
|
||||
offset = Rex::Text.pattern_offset(buffer, value)
|
||||
|
||||
# Handle cases where there is no match by looking for "close" matches
|
||||
unless offset
|
||||
found = false
|
||||
$stderr.puts "[*] No exact matches, looking for likely candidates..."
|
||||
|
||||
# Look for shifts by a single byte
|
||||
0.upto(3) do |idx|
|
||||
0.upto(255) do |c|
|
||||
nvb = [value].pack("V")
|
||||
nvb[idx, 1] = [c].pack("C")
|
||||
nvi = nvb.unpack("V").first
|
||||
|
||||
off = Rex::Text.pattern_offset(buffer, nvi)
|
||||
if off
|
||||
mle = value - buffer[off,4].unpack("V").first
|
||||
mbe = value - buffer[off,4].unpack("N").first
|
||||
puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] ) byte offset #{idx}"
|
||||
found = true
|
||||
opt.on_tail('-h', '--help', 'Show this message') do
|
||||
$stdout.puts opt
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
parser.parse!(args)
|
||||
|
||||
if options.empty?
|
||||
raise OptionParser::MissingArgument, 'No options set, try -h for usage'
|
||||
elsif options[:query].blank?
|
||||
raise OptionParser::MissingArgument, '-q <query> is required'
|
||||
elsif options[:length].blank? && options[:sets]
|
||||
raise OptionParser::MissingArgument, '-l <length> is required'
|
||||
end
|
||||
|
||||
options[:sets] = nil unless options[:sets]
|
||||
options[:length] = 1024 unless options[:length]
|
||||
|
||||
options
|
||||
end
|
||||
end
|
||||
|
||||
exit if found
|
||||
class Driver
|
||||
def initialize
|
||||
begin
|
||||
@opts = OptsConsole.parse(ARGV)
|
||||
rescue OptionParser::ParseError => e
|
||||
$stderr.puts "[x] #{e.message}"
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
# Look for 16-bit offsets
|
||||
[0, 2].each do |idx|
|
||||
0.upto(65535) do |c|
|
||||
nvb = [value].pack("V")
|
||||
nvb[idx, 2] = [c].pack("v")
|
||||
nvi = nvb.unpack("V").first
|
||||
def run
|
||||
query = (@opts[:query])
|
||||
|
||||
off = Rex::Text.pattern_offset(buffer, nvi)
|
||||
if off
|
||||
mle = value - buffer[off,4].unpack("V").first
|
||||
mbe = value - buffer[off,4].unpack("N").first
|
||||
puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] )"
|
||||
found = true
|
||||
if query.length >= 8 && query.hex > 0
|
||||
query = query.hex
|
||||
# However, you can also specify a four-byte string
|
||||
elsif query.length == 4
|
||||
query = query.unpack("V").first
|
||||
else
|
||||
# Or even a hex query that isn't 8 bytes long
|
||||
query = query.to_i(16)
|
||||
end
|
||||
|
||||
buffer = Rex::Text.pattern_create(@opts[:length], @opts[:sets])
|
||||
offset = Rex::Text.pattern_offset(buffer, query)
|
||||
|
||||
# Handle cases where there is no match by looking for "close" matches
|
||||
unless offset
|
||||
found = false
|
||||
$stderr.puts "[*] No exact matches, looking for likely candidates..."
|
||||
|
||||
# Look for shifts by a single byte
|
||||
0.upto(3) do |idx|
|
||||
0.upto(255) do |c|
|
||||
nvb = [query].pack("V")
|
||||
nvb[idx, 1] = [c].pack("C")
|
||||
nvi = nvb.unpack("V").first
|
||||
|
||||
off = Rex::Text.pattern_offset(buffer, nvi)
|
||||
if off
|
||||
mle = query - buffer[off, 4].unpack("V").first
|
||||
mbe = query - buffer[off, 4].unpack("N").first
|
||||
puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] ) byte offset #{idx}"
|
||||
found = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
exit! if found
|
||||
|
||||
# Look for 16-bit offsets
|
||||
[0, 2].each do |idx|
|
||||
0.upto(65535) do |c|
|
||||
nvb = [query].pack("V")
|
||||
nvb[idx, 2] = [c].pack("v")
|
||||
nvi = nvb.unpack("V").first
|
||||
|
||||
off = Rex::Text.pattern_offset(buffer, nvi)
|
||||
if off
|
||||
mle = query - buffer[off, 4].unpack("V").first
|
||||
mbe = query - buffer[off, 4].unpack("N").first
|
||||
puts "[+] Possible match at offset #{off} (adjusted [ little-endian: #{mle} | big-endian: #{mbe} ] )"
|
||||
found = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while offset
|
||||
puts "[*] Exact match at offset #{offset}"
|
||||
offset = Rex::Text.pattern_offset(buffer, query, offset + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
while offset
|
||||
puts "[*] Exact match at offset #{offset}"
|
||||
offset = Rex::Text.pattern_offset(buffer, value, offset + 1)
|
||||
if __FILE__ == $PROGRAM_NAME
|
||||
driver = PatternOffset::Driver.new
|
||||
begin
|
||||
driver.run
|
||||
rescue ::StandardError => e
|
||||
elog("#{e.class}: #{e.message}\n#{e.backtrace * "\n"}")
|
||||
$stderr.puts "[x] #{e.class}: #{e.message}"
|
||||
$stderr.puts "[*] If necessary, please refer to framework.log for more details."
|
||||
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user