#!/usr/bin/env ruby msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__ $:.unshift(File.join(File.dirname(msfbase), 'lib')) $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] require 'rex' require 'msf/ui' require 'msf/base' OutStatus = "[*] " OutError = "[-] " $args = Rex::Parser::Arguments.new( "-i" => [ true, "Encode the contents of the supplied file path" ], "-m" => [ true, "Specifies an additional module search path" ], "-a" => [ true, "The architecture to encode as" ], "-t" => [ true, "The format to display the encoded buffer with (raw, ruby, perl, c)" ], "-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ], "-s" => [ true, "The maximum size of the encoded data" ], "-e" => [ true, "The encoder to use" ], "-o" => [ true, "The output file" ], "-n" => [ false, "Dump encoder information" ], "-h" => [ false, "Help banner" ], "-l" => [ false, "List available encoders" ]) # # Dump the list of encoders # def dump_encoders(arch = nil) tbl = Rex::Ui::Text::Table.new( 'Indent' => 4, 'Header' => "Framework Encoders" + ((arch) ? " (architectures: #{arch})" : ""), 'Columns' => [ "Name", "Rank", "Description" ]) cnt = 0 $framework.encoders.each_module( 'Arch' => arch ? arch.split(',') : nil) { |name, mod| tbl << [ name, mod.rank_to_s, mod.new.name ] cnt += 1 } (cnt > 0) ? "\n" + tbl.to_s + "\n" : "\nNo compatible encoders found.\n\n" end # # Returns the list of encoders to try # def get_encoders(arch, encoder) encoders = [] if (encoder) encoders << $framework.encoders.create(encoder) else $framework.encoders.each_module_ranked( 'Arch' => arch ? arch.split(',') : nil) { |name, mod| encoders << mod.new } end encoders end # # Nuff said. # def usage $stderr.puts("\n" + " Usage: #{$0} \n" + $args.usage) exit end # Initialize the simplified framework instance. $framework = Msf::Simple::Framework.create # Defaults cmd = "encode" arch = nil badchars = '' space = nil encoder = nil fmt = "c" input = $stdin options = '' delim = '_|_' output = nil # Parse the argument and rock that shit. $args.parse(ARGV) { |opt, idx, val| case opt when "-i" begin input = File.new(val) rescue $stderr.puts(OutError + "Failed to open file #{val}: #{$!}") exit end when "-m" $framework.modules.add_module_path(val) when "-l" cmd = "list" when "-n" cmd = "dump" when "-a" arch = val when "-b" badchars = Rex::Text.hex_to_raw(val) when "-s" space = val.to_i when "-t" if (val =~ /^(perl|ruby|raw|c|exe)$/) fmt = val else $stderr.puts(OutError + "Invalid format: #{val}") exit end when "-o" output = val when "-e" encoder = val when "-h" usage else if (val =~ /=/) options += ((options.length > 0) ? delim : "") + "#{val}" end end } # Get the list of encoders to try encoders = get_encoders(arch, encoder) # Process the actual command case cmd when "list" $stderr.puts(dump_encoders(arch)) when "dump" enc = encoder ? $framework.encoders.create(encoder) : nil if (enc) $stderr.puts(Msf::Serializer::ReadableText.dump_module(enc)) else $stderr.puts(OutError + "Invalid encoder specified.") end when "encode" buf = input.read encoders.each { |enc| next if not enc begin # Imports options enc.datastore.import_options_from_s(options, delim) # Encode it up raw = enc.encode(buf, badchars) # Is it too big? if (space and space > 0 and raw.length > space) $stderr.puts(OutError + "#{enc.refname} created buffer that is too big (#{raw.length})") next end # Print it out $stderr.puts(OutStatus + "#{enc.refname} succeeded, final size #{raw.length}\n\n") if(fmt != "exe") if(not output) $stdout.print(Msf::Simple::Buffer.transform(raw, fmt)) else File.open(output, "wb") do |fd| fd.write(Msf::Simple::Buffer.transform(raw, fmt)) end end else exe = Rex::Text.to_win32pe(buf, "") if(not output) $stdout.write(exe) else File.open(output, "wb") do |fd| fd.write(exe) end end end exit rescue $stderr.puts(OutError + "#{enc.refname} failed: #{$!}") end } $stderr.puts(OutError + "No encoders succeeded.") end