#!/usr/bin/perl
# This is a utility to parse a F-Prot Anti Virus log file, 
# in order to sort them into a malware archive for easier 
# maintanence of your collection.
# By: magikh0e 
# Version: 1a - 02-20-2011

## Path Info (defaults) ##
# /vx/Architecture/Type/VX_Name/md5.bin
##
## Sample (defaults) ##
# /vx/W32/virus/TestVirus/38509238509328598345rfewfr0.bin

$ArcPath = "vx";  # change this to the path you wish to store the collection. No trailing /

## F-Prot Scanner Usage ############################
# run fpscan -r directory/ > fpscan.log            #
# execute fprotLogParser.pl from the same directory.  # 
####################################################

use Digest::MD5;
use Getopt::Std;
%opts=();
getopts('vdr:hRpf:F:', \%opts);
$VERSION = "1a";
$fpscan_log = "fpscan.log" unless $fpscan_log = $opts{f};
$report_file = "fprotParserReport.txt";
usage() if $opts{h} || !$opts{p};
$debugging = 0 unless $debugging = $opt{d};
$verbose = 0 unless $verbose = $opts{v};
$enable_report = 0 unless $enable_report = $opts{r};
$report_only = 0 unless $report_only = $opts{R};
$process_files = 0 unless $process_files = $opts{p};

sub usage {
print <<eof;
\n\t\t\t-$0 Ver: $VERSION-
\t\tBy: magikh0e - <magikh0e\@ihtb.org>
\t\tHttp://magikh0e.ihtb.org\n
This is a utility to parse a F-Prot Anti Virus log file, 
in order to sort them into a malware archive for easier 
maintanence of your collection.

Usage:
Notes: At a minimal, -p must be used. 
       -v or -d must be enabled for reporting features to work.

 -h Help. - You are here...
 -d Enable Debugging - turn on debugging
 -v Enable Verbosity - verbose output
 -r Enable Reporting - Creates report/statistics file about scanned files
 -F <file> - Path to report file. Default: $report_file -DISABLED
 -R Report only - process files, but report only. No files are moved.
 -p Process files - copy files from archive into collection directory defined by setting \$ArcPath
 -f <file> - specifies the path to the F-Prot log file. Default: $fpscan_log
eof
}

if ($report_only || $process_files) {
open FPS, $fpscan_log;
$fcount=0;
foreach $line (<FPS>) { 
if ($line =~ m/Files:\s{1,5}(\d+)/) { $stats_files = $1; }
if ($line =~ m/Infected objects:\s{1,5}(\d+)/) { $stats_io = $1; }
if ($line =~ m/Objects scanned:\s{1,5}(\d+)/) { $stats_os = $1; }
if ($line =~ m/Skipped files:\s{1,5}(\d+)/) { $stats_sf = $1; }
if ($line =~ m/Files with errors:\s{1,5}(\d+)/) { $stats_fe = $1; }

 if ($line =~  m/\[Found ([^.]+)\] <(.+?)>\s{1,32}(.+?\.[a-zA-Z0-9]{1,6})/) { 
     $fcount++;
     $category = $1;
     $fileName = $3;
     @category = $category;
 if ($3 =~ /([^ ]+)[-]>([^ ]+)/) { $fileName = $1; $gbg = $2; } else { $fileName = $3; }
 if ($2 =~ m/([^ ]+)\/([^ ]+)/) { $arch = $1; $vx_name = $2; } else { $arch = ""; $vx_name =$2; }
    
  ($vX, $ot) = split('!', $vx_name);  ($VX, $junk) = split('@', $vX); 
  ($vx,$variant) = split('\.', $VX);
  @vx = $vx;
   process_files() if $process_files; 
   }  
foreach $cat (@category) { $cnt{$cat}++; }
foreach $vx (@vx) { $cnt{$vx}++; }
 }  close FPS;

run_report() if $enable_report;

}

sub run_report { 
open (REPORT, '>fprotParserReport.txt') or warn "unable to open file: $!";
	print REPORT "\n\n=Category Statistics=\n\n";
	print REPORT "\tFiles Scanned: $stats_files\n";
	print REPORT "\tInfected Objects: $stats_io\n";
	print REPORT "\tObjects Scanned: $stats_os\n";
	print REPORT "\tFiles Skipped: $stats_sf\n";
	print REPORT"\tFiles with Errors: $stats_fe\n";
	foreach $cat (sort by_cat_count keys %cnt) { 
			print REPORT "\t$cat: $cnt{$cat} \n";
	}

	print REPORT "\n\n=Malware Name Statistics=\n\n";

	foreach $vx (sort by_vx_count keys %cnt) { 
			print REPORT "\t$vx: $cnt{$vx} \n";
	}
}

print "\nReport file generated: $report_file\n" if $enable_report;
close REPORT;

sub by_cat_count { $cnt{$b} <=> $cnt{$a}; }
sub by_vx_count { $cnt{$b} <=> $cnt{$a}; }

sub process_files {
  shift;
  $md5 = md5sum($fileName);
print "FileName: $fileName \nPath: $ArcPath/$arch/$category/$vx\n" if $debugging;
($file, $ext) = split('\.', $fileName); if ($variant =~ "gen") { $variant =""; }

#if ($category =~ "security risk" || $category =~ "worm" || $category =~ "password stealer" || $category =~ "trojan" || $category eq "virus" || $category =~ "downloader" || $category =~ "backdoor" || $category =~ "P2P worm" || $category =~ "IRC") {

unless ( -d "$ArcPath/$arch/$category/$vx/") { 
         print "Creating Dir: $ArcPath/$arch/$category/$vx\n" 
         if $debugging;
         system("mkdir -p '$ArcPath/$arch/$category/$vx'") unless $report_only; 
	} 
 
 if ($variant) { 
     print "Creating Dir: $ArcPath/$arch/$category/$vx/$variant\n" 
     if $debugging;
     
     system("mkdir -p '$ArcPath/$arch/$category/$vx/$vx-$variant'") unless $report_only;  
     system "cp '" . $fileName . "' '$ArcPath/$arch/$category/$vx/$vx-$variant/$md5.$ext'\n" unless $report_only;
     
     print "cp $fileName $ArcPath/$arch/$category/$vx/$vx-$variant/$md5.$ext" 
     if $debugging && $verbose;  
    }

 if (!$variant) { 
     system "cp '" . $fileName . "' '$ArcPath/$arch/$category/$vx/$md5.$ext'\n" 
     unless $report_only; 
     
     print "cp $fileName $ArcPath/$arch/$category/$vx/$md5.$ext" 
     if $debugging && $verbose; 
    }
     print "\n$fcount - Arch: $arch - Type: $category - VX: $vx - Variant: $variant\n" 
     if $debugging;
#} else { print "SKipping: not proper category\n" if $verbose; }
}


sub md5sum{
  my $file = shift;
  my $digest = "";
  eval{
    open(FILE, $file) or die "Can't find file $file\n";
    my $ctx = Digest::MD5->new;
    $ctx->addfile(*FILE);
    $digest = $ctx->hexdigest;
    close(FILE);
  };

  if($@){ print $@; return ""; }
          return $digest;
}

sub trim {
    my($str) = shift =~ m!^\s*(.+?)\s*$!i;
    defined $str ? return $str : return '';
} 