# # $Date: 2006/05/03 22:12:57 $ # # Metadata mode # # Brian Carrier [carrier@sleuthkit.org] # Copyright (c) 2001-2005 by Brian Carrier. All rights reserved # # This file is part of the Autopsy Forensic Browser (Autopsy) # # Autopsy is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # Autopsy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Autopsy; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. # IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Updated 1/13 package Meta; $Meta::FRAME = 0; $Meta::ENTER = 1; $Meta::STATS = 2; $Meta::EXPORT = 3; $Meta::FFIND = 4; $Meta::LIST = 5; $Meta::REPORT = 6; $Meta::BLANK = 7; sub main { # By default, show the main frame $Args::args{'view'} = $Args::enc_args{'view'} = $Meta::FRAME unless (exists $Args::args{'view'}); Args::check_view(); my $view = Args::get_view(); # Check Basic Args Args::check_vol('vol'); # These windows don't need the meta data address if ($view == $Meta::FRAME) { return frame(); } elsif ($view == $Meta::ENTER) { return enter(); } elsif ($view == $Meta::LIST) { return list(); } elsif ($view == $Meta::BLANK) { return blank(); } # These windows do need the meta data address Args::check_meta('meta'); if ($view == $Meta::STATS) { return stats(); } elsif ($view == $Meta::FFIND) { return findfile(); } Args::check_recmode(); if ($view == $Meta::EXPORT) { return export(); } elsif ($view == $Meta::REPORT) { return report(); } else { Print::print_check_err("Invalid Meta View"); } } # Print the two frames sub frame { my $vol = Args::get_vol('vol'); Print::print_html_header_frameset( "Meta Data Browse on $Caseman::vol2sname{$vol}"); print "\n"; # Print the frame where an addres can be entered and a frame for the # contents if (exists $Args::enc_args{'meta'}) { print "\n" . "\n\n"; } else { print "\n" . "\n\n"; } Print::print_html_footer_frameset(); return 0; } # Generate the frame to enter the data into sub enter { Print::print_html_header(""); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; # Address print "
\n" . "$Fs::meta_str{$ftype} Number:
    " . "\n" . "\n" . "\n" . "\n" . Args::make_hidden() . # View Button "

\n"; # Allocation List print "

" . "" . "\"Allocation" . "\n"; Print::print_html_footer(); return 0; } # Display the contents of meta sub stats { Print::print_html_header(""); my $meta = Args::get_meta('meta'); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; my $img = $Caseman::vol2path{$vol}; my $offset = $Caseman::vol2start{$vol}; my $imgtype = $Caseman::vol2itype{$vol}; my $tz = ""; $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq ""); Print::log_host_inv( "$Caseman::vol2sname{$vol}: Displaying details of $Fs::meta_str{$ftype} $meta" ); my $meta_int = $meta; $meta_int = $1 if ($meta =~ /^(\d+)-\d+(-\d)?/); my $prev = $meta_int - 1; my $next = $meta_int + 1; # We need to get the allocation status of this structure my $recmode = $File::REC_NO; local *OUT; Exec::exec_pipe(*OUT, "'$::TSKDIR/ils' -f $ftype -e -o $offset -i $imgtype $img $meta_int"); while ($_ = Exec::read_pipe_line(*OUT)) { chop; next unless ($_ =~ /^$meta_int/); if ($_ =~ /^$meta_int\|f/) { $recmode = $File::REC_YES; } elsif ($_ =~ /^$meta_int\|a/) { $recmode = $File::REC_NO; } else { Print::print_err("Error parsing ils output: $_"); } } close(OUT); print "

\n"; print "" . "\"previous\"\n" unless ($prev < $Fs::first_meta{$ftype}); print "" . "\"next\"\n
"; # Report print "\n" . "\n"; # View (File Mode) print "\n"; # Export print ""; # Notes print "" if ($::USE_NOTES == 1); print "
" . "\"report\"" . "" . "\"view" . "" . "\"export\"" . "" . "\"Add" . "
\n
\n"; my $tmpr = $Caseman::vol2mnt{$vol}; if ($ftype =~ /fat/) { print "Search for File Name

