msfelfscan 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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/elfparsey'
  15. require 'rex/elfscan'
  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::ElfScan::Scanner::JmpRegScanner
  39. param['args'] = regnums
  40. end
  41. opt.on('-p', '--poppopret', 'Search for pop+pop+ret combinations') do |t|
  42. worker = Rex::ElfScan::Scanner::PopPopRetScanner
  43. param['args'] = t
  44. end
  45. opt.on('-r', '--regex [regex]', 'Search for regex match') do |t|
  46. worker = Rex::ElfScan::Scanner::RegexScanner
  47. param['args'] = t
  48. end
  49. opt.on('-a', '--analyze-address [address]', 'Display the code at the specified address') do |t|
  50. worker = Rex::ElfScan::Search::DumpRVA
  51. param['args'] = opt2i(t)
  52. end
  53. opt.on('-b', '--analyze-offset [offset]', 'Display the code at the specified offset') do |t|
  54. worker = Rex::ElfScan::Search::DumpOffset
  55. param['args'] = opt2i(t)
  56. end
  57. opt.separator('')
  58. opt.separator('Options:')
  59. opt.on('-A', '--after [bytes]', 'Number of bytes to show after match (-a/-b)') do |t|
  60. param['after'] = opt2i(t)
  61. end
  62. opt.on('-B', '--before [bytes]', 'Number of bytes to show before match (-a/-b)') do |t|
  63. param['before'] = opt2i(t)
  64. end
  65. opt.on('-D', '--disasm', 'Disassemble the bytes at this address') do |t|
  66. param['disasm'] = true
  67. end
  68. opt.on('-I', '--image-base [address]', 'Specify an alternate ImageBase') do |t|
  69. param['imagebase'] = opt2i(t)
  70. end
  71. opt.on_tail("-h", "--help", "Show this message") do
  72. puts opt
  73. exit(1)
  74. end
  75. begin
  76. opt.parse!
  77. rescue OptionParser::InvalidOption
  78. puts "Invalid option, try -h for usage"
  79. exit(1)
  80. end
  81. if (! worker)
  82. puts opt
  83. exit(1)
  84. end
  85. ARGV.each do |file|
  86. param['file'] = file
  87. begin
  88. elf = Rex::ElfParsey::Elf.new_from_file(file, true)
  89. rescue Rex::ElfParsey::ElfHeaderError
  90. if $!.message == 'Invalid magic number'
  91. $stderr.puts("Skipping #{file}: #{$!}")
  92. next
  93. end
  94. raise $!
  95. rescue Errno::ENOENT
  96. $stderr.puts("File does not exist: #{file}")
  97. next
  98. end
  99. if (param['imagebase'])
  100. elf.base_addr = param['imagebase'];
  101. end
  102. o = worker.new(elf)
  103. o.scan(param)
  104. elf.close
  105. end