Autopsy  4.17.0
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 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 org.openide.modules.InstalledFileLocator;
37 import org.openide.util.NbBundle.Messages;
49 import org.sleuthkit.datamodel.AbstractFile;
50 import org.sleuthkit.datamodel.Blackboard;
51 import org.sleuthkit.datamodel.BlackboardArtifact;
52 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
53 import org.sleuthkit.datamodel.BlackboardAttribute;
54 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
55 import org.sleuthkit.datamodel.Content;
56 import org.sleuthkit.datamodel.TskCoreException;
57 
63 final class ExtractPrefetch extends Extract {
64 
65  private static final Logger logger = Logger.getLogger(ExtractPrefetch.class.getName());
66 
67  private IngestJobContext context;
68 
69  private static final String MODULE_NAME = "extractPREFETCH"; //NON-NLS
70 
71  private static final String PREFETCH_TSK_COMMENT = "Prefetch File";
72  private static final String PREFETCH_FILE_LOCATION = "/windows/prefetch";
73  private static final String PREFETCH_TOOL_FOLDER = "markmckinnon"; //NON-NLS
74  private static final String PREFETCH_TOOL_NAME_WINDOWS_64 = "parse_prefetch_x64.exe"; //NON-NLS
75  private static final String PREFETCH_TOOL_NAME_WINDOWS_32 = "parse_prefetch_x32.exe"; //NON-NLS
76  private static final String PREFETCH_TOOL_NAME_MACOS = "parse_prefetch_macos"; //NON-NLS
77  private static final String PREFETCH_TOOL_NAME_LINUX = "parse_prefetch_linux"; //NON-NLS
78  private static final String PREFETCH_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS
79  private static final String PREFETCH_ERROR_FILE_NAME = "Error.txt"; //NON-NLS
80  private static final String PREFETCH_PARSER_DB_FILE = "Autopsy_PF_DB.db3"; //NON-NLS
81  private static final String PREFETCH_DIR_NAME = "prefetch"; //NON-NLS
82 
83  @Messages({
84  "ExtractPrefetch_module_name=Windows Prefetch Extractor",
85  "# {0} - sub module name",
86  "ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files"
87  })
88  ExtractPrefetch() {
89  this.moduleName = Bundle.ExtractPrefetch_module_name();
90  }
91 
92  @Override
93  void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
94 
95  this.context = context;
96 
97  String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + PREFETCH_DIR_NAME;
98  File dir = new File(modOutPath);
99  if (dir.exists() == false) {
100  boolean dirMade = dir.mkdirs();
101  if (!dirMade) {
102  logger.log(Level.SEVERE, "Error creating directory to store prefetch output database"); //NON-NLS
103  return; //If we cannot create the directory then we need to exit
104  }
105  }
106 
107  extractPrefetchFiles(dataSource);
108 
109  final String prefetchDumper = getPathForPrefetchDumper();
110  if (prefetchDumper == null) {
111  logger.log(Level.SEVERE, "Error finding parse_prefetch program"); //NON-NLS
112  return; //If we cannot find the parse_prefetch program we cannot proceed
113  }
114 
115  if (context.dataSourceIngestIsCancelled()) {
116  return;
117  }
118 
119  String modOutFile = modOutPath + File.separator + dataSource.getName() + "-" + PREFETCH_PARSER_DB_FILE;
120  try {
121  String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), dataSource.getName() + "-" + PREFETCH_DIR_NAME);
122  parsePrefetchFiles(prefetchDumper, tempDirPath, modOutFile, modOutPath);
123  createAppExecArtifacts(modOutFile, dataSource);
124  } catch (IOException ex) {
125  logger.log(Level.SEVERE, "Error parsing prefetch files", ex); //NON-NLS
126  addErrorMessage(Bundle.ExtractPrefetch_errMsg_prefetchParsingFailed(Bundle.ExtractPrefetch_module_name()));
127  }
128  }
129 
136  void extractPrefetchFiles(Content dataSource) {
137  List<AbstractFile> pFiles;
138 
139  FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
140 
141  try {
142  pFiles = fileManager.findFiles(dataSource, "%.pf"); //NON-NLS
143  } catch (TskCoreException ex) {
144  logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
145  return; // No need to continue
146  }
147 
148  for (AbstractFile pFile : pFiles) {
149 
150  if (context.dataSourceIngestIsCancelled()) {
151  return;
152  }
153 
154  String prefetchFile = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), dataSource.getName() + "-" + PREFETCH_DIR_NAME) + File.separator + pFile.getName();
155  if (pFile.getParentPath().toLowerCase().contains(PREFETCH_FILE_LOCATION.toLowerCase())) {
156  try {
157  ContentUtils.writeToFile(pFile, new File(prefetchFile));
158  } catch (IOException ex) {
159  logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", pFile.getName(), prefetchFile), ex); //NON-NLS
160  }
161  }
162  }
163 
164  }
165 
178  void parsePrefetchFiles(String prefetchExePath, String prefetchDir, String tempOutFile, String tempOutPath) throws FileNotFoundException, IOException {
179  final Path outputFilePath = Paths.get(tempOutPath, PREFETCH_OUTPUT_FILE_NAME);
180  final Path errFilePath = Paths.get(tempOutPath, PREFETCH_ERROR_FILE_NAME);
181 
182  List<String> commandLine = new ArrayList<>();
183  commandLine.add(prefetchExePath);
184  commandLine.add(prefetchDir); //NON-NLS
185  commandLine.add(tempOutFile);
186 
187  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
188  processBuilder.redirectOutput(outputFilePath.toFile());
189  processBuilder.redirectError(errFilePath.toFile());
190 
191  ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
192  }
193 
201  private String getPathForPrefetchDumper() {
202  Path path = null;
203  if (PlatformUtil.isWindowsOS()) {
204  if (PlatformUtil.is64BitOS()) {
205  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_64);
206  } else {
207  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_WINDOWS_32);
208  }
209  } else {
210  if ("Linux".equals(PlatformUtil.getOSName())) {
211  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_LINUX);
212  } else {
213  path = Paths.get(PREFETCH_TOOL_FOLDER, PREFETCH_TOOL_NAME_MACOS);
214  }
215  }
216  File prefetchToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
217  ExtractPrefetch.class.getPackage().getName(), false);
218  if (prefetchToolFile != null) {
219  return prefetchToolFile.getAbsolutePath();
220  }
221 
222  return null;
223 
224  }
225 
234  private void createAppExecArtifacts(String prefetchDb, Content dataSource) {
235  List<BlackboardArtifact> blkBrdArtList = new ArrayList<>();
236 
237  String sqlStatement = "SELECT prefetch_File_Name, actual_File_Name, file_path, Number_time_file_run, Embeded_date_Time_Unix_1, "
238  + " Embeded_date_Time_Unix_2, Embeded_date_Time_Unix_3, Embeded_date_Time_Unix_4, Embeded_date_Time_Unix_5,"
239  + " Embeded_date_Time_Unix_6, Embeded_date_Time_Unix_7, Embeded_date_Time_Unix_8 "
240  + " FROM prefetch_file_info;"; //NON-NLS
241 
242  try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + prefetchDb); //NON-NLS
243  ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
244 
245  while (resultSet.next()) {
246 
247  if (context.dataSourceIngestIsCancelled()) {
248  logger.log(Level.INFO, "Cancelled Prefetch Artifact Creation."); //NON-NLS
249  return;
250  }
251 
252  String prefetchFileName = resultSet.getString("prefetch_File_Name");
253  String applicationName = resultSet.getString("actual_File_Name"); //NON-NLS
254  List<Long> executionTimes = new ArrayList<>();
255  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_1")));
256  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_2")));
257  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_3")));
258  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_4")));
259  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_5")));
260  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_6")));
261  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_7")));
262  executionTimes.add(Long.valueOf(resultSet.getInt("Embeded_date_Time_Unix_8")));
263  String timesProgramRun = resultSet.getString("Number_time_file_run");
264  String filePath = resultSet.getString("file_path");
265 
266  AbstractFile pfAbstractFile = getAbstractFile(prefetchFileName, PREFETCH_FILE_LOCATION, dataSource);
267 
268  Set<Long> prefetchExecutionTimes = findNonZeroExecutionTimes(executionTimes);
269 
270  if (pfAbstractFile != null) {
271  for (Long executionTime : prefetchExecutionTimes) {
272 
273  // only add prefetch file entries that have an actual date associated with them
274  Collection<BlackboardAttribute> blkBrdAttributes = Arrays.asList(
275  new BlackboardAttribute(
276  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getName(),
277  applicationName),//NON-NLS
278  new BlackboardAttribute(
279  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, getName(), filePath),
280  new BlackboardAttribute(
281  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getName(),
282  executionTime),
283  new BlackboardAttribute(
284  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT, getName(), Integer.valueOf(timesProgramRun)),
285  new BlackboardAttribute(
286  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getName(), PREFETCH_TSK_COMMENT));
287 
288  try {
289  BlackboardArtifact blkBrdArt = pfAbstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN);
290  blkBrdArt.addAttributes(blkBrdAttributes);
291  blkBrdArtList.add(blkBrdArt);
292  BlackboardArtifact associatedBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), filePath, blkBrdArt, dataSource);
293  if (associatedBbArtifact != null) {
294  blkBrdArtList.add(associatedBbArtifact);
295  }
296  } catch (TskCoreException ex) {
297  logger.log(Level.SEVERE, "Exception Adding Artifact.", ex);//NON-NLS
298  }
299  }
300  } else {
301  logger.log(Level.WARNING, "File has a null value " + prefetchFileName);//NON-NLS
302  }
303 
304  }
305  } catch (SQLException ex) {
306  logger.log(Level.SEVERE, "Error while trying to read into a sqlite db.", ex);//NON-NLS
307  }
308 
309  if (!blkBrdArtList.isEmpty()) {
310  try {
311  blackboard.postArtifacts(blkBrdArtList, MODULE_NAME);
312  } catch (Blackboard.BlackboardException ex) {
313  logger.log(Level.SEVERE, "Error Posting Artifact.", ex);//NON-NLS
314  }
315  }
316  }
317 
327  private Set<Long> findNonZeroExecutionTimes(List<Long> executionTimes) {
328  Set<Long> prefetchExecutionTimes = new HashSet<>();
329  for (Long executionTime : executionTimes) { // only add prefetch file entries that have an actual date associated with them
330  if (executionTime > 0) {
331  prefetchExecutionTimes.add(executionTime);
332  }
333  }
334  return prefetchExecutionTimes;
335  }
336 
348  private BlackboardArtifact createAssociatedArtifact(String fileName, String filePathName, BlackboardArtifact bba, Content dataSource) {
349  AbstractFile sourceFile = getAbstractFile(fileName, filePathName, dataSource);
350  if (sourceFile != null) {
351  Collection<BlackboardAttribute> bbattributes2 = new ArrayList<>();
352  bbattributes2.addAll(Arrays.asList(
353  new BlackboardAttribute(TSK_ASSOCIATED_ARTIFACT, this.getName(),
354  bba.getArtifactID())));
355 
356  BlackboardArtifact associatedObjectBba = createArtifactWithAttributes(TSK_ASSOCIATED_OBJECT, sourceFile, bbattributes2);
357  if (associatedObjectBba != null) {
358  return associatedObjectBba;
359  }
360  }
361 
362  return null;
363  }
364 
375  AbstractFile getAbstractFile(String fileName, String filePath, Content dataSource) {
376  List<AbstractFile> files;
377 
378  FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
379 
380  try {
381  files = fileManager.findFiles(dataSource, fileName); //NON-NLS
382 
383  } catch (TskCoreException ex) {
384  logger.log(Level.WARNING, "Unable to find prefetch files.", ex); //NON-NLS
385  return null; // No need to continue
386  }
387 
388  for (AbstractFile pFile : files) {
389 
390  if (pFile.getParentPath().toLowerCase().endsWith(filePath.toLowerCase() + '/')) {
391  return pFile;
392  }
393  }
394 
395  return null;
396 
397  }
398 
399 }

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.