19package org.sleuthkit.autopsy.modules.leappanalyzers;
21import java.io.BufferedReader;
23import java.io.FileNotFoundException;
24import java.io.FileReader;
25import java.io.IOException;
26import java.io.UncheckedIOException;
27import java.nio.file.Files;
28import java.nio.file.Path;
29import java.nio.file.Paths;
30import java.text.SimpleDateFormat;
31import java.util.Arrays;
33import java.util.ArrayList;
34import java.util.Locale;
35import java.util.logging.Level;
36import java.util.stream.Collectors;
37import java.util.stream.Stream;
38import org.apache.commons.io.FilenameUtils;
39import org.openide.modules.InstalledFileLocator;
40import org.openide.util.NbBundle;
41import org.sleuthkit.autopsy.casemodule.Case;
42import static org.sleuthkit.autopsy.casemodule.Case.getCurrentCase;
43import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
44import org.sleuthkit.autopsy.casemodule.services.FileManager;
45import org.sleuthkit.autopsy.coreutils.ExecUtil;
46import org.sleuthkit.autopsy.coreutils.Logger;
47import org.sleuthkit.autopsy.coreutils.PlatformUtil;
48import org.sleuthkit.autopsy.datamodel.ContentUtils;
49import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
50import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
51import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
52import org.sleuthkit.autopsy.ingest.IngestJobContext;
53import org.sleuthkit.autopsy.ingest.IngestMessage;
54import org.sleuthkit.autopsy.ingest.IngestServices;
55import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
56import org.sleuthkit.datamodel.AbstractFile;
57import org.sleuthkit.datamodel.Content;
58import org.sleuthkit.datamodel.FileSystem;
59import org.sleuthkit.datamodel.Image;
60import org.sleuthkit.datamodel.LocalFilesDataSource;
61import org.sleuthkit.datamodel.ReadContentInputStream;
62import org.sleuthkit.datamodel.TskCoreException;
63import org.sleuthkit.datamodel.TskData;
73 private static final String
ILEAPP =
"iLeapp";
78 private static final String
XMLFILE =
"ileapp-artifact-attribute-reference.xml";
84 new String[]{
"sms.db",
"/private/var/mobile/Library/SMS/"},
85 new String[]{
"sms.db",
"/var/mobile/Library/SMS/"},
86 new String[]{
"AddressBook.sqlitedb",
"/private/var/mobile/Library/AddressBook/"},
87 new String[]{
"AddressBook.sqlitedb",
"/var/mobile/Library/AddressBook/"},
88 new String[]{
"com.apple.mobilephone.plist",
"/private/var/mobile/Library/Preferences/"},
89 new String[]{
"com.apple.mobilephone.plist",
"/var/mobile/Library/Preferences/"});
97 ILeappAnalyzerIngestModule() {
102 "ILeappAnalyzerIngestModule.executable.not.found=iLeapp Executable Not Found.",
103 "ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows.",
104 "ILeappAnalyzerIngestModule.error.ileapp.file.processor.init=Failure to initialize ILeappProcessFile"})
110 throw new IngestModuleException(NbBundle.getMessage(
this.getClass(),
"IleappAnalyzerIngestModule.not.64.bit.os"));
120 throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_error_ileapp_file_processor_init(), ex);
125 }
catch (FileNotFoundException exception) {
126 logger.log(Level.WARNING,
"iLeapp executable not found.", exception);
127 throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_executable_not_found(), exception);
133 "ILeappAnalyzerIngestModule.error.running.iLeapp=Error running iLeapp, see log file.",
134 "ILeappAnalyzerIngestModule.error.creating.output.dir=Error creating iLeapp module output directory.",
135 "ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp",
136 "ILeappAnalyzerIngestModule_processing_iLeapp_results=Processing iLeapp results",
137 "ILeappAnalyzerIngestModule.has.run=iLeapp",
138 "ILeappAnalyzerIngestModule.iLeapp.cancelled=iLeapp run was canceled",
139 "ILeappAnalyzerIngestModule.completed=iLeapp Processing Completed",
140 "ILeappAnalyzerIngestModule.report.name=iLeapp Html Report",
141 "ILeappAnalyzerIngestModule.notIOS.skipped=iLeapp skipped: data source does not appear to be an iOS device."})
146 logger.log(Level.INFO,
"iLeapp: data source does not appear to be iOS, skipping.");
148 MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_notIOS_skipped());
154 statusHelper.
progress(Bundle.ILeappAnalyzerIngestModule_running_iLeapp());
159 Files.createDirectories(tempOutputPath);
160 }
catch (IOException ex) {
161 logger.log(Level.SEVERE, String.format(
"Error creating iLeapp output directory %s", tempOutputPath.toString()), ex);
166 List<String> iLeappPathsToProcess;
171 logger.log(Level.SEVERE, String.format(
"Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
176 if (iLeappPathsToProcess.isEmpty()) {
177 logger.log(Level.SEVERE, String.format(
"Error getting file paths to search, list is empty"));
181 }
catch (IOException ex) {
182 logger.log(Level.SEVERE, String.format(
"Error when trying to execute iLeapp program getting file paths to search"), ex);
187 if ((
context.getDataSource() instanceof LocalFilesDataSource)) {
193 List<AbstractFile> iLeappFilesToProcess =
LeappFileProcessor.findLeappFilesToProcess(dataSource);
194 if (!iLeappFilesToProcess.isEmpty()) {
196 Integer filesProcessedCount = 0;
197 for (AbstractFile iLeappFile : iLeappFilesToProcess) {
198 processILeappFile(dataSource, currentCase, statusHelper, filesProcessedCount, iLeappFile);
199 filesProcessedCount++;
205 statusHelper.
progress(Bundle.ILeappAnalyzerIngestModule_processing_iLeapp_results());
207 processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
210 Bundle.ILeappAnalyzerIngestModule_has_run(),
211 Bundle.ILeappAnalyzerIngestModule_completed());
227 AbstractFile iLeappFile) {
228 statusHelper.
progress(NbBundle.getMessage(
this.getClass(),
"ILeappAnalyzerIngestModule.processing.file", iLeappFile.getName()), filesProcessedCount);
230 String currentTime =
new SimpleDateFormat(
"yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());
233 Files.createDirectories(moduleOutputPath);
234 }
catch (IOException ex) {
235 logger.log(Level.SEVERE, String.format(
"Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
239 ProcessBuilder iLeappCommand =
buildiLeappCommand(moduleOutputPath, iLeappFile.getLocalAbsPath(), iLeappFile.getNameExtension());
243 logger.log(Level.WARNING, String.format(
"Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
249 }
catch (IOException ex) {
250 logger.log(Level.SEVERE, String.format(
"Error when trying to execute iLeapp program against file %s", iLeappFile.getLocalAbsPath()), ex);
254 if (
context.dataSourceIngestIsCancelled()) {
255 logger.log(Level.INFO,
"ILeapp Analyser ingest module run was canceled");
271 statusHelper.
progress(NbBundle.getMessage(
this.getClass(),
"ILeappAnalyzerIngestModule.processing.filesystem"));
272 String currentTime =
new SimpleDateFormat(
"yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());
275 Files.createDirectories(moduleOutputPath);
276 }
catch (IOException ex) {
277 logger.log(Level.SEVERE, String.format(
"Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
281 ProcessBuilder iLeappCommand =
buildiLeappCommand(moduleOutputPath, directoryToProcess,
"fs");
285 logger.log(Level.WARNING, String.format(
"Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
291 }
catch (IOException ex) {
292 logger.log(Level.SEVERE, String.format(
"Error when trying to execute iLeapp program against file system"), ex);
296 if (
context.dataSourceIngestIsCancelled()) {
297 logger.log(Level.INFO,
"ILeapp Analyser ingest module run was canceled");
313 private ProcessBuilder
buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType) {
317 "-t", iLeappFileSystemType,
318 "-i", sourceFilePath,
319 "-o", moduleOutputPath.toString()
321 processBuilder.directory(moduleOutputPath.toFile());
322 processBuilder.redirectError(moduleOutputPath.resolve(
"iLeapp_err.txt").toFile());
323 processBuilder.redirectOutput(moduleOutputPath.resolve(
"iLeapp_out.txt").toFile());
324 return processBuilder;
341 processBuilder.directory(moduleOutputPath.toFile());
342 processBuilder.redirectError(moduleOutputPath.resolve(
"iLeapp_paths_error.txt").toFile());
343 processBuilder.redirectOutput(moduleOutputPath.resolve(
"iLeapp_paths.txt").toFile());
344 return processBuilder;
348 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
353 processBuilder.environment().put(
"__COMPAT_LAYER",
"RunAsInvoker");
354 return processBuilder;
358 String executableToFindName = Paths.get(
ILEAPP, executableName).toString();
360 File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, ILeappAnalyzerIngestModule.class.getPackage().getName(),
false);
361 if (
null == exeFile || exeFile.canExecute() ==
false) {
362 throw new FileNotFoundException(executableName +
" executable not found.");
372 List<String> allIndexFiles;
374 try (Stream<Path> walk = Files.walk(iLeappOutputDir)) {
376 allIndexFiles = walk.map(x -> x.toString())
377 .filter(f -> f.toLowerCase().endsWith(
"index.html")).collect(Collectors.toList());
379 if (!allIndexFiles.isEmpty()) {
381 String filePath = FilenameUtils.getFullPathNoEndSeparator(allIndexFiles.get(0));
382 File dataFilesDir =
new File(Paths.get(filePath,
"_TSV Exports").toString());
383 if (dataFilesDir.exists()) {
384 currentCase.
addReport(allIndexFiles.get(0),
MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_report_name());
388 }
catch (IOException | UncheckedIOException | TskCoreException ex) {
390 logger.log(Level.WARNING, String.format(
"Error finding index file in path %s", iLeappOutputDir.toString()), ex);
400 private List<String>
loadIleappPathFile(Path moduleOutputPath)
throws FileNotFoundException, IOException {
401 List<String> iLeappPathsToProcess =
new ArrayList<>();
405 try (BufferedReader reader =
new BufferedReader(
new FileReader(filePath.toString()))) {
406 String line = reader.readLine();
407 while (line !=
null) {
408 if (line.contains(
"path list generation") || line.length() < 2) {
409 line = reader.readLine();
412 iLeappPathsToProcess.add(line.trim());
413 line = reader.readLine();
417 return iLeappPathsToProcess;
428 FileManager fileManager = getCurrentCase().getServices().getFileManager();
430 for (String fullFilePath : iLeappPathsToProcess) {
432 if (
context.dataSourceIngestIsCancelled()) {
433 logger.log(Level.INFO,
"ILeapp Analyser ingest module run was canceled");
437 String ffp = fullFilePath.replaceAll(
"\\*",
"%");
438 ffp = FilenameUtils.normalize(ffp,
true);
439 String fileName = FilenameUtils.getName(ffp);
440 String filePath = FilenameUtils.getPath(ffp);
442 List<AbstractFile> iLeappFiles;
444 if (filePath.isEmpty()) {
445 iLeappFiles = fileManager.
findFiles(dataSource, fileName);
447 iLeappFiles = fileManager.
findFiles(dataSource, fileName, filePath);
449 }
catch (TskCoreException ex) {
450 logger.log(Level.WARNING,
"No files found to process");
454 for (AbstractFile iLeappFile : iLeappFiles) {
455 Path parentPath = Paths.get(moduleOutputPath.toString(), iLeappFile.getParentPath());
456 File fileParentPath =
new File(parentPath.toString());
471 private void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath) {
472 if (fileParentPath.exists()) {
473 if (!iLeappFile.isDir()) {
477 Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
478 }
catch (IOException ex) {
479 logger.log(Level.INFO, String.format(
"Error creating iLeapp output directory %s", parentPath.toString()), ex);
484 Files.createDirectories(parentPath);
485 }
catch (IOException ex) {
486 logger.log(Level.INFO, String.format(
"Error creating iLeapp output directory %s", parentPath.toString()), ex);
488 if (!iLeappFile.isDir()) {
492 Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
493 }
catch (IOException ex) {
494 logger.log(Level.INFO, String.format(
"Error creating iLeapp output directory %s", parentPath.toString()), ex);
507 private void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath) {
508 String fileName = iLeappFile.getName().replace(
":",
"-");
509 if (!fileName.matches(
".") && !fileName.matches(
"..") && !fileName.toLowerCase().endsWith(
"-slack")) {
510 Path filePath = Paths.get(parentPath, fileName);
511 File localFile =
new File(filePath.toString());
514 }
catch (ReadContentInputStream.ReadContentInputStreamException ex) {
515 logger.log(Level.WARNING, String.format(
"Error reading file '%s' (id=%d).",
516 iLeappFile.getName(), iLeappFile.getId()), ex);
517 }
catch (IOException ex) {
518 logger.log(Level.WARNING, String.format(
"Error writing file local file '%s' (id=%d).",
519 filePath.toString(), iLeappFile.getId()), ex);
536 if (dataSource instanceof Image) {
538 boolean hasDefinitelyNonIOSFs =
false;
539 for (FileSystem fs : ((Image) dataSource).getFileSystems()) {
540 switch (fs.getFsType()) {
541 case TSK_FS_TYPE_EXT2:
542 case TSK_FS_TYPE_EXT3:
543 case TSK_FS_TYPE_EXT4:
544 case TSK_FS_TYPE_EXT_DETECT:
545 case TSK_FS_TYPE_YAFFS2:
546 case TSK_FS_TYPE_YAFFS2_DETECT:
547 case TSK_FS_TYPE_NTFS:
548 case TSK_FS_TYPE_NTFS_DETECT:
549 hasDefinitelyNonIOSFs =
true;
555 if (hasDefinitelyNonIOSFs) {
559 }
catch (TskCoreException ex) {
560 logger.log(Level.WARNING,
"Error checking filesystem types for iLeapp iOS detection", ex);
576 FileManager fileManager = getCurrentCase().getServices().getFileManager();
579 if (!fileManager.
findFiles(dataSource, fileInfo[0], fileInfo[1]).isEmpty()) {
582 }
catch (TskCoreException ex) {
583 logger.log(Level.WARNING, String.format(
"Error searching for iOS indicator file '%s'", fileInfo[0]), ex);
597 Bundle.ILeappAnalyzerIngestModule_error_running_iLeapp());
void addReport(String localPath, String srcModuleName, String reportName)
static Case getCurrentCase()
String getModuleDirectory()
String getTempDirectory()
List< AbstractFile > findFiles(String fileName)
static int execute(ProcessBuilder processBuilder)
synchronized static Logger getLogger(String name)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void progress(int workUnits)
void switchToIndeterminate()
void switchToDeterminate(int workUnits)
static IngestMessage createMessage(MessageType messageType, String source, String subject, String detailsHtml)
void postMessage(final IngestMessage message)
static synchronized IngestServices getInstance()
void addILeappReportToReports(Path iLeappOutputDir, Case currentCase)
ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper)
void processILeappFile(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, int filesProcessedCount, AbstractFile iLeappFile)
ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType)
LeappFileProcessor iLeappFileProcessor
void writeErrorMsgToIngestInbox()
static final String ILEAPP_FS
static final String ILEAPP_EXECUTABLE
static final String ILEAPP_PATHS_FILE
static File locateExecutable(String executableName)
void extractFilesFromDataSource(Content dataSource, List< String > iLeappPathsToProcess, Path moduleOutputPath)
void processILeappFs(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, String directoryToProcess)
boolean isIOSDataSource(Content dataSource)
static final String XMLFILE
static final String MODULE_NAME
List< String > loadIleappPathFile(Path moduleOutputPath)
static final Logger logger
static final String ILEAPP
void startUp(IngestJobContext context)
static final List< String[]> IOS_INDICATOR_FILES
static ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine)
boolean hasIOSIndicatorFiles(Content dataSource)
void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath)
ProcessBuilder buildiLeappListCommand(Path moduleOutputPath)
void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath)