#!/usr/bin/env ruby msfbase = __FILE__ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end $:.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 (c, elf, exe, java, perl, raw, ruby, vba, vbs, loop-vbs)" ], "-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" ], "-c" => [ true, "The number of times to encode the data" ], "-n" => [ false, "Dump encoder information" ], "-h" => [ false, "Help banner" ], "-x" => [ true, "Specify an alternate win32 executable template" ], "-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 # Defaults cmd = "encode" arch = nil badchars = '' space = nil encoder = nil fmt = nil input = $stdin options = '' delim = '_|_' output = nil ecount = 1 altexe = 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 "-c" ecount = val.to_i when "-b" badchars = Rex::Text.hex_to_raw(val) when "-s" space = val.to_i when "-t" if (val =~ /^(perl|ruby|rb|raw|c|js_le|js_be|java|exe|elf|vba|vbs|loop-vbs)$/) fmt = val else $stderr.puts(OutError + "Invalid format: #{val}") exit end when "-o" output = val when "-e" encoder = val when "-x" altexe = val when "-h" usage else if (val =~ /=/) options += ((options.length > 0) ? delim : "") + "#{val}" end end } if(not fmt and output) pre,ext = output.split('.') if(ext and not ext.empty?) fmt = ext end end # Initialize the simplified framework instance. $framework = Msf::Simple::Framework.create( :module_types => [ Msf::MODULE_ENCODER, Msf::MODULE_NOP ] ) # 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) skip = false eout = buf.dup raw = nil 1.upto(ecount) do |iteration| # Encode it up raw = enc.encode(eout, 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})") skip = true break end # Print it out $stderr.puts(OutStatus + "#{enc.refname} succeeded with size #{raw.length} (iteration=#{iteration})\n\n") eout = raw end next if skip case fmt when 'exe' exe = nil if(not arch or (arch.index(ARCH_X86))) exe = Msf::Util::EXE.to_win32pe($framework, raw, {:template => altexe}) end if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 ))) exe = Msf::Util::EXE.to_win64pe($framework, raw, {:template => altexe}) end if(not output) $stdout.write(exe) else File.open(output, "wb") do |fd| fd.write(exe) end end when 'elf' elf = Msf::Util::EXE.to_linux_x86_elf($framework, raw) if(not output) $stdout.write(elf) else File.open(output, "wb") do |fd| fd.write(elf) end end when 'vba' exe = Msf::Util::EXE.to_win32pe($framework, raw, {:template => altexe}) vba = Msf::Util::EXE.to_exe_vba(exe) if(not output) $stdout.write(vba) else File.open(output, "wb") do |fd| fd.write(vba) end end when 'vbs' vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:persist => false, :template => altexe}) if(not output) $stdout.write(vbs) else File.open(output, "wb") do |fd| fd.write(vbs) end end when 'loop-vbs' vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, {:persist => true, :template => altexe}) if(not output) $stdout.write(vbs) else File.open(output, "wb") do |fd| fd.write(vbs) end end else fmt ||= "ruby" 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 end exit rescue => e $stderr.puts(OutError + "#{enc.refname} failed: #{e} #{e.backtrace}") end } $stderr.puts(OutError + "No encoders succeeded.") end