#!/usr/bin/perl # # PEFix v0.1, written by Hexacorn.com # # This is a simple script that rebuilds the PE file from the memory dump # # Usage: # perl PEFix.pl # Examples: # perl PEFix.pl mem_1600_01000000.bin # use strict; use warnings; $| = 1; print STDERR " ============================================================================ PEFix v0.1, written by Hexacorn.com ============================================================================ "; use strict; use warnings; $| = 1; my $arg = shift; if (!defined($arg)) { print "Gimme a file name!\n"; exit; } my $file = $arg; print STDERR "Processing file: $file\n"; my $file_size = -s $file; if ($file_size<512) { print "\"$file\" too small\n"; exit; } if (!open (FILE, '<'.$file)) { print "Can't open \"$file\"\n"; exit; } binmode (FILE); my $topdata; if (!read (FILE, $topdata, 2)) { close FILE; print "Can't read \"$file\"\n"; exit; } if ($topdata ne 'MZ') { print "Not an MZ file\n"; exit; } seek (FILE, 0x3C, 0); read (FILE, my $o2PE,4); $o2PE = unpack("I",$o2PE); if ($o2PE>16384) { close FILE; print "Offset to PE header (=$o2PE) seems to be quite high - modify script if you think it's fine (some packers mess around with this value)\n"; exit; } seek (FILE, $o2PE, 0); read (FILE, my $PEHeader,32); $PEHeader = substr($PEHeader,0,2); if ($PEHeader ne 'PE') { close FILE; print "Not an PE file\n"; exit; } seek (FILE, $o2PE+4 ,0); read (FILE, my $MachineID,2); $MachineID = unpack("S",$MachineID); if ($MachineID != 0x14c && $MachineID != 0x8664) { close FILE; print "PE file type (=$MachineID) not supported \n"; exit; } seek (FILE, $o2PE+6 ,0); read (FILE, my $NumOfSections,2); $NumOfSections = unpack("S",$NumOfSections); if ($NumOfSections==0) { close FILE; print "PE file has no sections (could be a result of some PE tricks being applied to PE structure)\n"; exit; } seek (FILE, $o2PE+20,0); read (FILE, my $OptHdrSize,2); $OptHdrSize = unpack("S",$OptHdrSize); seek (FILE, $o2PE + 24 + $OptHdrSize , 0); read (FILE, my $sections, $NumOfSections * 40); my @sections; open FIXED,">$file.fixed" ; binmode FIXED; for (my $k = 0;$k<$NumOfSections;$k++) { my $sectiondata; seek (FILE, $o2PE + 24 + $OptHdrSize + $k*40, 0); read (FILE, my $sectionname,8); $sectionname =~ s/[^\x20-\x7F]/ /gs; read (FILE, my $vs,4); $vs = unpack("I",$vs); read (FILE, my $vo,4); $vo = unpack("I",$vo); read (FILE, my $fs,4); $fs = unpack("I",$fs); read (FILE, my $fo,4); $fo = unpack("I",$fo); seek (FILE, $o2PE + 24 + $OptHdrSize + $k*40+8+4*4+4+4+4, 0); read (FILE, my $sectionflagsbin,4); $sectionflagsbin = unpack("I",$sectionflagsbin); my $sectionflags = ''; if ($sectionflagsbin & 0x20000000) { $sectionflags.='X'; } if ($sectionflagsbin & 0x80000000) { $sectionflags.='W'; } if ($sectionflagsbin & 0x40000000) { $sectionflags.='R'; } if ($sectionflagsbin & 0x10000000) { $sectionflags.='S'; } if ($sectionflagsbin & 0x00000020) { if ($sectionflags ne '') {$sectionflags.='_'; } $sectionflags.='CODE'; } if ($sectionflagsbin & 0x00000040) { if ($sectionflags ne '') {$sectionflags.='_'; } $sectionflags.='IDATA'; } if ($sectionflagsbin & 0x00000080) { if ($sectionflags ne '') {$sectionflags.='_'; } $sectionflags.='BSS'; } if ($sectionflagsbin & 0x04000000) { if ($sectionflags ne '') {$sectionflags.='_'; } $sectionflags.='NONCACHE'; } if ($sectionflagsbin & 0x08000000) { if ($sectionflags ne '') {$sectionflags.='_'; } $sectionflags.='NONPAGE'; } $sectionname =~ s/^\s*(.*?)\s*$/$1/; if ($sectionname eq '') { $sectionname='SECTION_'.$k; } print STDERR sprintf ("%-8s, vo = %08lX, vs = %08lX, fo = %08lX, fs = %08lX, flags = %08lX, %s", $sectionname, $vo, $vs, $fo, $fs, $sectionflagsbin, $sectionflags); if ($k==0) { seek (FILE, 0 , 0); read (FILE, $sectiondata, $fo); print FIXED $sectiondata; } if ($fs != 0) { seek (FILE, $vo , 0); if ($k==$NumOfSections-1) { if ($vo+$fs<$file_size) { $fs=$file_size-$vo; } } read (FILE, $sectiondata, $fs); print STDERR " -> Writing"; print FIXED $sectiondata; } else { print STDERR " -> Skipping"; } print STDERR "\n"; } close FIXED;