Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/tools/exploit/metasm_shell.rb
Views: 11766
#!/usr/bin/env ruby12##3# This module requires Metasploit: https://metasploit.com/download4# Current source: https://github.com/rapid7/metasploit-framework5##67#8# This tool provides an easy way to see what opcodes are associated with9# certain x86 instructions by making use of Metasm! Also allows to get10# friendly output from a GAS assembler source code file.11#1213#14# This file is part of Metasm, the Ruby assembly manipulation suite15# Copyright (C) 2007 Yoann GUILLOT16#17# Licence is LGPL, see LICENCE in the top-level directory18#19begin20msfbase = __FILE__21while File.symlink?(msfbase)22msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))23end2425gem 'rex-text'2627$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))28require 'msfenv'2930$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']3132require 'rex'33require 'readline'34require 'metasm'3536#PowerPC, seems broken for now in metasm37#@Arch = ['Ia32','MIPS','PowerPC','ARM','X86_64']38@Arch = ['Ia32','MIPS','ARM','X86_64']39@Endian = ['little','big']40@architecture = ""41@endianness = ""4243def usage44$stderr.puts("\nUsage: #{$0} <options>\n" + $args.usage)45exit46end4748$args = Rex::Parser::Arguments.new(49"-a" => [ true, "The architecture to encode as (#{@Arch.sort.collect{|a| a + ', ' }.join.gsub(/\, $/,'')})"],50"-e" => [ true, "The endianness to encode as (#{@Endian.sort.collect{|a| a + ', ' }.join.gsub(/\, $/,'')})" ],51"-h" => [ false, "Display this help information" ])5253$args.parse(ARGV) { |opt, idx, val|54case opt55when "-a"56found = nil57@Arch.each { |a|58if val.downcase == a.downcase59@architecture = a60found = true61end62}63usage if not found64when "-e"65found = nil66@Endian.each { |e|67if val.downcase == e.downcase68@endianness = e69found = true70end71}72usage if not found73when "-h"74usage75else76usage77end78}7980unless @architecture.empty?81if @endianness.empty?82String.class_eval("@@cpu = Metasm::#{@architecture}.new")83else84String.class_eval("@@cpu = Metasm::#{@architecture}.new(:#{@endianness})")85end86end8788class String89@@cpu ||= Metasm::Ia32.new90class << self91def cpu() @@cpu end92def cpu=(c) @@cpu=c end93end9495# encodes the current string as a Shellcode, returns the resulting EncodedData96def metasm_encode_edata97s = Metasm::Shellcode.assemble @@cpu, self98s.encoded99end100101# encodes the current string as a Shellcode, returns the resulting binary String102# outputs warnings on unresolved relocations103def metasm_encode104ed = metasm_encode_edata105if not ed.reloc.empty?106puts 'W: encoded string has unresolved relocations: ' + ed.reloc.map { |o, r| r.target.inspect }.join(', ')107end108ed.fill109ed.data110end111112# decodes the current string as a Shellcode, with specified base address113# returns the resulting Disassembler114def metasm_decode_blocks(base_addr=0, eip=base_addr)115sc = Metasm::Shellcode.metasm_decode(self, @@cpu)116sc.base_addr = base_addr117sc.metasm_disassemble(eip)118end119120# decodes the current string as a Shellcode, with specified base address121# returns the asm source equivallent122def metasm_decode(base_addr=0, eip=base_addr)123metasm_decode_blocks(base_addr, eip).to_s124end125126def metasm_disassemble(str, eip=0)127Metasm::Shellcode.metasm_disassemble(@@cpu, str, eip)128end129130end131132def parse_gas_file(filename)133filename = File.expand_path(filename)134unless ::File.exist?(filename)135puts "File #{filename} not found"136return137end138shellcode = ""139puts "Reading file #{filename}"140::File.open(filename, "rb") do |f|141f.each_line do |l|142l.gsub!(/#.*$/, "") # Delete comments143l.gsub!(/@.*$/, "") # Delete comments144l.gsub!(/\..*$/, "") # Delete directives145l.gsub!(/(\r|\n)/, '') # Delete newlines... just in case...146next if l.strip.empty?147shellcode << "#{l}\n"148end149end150151begin152encoded = shellcode.metasm_encode153puts Rex::Text.to_ruby(encoded)154puts encoded.metasm_disassemble(shellcode.metasm_encode)155rescue Metasm::Exception => e156puts "Error: #{e.class} #{e.message}"157end158end159160# Start a pseudo shell and dispatch lines to be assembled and then161# disassembled.162history_file = File.join(Msf::Config.config_directory, 'metasm_history')163shell = Rex::Ui::Text::PseudoShell.new("%bldmetasm%clr", '>', history_file)164shell.init_ui(Rex::Ui::Text::Input::Stdio.new, Rex::Ui::Text::Output::Stdio.new)165shell.history_manager = Rex::Ui::Text::Shell::HistoryManager.new166167puts [168'type "exit" or "quit" to quit',169'use ";" or "\\n" for newline',170'type "file <file>" to parse a GAS assembler source file',171'']172173shell.run { |l|174l.gsub!(/(\r|\n)/, '')175l.gsub!(/\\n/, "\n")176l.gsub!(';', "\n")177178break if %w[quit exit].include? l.chomp179if l.chomp.index(/^file (.*)/)180parse_gas_file($1)181next182end183next if l.strip.empty?184185begin186l = l.metasm_encode187puts '"' + l.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'188rescue Metasm::Exception => e189puts "Error: #{e.class} #{e.message}"190end191}192rescue SignalException => e193puts("Aborted! #{e}")194end195196197