root/framework2/trunk/msfelfscan

Revision 2125, 6.7 kB (checked in by vlad902, 3 years ago)

Updated PE

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/perl
2 ###############
3
4 ##
5 #         Name: msfelfscan
6 #       Author: Richard Johnson <rjohnson [at] uninformed.org>
7 #      Version: $Revision$
8 #  Description: Search ELF files for given opcodes
9 #      License:
10 #
11 #      This file is part of the Metasploit Exploit Framework
12 #      and is subject to the same licenses and copyrights as
13 #      the rest of this package.
14 #
15 ##
16
17 require 5.6.0;
18
19 use FindBin qw{$RealBin};
20 use lib "$RealBin/lib";
21 use Getopt::Std;
22 use strict;
23
24 use Pex::ELFInfo;
25 use Pex::Nasm::Ndisasm;
26 use Pex;
27
28 use Msf::ColPrint;
29 use Msf::TextUI;
30
31 no utf8;
32 no locale;
33
34 Msf::UI::ActiveStateSucks();
35 Msf::UI::BrokenUTF8();
36
37 my $VERSION = '$Revision$';
38
39 my %opts = ();
40 my %jmps =
41     (
42         "\xff\xd0" => ["eax", "call"],
43         "\xff\xe0" => ["eax", "jmp" ],
44         "\xff\xd1" => ["ecx", "call"],
45         "\xff\xe1" => ["ecx", "jmp" ],
46         "\xff\xd2" => ["edx", "call"],
47         "\xff\xe2" => ["edx", "jmp" ],
48         "\xff\xd3" => ["ebx", "call"],
49         "\xff\xe3" => ["ebx", "jmp" ],
50         "\xff\xe4" => ["esp", "jmp" ],
51         "\xff\xd5" => ["ebp", "call"],
52         "\xff\xe5" => ["ebp", "jmp" ],
53         "\xff\xd6" => ["esi", "call"],
54         "\xff\xe6" => ["esi", "jmp" ],
55         "\xff\xd7" => ["edi", "call"],
56         "\xff\xe7" => ["edi", "jmp" ],
57        
58         "\x50\xc3" => ["eax", "push"],
59         "\x53\xc3" => ["ebx", "push"],
60         "\x51\xc3" => ["ecx", "push"],
61         "\x52\xc3" => ["edx", "push"],
62         "\x54\xc3" => ["esp", "push"],
63         "\x55\xc3" => ["ebp", "push"],
64         "\x56\xc3" => ["esi", "push"],
65         "\x57\xc3" => ["edi", "push"],
66     );
67
68 my %pops =
69     (
70         "eax"   => "\x58",
71         "ebx"   => "\x5b",
72         "ecx"   => "\x59",
73         "edx"   => "\x5a",
74         "esi"   => "\x5e",
75         "edi"   => "\x5f",
76         "ebp"   => "\x5d",
77     );
78
79
80 getopts("f:d:j:sx:a:B:A:I:nhvED", \%opts);
81 Usage()   if($opts{'h'});
82 Version() if($opts{'v'});
83
84 if ($opts{'h'} ||
85      (! defined($opts{'f'}) && ! defined($opts{'d'})) ||
86      (! defined($opts{'j'}) &&
87       ! defined($opts{'x'}) &&
88       ! defined($opts{'a'}) &&
89       ! defined($opts{'D'}) &&
90       ! $opts{'s'})
91    )
92 {
93    Usage();
94    exit(0);
95 }
96
97 my $func;
98 my $args = { };
99
100 if(exists($opts{'s'})) {
101   $func = \&popPopRet;
102 }
103 elsif(exists($opts{'j'})) {
104   $func = \&jmpReg;
105   $args->{'reg'} = $opts{'j'};
106 }
107 elsif(exists($opts{'x'})) {
108   $func = \&regex;
109   $args->{'regex'} = $opts{'x'};
110 }
111 elsif(exists($opts{'a'})) {
112   $func = \&address;
113   $args->{'address'} = hex($opts{'a'});
114 }
115 elsif(exists($opts{'D'})) {
116   $func = \&dumpinfo;
117   $args->{'dumpinfo'} = hex($opts{'D'});
118 }
119
120 $args->{'before'} = $opts{'B'} if(exists($opts{'B'}));
121 $args->{'after'} = $opts{'A'} if(exists($opts{'A'}));
122
123 if($opts{'f'}) {
124
125   my $filename = $opts{'f'};
126   my $elf = Pex::ELFInfo->new('File' => $filename, 'Debug' => $opts{'E'});
127   if (! $elf)
128   {
129       print STDERR "$0: could not load ELF image from file.\n";
130       exit(0);
131   }
132   if ($opts{'I'}) { $elf->ImageBase($opts{'I'}) }
133   &{$func}($elf, $args);
134 }
135
136 sub dumpinfo {
137     my $elf = shift;
138     my $args = shift;
139     my $col;
140     my @Ehdr    = $elf->ElfHeaders;
141     my @Phdr   = $elf->ProgramHeaders;
142    
143     print "\n\n[ ELF Header ]\n\n";
144     $col = Msf::ColPrint->new(4, 4);
145     foreach my $hdr (@Ehdr) {
146             $col->AddRow($hdr, sprintf("0x%.8x",$elf->ElfHeader($hdr)));
147     }
148     print $col->GetOutput;
149
150     print "\n\n[ Program Headers ]\n\n";
151     my $e_phnum = $elf->ElfHeader("e_phnum");
152     for(my $i = 0; $i < $e_phnum; $i++)
153     {       
154         $col = Msf::ColPrint->new(4, 4);
155         foreach my $hdr (@Phdr) {
156                     $col->AddRow($hdr, sprintf("0x%.8x",$elf->ProgramHeader($i, $hdr)));
157         }
158         print $col->GetOutput;
159         printf("\n----\n");
160     }
161    
162 }
163
164
165 # Scan for pop/pop/ret addresses
166 sub popPopRet
167 {
168     my $elf = shift;
169     my $data = $elf->Raw;
170     my $args = shift;
171     foreach my $rA (keys(%pops))
172     {
173         foreach my $rB (keys(%pops))
174         {
175             my $opc = $pops{$rA} . $pops{$rB} . "\xc3";
176             my $lst = 0;
177             my $idx = index($data,  $opc, $lst);
178             while ($idx > 0)
179             {
180                 printf("0x%.8x   $rA $rB ret\n", $elf->OffsetToVirtual($idx));
181                 $lst = $idx + 1;
182                 $idx = index($data, $opc, $lst);
183             }
184         }
185     }
186 }
187
188 # Scan for jmp/call/push,ret addresses
189 sub jmpReg
190 {
191     my $elf = shift;
192     my $data = $elf->Raw;
193     my $args = shift;
194     my $reg = $args->{'reg'};
195     foreach my $opc (keys(%jmps))
196     {
197         next if ($reg && lc($reg) ne $jmps{$opc}->[0]);
198
199         my $lst = 0;
200         my $idx = index($data, $opc, $lst);
201         while ($idx > 0)
202         {
203             my ($reg, $typ) = @{$jmps{$opc}};
204             printf("0x%.8x   $typ $reg\n", $elf->OffsetToVirtual($idx));
205             $lst = $idx + 1;
206             $idx = index($data, $opc, $lst);
207         }
208     }
209 }
210
211 # Regex
212 sub regex {
213   my $elf = shift;
214   my $data = $elf->Raw;
215   my $args = shift;
216   my $regex = $args->{'regex'};
217   $regex .= '.' x $args->{'after'} if($args->{'after'});
218   $regex = ('.' x $args->{'before'}) . $regex if($args->{'before'});
219
220   while($data =~ m/($regex)/g) {
221     my $found = $1;
222     my $index = pos($data) - length($found);
223     printf("0x%.8x   %s\n", $elf->OffsetToVirtual($index), hexOutput($found));
224   }
225 }
226
227 sub address {
228   my $elf = shift;
229   my $data = $elf->Raw;
230   my $args = shift;
231
232   my $address = $args->{'address'} - $args->{'before'};
233   my $length = $args->{'before'} + $args->{'after'};
234   $length = 1 if(!$length);
235   my $index = $elf->VirtualToOffset($address);
236   my $found = substr($data, $index, $length);
237   return if(!defined($index) || length($found) == 0);
238   printf("0x%.8x   %s\n", $address, hexOutput($found));
239 }
240
241 sub hexOutput {
242   my $data = shift;
243   my $string = unpack('H*', $data);
244   if($opts{'n'}) {
245 #    my $tempString = $string;
246 #    $tempString =~ s/(..)/\\x$1/g;
247     $string .= "\n--- ndisasm output ---\n";
248 #    $string .= `echo -ne "$tempString" | ndisasm -u /dev/stdin`;
249     $string .= Pex::Nasm::Ndisasm->DisasData($data);
250     $string .= "--- ndisasm output ---";
251   }
252   return($string);
253 }
254
255
256 sub Usage
257 {
258     print STDERR
259 qq{  Usage: $0 <input> <mode> <options>
260 Inputs:
261          -f  <file>    Read in ELF file
262 Modes:
263          -j  <reg>     Search for jump equivalent instructions
264          -s            Search for pop+pop+ret combinations
265          -x  <regex>   Search for regex match
266          -a  <address> Show code at specified virtual address
267 Options:
268          -A  <count>   Number of bytes to show after match
269          -B  <count>   Number of bytes to show before match
270          -I  address   Specify an alternate base load address
271          -n            Print disassembly of matched data
272 };
273   exit(0);
274
275 }
276 sub Version {
277     my $ver = Pex::Utils::Rev2Ver($VERSION);
278     print STDERR qq{
279    Msfelfscan Version:  $ver
280
281 };
282   exit(0);
283 }
284
Note: See TracBrowser for help on using the browser.