From 3f1f69688059e88f898044dcb4dbfa438ced0889 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Jan 2016 17:10:51 -0500 Subject: [PATCH] First draft of VMExtractor module prototype --- .../modules/vmextractor/Bundle.properties | 3 + .../vmextractor/VMExtractorIngestModule.java | 183 ++++++++++++++++++ .../VMExtractorIngestModuleFactory.java | 84 ++++++++ 3 files changed, 270 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/vmextractor/Bundle.properties create mode 100644 Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java create mode 100644 Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModuleFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/vmextractor/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/Bundle.properties new file mode 100644 index 0000000000..e14e90fdc6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/Bundle.properties @@ -0,0 +1,3 @@ +VMExtractorIngestModuleFactory.moduleDisplayName=Virtual Machine Extractor +VMExtractorIngestModuleFactory.moduleDescription=Extracts virtual machine files and adds them to a case as data sources. +VMExtractorIngestModuleFactory.version=1.0 \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java new file mode 100644 index 0000000000..42a8987386 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModule.java @@ -0,0 +1,183 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2012-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.vmextractor; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.ImageDSProcessor; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleAdapter; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; +import org.sleuthkit.autopsy.ingest.IngestJobSettings; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.RunIngestModulesDialog; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * An ingest module that extracts virtual machine files and adds them to a case + * as data sources. + */ +@Immutable +final class VMExtractorIngestModule extends DataSourceIngestModuleAdapter { + + private static final Logger logger = Logger.getLogger(VMExtractorIngestModule.class.getName()); + private final List vmImages = new ArrayList<>(); + + /** + * @inheritDoc + */ + @Override + public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) { + try { + List vmFiles = Case.getCurrentCase().getServices().getFileManager().findFiles(dataSource, "%.img"); + // RJCTODO: Progress bar set up + for (AbstractFile file : vmFiles) { + try { + ingestVirtualMachineImage(file); + // RJCTODO: Progress bar update + } catch (InterruptedException ex) { + logger.log(Level.INFO, "Interrupted while adding image", ex); // RJCTODO: Improve logging + } catch (IOException ex) { + logger.log(Level.INFO, "Unable to save VM file to disk", ex); // RJCTODO: Improve logging + } + } + return ProcessResult.OK; + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error querying case database", ex); // RJCTODO: Improve logging + return ProcessResult.ERROR; + } + } + + /** + * RJCTODO + * + * @param vmFile + */ + private void ingestVirtualMachineImage(AbstractFile vmFile) throws InterruptedException, IOException { + /* + * Write the virtual machine file to disk. + */ + String imageFileName = vmFile.getName() + "_" + vmFile.getId(); + Path imageFilePath = Paths.get(Case.getCurrentCase().getModuleDirectory(), imageFileName); + File imageFile = imageFilePath.toFile(); + ContentUtils.writeToFile(vmFile, imageFile); + + /* + * Try to add the virtual machine file to the case as an image. + */ + vmImages.clear(); + UUID taskId = UUID.randomUUID(); + Case.getCurrentCase().notifyAddingDataSource(taskId); + ImageDSProcessor dataSourceProcessor = new ImageDSProcessor(); + dataSourceProcessor.setDataSourceOptions(imageFile.getAbsolutePath(), "", false); // RJCTODO: Setting for FAT orphans? + synchronized (this) { + dataSourceProcessor.run(new AddDataSourceProgressMonitor(), new AddDataSourceCallback()); + this.wait(); + } + + /* + * If the image was added, analyze it with the ingest modules for this + * ingest context. + */ + if (!vmImages.isEmpty()) { + Case.getCurrentCase().notifyDataSourceAdded(vmImages.get(0), taskId); + List images = new ArrayList<>(vmImages); + IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName()); // RJCTODO: Problem to solve, context string sharing! + for (String warning : ingestJobSettings.getWarnings()) { + logger.log(Level.WARNING, warning); + } + IngestManager.getInstance().queueIngestJob(images, ingestJobSettings); + } else { + Case.getCurrentCase().notifyFailedAddingDataSource(taskId); + // RJCTODO: Some logging here + } + } + + /** + * RJCTODO + */ + // RJCTODO: Consider implementing in terms of the ingest progress monitor + private static final class AddDataSourceProgressMonitor implements DataSourceProcessorProgressMonitor { + + @Override + public void setIndeterminate(final boolean indeterminate) { + } + + @Override + public void setProgress(final int progress) { + } + + @Override + public void setProgressText(final String text) { + } + + } + + /** + * A callback for the data source processor. + */ + private final class AddDataSourceCallback extends DataSourceProcessorCallback { + + /** + * @inheritDoc + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List content) { + /* + * Save a reference to the content object so it can be used to + * create a new ingest job. + */ + if (!content.isEmpty()) { + vmImages.add(content.get(0)); + } + + // RJCTODO: Log errors if any + + /* + * Unblock the processing thread. + */ + synchronized (VMExtractorIngestModule.this) { + VMExtractorIngestModule.this.notify(); + } + } + + /** + * @inheritDoc + */ + @Override + public void doneEDT(DataSourceProcessorResult result, List errList, List newContents) { + done(result, errList, newContents); + } + + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModuleFactory.java new file mode 100644 index 0000000000..c853dbd488 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/vmextractor/VMExtractorIngestModuleFactory.java @@ -0,0 +1,84 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2012-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.vmextractor; + +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; +import org.sleuthkit.autopsy.ingest.IngestModuleFactory; +import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * An factory for ingest modules that extracts virtual machine files and adds + * them to a case as data sources. + */ +@ServiceProvider(service = IngestModuleFactory.class) +public final class VMExtractorIngestModuleFactory extends IngestModuleFactoryAdapter { + + /** + * Gets the module name. + * + * @return The module name as a string. + */ + static String getModuleName() { + return NbBundle.getMessage(VMExtractorIngestModuleFactory.class, "VMExtractorIngestModuleFactory.moduleDisplayName"); + } + + /** + * @inheritDoc + */ + @Override + public String getModuleDisplayName() { + return getModuleName(); + } + + /** + * @inheritDoc + */ + @Override + public String getModuleDescription() { + return NbBundle.getMessage(this.getClass(), "VMExtractorIngestModuleFactory.moduleDescription"); + } + + /** + * @inheritDoc + */ + @Override + public String getModuleVersionNumber() { + return NbBundle.getMessage(this.getClass(), "VMExtractorIngestModuleFactory.version"); + } + + /** + * @inheritDoc + */ + @Override + public boolean isDataSourceIngestModuleFactory() { + return true; + } + + /** + * @inheritDoc + */ + @Override + public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) { + return new VMExtractorIngestModule(); + } + +}