msfmachscan 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/env ruby
  2. # -*- coding: binary -*-
  3. #
  4. # $Id$
  5. # $Revision$
  6. #
  7. msfbase = __FILE__
  8. while File.symlink?(msfbase)
  9. msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
  10. end
  11. $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
  12. require 'msfenv'
  13. $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
  14. require 'rex/machparsey'
  15. require 'rex/machscan'
  16. require 'rex/arch/x86'
  17. require 'optparse'
  18. def opt2i(o)
  19. o.index("0x")==0 ? o.hex : o.to_i
  20. end
  21. opt = OptionParser.new
  22. opt.banner = "Usage: #{$PROGRAM_NAME} [mode] <options> [targets]"
  23. opt.separator('')
  24. opt.separator('Modes:')
  25. worker = nil
  26. param = {}
  27. opt.on('-j', '--jump [regA,regB,regC]', 'Search for jump equivalent instructions') do |t|
  28. # take csv of register names (like eax,ebx) and convert
  29. # them to an array of register numbers
  30. regnums = t.split(',').collect { |o|
  31. begin
  32. Rex::Arch::X86.reg_number(o)
  33. rescue
  34. puts "Invalid register \"#{o}\""
  35. exit(1)
  36. end
  37. }
  38. worker = Rex::MachScan::Scanner::JmpRegScanner
  39. param['args'] = regnums
  40. end
  41. opt.on('-p', '--poppopret', 'Search for pop+pop+ret combinations') do |t|
  42. worker = Rex::MachScan::Scanner::PopPopRetScanner
  43. param['args'] = t
  44. end
  45. opt.on('-r', '--regex [regex]', 'Search for regex match') do |t|
  46. worker = Rex::MachScan::Scanner::RegexScanner
  47. param['args'] = t
  48. end
  49. opt.separator('')
  50. opt.separator('Options:')
  51. opt.on('-A', '--after [bytes]', 'Number of bytes to show after match (-a/-b)') do |t|
  52. param['after'] = opt2i(t)
  53. end
  54. opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b)') do |t|
  55. param['before'] = opt2i(t)
  56. end
  57. opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase') do |t|
  58. param['imagebase'] = opt2i(t)
  59. end
  60. opt.on_tail("-h", "--help", "Show this message") do
  61. puts opt
  62. exit(1)
  63. end
  64. begin
  65. opt.parse!
  66. rescue OptionParser::InvalidOption
  67. puts "Invalid option, try -h for usage"
  68. exit(1)
  69. end
  70. if (! worker)
  71. puts opt
  72. exit(1)
  73. end
  74. ARGV.each do |file|
  75. param['file'] = file
  76. begin
  77. mach = Rex::MachParsey::Mach.new_from_file(file, true)
  78. o = worker.new(mach)
  79. o.scan(param)
  80. mach.close
  81. rescue Rex::MachParsey::MachHeaderError
  82. $stderr.puts("File is not a Mach-O binary, trying Fat..\n")
  83. fat = Rex::MachParsey::Fat.new_from_file(file, true)
  84. o = worker.new(fat)
  85. o.scan(param)
  86. fat.close
  87. rescue Errno::ENOENT
  88. $stderr.puts("File does not exist: #{file}")
  89. next
  90. end
  91. end