#!/usr/bin/perl -w use strict; use File::Slurp; use Win32::Exe; use Data::Dumper; BEGIN { push @INC, "/home/bob/src/disassemblers/X86-Disasm/blib/lib"; push @INC, "/home/bob/src/disassemblers/X86-Disasm/blib/arch"; require X86::Disasm; X86::Disasm->import qw($x86_asm_format_enum); push @INC, "/home/bob/src/disassemblers/X86-Distorm64/blib/lib"; push @INC, "/home/bob/src/disassemblers/X86-Distorm64/blib/arch"; require X86::Distorm64; push @INC, "/home/bob/src/disassemblers/X86-Udis86/blib/lib"; push @INC, "/home/bob/src/disassemblers/X86-Udis86/blib/arch"; require X86::Udis86; require Disassemble::X86; } (@ARGV == 2) or die "Need to pass a disassembler (none, disasm, distorm64, udis86, perlx86) and a filename, $!"; my $disassembler = $ARGV[0]; my $file = $ARGV[1]; my $exe = Win32::Exe->new($file); #print "EXE is ",Data::Dumper->Dump([$exe]); #my $data = $exe->{struct}->{Data}; my $data = read_file($file); print "DATA LENGTH is ",length($data)," or ",sprintf("%#x", length($data)),"\n"; print "DATA STARTS WITH ",unpack("H*", substr($data,0,512)),"\n"; my $entry_point = $exe->{struct}->{EntryPointRVA}; print "Entry Point RVA is ",sprintf("%#x", $entry_point),"\n"; my $image_base = $exe->{struct}->{ImageBase}; print "ImageBase is ",sprintf("%#x", $image_base),"\n"; my $section_name = ""; my $section = {}; my ($sections) = $exe->sections; print "KEYS are ",join (" ", keys %$sections),"\n"; foreach (@{$sections->{parent}->{children}->{Section}}) { my $struct = $_->{struct}; if ($entry_point > $struct->{VirtualAddress} and $entry_point < $struct->{VirtualAddress} + $struct->{FileSize}) { #print "*** EP is $entry_point, VA is $struct->{VirtualAddress}, FileSize is $struct->{FileSize}\n"; $section_name = $struct->{Name}; $section->{name} = $struct->{Name}; $section->{raw} = $struct->{FileOffset}; $section->{va} = $struct->{VirtualAddress}; $section->{file_size} = $struct->{FileSize}; $section->{code_size} = $struct->{VirtualAddress} + $struct->{FileSize} - $entry_point; last; } } print "SECTION is ",Dumper($section); #die "Can't find section name" unless (length $section_name); my $ep_phys = $section->{raw} + $entry_point - $section->{va}; printf("Entry point RVA is %#x and Physical Offset is %#x\n",$entry_point, $ep_phys); my $code = substr($data, $ep_phys, $section->{code_size}); print "CODE STARTS WITH ",unpack("H*", substr($data,$ep_phys,$section->{code_size})),"\n"; print "CODE LENGTH is ",$section->{code_size},"\n"; #my $file_offset = 0x250; if ($disassembler eq 'disasm') { # disasm($code); disasm(); } elsif ($disassembler eq 'distorm64') { # distorm64($code); distorm64(); } elsif ($disassembler eq 'udis86') { # udis86($code); udis86(); } elsif ($disassembler eq 'perlx86') { # perlx86($code); perlx86(); } elsif ($disassembler eq 'benchmark') { use Benchmark qw(:all) ; my $count = 10000; timethese($count, { 'disasm' => \&disasm, 'distorm64' => \&distorm64, 'udis86' => \&udis86, 'perlx86' => \&perlx86, }); # select($oldfh); } else { # perldoc $0; } exit; sub disasm { my $print = @_ ? shift : undef; # my $ep_phys = shift; # BEGIN { # push @INC, "/home/bob/src/disassemblers/X86-Disasm/blib/lib"; # push @INC, "/home/bob/src/disassemblers/X86-Disasm/blib/arch"; # require X86::Disasm; # X86::Disasm->import qw($x86_asm_format_enum); # } my $disasm = X86::Disasm->new; #my $disasm_rva = $text_va - $text_raw + $file_offset; # my $disasm_rva = $section->{va} - $section->{raw} + $file_offset; my $disasm_rva = 0; # printf("disasm_rva is %#x\n", $disasm_rva); # my $offset = $ep_phys - $file_offset; # my $offset = $ep_phys; my $offset = 0; # print "OFFSET is $offset or ",sprintf("%#x", $offset),"\n"; my $syntax = 'intel_syntax'; # my $output = $disasm->disassemble_list($data, $disasm_rva, $offset, $X86::Disasm::x86_asm_format_enum->{$syntax}); my $output = $disasm->disassemble_list($code, $disasm_rva, 0, $X86::Disasm::x86_asm_format_enum->{$syntax}); print Data::Dumper->Dump([$output]) if (defined $print); } sub distorm64 { # my $code = shift; my $print = @_ ? shift : undef; # BEGIN { # push @INC, "/home/bob/src/disassemblers/X86-Distorm64/blib/lib"; # push @INC, "/home/bob/src/disassemblers/X86-Distorm64/blib/arch"; # require X86::Distorm64; # } my $buf_rva = 0; my $offset = 0; #typedef enum {Decode16Bits = 0, Decode32Bits = 1, Decode64Bits = 2} _DecodeType; my $decode_type = 1; my $max_instructions = length($code); # must be > 15 or else code will fallout my @result; my ($retval, $result_ptr, $used_instructions_count); my $running = 1; while ($running) { ($retval, $used_instructions_count, @result) = X86::Distorm64::distorm_decode64($offset, $code, length $code, $decode_type, $max_instructions); if (defined $print) { for (my $i = 0; $i < $used_instructions_count; $i++) { print join("\t", $result[$i]->instructionHex->pstring, $result[$i]->mnemonic->pstring, $result[$i]->operands->pstring), "\n"; } } $running = 0 if (($retval == 1) or ($used_instructions_count == 0)); } } sub udis86 { # my $code = shift; my $print = @_ ? shift : undef; # BEGIN { # push @INC, "/home/bob/src/disassemblers/X86-Udis86/blib/lib"; # push @INC, "/home/bob/src/disassemblers/X86-Udis86/blib/arch"; # require X86::Udis86; # } my $ud_obj = X86::Udis86->new; # $ud_obj->set_input_file($file); $ud_obj->set_input_buffer($code, length($code)); $ud_obj->set_mode(32); $ud_obj->set_syntax("intel"); while($ud_obj->disassemble) { print join(" ",sprintf("%016x", $ud_obj->insn_off), sprintf("%-32s", $ud_obj->insn_hex), $ud_obj->insn_asm,"\n") if (defined $print); # sprintf("%-32x", hex($ud_obj->insn_hex)), # print "insn_len is ",$ud_obj->insn_len,"\n"; # print "pc is ",$ud_obj->pc,"\n"; # my $operands = $ud_obj->operands; # my $max = $ud_obj->insn_len < 3 ? $ud_obj->insn_len : 3; # for (my $i=0; $i<$max; $i++) { # my $operand = $operands->[$i]; # next if ($operand->type_as_string eq "UD_NONE"); # $operand->info($i); # } } } sub perlx86 { # my $code = shift; my $print = @_ ? shift : undef; # BEGIN { # require Disassemble::X86; # } my $d = Disassemble::X86->new(text => $code, addr_size => 32, data_size => 32, size => 32, format => "Text", ); while (defined(my $op = $d->disasm() )) { if (defined $print) { printf "%08x %s\n", $image_base + $entry_point + $d->op_start(), $op; } } }