#!/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'))) require 'msfenv' $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] require 'rex' if ARGV.length < 1 $stderr.puts("Usage: #{File.basename($0)} ") $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 value = ARGV.shift len = ARGV.shift || 8192 =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 end end end exit if found # 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 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 end end end end while offset puts "[*] Exact match at offset #{offset}" offset = Rex::Text.pattern_offset(buffer, value, offset + 1) end