Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ILeappAnalyzerIngestModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.modules.leappanalyzers;
20 
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.io.UncheckedIOException;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.text.SimpleDateFormat;
31 import java.util.List;
32 import java.util.ArrayList;
33 import java.util.Locale;
34 import java.util.logging.Level;
35 import java.util.stream.Collectors;
36 import java.util.stream.Stream;
37 import org.apache.commons.io.FilenameUtils;
38 import org.openide.modules.InstalledFileLocator;
39 import org.openide.util.NbBundle;
55 import org.sleuthkit.datamodel.AbstractFile;
56 import org.sleuthkit.datamodel.Content;
57 import org.sleuthkit.datamodel.LocalFilesDataSource;
58 import org.sleuthkit.datamodel.ReadContentInputStream;
59 import org.sleuthkit.datamodel.TskCoreException;
60 
65 
66  private static final Logger logger = Logger.getLogger(ILeappAnalyzerIngestModule.class.getName());
67  private static final String MODULE_NAME = ILeappAnalyzerModuleFactory.getModuleName();
68 
69  private static final String ILEAPP = "iLeapp"; //NON-NLS
70  private static final String ILEAPP_FS = "fs_"; //NON-NLS
71  private static final String ILEAPP_EXECUTABLE = "ileapp.exe";//NON-NLS
72  private static final String ILEAPP_PATHS_FILE = "iLeapp_paths.txt"; //NON-NLS
73 
74  private static final String XMLFILE = "ileap-artifact-attribute-reference.xml"; //NON-NLS
75 
76 
77  private File iLeappExecutable;
78 
80 
82 
84  // This constructor is intentionally empty. Nothing special is needed here.
85  }
86 
87  @NbBundle.Messages({
88  "ILeappAnalyzerIngestModule.executable.not.found=iLeapp Executable Not Found.",
89  "ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows.",
90  "ILeappAnalyzerIngestModule.error.ileapp.file.processor.init=Failure to initialize ILeappProcessFile"})
91  @Override
92  public void startUp(IngestJobContext context) throws IngestModuleException {
93  this.context = context;
94 
95  if (false == PlatformUtil.isWindowsOS()) {
96  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_requires_windows());
97  }
98 
99  try {
100  iLeappFileProcessor = new LeappFileProcessor(XMLFILE);
101  } catch (IOException | IngestModuleException | NoCurrentCaseException ex) {
102  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_error_ileapp_file_processor_init(), ex);
103  }
104 
105  try {
106  iLeappExecutable = locateExecutable(ILEAPP_EXECUTABLE);
107  } catch (FileNotFoundException exception) {
108  logger.log(Level.WARNING, "iLeapp executable not found.", exception); //NON-NLS
109  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_executable_not_found(), exception);
110  }
111 
112  }
113 
114  @NbBundle.Messages({
115  "ILeappAnalyzerIngestModule.error.running.iLeapp=Error running iLeapp, see log file.",
116  "ILeappAnalyzerIngestModule.error.creating.output.dir=Error creating iLeapp module output directory.",
117  "ILeappAnalyzerIngestModule.starting.iLeapp=Starting iLeapp",
118  "ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp",
119  "ILeappAnalyzerIngestModule.has.run=iLeapp",
120  "ILeappAnalyzerIngestModule.iLeapp.cancelled=iLeapp run was canceled",
121  "ILeappAnalyzerIngestModule.completed=iLeapp Processing Completed",
122  "ILeappAnalyzerIngestModule.report.name=iLeapp Html Report"})
123  @Override
124  public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
125 
126  Case currentCase = Case.getCurrentCase();
127  Path tempOutputPath = Paths.get(currentCase.getTempDirectory(), ILEAPP, ILEAPP_FS + dataSource.getId());
128  try {
129  Files.createDirectories(tempOutputPath);
130  } catch (IOException ex) {
131  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", tempOutputPath.toString()), ex);
132  return ProcessResult.ERROR;
133  }
134 
135  List<String> iLeappPathsToProcess = new ArrayList<>();
136  ProcessBuilder iLeappCommand = buildiLeappListCommand(tempOutputPath);
137  try {
138  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
139  if (result != 0) {
140  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
141  return ProcessResult.ERROR;
142  }
143  iLeappPathsToProcess = loadIleappPathFile(tempOutputPath);
144  } catch (IOException ex) {
145  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search"), ex);
146  return ProcessResult.ERROR;
147  }
148 
149  statusHelper.progress(Bundle.ILeappAnalyzerIngestModule_starting_iLeapp(), 0);
150 
151  List<AbstractFile> iLeappFilesToProcess = new ArrayList<>();
152 
153  if (!(context.getDataSource() instanceof LocalFilesDataSource)) {
154  extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
155  statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
156  processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
157  } else {
158  iLeappFilesToProcess = findiLeappFilesToProcess(dataSource);
159  statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
160 
161  Integer filesProcessedCount = 0;
162  for (AbstractFile iLeappFile : iLeappFilesToProcess) {
163  processILeappFile(dataSource, currentCase, statusHelper, filesProcessedCount, iLeappFile);
164  filesProcessedCount++;
165  }
166  // Process the logical image as a fs in iLeapp to make sure this is not a logical fs that was added
167  extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
168  processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
169  }
170 
172  Bundle.ILeappAnalyzerIngestModule_has_run(),
173  Bundle.ILeappAnalyzerIngestModule_completed());
175  return ProcessResult.OK;
176  }
177 
186  private void processILeappFile(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, int filesProcessedCount,
187  AbstractFile iLeappFile) {
188  String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
189  Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
190  try {
191  Files.createDirectories(moduleOutputPath);
192  } catch (IOException ex) {
193  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
194  return;
195  }
196 
197  statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.file", iLeappFile.getName()), filesProcessedCount);
198  ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, iLeappFile.getLocalAbsPath(), iLeappFile.getNameExtension());
199  try {
200  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
201  if (result != 0) {
202  logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
203  return;
204  }
205 
206  addILeappReportToReports(moduleOutputPath, currentCase);
207 
208  } catch (IOException ex) {
209  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file %s", iLeappFile.getLocalAbsPath()), ex);
210  return;
211  }
212 
213  if (context.dataSourceIngestIsCancelled()) {
214  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
215  return;
216  }
217 
218  ProcessResult fileProcessorResult = iLeappFileProcessor.processFiles(dataSource, moduleOutputPath, iLeappFile);
219 
220  if (fileProcessorResult == ProcessResult.ERROR) {
221  return;
222  }
223  }
224 
232  private void processILeappFs(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, String directoryToProcess) {
233  String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
234  Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
235  try {
236  Files.createDirectories(moduleOutputPath);
237  } catch (IOException ex) {
238  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
239  return;
240  }
241 
242  statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.filesystem"));
243  ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, directoryToProcess, "fs");
244  try {
245  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
246  if (result != 0) {
247  logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
248  return;
249  }
250 
251  addILeappReportToReports(moduleOutputPath, currentCase);
252 
253  } catch (IOException ex) {
254  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file system"), ex);
255  return;
256  }
257 
258  if (context.dataSourceIngestIsCancelled()) {
259  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
260  return;
261  }
262 
263  ProcessResult fileProcessorResult = iLeappFileProcessor.processFileSystem(dataSource, moduleOutputPath);
264 
265  if (fileProcessorResult == ProcessResult.ERROR) {
266  return;
267  }
268 
269  }
270 
278  private List<AbstractFile> findiLeappFilesToProcess(Content dataSource) {
279 
280  List<AbstractFile> iLeappFiles = new ArrayList<>();
281 
282  FileManager fileManager = getCurrentCase().getServices().getFileManager();
283 
284  // findFiles use the SQL wildcard % in the file name
285  try {
286  iLeappFiles = fileManager.findFiles(dataSource, "%", "/"); //NON-NLS
287  } catch (TskCoreException ex) {
288  logger.log(Level.WARNING, "No files found to process"); //NON-NLS
289  return iLeappFiles;
290  }
291 
292  List<AbstractFile> iLeappFilesToProcess = new ArrayList<>();
293  for (AbstractFile iLeappFile : iLeappFiles) {
294  if (((iLeappFile.getLocalAbsPath() != null)
295  && (!iLeappFile.getNameExtension().isEmpty() && (!iLeappFile.isVirtual())))
296  && ((iLeappFile.getName().toLowerCase().contains(".zip") || (iLeappFile.getName().toLowerCase().contains(".tar")))
297  || iLeappFile.getName().toLowerCase().contains(".tgz"))) {
298  iLeappFilesToProcess.add(iLeappFile);
299 
300  }
301  }
302 
303  return iLeappFilesToProcess;
304  }
305 
313  private ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType) {
314 
315  ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
316  "\"" + iLeappExecutable + "\"", //NON-NLS
317  "-t", iLeappFileSystemType, //NON-NLS
318  "-i", sourceFilePath, //NON-NLS
319  "-o", moduleOutputPath.toString()
320  );
321  processBuilder.redirectError(moduleOutputPath.resolve("iLeapp_err.txt").toFile()); //NON-NLS
322  processBuilder.redirectOutput(moduleOutputPath.resolve("iLeapp_out.txt").toFile()); //NON-NLS
323  return processBuilder;
324  }
325 
331  private ProcessBuilder buildiLeappListCommand(Path moduleOutputPath) {
332 
333  ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
334  "\"" + iLeappExecutable + "\"", //NON-NLS
335  "-p"
336  );
337  processBuilder.redirectError(moduleOutputPath.resolve("iLeapp_paths_error.txt").toFile()); //NON-NLS
338  processBuilder.redirectOutput(moduleOutputPath.resolve("iLeapp_paths.txt").toFile()); //NON-NLS
339  return processBuilder;
340  }
341 
342  static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) {
343  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
344  /*
345  * Add an environment variable to force iLeapp to run with
346  * the same permissions Autopsy uses.
347  */
348  processBuilder.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS
349  return processBuilder;
350  }
351 
352  private static File locateExecutable(String executableName) throws FileNotFoundException {
353  String executableToFindName = Paths.get(ILEAPP, executableName).toString();
354 
355  File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, ILeappAnalyzerIngestModule.class.getPackage().getName(), false);
356  if (null == exeFile || exeFile.canExecute() == false) {
357  throw new FileNotFoundException(executableName + " executable not found.");
358  }
359  return exeFile;
360  }
361 
366  private void addILeappReportToReports(Path iLeappOutputDir, Case currentCase) {
367  List<String> allIndexFiles = new ArrayList<>();
368 
369  try (Stream<Path> walk = Files.walk(iLeappOutputDir)) {
370 
371  allIndexFiles = walk.map(x -> x.toString())
372  .filter(f -> f.toLowerCase().endsWith("index.html")).collect(Collectors.toList());
373 
374  if (!allIndexFiles.isEmpty()) {
375  // Check for existance of directory that holds report data if does not exist then report contains no data
376  String filePath = FilenameUtils.getFullPathNoEndSeparator(allIndexFiles.get(0));
377  File dataFilesDir = new File(Paths.get(filePath, "_TSV Exports").toString());
378  if (dataFilesDir.exists()) {
379  currentCase.addReport(allIndexFiles.get(0), MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_report_name());
380  }
381  }
382 
383  } catch (IOException | UncheckedIOException | TskCoreException ex) {
384  // catch the error and continue on as report is not added
385  logger.log(Level.WARNING, String.format("Error finding index file in path %s", iLeappOutputDir.toString()), ex);
386  }
387 
388  }
389 
390  /*
391  * Reads the iLeapp paths file to get the paths that we want to extract
392  *
393  * @param moduleOutputPath path where the file paths output will reside
394  */
395  private List<String> loadIleappPathFile(Path moduleOutputPath) throws FileNotFoundException, IOException {
396  List<String> iLeappPathsToProcess = new ArrayList<>();
397 
398  Path filePath = Paths.get(moduleOutputPath.toString(), ILEAPP_PATHS_FILE);
399 
400  try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toString()))) {
401  String line = reader.readLine();
402  while (line != null) {
403  if (line.contains("path list generation") || line.length() < 2) {
404  line = reader.readLine();
405  continue;
406  }
407  iLeappPathsToProcess.add(line.trim());
408  line = reader.readLine();
409  }
410  }
411 
412  return iLeappPathsToProcess;
413  }
414 
421  private void extractFilesFromImage(Content dataSource, List<String> iLeappPathsToProcess, Path moduleOutputPath) {
422  FileManager fileManager = getCurrentCase().getServices().getFileManager();
423 
424  for (String fullFilePath : iLeappPathsToProcess) {
425 
426  if (context.dataSourceIngestIsCancelled()) {
427  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
428  break;
429  }
430 
431  String ffp = fullFilePath.replaceAll("\\*", "%");
432  ffp = FilenameUtils.normalize(ffp, true);
433  String fileName = FilenameUtils.getName(ffp);
434  String filePath = FilenameUtils.getPath(ffp);
435 
436  List<AbstractFile> iLeappFiles = new ArrayList<>();
437  try {
438  if (filePath.isEmpty()) {
439  iLeappFiles = fileManager.findFiles(dataSource, fileName); //NON-NLS
440  } else {
441  iLeappFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS
442  }
443  } catch (TskCoreException ex) {
444  logger.log(Level.WARNING, "No files found to process"); //NON-NLS
445  return;
446  }
447 
448  for (AbstractFile iLeappFile : iLeappFiles) {
449  Path parentPath = Paths.get(moduleOutputPath.toString(), iLeappFile.getParentPath());
450  File fileParentPath = new File(parentPath.toString());
451 
452  extractFileToOutput(dataSource, iLeappFile, fileParentPath, parentPath);
453  }
454  }
455  }
456 
464  private void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath) {
465  if (fileParentPath.exists()) {
466  if (!iLeappFile.isDir()) {
467  writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
468  } else {
469  try {
470  Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
471  } catch (IOException ex) {
472  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
473  }
474  }
475  } else {
476  try {
477  Files.createDirectories(parentPath);
478  } catch (IOException ex) {
479  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
480  }
481  if (!iLeappFile.isDir()) {
482  writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
483  } else {
484  try {
485  Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
486  } catch (IOException ex) {
487  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
488  }
489  }
490  }
491  }
492 
499  private void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath) {
500  String fileName = iLeappFile.getName().replace(":", "-");
501  if (!fileName.matches(".") && !fileName.matches("..") && !fileName.toLowerCase().endsWith("-slack")) {
502  Path filePath = Paths.get(parentPath, fileName);
503  File localFile = new File(filePath.toString());
504  try {
505  ContentUtils.writeToFile(iLeappFile, localFile, context::dataSourceIngestIsCancelled);
506  } catch (ReadContentInputStream.ReadContentInputStreamException ex) {
507  logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).",
508  iLeappFile.getName(), iLeappFile.getId()), ex); //NON-NLS
509  } catch (IOException ex) {
510  logger.log(Level.WARNING, String.format("Error writing file local file '%s' (id=%d).",
511  filePath.toString(), iLeappFile.getId()), ex); //NON-NLS
512  }
513  }
514  }
515 }
void extractFilesFromImage(Content dataSource, List< String > iLeappPathsToProcess, Path moduleOutputPath)
void processILeappFs(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, String directoryToProcess)
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:172
void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath)
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void addReport(String localPath, String srcModuleName, String reportName)
Definition: Case.java:1654
ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType)
ProcessResult processFileSystem(Content dataSource, Path moduleOutputPath)
ProcessResult processFiles(Content dataSource, Path moduleOutputPath, AbstractFile LeappFile)
void postMessage(final IngestMessage message)
synchronized List< AbstractFile > findFiles(String fileName)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper)
void processILeappFile(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, int filesProcessedCount, AbstractFile iLeappFile)
void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath)
static synchronized IngestServices getInstance()

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.