Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions RecentActivity/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<copy todir="${basedir}/release/markmckinnon/" >
<fileset dir="${thirdparty.dir}/markmckinnon/" />
</copy>
<copy todir="${basedir}/release/thumbcache_parser/" >
<fileset dir="${thirdparty.dir}/thumbcache_parser/" />
</copy>
</target>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ cannotParseXml=Unable to parse XML file:
ChromeCacheExtract_adding_artifacts_msg=Chrome Cache: Adding %d artifacts for analysis.
ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis.
ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s.
# {0} - module name
# {1} - row number
# {2} - table length
# {3} - cache path
ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3}
DataSourceUsage_AndroidMedia=Android Media Card
DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card
DataSourceUsage_FlashDrive=Flash Drive
# {0} - OS name
DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0})
DataSourceUsageAnalyzer.displayName=Data Source Usage Analyzer
DefaultPriorityDomainCategorizer_searchEngineCategory=Search Engine
Expand All @@ -26,7 +21,6 @@ ExtractEdge_process_errMsg_spartanFail=Failure processing Microsoft Edge spartan
ExtractEdge_process_errMsg_unableFindESEViewer=Unable to find ESEDatabaseViewer
ExtractEdge_process_errMsg_webcacheFail=Failure processing Microsoft Edge WebCacheV01.dat file
ExtractFavicon_Display_Name=Favicon
# {0} - sub module name
ExtractIE_executePasco_errMsg_errorRunningPasco={0}: Error analyzing Internet Explorer web history
ExtractOs.androidOs.label=Android
ExtractOs.androidVolume.label=OS Drive (Android)
Expand Down Expand Up @@ -59,7 +53,6 @@ ExtractOs.windowsVolume.label=OS Drive (Windows)
ExtractOs.yellowDogLinuxOs.label=Linux (Yellow Dog)
ExtractOs.yellowDogLinuxVolume.label=OS Drive (Linux Yellow Dog)
ExtractOS_progressMessage=Checking for OS
# {0} - sub module name
ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files
ExtractPrefetch_module_name=Windows Prefetch Analyzer
ExtractRecycleBin_module_name=Recycle Bin Analyzer
Expand All @@ -75,6 +68,8 @@ ExtractSru_process_errormsg_find_software_hive=Unable to find SOFTWARE HIVE file
ExtractSru_process_errormsg_find_srudb_dat=Unable to find srudb.dat file
ExtractSru_process_errormsg_write_software_hive=Unable to write SOFTWARE HIVE file
ExtractSru_process_errormsg_write_srudb_dat=Unable to write srudb.dat file
ExtractThumbcache_error_finding_program=Could not find thumbcache_viewer_cmd.exe program
ExtractThumbcache_module_name=Thumbcache Analyzer
ExtractWebAccountType.role.admin=Administrator role
ExtractWebAccountType.role.moderator=Moderator role
ExtractWebAccountType.role.user=User role
Expand Down Expand Up @@ -170,21 +165,15 @@ Firefox.getDlV24.errMsg.errAnalyzeFile={0}: Error while trying to analyze file:{
Firefox.getDlV24.errMsg.errParsingArtifacts={0}: Error parsing {1} Firefox web download artifacts.
Progress_Message_Analyze_Registry=Analyzing Registry Files
Progress_Message_Analyze_Usage=Data Sources Usage Analysis
# {0} - browserName
Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}
# {0} - browserName
Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}
Progress_Message_Chrome_Cache=Chrome Cache
# {0} - browserName
Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}
# {0} - browserName
Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}
Progress_Message_Chrome_Extensions=Chrome Extensions {0}
Progress_Message_Chrome_Favicons=Chrome Downloads Favicons {0}
Progress_Message_Chrome_FormHistory=Chrome Form History
# {0} - browserName
Progress_Message_Chrome_History=Chrome History Browser {0}
# {0} - browserName
Progress_Message_Chrome_Logins=Chrome Logins Browser {0}
Progress_Message_Chrome_Profiles=Chrome Profiles {0}
Progress_Message_Edge_Bookmarks=Microsoft Edge Bookmarks
Expand Down Expand Up @@ -247,7 +236,6 @@ Sam_Security_Answer_3_Attribute_Display_Name=Security Answer 3
Sam_Security_Question_1_Attribute_Display_Name=Security Question 1
Sam_Security_Question_2_Attribute_Display_Name=Security Question 2
Sam_Security_Question_3_Attribute_Display_Name=Security Question 3
# {0} - file name
SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}.
SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine Query Analyzer
SearchEngineURLQueryAnalyzer.engineName.none=NONE
Expand All @@ -260,4 +248,6 @@ ExtractWebAccountType.parentModuleName=Recent Activity
Shellbag_Artifact_Display_Name=Shell Bags
Shellbag_Key_Attribute_Display_Name=Key
Shellbag_Last_Write_Attribute_Display_Name=Last Write
Thumbcache_Files_Not_Found=Thumbcache files not found
Thumbcache_process_error_executing_export_thumbcache_program=Error running thumbcache program
UsbDeviceIdMapper.parseAndLookup.text=Product: {0}
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2020-2025 Sleuth Kit Labs.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.recentactivity;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.commons.io.FileUtils;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;

