19package org.sleuthkit.autopsy.recentactivity;
22import java.io.FileNotFoundException;
23import java.io.IOException;
24import java.nio.file.Files;
25import java.nio.file.Path;
26import java.nio.file.Paths;
27import java.nio.file.attribute.BasicFileAttributes;
28import java.util.ArrayList;
29import java.util.Arrays;
31import java.util.concurrent.TimeUnit;
32import java.util.logging.Level;
33import org.apache.commons.io.FileUtils;
34import org.openide.modules.InstalledFileLocator;
35import org.openide.util.NbBundle.Messages;
36import org.sleuthkit.autopsy.casemodule.Case;
37import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
38import org.sleuthkit.autopsy.casemodule.services.FileManager;
39import org.sleuthkit.autopsy.coreutils.ExecUtil;
40import org.sleuthkit.autopsy.coreutils.Logger;
41import org.sleuthkit.autopsy.coreutils.PlatformUtil;
42import org.sleuthkit.autopsy.datamodel.ContentUtils;
43import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
44import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
45import org.sleuthkit.autopsy.ingest.IngestJobContext;
46import org.sleuthkit.autopsy.ingest.IngestServices;
47import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
48import org.sleuthkit.datamodel.AbstractFile;
49import org.sleuthkit.datamodel.Content;
50import org.sleuthkit.datamodel.DerivedFile;
51import org.sleuthkit.datamodel.TskCoreException;
52import org.sleuthkit.datamodel.TskData;
58final class ExtractThumbcache
extends Extract {
60 private static final Logger logger = Logger.getLogger(ExtractThumbcache.class.getName());
62 private static final String THUMBCACHE_TOOL_FOLDER =
"thumbcache_parser";
63 private static final String THUMBCACHE_TOOL_NAME_WINDOWS =
"thumbcache_viewer_cmd.exe";
64 private static final String THUMBCACHE_OUTPUT_FILE_NAME =
"Output.txt";
65 private static final String THUMBCACHE_ERROR_FILE_NAME =
"Error.txt";
67 private final IngestJobContext context;
69 @Messages({
"ExtractThumbcache_module_name=Thumbcache Analyzer"})
71 ExtractThumbcache(IngestJobContext context) {
72 super(Bundle.ExtractThumbcache_module_name(), context);
73 this.context = context;
77 "Thumbcache_Files_Not_Found=Thumbcache files not found",
78 "ExtractThumbcache_error_finding_program=Could not find thumbcache_viewer_cmd.exe program",
79 "Thumbcache_process_error_executing_export_thumbcache_program=Error running thumbcache program",
80 "Thumbcache_Files_TSK_Error=TSK error searching for thumbcache files"
84 void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
86 if (!PlatformUtil.isWindowsOS()) {
87 logger.log(Level.WARNING,
"Thumbcache only Supported on Windows Platform.");
91 String modOutPath = RAImageIngestModule.getRAOutputPath(Case.getCurrentCase(),
"thumbcache", context.getJobId());
92 File dir =
new File(modOutPath);
93 if (dir.exists() ==
false) {
97 String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(),
"thumbcache", context.getJobId());
98 List<AbstractFile> thumbcacheFiles = getThumbcacheFiles(dataSource, tempDirPath);
99 if (thumbcacheFiles ==
null) {
100 this.addErrorMessage(Bundle.Thumbcache_Files_TSK_Error());
104 if (thumbcacheFiles.isEmpty()) {
105 logger.log(Level.WARNING,
"Error finding thumbcache files");
109 final String thumbcacheDumper = getPathForThumbcacheDumper();
110 if (thumbcacheDumper ==
null) {
111 this.addErrorMessage(Bundle.ExtractThumbcache_error_finding_program());
112 logger.log(Level.WARNING,
"Error finding thumbcache parsing program");
116 if (context.dataSourceIngestIsCancelled()) {
120 String thumbcacheFileLocation =
null;
121 for (AbstractFile thumbcacheFile: thumbcacheFiles) {
122 if (context.dataSourceIngestIsCancelled()) {
126 File thumbcacheFileName =
new File(tempDirPath + File.separator + thumbcacheFile.getId() +
"_" + thumbcacheFile.getName());
127 if (thumbcacheFileName.exists()) {
128 String modOutFile = modOutPath + File.separator + thumbcacheFile.getId() +
"_" +thumbcacheFile.getName();
129 thumbcacheFileLocation = tempDirPath + File.separator + thumbcacheFile.getId() +
"_" + thumbcacheFile.getName();
131 dir =
new File(modOutFile);
132 if (dir.exists() ==
false) {
136 extractThumbcacheFiles(thumbcacheDumper, modOutFile, thumbcacheFileLocation);
137 addThumbcacheDerivedFiles(modOutFile, thumbcacheFile);
139 }
catch (IOException ex) {
140 logger.log(Level.SEVERE, String.format(
"Error processing thumbcache file %s", thumbcacheFile.getId() +
"_" + thumbcacheFile.getName()), ex);
153 List<AbstractFile> getThumbcacheFiles(Content dataSource, String tempDirPath) {
154 FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
156 List<AbstractFile> thumbcacheFiles;
159 thumbcacheFiles = fileManager.findFiles(dataSource,
"thumbcache_%.db",
"");
160 }
catch (TskCoreException ex) {
161 logger.log(Level.SEVERE,
"TskCoreException Looking for thumbcache file.", ex);
165 if (thumbcacheFiles.isEmpty()) {
166 return new ArrayList<>();
169 for (AbstractFile thumbcacheFile : thumbcacheFiles) {
170 String thumbcacheFileName = tempDirPath + File.separator + thumbcacheFile.getId() +
"_" + thumbcacheFile.getName();
173 ContentUtils.writeToFile(thumbcacheFile,
new File(thumbcacheFileName));
174 }
catch (IOException ex) {
175 logger.log(Level.WARNING, String.format(
"Unable to write %s to temp directory. File name: %s", thumbcacheFile.getName(), thumbcacheFile), ex);
179 return thumbcacheFiles;
192 void extractThumbcacheFiles(String thumbcacheExePath, String thumbcacheFilePath, String thumbcacheFile)
throws IOException {
193 final Path outputFilePath = Paths.get(thumbcacheFilePath, THUMBCACHE_OUTPUT_FILE_NAME);
194 final Path errFilePath = Paths.get(thumbcacheFilePath, THUMBCACHE_ERROR_FILE_NAME);
197 List<String> commandLine =
new ArrayList<>();
198 commandLine.add(thumbcacheExePath);
199 commandLine.add(
"-O");
200 commandLine.add(thumbcacheFilePath);
201 commandLine.add(thumbcacheFile);
204 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
205 processBuilder.redirectOutput(outputFilePath.toFile());
206 processBuilder.redirectError(errFilePath.toFile());
208 ExecUtil.execute(processBuilder,
new DataSourceIngestModuleProcessTerminator(context,
true));
211 private String getPathForThumbcacheDumper() {
212 Path path = Paths.get(THUMBCACHE_TOOL_FOLDER, THUMBCACHE_TOOL_NAME_WINDOWS);
213 File thumbcacheToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
214 ExtractThumbcache.class.getPackage().getName(),
false);
215 if (thumbcacheToolFile !=
null) {
216 return thumbcacheToolFile.getAbsolutePath();
222 private void addThumbcacheDerivedFiles(String outputFolder, AbstractFile thumbcacheFile) {
223 Path outputFolderPath = Paths.get(outputFolder);
224 java.util.Collection<File> files = (List<File>) FileUtils.listFiles(outputFolderPath.toFile(),
null,
true);
225 for (File file : files) {
226 if (context.dataSourceIngestIsCancelled()) {
230 Path candidate = file.toPath();
232 if (candidate.getFileName().toString().equals(THUMBCACHE_ERROR_FILE_NAME) || candidate.getFileName().toString().equals(THUMBCACHE_OUTPUT_FILE_NAME)) {
236 final Case currentCase = Case.getCurrentCaseThrows();
237 final Path caseDirectory = Paths.get(currentCase.getCaseDirectory());
238 final BasicFileAttributes attrs = Files.readAttributes(candidate, BasicFileAttributes.class);
239 final Path localCasePath = caseDirectory.relativize(candidate);
241 final DerivedFile tcacheFile = currentCase.getSleuthkitCase()
242 .addDerivedFile(candidate.getFileName().toString(),
243 localCasePath.toString(), attrs.size(), 0L,
244 attrs.creationTime().to(TimeUnit.SECONDS),
245 attrs.lastAccessTime().to(TimeUnit.SECONDS),
246 attrs.lastModifiedTime().to(TimeUnit.SECONDS),
247 attrs.isRegularFile(), thumbcacheFile,
"",
248 "",
"",
"", TskData.EncodingType.NONE);
250 context.addFilesToJob(Arrays.asList(tcacheFile));
251 IngestServices.getInstance().fireModuleContentEvent(
new ModuleContentEvent(tcacheFile));
253 }
catch (IOException ex) {
254 logger.log(Level.WARNING,
"I/O error encountered during thumbcache processing.", ex);
255 }
catch (TskCoreException ex) {
256 logger.log(Level.SEVERE,
"Unable to add thumbcache as derived files.", ex);
257 }
catch (NoCurrentCaseException ex) {
258 logger.log(Level.WARNING,
"No open case!", ex);