Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractPrefetch.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2020-2021 Basis Technology Corp.
6  *
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.sleuthkit.autopsy.recentactivity;
21 
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Set;
35 import java.util.logging.Level;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38 import org.apache.commons.io.FilenameUtils;
39 import org.openide.modules.InstalledFileLocator;
40 import org.openide.util.NbBundle.Messages;
53 import org.sleuthkit.datamodel.AbstractFile;
54 import org.sleuthkit.datamodel.BlackboardArtifact;
55 import org.sleuthkit.datamodel.BlackboardAttribute;
56 import org.sleuthkit.datamodel.Content;
57 import org.sleuthkit.datamodel.TskCoreException;
58 
64 final class ExtractPrefetch extends Extract {
65 
66  private static final Logger logger = Logger.getLogger(ExtractPrefetch.class.getName());
67 
68  private final IngestJobContext context;
69  private static final String PREFETCH_TSK_COMMENT = "Prefetch File";
70  private static final String PREFETCH_FILE_LOCATION = "/windows/prefetch";
71  private static final String PREFETCH_TOOL_FOLDER = "markmckinnon"; //NON-NLS
72  private static final String PREFETCH_TOOL_NAME_WINDOWS_64 = "parse_prefetch_x64.exe"; //NON-NLS
73  private static final String PREFETCH_TOOL_NAME_WINDOWS_32 = "parse_prefetch_x32.exe"; //NON-NLS
74  private static final String PREFETCH_TOOL_NAME_MACOS = "parse_prefetch_macos"; //NON-NLS
75  private static final String PREFETCH_TOOL_NAME_LINUX = "parse_prefetch_linux"; //NON-NLS
76  private static final String PREFETCH_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS
77  private static final String PREFETCH_ERROR_FILE_NAME = "Error.txt"; //NON-NLS
78  private static final String PREFETCH_PARSER_DB_FILE = "Autopsy_PF_DB.db3"; //NON-NLS
79  private static final String PREFETCH_DIR_NAME = "prefetch"; //NON-NLS
80 
81  @Messages({
82  "ExtractPrefetch_module_name=Windows Prefetch Analyzer",
83  "# {0} - sub module name",
84  "ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files"
85  })
86  ExtractPrefetch(IngestJobContext context) {
87  super(Bundle.ExtractPrefetch_module_name(), context);
88  this.context = context;
89  }
90 
98  private String getPrefetchTempFolder(Content dataSource) {
99  return dataSource.getId() + "-" + PREFETCH_PARSER_DB_FILE;
100  }
101 
102  @Override
103  void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
104 
105  long ingestJobId = context.getJobId();
106 
107  String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + PREFETCH_DIR_NAME;
108  File dir = new File(modOutPath);
109  if (dir.exists() == false) {
110  boolean dirMade = dir.mkdirs();
111  if (!dirMade) {
112  logger.log(Level.SEVERE, "Error creating directory to store prefetch output database"); //NON-NLS
113  return; //If we cannot create the directory then we need to exit
114  }
115  }
116 
117  extractPrefetchFiles(dataSource, ingestJobId);
118 
119  final String prefetchDumper = getPathForPrefetchDumper();
120  if (prefetchDumper == null) {
121  logger.log(Level.SEVERE, "Error finding parse_prefetch program"); //NON-NLS
122  return; //If we cannot find the parse_prefetch program we cannot proceed
123  }
124 
125  if (context.dataSourceIngestIsCancelled()) {
126  return;
127  }
128 
129  String modOutFile = modOutPath + File.separator + getPrefetchTempFolder(dataSource);
130  try {
131  String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), getPrefetchTempFolder(dataSource), ingestJobId);
132  parsePrefetchFiles(prefetchDumper, tempDirPath, modOutFile, modOutPath);
133  File prefetchDatabase = new File(modOutFile);
134  if (prefetchDatabase.exists()) {
135  createAppExecArtifacts(modOutFile, dataSource);
136  }
137  } catch (IOException ex) {
138  logger.log(Level.SEVERE, "Error parsing prefetch files", ex); //NON-NLS
139  addErrorMessage(Bundle.ExtractPrefetch_errMsg_prefetchParsingFailed(Bundle.ExtractPrefetch_module_name()));
140  }
141  }
142 
149  void extractPrefetchFiles(Content dataSource, long ingestJobId) {
150  List<AbstractFile> pFiles;
151 
152  FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
153 
154  try {
155  pFiles = fileManager.findFiles(dataSource, "%.pf"); //NON-NLS
156  } catch (TskCoreException ex) {
157  logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
158  return; // No need to continue
159  }
160 
161  for (AbstractFile pFile : pFiles) {
162 
163  if (context.dataSourceIngestIsCancelled()) {
164  return;
165  }
166 
167  if (pFile.getParentPath().toLowerCase().contains(PREFETCH_FILE_LOCATION.toLowerCase()) && pFile.getSize() > 0) {
168  String origFileName = pFile.getName();
169  String ext = FilenameUtils.getExtension(origFileName);
170  String baseName = FilenameUtils.getBaseName(origFileName);
171  String fileName = escapeFileName(String.format("%s_%d.%s", baseName, pFile.getId(), ext));
172  String baseRaTempPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), getPrefetchTempFolder(dataSource), ingestJobId);
173  String prefetchFile = Paths.get(baseRaTempPath, fileName).toString();
174  try {
175  ContentUtils.writeToFile(pFile, new File(prefetchFile));
176  } catch (IOException ex) {
177  logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", pFile.getName(), prefetchFile), ex); //NON-NLS
178  }
179  }
180  }
181 
182  }
183 
196  void parsePrefetchFiles(String prefetchExePath, String prefetchDir, String tempOutFile, String tempOutPath) throws FileNotFoundException, IOException {
197  final Path outputFilePath = Paths.get(tempOutPath, PREFETCH_OUTPUT_FILE_NAME);
198  final Path errFilePath = Paths.get(tempOutPath, PREFETCH_ERROR_FILE_NAME);
199 
200  List<String> commandLine = new ArrayList<>();
201  commandLine.add(prefetchExePath);
202  commandLine.add(prefetchDir); //NON-NLS
203  commandLine.add(tempOutFile);
204 
205  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
206  processBuilder.redirectOutput(outputFilePath.toFile());
207  processBuilder.redirectError(errFilePath.toFile());
208 
209  ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
210  }
211 
219  private String getPathForPrefetchDumper() {
220  Path path = null;
221  if (PlatformUtil.isWindowsOS()) {
222  if (PlatformUtil.is64BitOS()) {
223  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_64);
224  } else {
225  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_32);
226  }
227  } else {
228  if ("Linux".equals(PlatformUtil.getOSName())) {
229  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_LINUX);
230  } else {
231  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_MACOS);
232  }
233  }
234  File prefetchToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
235  ExtractPrefetch.class.getPackage().getName(), false);
236  if (prefetchToolFile != null) {
237  return prefetchToolFile.getAbsolutePath();
238  }
239 
240  return null;
241 
242  }
243 
252  private void createAppExecArtifacts(String prefetchDb, Content dataSource) {
253  List<BlackboardArtifact> blkBrdArtList = new ArrayList<>();
254 
255  String sqlStatement = "SELECT prefetch_File_Name, actual_File_Name, file_path, Number_time_file_run, Embeded_date_Time_Unix_1, "
256  + " Embeded_date_Time_Unix_2, Embeded_date_Time_Unix_3, Embeded_date_Time_Unix_4, Embeded_date_Time_Unix_5,"
257  + " Embeded_date_Time_Unix_6, Embeded_date_Time_Unix_7, Embeded_date_Time_Unix_8 "
258  + " FROM prefetch_file_info;"; //NON-NLS
259 
260  try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + prefetchDb); //NON-NLS
261  ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
262 
263  while (resultSet.next()) {
264 
265  if (context.dataSourceIngestIsCancelled()) {
266  logger.log(Level.INFO, "Cancelled Prefetch Artifact Creation."); //NON-NLS
267  return;
268  }
269 
270  String prefetchFileName = resultSet.getString("prefetch_File_Name");
271  String applicationName = resultSet.getString("actual_File_Name"); //NON-NLS
272  List<Long> executionTimes = new ArrayList<>();
273  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_1")));
274  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_2")));
275  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_3")));
276  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_4")));
277  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_5")));
278  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_6")));
279  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_7")));
280  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_8")));
281  String timesProgramRun = resultSet.getString("Number_time_file_run");
282  String filePath = resultSet.getString("file_path");
283 
284  Set<Long> prefetchExecutionTimes = findNonZeroExecutionTimes(executionTimes);
285 
286  String baseName = FilenameUtils.getBaseName(prefetchFileName);
287  Matcher match = Pattern.compile("_(?<objId>\\d*)\\s*$").matcher(baseName);
288  if (!match.find()) {
289  logger.log(Level.WARNING, "Invalid format for PF file: " + prefetchFileName);//NON-NLS
290  continue;
291  }
292 
301  AbstractFile pfAbstractFile = null;
302  try {
303  Content c = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(Long.parseLong(match.group("objId")));
304  if (c instanceof AbstractFile) {
305  pfAbstractFile = (AbstractFile) c;
306  }
307  } catch (NoCurrentCaseException | TskCoreException | NumberFormatException ex) {
308  logger.log(Level.SEVERE, "Unable to find content for: " + prefetchFileName, ex);
309  }
310 
311  if (pfAbstractFile != null) {
312  for (Long executionTime : prefetchExecutionTimes) {
313 
314  // only add prefetch file entries that have an actual date associated with them
315  Collection<BlackboardAttribute> blkBrdAttributes = Arrays.asList(
316  new BlackboardAttribute(
317  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getDisplayName(),
318  applicationName),//NON-NLS
319  new BlackboardAttribute(
320  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, getDisplayName(), filePath),
321  new BlackboardAttribute(
322  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getDisplayName(),
323  executionTime),
324  new BlackboardAttribute(
325  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT, getDisplayName(), Integer.valueOf(timesProgramRun)),
326  new BlackboardAttribute(
327  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getDisplayName(), PREFETCH_TSK_COMMENT));
328 
329  try {
330  BlackboardArtifact blkBrdArt = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_PROG_RUN, pfAbstractFile, blkBrdAttributes);
331  blkBrdArtList.add(blkBrdArt);
332  BlackboardArtifact associatedBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), filePath, blkBrdArt, dataSource);
333  if (associatedBbArtifact != null) {
334  blkBrdArtList.add(associatedBbArtifact);
335  }
336  } catch (TskCoreException ex) {
337  logger.log(Level.SEVERE, "Exception Adding Artifact.", ex);//NON-NLS
338  }
339  }
340  } else {
341  logger.log(Level.WARNING, "File has a null value " + prefetchFileName);//NON-NLS
342  }
343 
344  }
345  } catch (SQLException ex) {
346  logger.log(Level.WARNING, String.format("Error while trying to read into a sqlite db %s.", prefetchDb));//NON-NLS
347  logger.log(Level.WARNING, ex.getMessage());
348  }
349 
350  if (!blkBrdArtList.isEmpty() && !context.dataSourceIngestIsCancelled()) {
351  postArtifacts(blkBrdArtList);
352  }
353  }
354 
366  private BlackboardArtifact createAssociatedArtifact(String fileName, String filePathName, BlackboardArtifact bba, Content dataSource) throws TskCoreException {
367  AbstractFile sourceFile = getAbstractFile(fileName, filePathName, dataSource);
368  if (sourceFile != null) {
369  return createAssociatedArtifact(sourceFile, bba);
370  }
371  return null;
372  }
373 
384  AbstractFile getAbstractFile(String fileName, String filePath, Content dataSource) {
385  List<AbstractFile> files;
386 
387  FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
388 
389  try {
390  files = fileManager.findFiles(dataSource, fileName); //NON-NLS
391 
392  } catch (TskCoreException ex) {
393  logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
394  return null; // No need to continue
395  }
396 
397  for (AbstractFile pFile : files) {
398  if (pFile.getParentPath().toLowerCase().endsWith(filePath.toLowerCase() + '/')) {
399  return pFile;
400  }
401  }
402 
403  return null;
404 
405  }
406 
416  private Set<Long> findNonZeroExecutionTimes(List<Long> executionTimes) {
417  Set<Long> prefetchExecutionTimes = new HashSet<>();
418  for (Long executionTime : executionTimes) { // only add prefetch file entries that have an actual date associated with them
419  if (executionTime > 0) {
420  prefetchExecutionTimes.add(executionTime);
421  }
422  }
423  return prefetchExecutionTimes;
424  }
425 }
static String escapeFileName(String fileName)
Definition: FileUtil.java:169

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.