"; } else { print "Pointed to by file:
\n"; local *OUT; Exec::exec_pipe(*OUT, "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta"); my $cnt = 0; while ($_ = Exec::read_pipe_line(*OUT)) { chop; if (/^(\*)\s+\/*(.*)$/) { Print::print_output( "$tmpr$2 (deleted)

\n" ); } elsif (/^\/(.*)$/) { Print::print_output("$tmpr$1

\n"); } else { Print::print_output("$_

\n"); } $cnt++; } close(OUT); if ($cnt == 0) { print "
Invalid $Fs::meta_str{$ftype} value

\n"; return; } } if ($recmode == $File::REC_YES) { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -" ); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -" ); } my $file_type = Exec::read_pipe_line(*OUT); close(OUT); $file_type = "Error getting file type" if ((!defined $file_type) || ($file_type eq "")); if ($recmode == $File::REC_YES) { print "File Type (Recovered):
$file_type
\n"; } else { print "File Type:
$file_type

\n"; } # MD5 Value if ($recmode == $File::REC_YES) { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::TSKDIR/md5'" ); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::TSKDIR/md5'" ); } my $md5out = Exec::read_pipe_line(*OUT); close(OUT); $md5out = "Error getting MD5" if ((!defined $md5out) || ($md5out eq "")); chomp $md5out; if ($recmode == $File::REC_YES) { print "MD5 of recovered content:
$md5out

\n"; } else { print "MD5 of content:
$md5out

\n"; } # Hash Database Lookups if ( ( ($::NSRLDB ne "") || ($Caseman::alert_db ne "") || ($Caseman::exclude_db ne "") ) && ($md5out =~ /^$::REG_MD5$/o) ) { print "
\n" . Args::make_hidden() . "\n" . "\n" . "\n" . "\n"; if ($::NSRLDB ne "") { print "\n"; } if ($Caseman::alert_db ne "") { print "\n"; } if ($Caseman::exclude_db ne "") { print "\n"; } print "
" . "" . "NSRL" . "" . "Alert Database" . "" . "Exclude Database" . "" . "
\n
\n"; } # SHA-1 Value if ($recmode == $File::REC_YES) { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::TSKDIR/sha1'" ); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::TSKDIR/sha1'" ); } my $sha1out = Exec::read_pipe_line(*OUT); close(OUT); $sha1out = "Error getting SHA-1" if ((!defined $sha1out) || ($sha1out eq "")); chomp $sha1out; if ($recmode == $File::REC_YES) { print "SHA-1 of recovered content:
$sha1out

\n"; } else { print "SHA-1 of content:
$sha1out

\n"; } # istat output print "Details:

\n"; my $mode = 0; # set to 1 when showing blocks my $force = 0; # set to 1 if size of meta is 0 my @output; if (exists($Args::args{'force'})) { my $f = Args::get_force(); Exec::exec_pipe(*OUT, "'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -b $f -o $offset -i $imgtype $img $meta" ); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta" ); } while ($_ = Exec::read_pipe_line(*OUT)) { if ($mode == 1) { if (/^Indirect Blocks/) { print "$_
\n"; next; } elsif (/^Recover/) { print "$_
\n"; next; } elsif (/^Type: (\S+) \((\d+\-\d+)\) (.*)$/) { print "$1 (" . "$2) $3
\n"; next; } my $blk; foreach $blk (split(/ /, $_)) { if ($blk =~ /^\d+$/) { print "$blk "; } else { print "$blk "; } } print "
\n"; } else { if (/^Not Allocated$/) { print "$_
\n"; } else { print "$_
\n"; } $mode = 1 if (/^Direct Blocks|^Sectors/); $mode = 1 if (/^Attributes/); if ((/^size: (\d+)/) && ($1 == 0)) { $force = 1; } } } close(OUT); # display a text box to force X number of blocks to be displayed if ($force == 1) { print "
\n" . Args::make_hidden() . "\n" . "\n" . "\n" . "\n"; print "Enter number of $Fs::addr_unit{$ftype}s to display: \n"; print " (because the size is 0)\n
\n"; } Print::print_html_footer(); return 0; } sub findfile { Print::print_html_header("Find File"); my $meta = Args::get_meta('meta'); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; my $tmpr = $Caseman::vol2mnt{$vol}; my $img = $Caseman::vol2path{$vol}; my $offset = $Caseman::vol2start{$vol}; my $imgtype = $Caseman::vol2itype{$vol}; print "Pointed to by file:
\n"; local *OUT; Exec::exec_pipe(*OUT, "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta"); while ($_ = Exec::read_pipe_line(*OUT)) { chop; if (/(\*)\s+\/*(.*)/) { Print::print_output( "$tmpr$2 (deleted)
\n" ); } elsif (/^\/(.*)$/) { Print::print_output("$tmpr$1
\n"); } else { Print::print_output("$_
\n"); } } close(OUT); Print::print_html_footer(); return 0; } sub export { my $meta = Args::get_meta('meta'); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; my $img = $Caseman::vol2path{$vol}; my $offset = $Caseman::vol2start{$vol}; my $imgtype = $Caseman::vol2itype{$vol}; my $recmode = Args::get_recmode(); Print::log_host_inv( "$Caseman::vol2sname{$vol}: Saving contents of $Fs::meta_str{$ftype} $meta" ); Print::print_oct_header("$vol" . "-meta" . "$meta" . ".raw"); local *OUT; if ($recmode == $File::REC_YES) { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta"); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta"); } print "$_" while ($_ = Exec::read_pipe_data(*OUT, 512)); close(OUT); Print::print_oct_footer(); } sub report { my $meta = Args::get_meta('meta'); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; my $img = $Caseman::vol2path{$vol}; my $offset = $Caseman::vol2start{$vol}; my $imgtype = $Caseman::vol2itype{$vol}; my $recmode = Args::get_recmode(); my $tz = ""; $tz = "-z '$Caseman::tz'" unless ("$Caseman::tz" eq ""); Print::log_host_inv( "$Caseman::vol2sname{$vol}: Generating report for $Fs::meta_str{$ftype} $meta" ); Print::print_text_header("filename=$vol-meta$meta.txt"); print " Autopsy $Fs::meta_str{$ftype} Report\n\n" . "-" x 70 . "\n" . " GENERAL INFORMATION\n\n" . "$Fs::meta_str{$ftype}: $Args::args{'meta'}\n"; print "Pointed to by file(s):\n"; my $tmpr = $Caseman::vol2mnt{$vol}; local *OUT; Exec::exec_pipe(*OUT, "'$::TSKDIR/ffind' -f $ftype -a -o $offset -i $imgtype $img $meta"); while ($_ = Exec::read_pipe_line(*OUT)) { chop; if (/^(\*)\s+\/*(.*)$/) { Print::print_output(" $tmpr$2 (deleted)\n"); } elsif (/^\/(.*)$/) { Print::print_output(" $tmpr$1\n"); } else { Print::print_output(" $_\n"); } } close(OUT); Exec::exec_pipe(*OUT, "'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta | '$::TSKDIR/md5'" ); my $md5 = Exec::read_pipe_line(*OUT); close(OUT); $md5 = "Error getting MD5 Value" if ((!defined $md5) || ($md5 eq "")); chop $md5; print "MD5 of istat output: $md5\n"; Exec::exec_pipe(*OUT, "'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta | '$::TSKDIR/sha1'" ); my $sha1 = Exec::read_pipe_line(*OUT); close(OUT); $sha1 = "Error getting SHA-1 Value" if ((!defined $sha1) || ($sha1 eq "")); chop $sha1; print "SHA-1 of istat output: $sha1\n"; print "\nImage: $Caseman::vol2path{$vol}\n"; if (($Caseman::vol2start{$vol} == 0) && ($Caseman::vol2end{$vol} == 0)) { print "Offset: Full image\n"; } elsif ($Caseman::vol2end{$vol} == 0) { print "Offset: $Caseman::vol2start{$vol} to end\n"; } else { print "Offset: $Caseman::vol2start{$vol} to $Caseman::vol2end{$vol}\n"; } print "File System Type: $ftype\n"; my $date = localtime(); print "\nDate Generated: $date\n" . "Investigator: $Args::args{'inv'}\n\n" . "-" x 70 . "\n" . " META DATA INFORMATION\n\n"; Exec::exec_pipe(*OUT, "'$::TSKDIR/istat' -f $ftype $tz -s $Caseman::ts -o $offset -i $imgtype $img $meta" ); while ($_ = Exec::read_pipe_line(*OUT)) { print "$_"; } close(OUT); if ($recmode == $File::REC_YES) { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -r -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -" ); } else { Exec::exec_pipe(*OUT, "'$::TSKDIR/icat' -f $ftype -o $offset -i $imgtype $img $meta | '$::FILE_EXE' -z -b -" ); } my $file_type = Exec::read_pipe_line(*OUT); close(OUT); $file_type = "Error getting file type" if ((!defined $file_type) || ($file_type eq "")); print "\nFile Type: $file_type"; print "\n" . "-" x 70 . "\n" . " VERSION INFORMATION\n\n" . "Autopsy Version: $::VER\n"; print "The Sleuth Kit Version: " . ::get_tskver() . "\n"; Print::print_text_footer(); return 0; } # Display the meta Allocation Table sub list { my $ILS_GAP = 500; my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; my $img = $Caseman::vol2path{$vol}; my $offset = $Caseman::vol2start{$vol}; my $imgtype = $Caseman::vol2itype{$vol}; my $min = 0; $min = Args::get_min() if (exists $Args::args{'min'}); my $max = $min + $ILS_GAP - 1; # Because we can not use metas 0 and 1 for most FS, set fmin to the # minimum for this fs my $fmin = $min; $fmin = $Fs::first_meta{$ftype} if ($min < $Fs::first_meta{$ftype}); Print::print_html_header( "$Fs::meta_str{$ftype} Allocation List $fmin -> $max"); Print::log_host_inv( "$Caseman::vol2sname{$vol}: $Fs::meta_str{$ftype} Allocation List for $min to $max" ); print "