/**
* Extract the thumbcache files to a temp directory so it can be
* parsed and added as a derived file(s)
*/
final class ExtractThumbcache extends Extract {

private static final Logger logger = Logger.getLogger(ExtractThumbcache.class.getName());

private static final String THUMBCACHE_TOOL_FOLDER = "thumbcache_parser"; //NON-NLS
private static final String THUMBCACHE_TOOL_NAME_WINDOWS = "thumbcache_viewer_cmd.exe"; //NON-NLS
private static final String THUMBCACHE_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS
private static final String THUMBCACHE_ERROR_FILE_NAME = "Error.txt"; //NON-NLS

private final IngestJobContext context;

@Messages({"ExtractThumbcache_module_name=Thumbcache Analyzer"})

ExtractThumbcache(IngestJobContext context) {
super(Bundle.ExtractThumbcache_module_name(), context);
this.context = context;
}

@Messages({
"Thumbcache_Files_Not_Found=Thumbcache files not found",
"ExtractThumbcache_error_finding_program=Could not find thumbcache_viewer_cmd.exe program",
"Thumbcache_process_error_executing_export_thumbcache_program=Error running thumbcache program"
})

@Override
void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {

if (!PlatformUtil.isWindowsOS()) {
logger.log(Level.WARNING,"Thumbcache only Supported on Windows Plaatform."); //NON-NLS
return; // No need to continue
}

String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + "thumbcache";
File dir = new File(modOutPath);
if (dir.exists() == false) {
dir.mkdirs();
}

String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "thumbcache", context.getJobId()); //NON-NLS
List<AbstractFile> thumbcacheFiles = getThumbcacheFiles(dataSource, tempDirPath);
if (thumbcacheFiles == null) {
this.addErrorMessage(Bundle.Thumbcache_Files_Not_Found());
logger.log(Level.SEVERE, "Error finding thumbcache files"); //NON-NLS
return; //If we cannot find the thumbcache files we cannot proceed

}
final String thumbcacheDumper = getPathForThumbcacheDumper();
if (thumbcacheDumper == null) {
this.addErrorMessage(Bundle.ExtractThumbcache_error_finding_program());
logger.log(Level.SEVERE, "Error finding thumbcache parsing program"); //NON-NLS
return; //If we cannot find the usbParser program we cannot proceed
}

if (context.dataSourceIngestIsCancelled()) {
return;
}
String thumbcacheFileLocation = null;
for (AbstractFile thumbcacheFile: thumbcacheFiles) {
try {
File thumbcacheFileName = new File(tempDirPath + File.separator + thumbcacheFile.getId() + "_" + thumbcacheFile.getName());
if (thumbcacheFileName.exists()) {
String modOutFile = modOutPath + File.separator + thumbcacheFile.getId() + "_" +thumbcacheFile.getName();
thumbcacheFileLocation = tempDirPath + File.separator + thumbcacheFile.getId() + "_" + thumbcacheFile.getName();

dir = new File(modOutFile);
if (dir.exists() == false) {
dir.mkdirs();
}

extractThumbcacheFiles(thumbcacheDumper, modOutFile, thumbcacheFileLocation);
addThumbcacheDerivedFiles(modOutFile, thumbcacheFile);
}
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error processing thumbcache file %s", thumbcacheFile.getId() + "_" + thumbcacheFile.getName()), ex); //NON-NLS=
}
}
}

