0)&&($line[0]=="{")) { if (IsSet($result)) $counter = count($result); else $counter = 0; } if ((strlen($line)>4)&&(substr(strtolower($line), 0, 4)=="file")) { //echo "File: ". substr($line, 5) . "\n"; $result[$counter]['file']=substr($line, 5); } if ((strlen($line)>9)&&(substr(strtolower($line), 0, 9)=="extension")) { //echo "Extention: ". substr($line, 10) . "\n"; $result[$counter]['extension']=substr($line, 10); } if ((strlen($line)>4)&&(substr(strtolower($line), 0, 4)=="type")) { //echo "Type: ". substr($line, 5) . "\n"; $result[$counter]['type']=substr($line, 5); } if ((strlen($line)>6)&&(substr(strtolower($line), 0, 6)=="offset")) { //echo "Offset: ". substr($line, 7) . "\n"; $result[$counter]['offset']=substr($line, 7); } if ((strlen($line)>6)&&(substr(strtolower($line), 0, 6)=="header")) { //echo "Header: ". substr($line, 7) . "\n"; $result[$counter]['header']=substr($line, 7); } if ((strlen($line)>6)&&(substr(strtolower($line), 0, 6)=="footer")) { //echo "Footer: ". substr($line, 7) . "\n"; $result[$counter]['footer']=substr($line, 7); } if ((strlen($line)>0)&&($line[0]=="}")) { /*if (IsSet($result)) $counter = count($result); else $counter = 0;*/ } } fclose($handle); return $result; } // Takes the sector map list and tries to add some intelligent file start and termination points. function bytemap($sectormaplist) { // Lower case the header and footer information and strip out unexpected characters foreach ($sectormaplist as &$filetype) { if(IsSet($filetype['header'])) { $filetype['header'] = strtolower($filetype['header']); $filetype['header'] = str_replace(" ", "", $filetype['header']); $filetype['header'] = str_replace("-", "", $filetype['header']); //if (strlen($filetype['header'])>$searchlistmaxlen) // $searchlistmaxlen = (strlen(hex2bin($filetype['header']))); } if(IsSet($filetype['footer'])) { $filetype['footer'] = strtolower($filetype['footer']); $filetype['footer'] = str_replace(" ", "", $filetype['footer']); $filetype['footer'] = str_replace("-", "", $filetype['footer']); //if (strlen($filetype['footer'])>$searchlistmaxlen) // $searchlistmaxlen = (strlen(hex2bin($filetype['footer']))); } } // Lets tie together any simple header/footer alignments of same file type for ($counter = 0; $counter <= count($sectormaplist); $counter++) { // Lets see if this is a index record is a header. if (IsSet($sectormaplist[$counter]['header'])) { $sectormaplist[$counter]['header_offset']=$sectormaplist[$counter]['offset']; unSet($sectormaplist[$counter]['offset']); // This is start of file, so lets see if we can figure out where it ends and define it. if (IsSet($sectormaplist[$counter+1]['header'])) { // The next find is another header, so lets just say this file ends at the offset before. $sectormaplist[$counter]['footer_offset']=(hex2dec($sectormaplist[$counter+1]['offset'])-1); $sectormaplist[$counter]['footer_offset']=(dec2hex($sectormaplist[$counter]['footer_offset'])); } if (IsSet($sectormaplist[$counter+1]['footer'])&&(($sectormaplist[$counter+1]['extension'])==($sectormaplist[$counter]['extension']))) { // The next find is a footer for same file type, so lets say file ends there AT END OF FOOTER. Should check // to make sure the footer is for the same file type eventually. // ** Be sure to add to the end of the footer, otherwise the pointer will be to the beginning of // the footer and not actually include it! ** // //$sectormaplist[$counter]['footer_offset']=($sectormaplist[$counter+1]['offset']); //echo "Adding ". strlen(hex2bin($sectormaplist[$counter+1]['footer'])) . "to footer.\n"; $sectormaplist[$counter]['footer_offset']=dec2hex(hex2dec($sectormaplist[$counter+1]['offset'])+strlen(hex2bin($sectormaplist[$counter+1]['footer']-1))); // Should now clear out the next record since I moved its footer info into this record. unset($sectormaplist[$counter+1]); } } // Set footer_offset only here since no header info but we do have footer info that was not cleared by previous if (IsSet($sectormaplist[$counter]['footer'])) { $sectormaplist[$counter]['footer_offset']=$sectormaplist[$counter]['offset']; unSet($sectormaplist[$counter]['offset']); } } return $sectormaplist; } function hexfind($searchlist, $filename) { $searchlistmaxlen = 0; $filesize = filesize($filename); //HEX Array of positive hits //$result[][] = array()(); echo "þ Processing $filename ...\n"; // Lower case the header and footer information and strip out unexpected characters foreach ($searchlist as &$filetype) { if(IsSet($filetype['header'])) { $filetype['header'] = strtolower($filetype['header']); $filetype['header'] = str_replace(" ", "", $filetype['header']); $filetype['header'] = str_replace("-", "", $filetype['header']); if (strlen($filetype['header'])>$searchlistmaxlen) $searchlistmaxlen = (strlen(hex2bin($filetype['header']))); } if(IsSet($filetype['footer'])) { $filetype['footer'] = strtolower($filetype['footer']); $filetype['footer'] = str_replace(" ", "", $filetype['footer']); $filetype['footer'] = str_replace("-", "", $filetype['footer']); if (strlen($filetype['footer'])>$searchlistmaxlen) $searchlistmaxlen = (strlen(hex2bin($filetype['footer']))); } } // Count through each bit one at a time. for ($start = 0; $start <= $filesize; $start++) { // Jumping ahead to next proper bit place. $handle = fopen($filename, "r"); if($start>0) $contents = fseek($handle, $start); // Read in buffer size that is equal to maximum HEX header size $contents = fread($handle, $searchlistmaxlen); //echo "contents: ".bin2hex($contents) ."\n"; fclose($handle); // Compare each HEX header to the contents in memory. Note some headers are shorter than others. foreach ($searchlist as &$filetype) { //Compare BINARY string to BINARY header. if (IsSet($filetype['header'])) { $tcontents = substr($contents, 0, strlen(hex2bin($filetype['header']))); if ($tcontents==hex2bin($filetype['header'])) { if (DEBUG_MODE) echo "ÿû ". $filetype['type'] ." header(". $filetype['header'] .") found at Offset: ". (dec2hex($start)) ." (". ($start) ." bytes in)\n"; // Add HEX location to $result array if (IsSet($result)) $counter = count($result); else $counter = 0; $result[$counter]['extension']=$filetype['extension']; if (IsSet($filetype['type'])) $result[$counter]['type']=$filetype['type']; $result[$counter]['header']=$filetype['header']; $result[$counter]['offset']=(dec2hex($start)); // Should now jump to end of this buffer header since a confirmed hit $start=($start+strlen($filetype['header'])); } } if (IsSet($filetype['footer'])) { $tcontents = substr($contents, 0, strlen(hex2bin($filetype['footer']))); if ($tcontents==hex2bin($filetype['footer'])) { if (DEBUG_MODE) echo "ÿû ". $filetype['type'] ." footer(". $filetype['footer'] .") found at Offset: ". (dec2hex($start)) ." (". ($start) ." bytes in)\n"; // Add HEX location to $result array if (IsSet($result)) $counter = count($result); else $counter = 0; $result[$counter]['extension']=$filetype['extension']; if (IsSet($filetype['type'])) $result[$counter]['type']=$filetype['type']; $result[$counter]['footer']=$filetype['footer']; $result[$counter]['offset']=(dec2hex($start)); // Should now jump to end of this buffer header since a confirmed hit $start=($start+strlen($filetype['footer'])); } } } } if (isset($result)) return $result; else return 0; } // ***************** MAIN APP *************************** echo "\nTurkeyCarver v.1 - Gobble Gobble\n"; if (DEBUG_MODE) echo " using PHP ". phpversion() . "\n"; if (DEBUG_MODE) { echo 'The number of arguments that were fed: ', $_SERVER['argc'],"\n"; echo 'And those arguments are: '; print_r($_SERVER['argv']); echo "\n\n"; } if (!($_SERVER['argc'] > 1)) { Help(); die("\n\n"); } for ($counter = 0; $counter < count($_SERVER['argv']); $counter++) { if (strtolower($_SERVER['argv'][$counter]) == "-input") $filename = ($_SERVER['argv'][$counter+1]); if (strtolower($_SERVER['argv'][$counter]) == "-report") $log = ($_SERVER['argv'][$counter+1]); if (strtolower($_SERVER['argv'][$counter]) == "-output") $output = ($_SERVER['argv'][$counter+1]); } if (!IsSet($filename)) { Help(); exit; } if (!IsSet($output)) { Help(); exit; } $output = rtrim($output, "\\/"); if (!is_dir(str_replace("\\", "/", $output))) { if (!mkdir(str_replace("\\", "/", $output), 0777)) echo "ERROR Creating directory ". $output ."\n"; } if (!IsSet($log)) { $log = "$output/carveresults.log"; } report($log, $_SERVER['argv'][0]."-input $filename -output $output -report $log"); echo "Output Log: $log\n"; // Read the log file report($log, "Reading $filename"); $offsetlist = readlog($filename); // Put together neatly tied together headers and footers report($log, "Building header/footer list"); $bytemaplist = bytemap($offsetlist); // Need to purge empty records here and resort array without empty records. Note that the array still has listings of footers // without any actual headers. This needs to be fixed if we really want to be able to carve. /* // Show output of array foreach ($bytemaplist as &$hit) { if (IsSet($hit['file'])) echo "Source Filename: ". $hit['file'] ."\n"; if (IsSet($hit['extension'])) echo "File extension: ". $hit['extension'] ."\n"; if (IsSet($hit['type'])) echo "Desc: ". $hit['type'] ."\n"; if (IsSet($hit['header_offset'])) echo "Header Offset: ". $hit['header_offset'] ."(". hex2dec($hit['header_offset']) ." bits in)\n"; if (IsSet($hit['footer_offset'])) echo "Footer Offset: ". $hit['footer_offset'] ."(". hex2dec($hit['footer_offset']) ." bits in)\n"; if (IsSet($hit['offset'])) echo "Offset: ". $hit['offset'] ."(". hex2dec($hit['offset']) ." bits in)\n"; echo "\n"; } */ // Start carving turkey report($log, "Starting file carving process"); foreach ($bytemaplist as &$hit) { // Create root directory to dump data into. if (!is_dir(str_replace("\\", "/", $output))) { if (!mkdir(str_replace("\\", "/", $output), 0777)) echo "ERROR Creating directory ". $output ."\n"; } if (IsSet($hit['extension'])) { if (!is_dir(str_replace("\\", "/", $output) ."/". $hit['extension'])) { if (!mkdir(str_replace("\\", "/", $output) . "/". $hit['extension'], 0777)) echo "ERROR Creating directory $output\\". $hit['extension'] ."\n"; } } if ((IsSet($hit['header_offset']))&&(IsSet($hit['footer_offset']))) { if(is_file((str_replace("\\", "/", $output). $hit['extension'] ."/". $hit['header_offset'] . ".". $hit['extension']))) rename((str_replace("\\", "/", $output). $hit['extension'] ."/". $hit['header_offset'] . ".". $hit['extension']), (str_replace("\\", "/", $output). $hit['extension'] ."/". $hit['header_offset'] . ".2")); report($log, "Creating ". str_replace("\\", "/", $output) ."/". $hit['extension'] ."/". $hit['header_offset'] .".". $hit['extension']); $handle = fopen(str_replace("\\", "/", $output) ."/". $hit['extension'] ."/". $hit['header_offset'] .".". $hit['extension'], "w"); // Output to $handle all the data in file $hit[file] between $hit[header_offset] and $hit[footer_offset] $source = fopen($hit['file'], "r"); $contents = fseek($source, hex2dec($hit['header_offset'])); while (ftell($source)<=hex2dec($hit['footer_offset'])) { $contents = fread($source, 1); if (fwrite($handle, $contents) === FALSE) echo ("Cannot write to file ". str_replace("\\", "/", $output) ."/". $hit['extension'] ."/". $hit['header_offset'] . ".". $hit['extension'] ."\n"); } report($log, "Extracting ". $hit['extension'] ." file from ". $hit['file'] ." (Start Offset: ". $hit['header_offset'] ." / End Offset: ". $hit['footer_offset'] .")"); fclose($handle); fclose($source); } if (IsSet($log)) report($log, " Completed."); } /* 6-11: Added report function, as well as $_SERVER['argv'][0]. */ ?>