$Fs::meta_str{$ftype}: $fmin - $max

"; # Display next and previous links my $tmp; if ($min > $Fs::first_meta{$ftype}) { $tmp = $min - $ILS_GAP; print "" . "\"previous\" "; } $tmp = $min + $ILS_GAP; print " " . "\"next\"
"; print "
\n"; # The list local *OUT; Exec::exec_pipe(*OUT, "'$::TSKDIR/ils' -e -s $Caseman::ts -f $ftype -o $offset -i $imgtype $img $fmin-$max" ); while ($_ = Exec::read_pipe_line(*OUT)) { if (/^($::REG_META)\|([af])\|\d+\|\d+\|\d+\|\d+\|\d+\|/o) { print "" . "$1: "; if ($2 eq "a") { print "allocated
\n"; } else { print "free
\n"; } } } close(OUT); # Display next and previous links print "
\n"; if ($min > $Fs::first_meta{$ftype}) { $tmp = $min - $ILS_GAP; print "" . "\"previous\" "; } $tmp = $min + $ILS_GAP; print " " . "\"next\"
"; print "
\n"; Print::print_html_footer(); return 0; } # Blank Page sub blank { Print::print_html_header("Metadata Blank Page"); my $vol = Args::get_vol('vol'); my $ftype = $Caseman::vol2ftype{$vol}; print "

Metadata Mode


\n" . "Here you can view the details about any $Fs::meta_str{$ftype} in the file system.
\n" . "These are the data structures that store the file details.
\n" . "Enter the address in the field on the left.\n"; Print::print_html_footer(); return 0; }