Active Members Fi8sVrs Posted October 29, 2011 Active Members Report Posted October 29, 2011 Author(s)Joe StewartLatest Version0.1DescriptionForegone is a forensic file recovery tool written in Perl. It was inspired by the Air Force Office of Special Investigations' forensic tool known as "Foremost", which uses defined headers and footers of certain file types to search a raw disk image and extract files with those characteristics. Foregone is a Perl implementation of the same technique with some added features:Only searches for headers starting on a block boundary, for a speed increaseUses compression to reject interleaved blocks of dissimilar filesForegone should not be considered an investigative-level forensic tool, but merely a utility that may help you recover files from a corrupted filesystem.#!/usr/bin/perluse Compress::Zlib;## foregone.pl - recover files of a given type from a raw disk image even if## interleaved with other blocks (blocks must be in correct order)## ## (c)2003-2006 Joe Stewart <jstewart@lurhq.com>#### Foregone is released under the GNU General Public License.## examples #### PDF #### my $header = "\x25\x50\x44\x46\x2D";## my $footer = "\x25\x25\x45\x4F\x46";## my $extension = "pdf";## my $mustfind = "";## my $mustfind2 = "";## GNUCASH #### my $header = "<?xml version=\"1.0\"?>\n<gnc-";## my $footer = "<!-- End: -->";## my $extension = "xml";## my $mustfind = "<act";## my $mustfind2 = "<trn";## JPEG ##my $header = "\xff\xd8\xff\xe0";my $footer = "\xff\xd9";my $extension = "jpg";my $mustfind = "";my $mustfind2 = "";## Blocksize of filesystem being read ##my $blocksize = 1024;## Threshold to reject blocks based on compressed size ## compares initial block size when compressed with subsequent block## sizes when compressed ... good at rejecting dissimliar types of data## More than this zthreshold percent deviation will result in rejection## Adjust as needed depending on how many bad blocks you get in outputmy $zthreshold = 50; ## maximum size of any output file ##my $maxbytes = 3000000;## directory to write recovered files. Will be created if it doesn't exist ##my $recoverdir = "foregone-recover";my $image = $ARGV[0];my $size = (stat($image))[7];my $buf = "";my $buflength = length($header);my $found = 0;my $outbytes = 0;my $pos = 0;die "Usage: $0 <disk image>\n" unless $image;open (IN, $image) or die "Could not open $image : $!\n";unless (-e "$recoverdir") { mkdir("$recoverdir", 0755) or die "Could not create $recoverdir : $1\n";}while ($pos < $size) { my $blockpos = $pos; read(IN,$buf,$buflength) or last; $percent = ($pos / $size) * 100; printf("Looking at first %s bytes of block at offset $pos (%.2f%% done)\r", $buflength, $percent); if ($buf eq $header) { print "\nHeader match at $pos\n"; print "Extracting file...\n"; &extract_file; } $pos += $blocksize; seek(IN,$pos, 0) or die "\ncould not seek to $pos";}print "\nFinished.\n";close IN;sub extract_file { $found++; my $filename = sprintf("recovered.%05d.%s", $found, $extension); open(OUT, ">$recoverdir/$filename") or die "Couldn't write output file!\n"; print OUT $buf; my $tmpblocksize = $blocksize - $buflength; while ($pos < $size) { read(IN,$block,$tmpblocksize) or last; $tmpblocksize = $blocksize; my $zblock = compress($block); my $zblocklength = length($zblock); if (!$zfirstblock) { $zfirstblock = $zblocklength; $lowerlimit = ((100 - $zthreshold) / 100) * $zfirstblock; $upperlimit = ((100 + $zthreshold) / 100) * $zfirstblock; } else { if ($block !~ /$footer/) { # compressed block size is too different. reject it. if ($zblocklength > $upperlimit || $zblocklength < $lowerlimit) { print "Rejected block: compressed size = $zblocklength : $lowerlimit < $zfirstblock > $upperlimit\n"; next; } } } if ($mustfind) { next unless $block =~ /$mustfind|$mustfind2/; } if ($block =~ /$footer/ || $outbytes + $blocksize > $maxbytes ) { my ($blockt, $garbage) = split(/$footer/, $block); print OUT $blockt . $footer; $outbytes += length($blockt) + length($footer); if (length($blockt) + length($footer) == $blocksize) { print "Failed to truncate last block\n" } last; } $outbytes += $blocksize; print OUT $block; } print "Wrote $recoverdir/$filename ($outbytes bytes)\n"; $outbytes = 0; close OUT;}Source Quote