/**
* Extract the thumbcache file to the temp directory
*
* @param dataSource datasource where software hive is
* @param tempDirPath temp directory to write file to
* *
* @return hive file location
*/
List<AbstractFile> getThumbcacheFiles(Content dataSource, String tempDirPath) {
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();

List<AbstractFile> thumbcacheFiles;

try {
thumbcacheFiles = fileManager.findFiles(dataSource, "thumbcache_%.db", ""); //NON-NLS
} catch (TskCoreException ex) {
logger.log(Level.WARNING,"Unable to find thumbcache files.", ex); //NON-NLS
return null; // No need to continue
}

for (AbstractFile thumbcacheFile : thumbcacheFiles) {
String thumbcacheFileName = tempDirPath + File.separator + thumbcacheFile.getId() + "_" + thumbcacheFile.getName();

try {
ContentUtils.writeToFile(thumbcacheFile, new File(thumbcacheFileName));
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", thumbcacheFile.getName(), thumbcacheFile), ex); //NON-NLS
}
}

return thumbcacheFiles;
}

/**
* Run the thumbcache parser cmd program
*
* @param thumbcacheExePath - Eecutable for the thumbcache program
* @param thumbcacheFilePath - output directory for program
* @param tempOutPath - file to parse
*
* @throws FileNotFoundException
* @throws IOException
*/
void extractThumbcacheFiles(String thumbcacheExePath, String thumbcacheFilePath, String thumbcacheFile) throws IOException {
final Path outputFilePath = Paths.get(thumbcacheFilePath, THUMBCACHE_OUTPUT_FILE_NAME);
final Path errFilePath = Paths.get(thumbcacheFilePath, THUMBCACHE_ERROR_FILE_NAME);


List<String> commandLine = new ArrayList<>();
commandLine.add(thumbcacheExePath);
commandLine.add("-O"); //NON-NLS
commandLine.add(thumbcacheFilePath);
commandLine.add(thumbcacheFile);


ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
processBuilder.redirectOutput(outputFilePath.toFile());
processBuilder.redirectError(errFilePath.toFile());

ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
}

private String getPathForThumbcacheDumper() {
Path path = Paths.get(THUMBCACHE_TOOL_FOLDER, THUMBCACHE_TOOL_NAME_WINDOWS);
File thumbcacheToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
ExtractThumbcache.class.getPackage().getName(), false);
if (thumbcacheToolFile != null) {
return thumbcacheToolFile.getAbsolutePath();
}

return null;
}

private void addThumbcacheDerivedFiles(String outputFolder, AbstractFile thumbcacheFile) {
Path outputFolderPath = Paths.get(outputFolder);
List<File> files = (List<File>) FileUtils.listFiles(outputFolderPath.toFile(), null, true);
for (File file : files) {
if (context.dataSourceIngestIsCancelled()) {
return;
}

Path candidate = file.toPath();

if (candidate.getFileName().toString().equals("Error.txt") || candidate.getFileName().toString().equals("Output.txt")) {
continue;
}
try {
final Path caseDirectory = Paths.get(Case.getCurrentCaseThrows().getCaseDirectory());
final BasicFileAttributes attrs = Files.readAttributes(candidate, BasicFileAttributes.class);
final Path localCasePath = caseDirectory.relativize(candidate);

final DerivedFile tcacheFile = Case.getCurrentCaseThrows().getSleuthkitCase()
.addDerivedFile(candidate.getFileName().toString(),
localCasePath.toString(), attrs.size(), 0L,
attrs.creationTime().to(TimeUnit.SECONDS),
attrs.lastAccessTime().to(TimeUnit.SECONDS),
attrs.lastModifiedTime().to(TimeUnit.SECONDS),
attrs.isRegularFile(), thumbcacheFile, "",
"", "", "", TskData.EncodingType.NONE);

context.addFilesToJob(Arrays.asList(tcacheFile));
IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(tcacheFile));
} catch (IOException ex) {
logger.log(Level.WARNING, "I/O error encountered during thumbcache processing.", ex);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Unable to add thumbcache as derived files.", ex);
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "No open case!", ex);

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public void startUp(IngestJobContext context) throws IngestModuleException {
Extract webAccountType = new ExtractWebAccountType(context);
Extract messageDomainType = new DomainCategoryRunner(context);
Extract jumpList = new ExtractJumpLists(context);
Extract thumbcache = new ExtractThumbcache(context);

extractors.add(recycleBin);
extractors.add(jumpList);
Expand All @@ -98,6 +99,7 @@ public void startUp(IngestJobContext context) throws IngestModuleException {
extractors.add(zoneInfo); // this needs to run after the web browser modules
extractors.add(sru);
extractors.add(prefetch);
extractors.add(thumbcache);
extractors.add(messageDomainType);

browserExtractors.add(chrome);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ExtractThumbcache_module_name=Thumbcache Analyzer
Thumbcache_Files_Not_Found=Thumbcache files not found
Thumbcache_process_error_executing_export_thumbcache_program=Error running thumbcache program
Binary file not shown.