1# 2# Sort files based on their application type (content) 3# 4# Brian Carrier [carrier@sleuthkit.org] 5# Copyright (c) 2001-2008 by Brian Carrier. All rights reserved 6# 7# This file is part of the Autopsy Forensic Browser (Autopsy) 8# 9# Autopsy is free software; you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation; either version 2 of the License, or 12# (at your option) any later version. 13# 14# Autopsy is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with Autopsy; if not, write to the Free Software 21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22# 23# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 24# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 25# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. 26# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR 29# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 34package Appsort; 35 36$Appsort::FRAME = 1; 37$Appsort::MENU = 2; 38$Appsort::ENTER = 3; 39$Appsort::RUN = 4; 40$Appsort::VIEW = 5; 41$Appsort::BLANK = 6; 42 43sub main { 44 45 if ($::LIVE == 1) { 46 Print::print_html_header("Unsupported for Live Analysis"); 47 print 48"<center><h2>This feature is not available during a live analysis</h2></center>"; 49 Print::print_html_footer(); 50 return 0; 51 } 52 53 # By default, show the main frame 54 $Args::args{'view'} = $Args::enc_args{'view'} = $Appsort::FRAME 55 unless (exists $Args::args{'view'}); 56 57 Args::check_view(); 58 my $view = Args::get_view(); 59 60 if ($view == $Appsort::BLANK) { 61 return blank(); 62 } 63 64 # Check Basic Args 65 Args::check_vol('vol'); 66 67 # These windows don't need the meta data address 68 if ($view == $Appsort::FRAME) { 69 return frame(); 70 } 71 elsif ($view == $Appsort::ENTER) { 72 return enter(); 73 } 74 elsif ($view == $Appsort::MENU) { 75 return menu(); 76 } 77 elsif ($view == $Appsort::RUN) { 78 return run(); 79 } 80 elsif ($view == $Appsort::VIEW) { 81 return view(); 82 } 83 else { 84 Print::print_check_err("Invalid Application Sorting View"); 85 } 86} 87 88sub get_sorter_dir { 89 if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) { 90 return "$::host_dir" . "$::DATADIR/sorter-$1/"; 91 } 92 Print::print_err("Invalid Sorter Directory"); 93} 94 95sub get_sorter_graphics_dir { 96 if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) { 97 return "$::host_dir" . "$::DATADIR/sorter-graphics-$1/"; 98 } 99 Print::print_err("Invalid Sorter Graphics Directory"); 100} 101 102# sorter frameset 103sub frame { 104 Print::print_html_header_frameset("Sorter on $Args::args{'vol'}"); 105 106 print "<frameset cols=\"20%,80%\">\n"; 107 108 # Block List 109 print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::MENU&" 110 . "$Args::baseargs\">\n"; 111 112 # Blank 113 print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::BLANK&" 114 . "$Args::baseargs\" name=\"content\">\n" 115 . "</frameset>\n"; 116 117 Print::print_html_footer_frameset(); 118 return 0; 119} 120 121# The left-hand frame for running sorter 122sub menu { 123 Print::print_html_header("sorter menu"); 124 125 print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::ENTER&" 126 . "$Args::baseargs\" " 127 . "target=\"content\">Sort Files by Type</a>"; 128 129 print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::VIEW&" 130 . "$Args::baseargs\" " 131 . "target=\"content\">View Sorted Files</a>"; 132 133 Print::print_html_footer(); 134 return 0; 135} 136 137# Get the data and print the form so that sorter can be run 138sub enter { 139 Print::print_html_header("sorter - enter data to create"); 140 141 print "<center>" 142 . "<h3>File Type Sortings</h3></center><br>" 143 . "<form action=\"$::PROGNAME\" method=\"get\">\n" 144 . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_APPSORT\">\n" 145 . "<input type=\"hidden\" name=\"view\" value=\"$Appsort::RUN\">\n" 146 . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n" 147 . Args::make_hidden(); 148 149 print <<EOF1; 150<p>The <b>sorter</b> tool will process an image and organize the 151files based on their file type. The files are organized into categories 152that are defined in configuration files. The categories will be saved 153in the <tt>$::DATADIR</tt> directory. 154<hr> 155EOF1 156 157 my $sort_dir = get_sorter_dir(); 158 if (-d "$sort_dir") { 159 print "WARNING: This will overwrite any existing data in:<br>" 160 . " <tt>$sort_dir</tt><br>\n"; 161 } 162 163 my $tab = " "; 164 165 print <<EOF2; 166 167<p> 168<input type=\"checkbox\" name=\"sorter_cat\" value=\"1\" CHECKED> 169Sort files into categories by type 170 171 <p>$tab 172 <input type=\"checkbox\" name=\"sorter_unk\" value=\"1\"> 173 Do not save data about <tt>unknown</tt> file types 174 175 <p>$tab 176 <input type=\"checkbox\" name=\"sorter_save\" value=\"1\"> 177 Save a copy of files in category directory (may require lots of disk space) 178 179 <p>$tab 180 <input type=\"checkbox\" name=\"sorter_img\" value=\"1\"> 181 Save ONLY graphic images and make thumbnails <br> 182 $tab (may require lots of disk space and will save to a different directory than sorting all file types) 183 184<p> 185<input type=\"checkbox\" name=\"sorter_ext\" value=\"1\" CHECKED> 186Extension and File Type Validation 187 188EOF2 189 190 if (($::NSRLDB ne "") && (-e "$::NSRLDB")) { 191 192 # NSRL 193 print 194"<p><input type=\"checkbox\" name=\"sorter_nsrl\" value=\"1\" CHECKED>" 195 . "Exclude files in the <b>NIST NSRL</b>\n"; 196 } 197 198 if (($Caseman::alert_db ne "") && (-e "$Caseman::alert_db")) { 199 print 200"<p><input type=\"checkbox\" name=\"sorter_alert\" value=\"1\" CHECKED>" 201 . "Alert files that are found in the <b>Alert Hash Database</b>\n"; 202 } 203 204 if (($Caseman::exclude_db ne "") && (-e "$Caseman::exclude_db")) { 205 print 206"<p><input type=\"checkbox\" name=\"sorter_exclude\" value=\"1\" CHECKED>" 207 . "Ignore files that are found in the <b>Exclude Hash Database</b>\n"; 208 } 209 210 print "<p><input type=\"image\" src=\"pict/but_ok.jpg\" " 211 . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n"; 212 213 Print::print_html_footer(); 214 return; 215} 216 217# Run sorter on the image 218sub run { 219 Print::print_html_header("sorter - create"); 220 221 my $sort_args = ""; 222 my $ext = 0; 223 my $cat = 0; 224 225 my $vol = Args::get_vol('vol'); 226 my $mnt = $Caseman::vol2mnt{$vol}; 227 228 my $ftype = $Caseman::vol2ftype{$vol}; 229 my $img = $Caseman::vol2path{$vol}; 230 my $offset = $Caseman::vol2start{$vol}; 231 my $imgtype = $Caseman::vol2itype{$vol}; 232 233 Print::log_host_inv("Running 'sorter' on ($Caseman::vol2sname{$vol}"); 234 235 $ext = 1 236 if ( (exists $Args::args{'sorter_ext'}) 237 && ($Args::args{'sorter_ext'} == 1)); 238 $cat = 1 239 if ( (exists $Args::args{'sorter_cat'}) 240 && ($Args::args{'sorter_cat'} == 1)); 241 242 if (($cat == 0) && ($ext == 0)) { 243 print "At least one action must be selected\n" 244 . "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&" 245 . "view=$Appsort::ENTER&$Args::baseargs\">" 246 . "<img border=0 src=\"pict/but_ok.jpg\" alt=\"Ok\" " 247 . "width=43 height=20></a>\n"; 248 249 return; 250 } 251 252 # If both actions are wanted then no flags are needed 253 $sort_args .= "-e " if (($ext == 1) && ($cat == 0)); 254 $sort_args .= "-E " if (($ext == 0) && ($cat == 1)); 255 256 my $sort_dir = get_sorter_dir(); 257 258 if ($cat == 1) { 259 if ( (exists $Args::args{'sorter_img'}) 260 && ($Args::args{'sorter_img'} == 1)) 261 { 262 my $config = "$::TSKDIR/../share/tsk3/sorter/images.sort"; 263 264 Print::print_err("images configuration file not found ($config)") 265 unless (-e "$config"); 266 267 $sort_args .= "-C \'$config\' -s -U "; 268 269 $sort_dir = get_sorter_graphics_dir(); 270 271 } 272 else { 273 $sort_args .= "-s " 274 if ( (exists $Args::args{'sorter_save'}) 275 && ($Args::args{'sorter_save'} == 1)); 276 277 $sort_args .= "-U " 278 if ( (exists $Args::args{'sorter_unk'}) 279 && ($Args::args{'sorter_unk'} == 1)); 280 } 281 } 282 283 if ($::NSRLDB ne "") { 284 $sort_args .= "-n \'$::NSRLDB\' " 285 if ( (exists $Args::args{'sorter_nsrl'}) 286 && ($Args::args{'sorter_nsrl'} == 1)); 287 } 288 289 if ($Caseman::alert_db ne "") { 290 $sort_args .= "-a \'$Caseman::alert_db\' " 291 if ( (exists $Args::args{'sorter_alert'}) 292 && ($Args::args{'sorter_alert'} == 1)); 293 } 294 295 if ($Caseman::exclude_db ne "") { 296 $sort_args .= "-x \'$Caseman::exclude_db\' " 297 if ( (exists $Args::args{'sorter_exclude'}) 298 && ($Args::args{'sorter_exclude'} == 1)); 299 } 300 301 unless (-d "$sort_dir") { 302 unless (mkdir "$sort_dir", $::MKDIR_MASK) { 303 Print::print_err("Error making $sort_dir"); 304 } 305 } 306 if (-e "$sort_dir/index.html") { 307 unlink("$sort_dir/index.html"); 308 } 309 310 my $exec = 311"-h -m '$mnt' -d '$sort_dir' -o $offset -i $imgtype -f $ftype $sort_args $img"; 312 313 # print "Executing: <tt>sorter $exec</tt><p>\n"; 314 315 # Execute Sorter 316 my $hit_cnt = 0; 317 $SIG{ALRM} = sub { 318 if (($hit_cnt++ % 5) == 0) { 319 print "+"; 320 } 321 else { 322 print "-"; 323 } 324 alarm(5); 325 }; 326 alarm(5); 327 328 local *OUT; 329 Exec::exec_pipe(*OUT, "LANG=C LC_ALL=C '$::TSKDIR/sorter' $exec"); 330 alarm(0); 331 $SIG{ALRM} = 'DEFAULT'; 332 333 while ($_ = Exec::read_pipe_line(*OUT)) { 334 print "$_<br>\n"; 335 $hit_cnt = 0; 336 } 337 338 close(OUT); 339 340 if (-e "$sort_dir/index.html") { 341 print "<p>Output can be found by viewing:<br>" 342 . " <tt>$sort_dir/index.html</tt><p>\n"; 343 344 # Print the index.html file from the output 345 print "<hr><center><h3>Results Summary</h3></center>\n"; 346 open INDEX, "<$sort_dir/index.html" 347 or die "Can't open sorter index file ($sort_dir/index.html)"; 348 349 while (<INDEX>) { 350 next if ((/^<HTML><HEAD><TITLE>/i) 351 || (/^<BODY><center><H2>/i)); 352 353 # Extract out the symlinks to the categories 354 if (/^\s*<li><a href="\.\/[\w\.]+">([\w\s]+)<\/a> \((\d+)\)\s*$/i) { 355 print "<LI>$1 ($2)\n"; 356 } 357 358 # Skip the link on the thumbnails link 359 elsif (/^\s*\(<a href=[\"\.\/\w]+>thumbnails<\/A>\)\s*$/) { 360 print "(thumbnails)\n"; 361 } 362 else { 363 print "$_"; 364 } 365 } 366 close(INDEX); 367 } 368 369 Print::print_html_footer(); 370 return; 371} 372 373# View Page 374sub view { 375 Print::print_html_header(""); 376 print "<center><h3>File Type Sorting</h3>\n" 377 . "Autopsy does not currently support viewing the sorted files.<br>\n" 378 . "After sorting, you can view the results by opening the following file:<p>\n"; 379 print "<tt>" . get_sorter_dir() . "index.html</tt>"; 380 381 Print::print_html_footer(); 382 return 0; 383} 384 385# Blank Page 386sub blank { 387 Print::print_html_header(""); 388 print "<center><h3>File Type Sorting</h3>\n" 389 . "In this mode, Autopsy will examine allocated and unallocated files<br> and " 390 . "sort them into categories and verify the extension.<p>This allows you to find a file based on" 391 . "its type and find \"hidden\" files.<p>\n" 392 . 393 394 "WARNING: This can be a time intensive process.<br>\n"; 395 396 Print::print_html_footer(); 397 return 0; 398} 399 400