#! c:\perl\bin\perl.exe #------------------------------------------------------------------------- # Script to extract USBMSC entries from Mac OS X kernel logs and # attempt to correlate the Vendor/Product ID of the log entry # with the content from "http://www.linux-usb.org/usb.ids". # # Author: Jason Hale # Version 20130125 #------------------------------------------------------------------------- use strict; use LWP::Simple; use Getopt::Long; my $version = 20130125; my @logs; my $totalRecords = 0; my %args; GetOptions(\%args,qw(dir|d=s usb_db|u=s help|?|h)); if ($args{help}) {printHelp(); exit;} #If -d flag is passed with a directory path, attempt to set @logs using file names from directory if($args{dir}) {opendir DIR, $args{dir} or die "Cannot open $args{dir}!"; @logs = grep(!/^\.{1,2}/, readdir(DIR)); closedir DIR;} #If the -d flag is not passed, attempt to allocate first entry in @logs to provided file else {$logs[0] = shift || die "You must enter a filename.\n";} print STDERR "\nMac OS X USBMSC Parser v.$version\n...................................\n"; print STDERR "Gathering USB ID Database Info...\n"; #If USB ID Database file not provided, set using online version of repository if(! $args{usb_db}) {$args{usb_db} = get("http://www.linux-usb.org/usb.ids"); print STDERR "USB ID Database obtained from linux-usb.org!\n";} #If USB ID Database file is provided, read in provided file else {open(FILE, '<', $args{usb_db}) || die "Could not open $args{usb_db}!"; $args{usb_db} = do { local $/; }; close(FILE); print STDERR "USB ID Database obtained from file!\n";} print "Date, Time, Host, USBMSC Identifier (non-unique), Vendor ID (0x), Product ID (0x), Device Release (0x)\n"; foreach my $log (@logs) { print STDERR "Parsing $log..."; if($args{dir}){$log = "$args{dir}\\$log";} open (FILE, $log) or die "Cannot open $log!"; my $numRecords = 0; while () { #Regex to find USBMSC entries (Also stores relevant portions as variables) if ($_ =~ m/(^[a-z]{3}\s{1,2}\d{1,2})\s(\d\d:\d\d:\d\d)\s(.+)\s[a-z]+\[\d+\]:\sUSBMSC\s.+:\s(.*)0x(.*)\s0x(.*)\s0x(.*)/i) { my $vid = $5; my $pid = $6; for (split /\n/, $args{usb_db}) #For loop to attempt to correlate VID/PID with USB ID Database { if ($vid eq $5) #If VID=value from log entry, attempt to locate value in USB ID Database {if ($_ =~ m/^0*$vid\s/i) {$vid = $_; chomp($vid); $vid =~ s/,//;} #Remove any commas } elsif ($_ !~ m/^\t/) {last;} #If the line being read in does not start with a tab, stop searching USB ID Database #The above line will prevent mistakenly associating the wrong PID with the device if the same PID is associated with a different VID listed after the found VID in the USB ID Database elsif ($_ =~ m/\t0*$pid\s/i) #If VID!=value from log entry (thus set from USB ID Database), look for PID in USB ID Database {$pid = $_; chomp($pid); $pid =~ s/,//; #Remove any commas last;} } print "$1,$2,$3,$4,$vid,$pid,$7\n"; $numRecords++; $totalRecords++;} } print STDERR "Found $numRecords USBMSC entries!\n"; close (FILE); } print STDERR "...................................\nTotal USBMSC Entries Found: $totalRecords\n"; sub printHelp() { print<< "EOT"; Mac OS X USBMSC Parser v.$version ................................... - Extracts USBMSC entries from Mac OS X kernel logs - Attempts to correlate USBMSC entries with USB ID Database Syntax: usbmsc.pl [-u path to USB DB file] [-d] path to log file/directory -d : Parse all files in the provided directory -u : Use the file provided for correlation instead of online repository Examples: 1) usbmsc.pl -d f:\\logs > usbmsc_entries.csv 2) usbmsc.pl -u f:\\usbRepository.txt f:\\kernel.log > usbmsc_entries.csv 3) usbmsc.pl f:\\kernel.log > usbmsc_entries.csv ................................... Author: Jason Hale EOT } exit;