#!/usr/bin/perl # # Copyright (c) 2003 nologin. All rights reserved. # # For more information, please visit http://www.nologin.org # # -- # # Usage: ./stackpush.pl [string] [clobber register (default=eax)] [intel/att] # # Example: # # # ./stackpush.pl kernel32.dll # xor eax, eax # push eax # push 0x6c6c642e # push 0x32336c65 # push 0x6e72656b # # ./stackpush.pl jumpz edx att # xor %edx, %edx # mov $0x7a, %dl # push %edx # push $0x706d756a # # This is particularly useful for using static strings in shellcode where they # can not be referenced directly all of the time. # # -- # # skape # mmiller@hick.org # if (not defined($ARGV[0])) { print "Usage: ./stackpush.pl [string] [clobber register (default=eax)] [intel/att]\n"; exit; } my $nullTerminate = 1; my $clobber = lc((defined($ARGV[1]) ? $ARGV[1] : 'eax')); my $style = lc((defined($ARGV[2]) ? $ARGV[2] : 'intel')); my $current = $ARGV[0]; my $buf = ""; my $static = ""; my %registerHash; $registerHash{'eax'} = { name => 'eax', masq => { b32 => 'eax', b16 => 'ax', b8 => 'al' } }; $registerHash{'ebx'} = { name => 'ebx', masq => { b32 => 'ebx', b16 => 'bx', b8 => 'bl' } }; $registerHash{'ecx'} = { name => 'ecx', masq => { b32 => 'ecx', b16 => 'cx', b8 => 'cl' } }; $registerHash{'edx'} = { name => 'edx', masq => { b32 => 'edx', b16 => 'dx', b8 => 'dl' } }; $registerHash{'edi'} = { name => 'edi', masq => { b32 => 'edi', b16 => 'di', b8 => undef } }; $registerHash{'esi'} = { name => 'esi', masq => { b32 => 'esi', b16 => 'si', b8 => undef } }; $registerHash{'esp'} = { name => 'esp', masq => { b32 => 'esp', b16 => 'sp', b8 => undef } }; $registerHash{'ebp'} = { name => 'ebp', masq => { b32 => 'ebp', b16 => 'bp', b8 => undef } }; if (not defined($registerHash{$clobber})) { print "Register $clobber is not a valid clobber register.\n"; exit; } if ($style eq 'att') { $registerHash{$clobber}->{'masq'}->{'b32'} = "\%" . $registerHash{$clobber}->{'masq'}->{'b32'}; $registerHash{$clobber}->{'masq'}->{'b16'} = "\%" . $registerHash{$clobber}->{'masq'}->{'b16'}; if (defined($registerHash{$clobber}->{'masq'}->{'b8'})) { $registerHash{$clobber}->{'masq'}->{'b8'} = "\%" . $registerHash{$clobber}->{'masq'}->{'b8'}; } $static = "\$"; } if ($nullTerminate) { my $nullpad = length($current) % 4; if ($nullpad == 0) { $buf .= getInstruction(op => 'xor', src => $registerHash{$clobber}->{'masq'}->{'b32'}, dst => $registerHash{$clobber}->{'masq'}->{'b32'}) . "\n"; $buf .= getInstruction(op => 'push', src => $registerHash{$clobber}->{'masq'}->{'b32'}) . "\n"; } else { my $sub = getBytes(string => $current, max => $nullpad, asHex => 1); my $bitsub; my $match; my $reg = undef; my $reg32 = $registerHash{$clobber}->{'masq'}->{'b32'}; if (length($sub) == 2) { $reg = $registerHash{$clobber}->{'masq'}->{'b8'}; $bitsub = "414141$sub"; $match = "929292ff"; } elsif (length($sub) == 4) { $reg = $registerHash{$clobber}->{'masq'}->{'b16'}; $bitsub = "4141$sub"; $match = "9292ffff"; } elsif (length($sub) == 6) { $reg = $registerHash{$clobber}->{'masq'}->{'b32'}; $bitsub = "41$sub"; $match = "92ffffff"; } if (not defined($reg) or length($sub) >= 6) { $buf .= getInstruction(op => 'mov', src => $static . "0x" . $bitsub, dst => $reg32) . "\n"; $buf .= getInstruction(op => 'and', src => $static . "0x" . $match, dst => $reg32) . "\n"; } else { $buf .= getInstruction(op => 'xor', src => $reg32, dst => $reg32) . "\n"; $buf .= getInstruction(op => 'mov', src => $static . "0x" . $sub, dst => $reg) . "\n"; } $buf .= getInstruction(op => 'push', src => $reg32) . "\n"; } $current = karate(string => $current, bytes => $nullpad); } while (defined($current)) { my $sub = getBytes(string => $current, max => 4, asHex => 1); if (length($sub) == 0) { last; } $buf .= "push $static" . "0x" . $sub . "\n"; $current = karate(string => $current, bytes => 4); } print $buf; sub getBytes { my ($string, $max, $asHex) = @{{@_}}{qw/string max asHex/}; my $ret = ""; if (not defined($max)) { $max = 4; } if (length($string) < $max) { $ret = $string; } else { $ret = substr($string, length($string) - $max, $max); } if ($asHex) { my $c = ""; my $index = $max - 1; my $x; while ($index >= 0 and $x = substr($ret, $index--, 1)) { $c .= sprintf("%.2x", ord($x) & 0xff); } $ret = $c; } return $ret; } sub getInstruction { my ($op, $src, $dst) = @{{@_}}{qw/op src dst/}; if ($style eq 'att') { return "$op $src" . ((defined($dst))?", $dst" : ""); } else { if (not defined($dst)) { return "$op $src"; } else { return "$op $dst, $src"; } } } sub karate { my ($string, $bytes) = @{{@_}}{qw/string bytes/}; if (length($string) <= $bytes) { return undef; } return substr($string, 0, length($string) - $bytes); }