#!/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 < \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 - 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 - 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 () { 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 ''; }