Autopsy  4.19.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.is64BitOS()) {
96  throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "IleappAnalyzerIngestModule.not.64.bit.os"));
97  }
98 
99  if (false == PlatformUtil.isWindowsOS()) {
100  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_requires_windows());
101  }
102 
103  try {
104  iLeappFileProcessor = new LeappFileProcessor(XMLFILE, ILeappAnalyzerModuleFactory.getModuleName());
105  } catch (IOException | IngestModuleException | NoCurrentCaseException ex) {
106  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_error_ileapp_file_processor_init(), ex);
107  }
108 
109  try {
110  iLeappExecutable = locateExecutable(ILEAPP_EXECUTABLE);
111  } catch (FileNotFoundException exception) {
112  logger.log(Level.WARNING, "iLeapp executable not found.", exception); //NON-NLS
113  throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_executable_not_found(), exception);
114  }
115 
116  }
117 
118  @NbBundle.Messages({
119  "ILeappAnalyzerIngestModule.error.running.iLeapp=Error running iLeapp, see log file.",
120  "ILeappAnalyzerIngestModule.error.creating.output.dir=Error creating iLeapp module output directory.",
121  "ILeappAnalyzerIngestModule.starting.iLeapp=Starting iLeapp",
122  "ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp",
123  "ILeappAnalyzerIngestModule.has.run=iLeapp",
124  "ILeappAnalyzerIngestModule.iLeapp.cancelled=iLeapp run was canceled",
125  "ILeappAnalyzerIngestModule.completed=iLeapp Processing Completed",
126  "ILeappAnalyzerIngestModule.report.name=iLeapp Html Report"})
127  @Override
128  public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
129 
130  Case currentCase = Case.getCurrentCase();
131  Path tempOutputPath = Paths.get(currentCase.getTempDirectory(), ILEAPP, ILEAPP_FS + dataSource.getId());
132  try {
133  Files.createDirectories(tempOutputPath);
134  } catch (IOException ex) {
135  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", tempOutputPath.toString()), ex);
136  return ProcessResult.ERROR;
137  }
138 
139  List<String> iLeappPathsToProcess = new ArrayList<>();
140  ProcessBuilder iLeappCommand = buildiLeappListCommand(tempOutputPath);
141  try {
142  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
143  if (result != 0) {
144  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
145  return ProcessResult.ERROR;
146  }
147  iLeappPathsToProcess = loadIleappPathFile(tempOutputPath);
148  } catch (IOException ex) {
149  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search"), ex);
150  return ProcessResult.ERROR;
151  }
152 
153  statusHelper.progress(Bundle.ILeappAnalyzerIngestModule_starting_iLeapp(), 0);
154 
155  List<AbstractFile> iLeappFilesToProcess = new ArrayList<>();
156 
157  if (!(context.getDataSource() instanceof LocalFilesDataSource)) {
158  extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
159  statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
160  processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
161  } else {
162  iLeappFilesToProcess = LeappFileProcessor.findLeappFilesToProcess(dataSource);
163  statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
164 
165  Integer filesProcessedCount = 0;
166  for (AbstractFile iLeappFile : iLeappFilesToProcess) {
167  processILeappFile(dataSource, currentCase, statusHelper, filesProcessedCount, iLeappFile);
168  filesProcessedCount++;
169  }
170  // Process the logical image as a fs in iLeapp to make sure this is not a logical fs that was added
171  extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
172  processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
173  }
174 
176  Bundle.ILeappAnalyzerIngestModule_has_run(),
177  Bundle.ILeappAnalyzerIngestModule_completed());
179  return ProcessResult.OK;
180  }
181 
190  private void processILeappFile(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, int filesProcessedCount,
191  AbstractFile iLeappFile) {
192  String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
193  Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
194  try {
195  Files.createDirectories(moduleOutputPath);
196  } catch (IOException ex) {
197  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
198  return;
199  }
200 
201  statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.file", iLeappFile.getName()), filesProcessedCount);
202  ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, iLeappFile.getLocalAbsPath(), iLeappFile.getNameExtension());
203  try {
204  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
205  if (result != 0) {
206  logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
207  return;
208  }
209 
210  addILeappReportToReports(moduleOutputPath, currentCase);
211 
212  } catch (IOException ex) {
213  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file %s", iLeappFile.getLocalAbsPath()), ex);
214  return;
215  }
216 
217  if (context.dataSourceIngestIsCancelled()) {
218  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
219  return;
220  }
221 
222  ProcessResult fileProcessorResult = iLeappFileProcessor.processFiles(dataSource, moduleOutputPath, iLeappFile);
223 
224  if (fileProcessorResult == ProcessResult.ERROR) {
225  return;
226  }
227  }
228 
236  private void processILeappFs(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, String directoryToProcess) {
237  String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
238  Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
239  try {
240  Files.createDirectories(moduleOutputPath);
241  } catch (IOException ex) {
242  logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
243  return;
244  }
245 
246  statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.filesystem"));
247  ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, directoryToProcess, "fs");
248  try {
249  int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
250  if (result != 0) {
251  logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
252  return;
253  }
254 
255  addILeappReportToReports(moduleOutputPath, currentCase);
256 
257  } catch (IOException ex) {
258  logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file system"), ex);
259  return;
260  }
261 
262  if (context.dataSourceIngestIsCancelled()) {
263  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
264  return;
265  }
266 
267  ProcessResult fileProcessorResult = iLeappFileProcessor.processFileSystem(dataSource, moduleOutputPath);
268 
269  if (fileProcessorResult == ProcessResult.ERROR) {
270  return;
271  }
272 
273  }
274 
282  private ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType) {
283 
284  ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
285  "\"" + iLeappExecutable + "\"", //NON-NLS
286  "-t", iLeappFileSystemType, //NON-NLS
287  "-i", sourceFilePath, //NON-NLS
288  "-o", moduleOutputPath.toString()
289  );
290  processBuilder.redirectError(moduleOutputPath.resolve("iLeapp_err.txt").toFile()); //NON-NLS
291  processBuilder.redirectOutput(moduleOutputPath.resolve("iLeapp_out.txt").toFile()); //NON-NLS
292  return processBuilder;
293  }
294 
300  private ProcessBuilder buildiLeappListCommand(Path moduleOutputPath) {
301 
302  ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
303  "\"" + iLeappExecutable + "\"", //NON-NLS
304  "-p"
305  );
306  processBuilder.redirectError(moduleOutputPath.resolve("iLeapp_paths_error.txt").toFile()); //NON-NLS
307  processBuilder.redirectOutput(moduleOutputPath.resolve("iLeapp_paths.txt").toFile()); //NON-NLS
308  return processBuilder;
309  }
310 
311  static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) {
312  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
313  /*
314  * Add an environment variable to force iLeapp to run with
315  * the same permissions Autopsy uses.
316  */
317  processBuilder.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS
318  return processBuilder;
319  }
320 
321  private static File locateExecutable(String executableName) throws FileNotFoundException {
322  String executableToFindName = Paths.get(ILEAPP, executableName).toString();
323 
324  File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, ILeappAnalyzerIngestModule.class.getPackage().getName(), false);
325  if (null == exeFile || exeFile.canExecute() == false) {
326  throw new FileNotFoundException(executableName + " executable not found.");
327  }
328  return exeFile;
329  }
330 
335  private void addILeappReportToReports(Path iLeappOutputDir, Case currentCase) {
336  List<String> allIndexFiles = new ArrayList<>();
337 
338  try (Stream<Path> walk = Files.walk(iLeappOutputDir)) {
339 
340  allIndexFiles = walk.map(x -> x.toString())
341  .filter(f -> f.toLowerCase().endsWith("index.html")).collect(Collectors.toList());
342 
343  if (!allIndexFiles.isEmpty()) {
344  // Check for existance of directory that holds report data if does not exist then report contains no data
345  String filePath = FilenameUtils.getFullPathNoEndSeparator(allIndexFiles.get(0));
346  File dataFilesDir = new File(Paths.get(filePath, "_TSV Exports").toString());
347  if (dataFilesDir.exists()) {
348  currentCase.addReport(allIndexFiles.get(0), MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_report_name());
349  }
350  }
351 
352  } catch (IOException | UncheckedIOException | TskCoreException ex) {
353  // catch the error and continue on as report is not added
354  logger.log(Level.WARNING, String.format("Error finding index file in path %s", iLeappOutputDir.toString()), ex);
355  }
356 
357  }
358 
359  /*
360  * Reads the iLeapp paths file to get the paths that we want to extract
361  *
362  * @param moduleOutputPath path where the file paths output will reside
363  */
364  private List<String> loadIleappPathFile(Path moduleOutputPath) throws FileNotFoundException, IOException {
365  List<String> iLeappPathsToProcess = new ArrayList<>();
366 
367  Path filePath = Paths.get(moduleOutputPath.toString(), ILEAPP_PATHS_FILE);
368 
369  try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toString()))) {
370  String line = reader.readLine();
371  while (line != null) {
372  if (line.contains("path list generation") || line.length() < 2) {
373  line = reader.readLine();
374  continue;
375  }
376  iLeappPathsToProcess.add(line.trim());
377  line = reader.readLine();
378  }
379  }
380 
381  return iLeappPathsToProcess;
382  }
383 
390  private void extractFilesFromImage(Content dataSource, List<String> iLeappPathsToProcess, Path moduleOutputPath) {
391  FileManager fileManager = getCurrentCase().getServices().getFileManager();
392 
393  for (String fullFilePath : iLeappPathsToProcess) {
394 
395  if (context.dataSourceIngestIsCancelled()) {
396  logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
397  break;
398  }
399 
400  String ffp = fullFilePath.replaceAll("\\*", "%");
401  ffp = FilenameUtils.normalize(ffp, true);
402  String fileName = FilenameUtils.getName(ffp);
403  String filePath = FilenameUtils.getPath(ffp);
404 
405  List<AbstractFile> iLeappFiles = new ArrayList<>();
406  try {
407  if (filePath.isEmpty()) {
408  iLeappFiles = fileManager.findFiles(dataSource, fileName); //NON-NLS
409  } else {
410  iLeappFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS
411  }
412  } catch (TskCoreException ex) {
413  logger.log(Level.WARNING, "No files found to process"); //NON-NLS
414  return;
415  }
416 
417  for (AbstractFile iLeappFile : iLeappFiles) {
418  Path parentPath = Paths.get(moduleOutputPath.toString(), iLeappFile.getParentPath());
419  File fileParentPath = new File(parentPath.toString());
420 
421  extractFileToOutput(dataSource, iLeappFile, fileParentPath, parentPath);
422  }
423  }
424  }
425 
433  private void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath) {
434  if (fileParentPath.exists()) {
435  if (!iLeappFile.isDir()) {
436  writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
437  } else {
438  try {
439  Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
440  } catch (IOException ex) {
441  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
442  }
443  }
444  } else {
445  try {
446  Files.createDirectories(parentPath);
447  } catch (IOException ex) {
448  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
449  }
450  if (!iLeappFile.isDir()) {
451  writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
452  } else {
453  try {
454  Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
455  } catch (IOException ex) {
456  logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
457  }
458  }
459  }
460  }
461 
468  private void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath) {
469  String fileName = iLeappFile.getName().replace(":", "-");
470  if (!fileName.matches(".") && !fileName.matches("..") && !fileName.toLowerCase().endsWith("-slack")) {
471  Path filePath = Paths.get(parentPath, fileName);
472  File localFile = new File(filePath.toString());
473  try {
474  ContentUtils.writeToFile(iLeappFile, localFile, context::dataSourceIngestIsCancelled);
475  } catch (ReadContentInputStream.ReadContentInputStreamException ex) {
476  logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).",
477  iLeappFile.getName(), iLeappFile.getId()), ex); //NON-NLS
478  } catch (IOException ex) {
479  logger.log(Level.WARNING, String.format("Error writing file local file '%s' (id=%d).",
480  filePath.toString(), iLeappFile.getId()), ex); //NON-NLS
481  }
482  }
483  }
484 }
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
List< AbstractFile > findFiles(String fileName)
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:1926
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 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: Fri Aug 6 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.