Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Sean-M 2013-05-31 11:13:34 -04:00
commit 2bcb924deb
31 changed files with 905 additions and 1299 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -825,7 +825,10 @@ public class IngestManager {
}
/**
* File ingest pipeline processor. Worker runs until AbstractFile queue is
* File ingest pipeline processor. Worker thread that queries
* the scheduler for new files.
* Modules are assumed to already be initialized.
* runs until AbstractFile queue is
* consumed New instance is created and started when data arrives and
* previous pipeline completed.
*/

View File

@ -23,7 +23,9 @@ package org.sleuthkit.autopsy.ingest;
/**
* Base interface for ingest modules
*/
public interface IngestModuleAbstract {
public abstract class IngestModuleAbstract {
private String args;
/**
* Possible module types for the implementing classes
@ -41,68 +43,78 @@ public interface IngestModuleAbstract {
};
/**
* Notification from manager that brand new ingest should be initiated..
* Module loads its configuration and performs initialization.
* Invoked once per new worker thread, per ingest.
* In this method initialize always IngestServices handle
* using IngestServices.getDefault() lazy-loading approach.
* Invoked every time an ingest session is started by the framework.
* A module should support multiple invocations of init() throughout the application life-cycle.
* In this method, the module should reinitialize its internal objects and resources and get them ready
* for a brand new ingest processing.
*
* Here are some things you may do in this method if you'll need them later.
* - Get a handle to the ingest services using org.sleuthkit.autopsy.ingest.IngestServices.getDefault().
* - Get the current case using org.sleuthkit.autopsy.ingest.IngestServices.getCurrentSleuthkitCaseDb().
*
* NEVER initialize IngestServices handle in the member declaration, because it might result
* in multiple instances of the singleton -- different class loaders are used in different modules.
* @param initContext context used to initialize some modules
*/
public void init(IngestModuleInit initContext);
abstract public void init(IngestModuleInit initContext);
/**
* Notification from manager that there is no more content to process and all work is done.
* Module performs any clean-up of internal resources, and finalizes processing to produce complete result
* Module also posts ingest message indicating it is done, and posts ingest stats and errors in the details of the message.
* Invoked when an ingest session completes.
* The module should perform any resource (files, handles, caches)
* cleanup in this method and submit final results and post a final ingest inbox message.
*/
public void complete();
abstract public void complete();
/**
* Notification from manager to stop processing due to some interruption (user, error, exception)
* Module performs any clean-up of internal resources
* It may also discard any pending results, but it should ensure it is in a defined state so that ingest can be rerun later.
* Invoked on a module when an ingest session is interrupted by the user or system.
* The method implementation should be similar to complete() in that the
* module should perform any cleanup work.
* If there is pending data to be processed or pending results to be reported by the module
* then the results should be rejected and ignored and the method should return as early as possible.
* It should ensure it is in a defined state so that ingest can be rerun later.
*/
public void stop();
abstract public void stop();
/**
* Gets specific name of the module
* The name should be unique across modules
* Returns unique name of the module. Should not have collisions.
* @return unique module name
*/
public String getName();
abstract public String getName();
/**
* Gets the module version
* @return module version string
*/
public String getVersion();
abstract public String getVersion();
/**
* Gets user-friendly description of the module
* @return module description
*/
public String getDescription();
abstract public String getDescription();
/**
* Returns type of the module
* Returns type of the module (Image-level or file-level)
* @return module type
*/
public ModuleType getType();
abstract public ModuleType getType();
/**
* Gets the arguments as set in XML
* @return arguments string
*/
public String getArguments();
public String getArguments() {
return args;
}
/**
* Sets the arguments from XML
* @param args arguments string in XML
*/
public void setArguments(String args);
public void setArguments(String a_args) {
args = a_args;
}
/**
* A module can manage and use additional threads to perform some work in the background.
@ -112,7 +124,7 @@ public interface IngestModuleAbstract {
* @return true if any background threads/workers managed by this module are still running or are pending to be run,
* false if all work has been done, or if background threads are not used/managed by this module
*/
public boolean hasBackgroundJobsRunning();
abstract public boolean hasBackgroundJobsRunning();
/**
@ -121,7 +133,9 @@ public interface IngestModuleAbstract {
*
* @return true if this module has a simple (run-time) configuration
*/
public boolean hasSimpleConfiguration();
public boolean hasSimpleConfiguration() {
return false;
}
/**
* Used to determine if a module has implemented an advanced (general)
@ -129,21 +143,23 @@ public interface IngestModuleAbstract {
*
* @return true if this module has an advanced configuration
*/
public boolean hasAdvancedConfiguration();
public boolean hasAdvancedConfiguration() {
return false;
}
/**
* Called by the ingest manager if the simple (run-time) configuration
* panel should save its current state so that the settings can be used
* during the ingest.
*/
public void saveSimpleConfiguration();
public void saveSimpleConfiguration() {}
/**
* If module implements advanced configuration panel
* it should read its current state and make it persistent / save it in this method
* so that the new configuration will be in effect during the ingest.
*/
public void saveAdvancedConfiguration();
public void saveAdvancedConfiguration() {}
/**
* Returns a panel that displays the simple (run-time) configuration.
@ -155,14 +171,18 @@ public interface IngestModuleAbstract {
*
* @return JPanel containing basic configuration widgets or null if simple configuration is not available
*/
public javax.swing.JPanel getSimpleConfiguration();
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
/**
* Implements advanced module configuration exposed to the user before ingest starts
* Implements advanced module conf iguration exposed to the user before ingest starts
* The module is responsible for preserving / saving its configuration state
* In addition, saveAdvancedConfiguration() can be used
*
* @return JPanel containing advanced configuration widgets or null if advanced configuration is not available
*/
public javax.swing.JPanel getAdvancedConfiguration();
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
};
}

View File

@ -23,7 +23,7 @@ import org.sleuthkit.datamodel.AbstractFile;
/**
* Ingest module interface that will be called for every file in the image
*/
public interface IngestModuleAbstractFile extends IngestModuleAbstract {
public abstract class IngestModuleAbstractFile extends IngestModuleAbstract {
/**
* Return value resulting from processing AbstractFile
@ -36,6 +36,11 @@ public interface IngestModuleAbstractFile extends IngestModuleAbstract {
UNKNOWN ///< Indicates that a return value for the module is not known. This should not be returned directly by modules, but is used to indicate the module has not set its return value (e.g. it never ran)
};
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
/**
* Entry point to process file / directory by the module. See \ref ingestmodule_making for details
* on what modules are responsible for doing.
@ -44,5 +49,5 @@ public interface IngestModuleAbstractFile extends IngestModuleAbstract {
* @param abstractFile file to process
* @return ProcessResult result of the processing that can be used in the pipeline as a hint whether to further process this file
*/
public ProcessResult process(PipelineContext<IngestModuleAbstractFile>pipelineContext, AbstractFile abstractFile);
abstract public ProcessResult process(PipelineContext<IngestModuleAbstractFile>pipelineContext, AbstractFile abstractFile);
}

View File

@ -26,26 +26,27 @@ import org.sleuthkit.datamodel.Image;
* Image ingest modules run each in its own background thread
* in parallel to the file processing ingest pipeline and other image ingest modules
*/
public interface IngestModuleImage extends IngestModuleAbstract {
public abstract class IngestModuleImage extends IngestModuleAbstract {
@Override
public ModuleType getType() {
return ModuleType.Image;
}
/**
* Entry point to process the image by the module.
* Called with the image to analyze.
*
* Module does all the processing work in this method.
* It is responsible for extracting content of interest from the image (i.e. using DataModel API) and processing it.
* Results of processing, such as extracted data or analysis results, should be posted to the blackboard.
* Modules typically use FileManager to get specific files to analyze.
*
* The module notifies the ingest inbox of interesting events (data, errors, warnings, infos)
* by posting ingest messages
* Results should be posted to the blackboard.
* The module should also send messages to the ingest inbox of interesting events (data, errors, warnings, infos).
* The module notifies data viewers by firing events using IngestManagerProxy.fireModuleDataEvent
*
* The module is responsible for posting progress to controller
* And to periodically check controller if it should break out of the processing loop because task has been canceled
* The module will have its own progress bar while it is running and it should update it with the Controller object.
*
* @param pipelineContext the context in which the ingest runs (with its own settings, modules, etc)
* @param image to process
* @param controller to post progress to and to use for checking if cancellation has occurred
* @param pipelineContext Context in which the ingest pipeline is running (Settings, modules, etc)
* @param image Image to process
* @param controller Used to update progress bar and to check if the task has been canceled.
*/
public void process(PipelineContext<IngestModuleImage>pipelineContext, Image image, IngestImageWorkerController controller);
abstract public void process(PipelineContext<IngestModuleImage>pipelineContext, Image image, IngestImageWorkerController controller);
}

View File

@ -222,27 +222,18 @@ public final class IngestModuleLoader {
//netbeans uses custom class loader, otherwise can't load classes from other modules
final Class<?> moduleClass = Class.forName(location, false, classLoader);
final Type[] intfs = moduleClass.getGenericInterfaces();
final Type intf = moduleClass.getGenericSuperclass();
if (intfs.length != 0 && pType != null) {
//check if one of the module interfaces matches the pipeline type
boolean interfaceFound = false;
if (pType != null) {
Class<?> moduleMeta = ((IngestModuleMapping) pType).getIngestModuleInterface();
String moduleIntNameCan = moduleMeta.getCanonicalName();
String[] moduleIntNameTok = moduleIntNameCan.split(" ");
String moduleIntName = moduleIntNameTok[moduleIntNameTok.length - 1];
for (Type intf : intfs) {
String intNameCan = intf.toString();
String[] intNameCanTok = intNameCan.split(" ");
String intName = intNameCanTok[intNameCanTok.length - 1];
if (intName.equals(moduleIntName)) {
interfaceFound = true;
break;
}
}
if (interfaceFound == false) {
String intNameCan = intf.toString();
String[] intNameCanTok = intNameCan.split(" ");
String intName = intNameCanTok[intNameCanTok.length - 1];
if (!intName.equals(moduleIntName)) {
moduleErrors = true;
logger.log(Level.WARNING, "Module class: " + location
+ " does not implement correct interface: " + moduleMeta.getName()

View File

@ -20,11 +20,9 @@ package org.sleuthkit.autopsy.exifparser;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.lang.GeoLocation;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.GpsDirectory;
@ -33,26 +31,19 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
@ -62,15 +53,13 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
* Ingests an image file and, if available, adds it's date, latitude, longitude,
* altitude, device model, and device make to a blackboard artifact.
*/
public final class ExifParserFileIngestModule implements IngestModuleAbstractFile {
public final class ExifParserFileIngestModule extends IngestModuleAbstractFile {
private IngestServices services;
final public static String MODULE_NAME = "Exif Parser";
final public static String MODULE_VERSION = "1.0";
private String args;
private static final int readHeaderSize = 2;
private final byte[] fileHeaderBuffer = new byte[readHeaderSize];
private static final char JPEG_SIGNATURE_BE = 0xFFD8;
@ -260,17 +249,6 @@ public final class ExifParserFileIngestModule implements IngestModuleAbstractFil
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public String getName() {
@ -297,41 +275,8 @@ public final class ExifParserFileIngestModule implements IngestModuleAbstractFil
//module specific cleanup due to interruption here
}
@Override
public IngestModuleAbstract.ModuleType getType() {
return IngestModuleAbstract.ModuleType.AbstractFile;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
}

View File

@ -47,13 +47,12 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskException;
public class HashDbIngestModule implements IngestModuleAbstractFile {
public class HashDbIngestModule extends IngestModuleAbstractFile {
private static HashDbIngestModule instance = null;
public final static String MODULE_NAME = "Hash Lookup";
public final static String MODULE_DESCRIPTION = "Identifies known and notables files using supplied hash databases, such as a standard NSRL database.";
final public static String MODULE_VERSION = "1.0";
private String args;
private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName());
private IngestServices services;
private SleuthkitCase skCase;
@ -195,16 +194,6 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public ProcessResult process(PipelineContext<IngestModuleAbstractFile>pipelineContext, AbstractFile file) {
@ -216,10 +205,6 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
return processFile(file);
}
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
public boolean hasBackgroundJobsRunning() {

View File

@ -74,7 +74,7 @@
<Component id="pagePreviousButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="pageNextButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="71" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="sourceComboBox" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane1" pref="0" max="32767" attributes="0"/>
@ -105,7 +105,7 @@
<Component id="pagePreviousButton" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="293" max="32767" attributes="0"/>
<Component id="jScrollPane1" pref="377" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -77,7 +77,7 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
*
* Registered as a module in layer.xml
*/
public final class KeywordSearchIngestModule implements IngestModuleAbstractFile {
public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
enum UpdateFrequency {
@ -98,7 +98,6 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile
public static final String MODULE_NAME = "Keyword Search";
public static final String MODULE_DESCRIPTION = "Performs file indexing and periodic search using keywords and regular expressions in lists.";
final public static String MODULE_VERSION = "1.0";
private String args;
private static KeywordSearchIngestModule instance = null;
private IngestServices services;
private Ingester ingester = null;
@ -326,16 +325,6 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
/**
* Initializes the module for new ingest run Sets up threads, timers,
* retrieves settings, keyword lists to run on
@ -427,11 +416,6 @@ public final class KeywordSearchIngestModule implements IngestModuleAbstractFile
searchTimer.start();
}
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
public boolean hasSimpleConfiguration() {
return true;

View File

@ -359,7 +359,7 @@ public class Server {
} else {
loggingPropertiesFilePath += "logging-release.properties";
}
loggingPropertiesFilePath = PlatformUtil.getOSFilePath(loggingPropertiesFilePath);
//loggingPropertiesFilePath = PlatformUtil.getOSFilePath(loggingPropertiesFilePath);
final String loggingProperties = loggingPropertiesOpt + loggingPropertiesFilePath;
final String [] SOLR_START_CMD = {

View File

@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.TskData;
/**
* Chrome recent activity extraction
*/
public class Chrome extends Extract implements IngestModuleImage {
public class Chrome extends Extract {
private static final String chquery = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "
+ "last_visit_time, urls.hidden, visits.visit_time, (SELECT urls.url FROM urls WHERE urls.id=visits.url) as from_visit, visits.transition FROM urls, visits WHERE urls.id = visits.url";
@ -67,7 +67,6 @@ public class Chrome extends Extract implements IngestModuleImage {
private final Logger logger = Logger.getLogger(this.getClass().getName());
public int ChromeCount = 0;
final public static String MODULE_VERSION = "1.0";
private String args;
private IngestServices services;
//hide public constructor to prevent from instantiation by ingest module loader
@ -80,15 +79,6 @@ public class Chrome extends Extract implements IngestModuleImage {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public void process(PipelineContext<IngestModuleImage>pipelineContext, Image image, IngestImageWorkerController controller) {
@ -468,38 +458,6 @@ public class Chrome extends Extract implements IngestModuleImage {
return "Extracts activity from the Google Chrome browser.";
}
@Override
public ModuleType getType() {
return ModuleType.Image;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public boolean hasBackgroundJobsRunning() {

View File

@ -34,7 +34,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.report.SQLiteDBConnect;
import org.sleuthkit.datamodel.*;
abstract public class Extract implements IngestModuleImage{
abstract public class Extract extends IngestModuleImage{
protected Case currentCase = Case.getCurrentCase(); // get the most updated case
protected SleuthkitCase tskCase = currentCase.getSleuthkitCase();

View File

@ -70,7 +70,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.*;
public class ExtractIE extends Extract implements IngestModuleImage {
public class ExtractIE extends Extract {
private static final Logger logger = Logger.getLogger(ExtractIE.class.getName());
private IngestServices services;
@ -91,7 +91,6 @@ public class ExtractIE extends Extract implements IngestModuleImage {
public LinkedHashMap<String, Object> IE_OBJ;
boolean pascoFound = false;
final public static String MODULE_VERSION = "1.0";
private String args;
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
private ExecUtil execPasco;
@ -106,15 +105,6 @@ public class ExtractIE extends Extract implements IngestModuleImage {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public void process(PipelineContext<IngestModuleImage>pipelineContext, Image image, IngestImageWorkerController controller) {
@ -593,39 +583,6 @@ public class ExtractIE extends Extract implements IngestModuleImage {
return "Extracts activity from Internet Explorer browser, as well as recent documents in windows.";
}
@Override
public ModuleType getType() {
return ModuleType.Image;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;

View File

@ -22,11 +22,8 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import java.io.*;
import java.io.File;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
@ -36,18 +33,18 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.openide.modules.InstalledFileLocator;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.datamodel.*;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.FileSystem;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -58,7 +55,7 @@ import org.xml.sax.SAXException;
/**
* Extracting windows registry data using regripper
*/
public class ExtractRegistry extends Extract implements IngestModuleImage {
public class ExtractRegistry extends Extract {
public Logger logger = Logger.getLogger(this.getClass().getName());
private String RR_PATH;
@ -66,7 +63,7 @@ public class ExtractRegistry extends Extract implements IngestModuleImage {
private int sysid;
private IngestServices services;
final public static String MODULE_VERSION = "1.0";
private String args;
private ExecUtil execRR;
//hide public constructor to prevent from instantiation by ingest module loader
@ -105,15 +102,6 @@ public class ExtractRegistry extends Extract implements IngestModuleImage {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
private void getRegistryFiles(Image image, IngestImageWorkerController controller) {
@ -441,38 +429,6 @@ public class ExtractRegistry extends Extract implements IngestModuleImage {
return "Extracts activity from the Windows registry utilizing RegRipper.";
}
@Override
public ModuleType getType() {
return ModuleType.Image;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public boolean hasBackgroundJobsRunning() {

View File

@ -51,7 +51,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* Firefox recent activity extraction
*/
public class Firefox extends Extract implements IngestModuleImage {
public class Firefox extends Extract {
private static final String ffquery = "SELECT moz_historyvisits.id,url,title,visit_count,(visit_date/1000000) as visit_date,from_visit,(SELECT url FROM moz_places WHERE id=moz_historyvisits.from_visit) as ref FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id AND hidden = 0";
private static final String ffcookiequery = "SELECT name,value,host,expiry,(lastAccessed/1000000) as lastAccessed,(creationTime/1000000) as creationTime FROM moz_cookies";
@ -60,7 +60,6 @@ public class Firefox extends Extract implements IngestModuleImage {
private static final String ffdownloadquery = "select target, source,(startTime/1000000) as startTime, maxBytes from moz_downloads";
public int FireFoxCount = 0;
final public static String MODULE_VERSION = "1.0";
private String args;
private IngestServices services;
//hide public constructor to prevent from instantiation by ingest module loader
@ -73,16 +72,6 @@ public class Firefox extends Extract implements IngestModuleImage {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public void process(PipelineContext<IngestModuleImage>pipelineContext, Image image, IngestImageWorkerController controller) {
this.getHistory(image, controller);
@ -364,39 +353,6 @@ public class Firefox extends Extract implements IngestModuleImage {
return "Extracts activity from the Mozilla FireFox browser.";
}
@Override
public ModuleType getType() {
return ModuleType.Image;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;

View File

@ -23,7 +23,6 @@
package org.sleuthkit.autopsy.recentactivity;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.PipelineContext;
@ -31,7 +30,6 @@ import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.IngestModuleImage;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.Image;
@ -40,7 +38,7 @@ import org.sleuthkit.datamodel.Image;
* Recent activity image ingest module
*
*/
public final class RAImageIngestModule implements IngestModuleImage {
public final class RAImageIngestModule extends IngestModuleImage {
private static final Logger logger = Logger.getLogger(RAImageIngestModule.class.getName());
private static RAImageIngestModule defaultInstance = null;
@ -49,7 +47,6 @@ public final class RAImageIngestModule implements IngestModuleImage {
private StringBuilder subCompleted = new StringBuilder();
private ArrayList<Extract> modules;
final public static String MODULE_VERSION = "1.0";
private String args;
//public constructor is required
//as multiple instances are created for processing multiple images simultenously
@ -179,54 +176,12 @@ public final class RAImageIngestModule implements IngestModuleImage {
logger.log(Level.INFO, "Recent Activity processes has been shutdown.");
}
@Override
public ModuleType getType() {
return ModuleType.Image;
}
@Override
public String getVersion() {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;

View File

@ -48,7 +48,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskException;
@ -66,13 +65,12 @@ import org.xml.sax.SAXException;
* To add search engines, edit SearchEngines.xml under RecentActivity
*
*/
public class SearchEngineURLQueryAnalyzer extends Extract implements IngestModuleImage {
public class SearchEngineURLQueryAnalyzer extends Extract {
private IngestServices services;
public static final String MODULE_NAME = "Search Engine URL Query Analyzer";
public final static String MODULE_VERSION = "1.0";
private String args;
public static final String XMLFILE = "SEUQAMappings.xml";
private static final String XSDFILE = "SearchEngineSchema.xsd";
@ -401,51 +399,9 @@ public class SearchEngineURLQueryAnalyzer extends Extract implements IngestModul
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public IngestModuleAbstract.ModuleType getType() {
return IngestModuleAbstract.ModuleType.Image;
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public JPanel getSimpleConfiguration() {
return null;
}
@Override
public JPanel getAdvancedConfiguration() {
return null;
}
}

View File

@ -64,13 +64,12 @@ import org.sleuthkit.datamodel.TskCoreException;
*
* Updates datamodel / directory tree with new files.
*/
public final class SevenZipIngestModule implements IngestModuleAbstractFile {
public final class SevenZipIngestModule extends IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(SevenZipIngestModule.class.getName());
public static final String MODULE_NAME = "Archive Extractor";
public static final String MODULE_DESCRIPTION = "Extracts archive files (zip, rar, arj, 7z, gzip, bzip2, tar), reschedules them to current ingest and populates directory tree with new files.";
final public static String MODULE_VERSION = "1.0";
private String args;
private IngestServices services;
private volatile int messageID = 0;
private int processedFiles = 0;
@ -600,53 +599,12 @@ public final class SevenZipIngestModule implements IngestModuleAbstractFile {
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public void saveSimpleConfiguration() {
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public JPanel getSimpleConfiguration() {
return null;
}
@Override
public JPanel getAdvancedConfiguration() {
return null;
}
public boolean isSupported(AbstractFile file) {
String fileNameLower = file.getName().toLowerCase();

View File

@ -1,4 +1,5 @@
#Updated by build script
#Thu, 23 May 2013 00:04:58 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=288
SPLASH_WIDTH=538
@ -6,3 +7,5 @@ SplashProgressBarBounds=3,236,533,6
SplashRunningTextBounds=5,212,530,17
SplashRunningTextColor=0x0
SplashRunningTextFontSize=18
currentVersion=Autopsy 20130523

View File

@ -1 +1,5 @@
#Updated by build script
#Updated by build script
#Thu, 23 May 2013 00:04:58 -0400
CTL_MainWindow_Title=Autopsy 20130523
CTL_MainWindow_Title_No_Project=Autopsy 20130523

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -1,18 +1,21 @@
/*! \mainpage Autopsy Forensic Browser Developer's Guide and API Reference
<h3>Overview</h3>
Autopsy has been designed as a platform for open source tools besides just The Sleuth Kit. This document is for developers who want to add functionality into Autopsy. This could be in the form of enhancing the existing functionality or by making a module that plugs into it and you may distribute from your own site or push it back into the base distribution.
- \subpage workflow_page
- \subpage platform_page
- \subpage mod_dev_page
- \subpage mod_ingest_page
- \subpage mod_report_page
- \subpage mod_content_page
- \subpage mod_result_page
- \subpage regression_test_page
<!-- Note that Case still has lots of content in package.dox -->
*/
/*! \mainpage Autopsy Forensic Browser Developer's Guide and API Reference
<h3>Overview</h3>
Autopsy has been designed as a platform for open source tools besides just The Sleuth Kit. This document is for developers who want to add functionality into Autopsy. This could be in the form of enhancing the existing functionality or by making a module that plugs into it and you may distribute from your own site or push it back into the base distribution.
If you want to write modules, then these pages are for you:
- \subpage platform_page
- \subpage mod_dev_page
- \subpage mod_ingest_page
- \subpage mod_report_page
- \subpage mod_content_page
- \subpage mod_result_page
These pages are more detailed if you want to modify Autopsy code instead of writing add-on modules.
- \subpage workflow_page
- \subpage regression_test_page
<!-- Note that Case still has lots of content in package.dox -->
*/

View File

@ -1,205 +1,196 @@
/*! \page mod_dev_page Development Basics
<!-- NOTE: This doc contains the concepts that apply when developing
any type of module. Information about specific types of modules should
go into the page for that module type. -->
<!-- @@@ Update -->
This page describes the basic concepts and setup that are needed regardless of the module type that you are building.
\section mod_dev_setup Basic Setup
\subsection mod_dev_setup_java The Java Environment
Currently, to develop modules for Autopsy, you must be using Java 1.6.
You can verify the module project is built for Java 1.6 by right clicking the project, choosing Properties, and checking that under Libraries the Java Platform is JDK 1.6 and under Sources the Source Level is 1.6.
\subsection mod_dev_setup_autopsy Setting up Development Environment
To setup a module development environment for Autopsy, you must have either:
\li Autopsy installed on your machine
\li The Autopsy source code, downloaded from GitHub
in order to for your project to import the Autopsy framework API.
If you used Autopsy installer that comes with an official release of Autopsy, you will get the more stable version of the framework, but possibly not the latest.
If you import Autopsy libraries pulled from GitHub,
you may get the latest version of the framework, but not the most stable and official one,
and still likely to be changed before the next official release.
If you have Autopsy installed on your machine and would like to use that as your development environment,
proceed to \ref mod_dev_module.
Note that older versions of Autopsy may not have the latest features available for module development.
To use the latest Autopsy source code as your development environment, first follow BUILDING.TXT to properly build and setup Autopsy in NetBeans. Make sure you are using Java 1.6.
Once Autopsy has been successfully built, right click on the Autopsy project in NetBeans and select Package as > ZIP Distribution.
Then extract the ZIP file to any directory of your choosing.
\section mod_dev_module How to Create a Module
In NetBeans go to File > New Project.
From the categories, choose NetBeans Modules, and then Module under Projects.
Click Next, name the module, and set the project location.
Select Standalone Module, and click the Manage button. Click on Add Platform and either browse to the directory Autopsy is installed or to the directory the ZIP distribution was extracted. Press Finish and then Close.
Autopsy has now been added as a "NetBeans Platform", meaning the development environment for NetBeans has been set to use the code from within Autopsy. This grants access to Autopsy Framework API (exported packages and classes) to external developers, without having to program inside the Autopsy project itself.
Click Next, and fill out the rest of the module-creation wizard.
Make sure to fill out the Module Name, Module Category (use "Ingest Module" for an Autopsy ingest module), Short and Long Descriptions.
Also fill out the Module Major Build version and Specification version in API Versioning section.
Autopsy requires that all modules restart Autopsy after they are installed -- otherwise the module might not be fully loaded and functional.
To setup your module in this fashion, right click on the module and choose Properties.
Under Build > Packaging, check the box that says Needs Restart on Install.
Press Finish when complete, and the module will be added as a standalone project in NetBeans.
After the module is created, it is important to verify the new project is using Java 1.6.
To check the version of Java, right click on the module in the Projects window and go to Properties.
Make sure that under the Libraries category the Java Platform is JDK 1.6, and under Sources the Source Level is 1.6.
See \ref mod_ingest_page for instructions on programming ingest modules for Autopsy.
Or read <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html">this guide from NetBeans.org</a> for general module development tips.
\subsection mod_dev_services_dependency Adding a Dependency
You need to first add dependencies to your module to import the relevant APIs needed for development of your module.
Adding the dependency will also help to resolve the dependencies of your module at runtime
and let the framework properly load your module.
To add a dependency on a module, in NetBeans IDE, right click the module and go to Properties.
In the Libraries category, you can see the current dependencies your module has.
Click the Add button and either scroll through the list of available modules
or filter the modules by class, package name, path, or display name.
When the desired module is found, press OK and it will appear in the list of current dependencies.
Currently you only need to specify Autopsy-Core as one of your module dependencies
- this will give you access to the Autopsy Framework Core API (such as interfaces and services)
and allow for plugging-in your custom Ingest Modules, Content Viewers and Reports.
Ensure that you select which Build and Specification version of the Autopsy-Core module your module depends on.
This will later help the plugin manager detect if dependencies are met for your module when the module is being loaded,
into a potentially different version of the framework.
When a module is added as a dependency, its APIs become available to the dependant module.
The relevant APIs for module development are the interfaces for different module types (for example, Ingest Modules),
defining which methods the module should be implementing. Also, there are services APIs, which are tools that framework provides for modules,
such as data storage, configuration, logging, etc.
TODO we should outline the process of adding a JAR file dependency for an external library.
E.g. adding jar directly to the module project, or (preferred) wrapping set of jars in another module
e.g. NewModuleName-Libs and adding a dependency on the libs module. Add info how to bundle OS-specific dlls in the jar (work in progress).
\section mod_dev_services Services
A Services class is provided to give developers access to the services provided by the Autopsy framework. Currently, the following
services are provided:
- FileManager: the org.sleuthkit.autopsy.casemodule.services.FileManager service provides an API for easy access to files and directories for a given image.
You can access the org.sleuthkit.autopsy.casemodule.services.FileManager service by calling the getFileManager() method of the
org.sleuthkit.autopsy.casemodule.services.Services class.
\section mod_dev_utilities Utilities
Autopsy-Core module contains the core Autopsy application and also the framework the application is built upon that other modules can use.
Among the Core APIs there are general utilities available to the Autopsy modules. The relevant packages include:
- org.sleuthkit.autopsy.casemodule.Case class - for the module to access Case data (TSK database) and subscribe to Case change events
- org.sleuthkit.autopsy.coreutils package has classes providing utilities for getting access to Autopsy loggers, configuration persistance API,
getting information about the Platform (such as locations of files and folders, info about the runtime environment),
extracting default settings files from the jar file to a user settings folder, etc.
Relevant service classes are org.sleuthkit.autopsy.coreutils.Version,
org.sleuthkit.autopsy.coreutils.PlatformUtil, org.sleuthkit.autopsy.coreutils.ModuleSettings,
org.sleuthkit.autopsy.coreutils.Logger and org.sleuthkit.autopsy.coreutils.FileUtil.
TODO: Add additional info about utility classes (log, Case, database, etc.) Similar to the C++ section about services (http://sleuthkit.org/sleuthkit/docs/framework-docs/mod_devpage.html)
TODO: Move the log content from the wiki (http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Logging_and_Error_Checking) to here.
Note: org.sleuthkit.autopsy.ingest.IngestServices provides services specifically for the ingest modules.
\section mod_dev_configuration Making a Configuration Panel
Some modules may have configuration settings for the users to set or review using GUI components, such as JPanels.
Autopsy provides two centralized locations for users to accesss these settings via panels registered by the module: the \ref mod_dev_configuration_ingest,
and the \ref mod_dev_configuration_options.
\subsection mod_dev_configuration_ingest Ingest Dialog Panel
The ingest configuration dialog panel is displayed anytime ingest is to be started/restarted.
It provides framework for two-levels of settings: "simple panel" as well as an "advanced panel".
The simple panel is shown directly in the ingest configuration panel on the right-hand side when a specific module is selected.
The advanced panel is opened in a new window if the user presses the Advanced button in the ingest configuration dialog.
Both of these panels can be created as a standard \c JPanel, and returned by your ingest module using
of the the ingest module methods implemented, that are declared in the ingest module interface.
It is recommended when making an ingest module to have the advanced panel also be accessible also via the main Options panel,
allowing the user access to the settings from Tools > Options and not only via the ingest module configuration.
See \ref ingestmodule_making_configuration how to implement hooks for having your ingest module configurations registered.
\subsection mod_dev_configuration_options Options Panel
To add panel to the options menu, right click the module and choose New > Other. Under the Module Development category, select Options Panel and press Next.
Select Create Primary Panel, name the panel (preferably with the module's name), select an icon, and add keywords, then click Next and Finish. Note that NetBeans will automatically copy the selected icon to the module's directory if not already there.
NetBeans will generate two Java files for you, the panel and the controller. For now, we only need to focus on the panel.
First, use NetBeans' GUI builder to design the panel. Be sure to include all options, settings, preferences, etc for the module, as this is what the user will see. The recommended size of an options panel is about 675 x 500.
Second, in the source code of the panel, there are two important methods: \c load() and \c store(). When the options panel is opened via Tools > Options in Autopsy, the \c load() method will be called. Conversely, when the user presses OK after editing the options, the \c store() method will be called.
If one wishes to make any additional panels within the original options panel, or panels which the original opens, Autopsy provides the org.sleuthkit.autopsy.corecomponents.OptionsPanel interface to help. This interface requires the \c store() and \c load() functions also be provided in the separate panels, allowing for easier child storing and loading.
Any storing or loading of settings or properties should be done in the \c store() and \c load() methods. Continue to \ref mod_dev_properties for more details.
\section mod_dev_properties Saving Settings and Properties
It is recommended to have the module settings persistent, so that when a change is made and Autopsy is re-opened
the user made changes remain effective and not reset back to defaults.
Use org.sleuthkit.autopsy.coreutils.ModuleSettings class for saving and reading back settings for your module.
\section mod_dev_events Registering for events
Modules may want to register for case change events using org.sleuthkit.autopsy.casemodule.Case.addPropertyChangeListener() method.
Modules may want to reinitialize and update their data views as case is changed.
If a module is a viewer interested in knowing when new data is available from ingest, it can register for listening of the ingest result updates using:
org.sleuthkit.autopsy.ingest.IngestManager.addPropertyChangeListener()
When developing Ingest modules specifically - their life cycle is managed by ingest manager
and an ingest module does not need to listen for case change events
or other general system-wide events.
However, it should make sure that it gets a new handle to the current Case every time the module's init() is invoked.
\section mod_dev_plugin Adding a Module to Autopsy
When the module is created and ready for use, it can be added to Autopsy via the plugins menu.
The plugins menu can be used to add modules (i.e. plugins) to Autopsy in a number of different ways, the simplest of which is through an NBM file.
To generate an NBM file, right click on the module and select Create NBM.
Then, launch Autopsy and choose Plugins under the Tools menu. Open the Downloaded tab and click Add Plugins. Navigate to the NBM file and open it. Next, click Install and follow the wizard. Autopsy will require a restart after installing the module, but afterwards the plugin will be integrated into Autopsy.
The options to uninstall or temporarily disable a plugin are also available under the plugins menu.
*/
/*! \page mod_dev_page Development Basics
<!-- NOTE: This doc contains the concepts that apply when developing
any type of module. Information about specific types of modules should
go into the page for that module type. -->
<!-- @@@ Update -->
This page describes the basic concepts and setup that are needed regardless of the module type that you are building.
\section mod_dev_setup Basic Setup
\subsection mod_dev_setup_nb NetBeans
Autopsy is built on top of the NetBeans Rich Client Platform, which makes it easy to make plug-in infrastructures. To do any development, you really need to download NetBeans first. You can in theory develop modules by command line only, but this document assumes that you are using the IDE. Download and install the latest version of the IDE from X.
\subsection mod_dev_setup_java Java
Autopsy currently requires Java 1.7. Ensure that it is installed.
\subsection mod_dev_setup_platform Autopsy Platform
Before we can make a module, we must configure NetBeans to know about Autopsy as a platform. This will allow you to access all of the classes and services that Autopsy provides. Therea are two ways of configuring the NetBeans IDE to know about Autopsy:
- Download an official release of Autopsy and build against it.
- Download Autopsy source code, build it, and make a platform to build against.
\subsubsection mod_dev_setup_platform_rel Released Platform
The easiest approach is install Autopsy on your computer. It will have everything that you need. If you installed it in "C:\Program Files\Autopsy", then the platform is in "C:\Program Files\Autopsy\platform".
\subsubsection mod_dev_setup_platform_src Source Code-based Platform
If you want to build against the bleeding edge code and updates that have occured since the last release, then you must download the latest source code and build it. This involves getting a full development environment setup.
// @@@ ADD LINK IN HERE TO DEV SETUP ON WIKI
To use the latest Autopsy source code as your development environment, first follow BUILDING.TXT in the root source repository to properly build and setup Autopsy in NetBeans.
Once Autopsy has been successfully built, right click on the Autopsy project in NetBeans and select Package as > ZIP Distribution. Once the ZIP file is created, extract its contents to a directory. This directory is the platform that you will build against. Note that you will building the module against this built platform. If you need to make changes to Autopsy infrastructure for your module, then you will need to then make a new ZIP file and configure your module to use it each time.
\section mod_dev_module Creating a Basic NetBeans Module
The Autopsy modules are encapsulated inside of NetBeans modules. A NetBeans module will be packaged as a single ".nbm" file. A single NetBeans module can contain many Autopsy modules. The NetBeans module is what the user will install and provides things like auto-update.
\subsection mod_dev_mod_nb Creating a NetBeans Module
If this is your first module, then you will need to make a NetBeans module. If you have already made an Autopsy module and are now working on a second one, you can consider adding it to your pevious NetBeans module.
To make a NetBeans module, open the NetBeans IDE and go to File -> New Project.
From the list of categories, choose "NetBeans Modules" and then "Module" from the list of "Projects". Click Next.
In the next panel of the wizard, give the module a name and directory. Select Standalone Module (the default is typically "Add to Suite") so that you build the module as an external module against Autopsy. You will need to tell NetBeans about the Autopsy platform, so choose the "Manage" button. Choose the "Add Platform" button and browse to the location of the platform discussed in the previous sections (as a reminder this will either be the location that you installed Autopsy into or where you opened up the ZIP file you created from source). Click Next.
Finally, enter the code base name. Press Finish.
You now have a NetBeans module that is using Autopsy as its build platform. That means you will have access to all of the services and utilities that Autopsy provides.
\subsection mod_dev_mod_config Configuring the NetBeans Module
After the module is created, you will need to do some further configuration. Right click on the newly created module and choose "Properties".
\subsubsection mod_dev_mod_config_library Dependencies
You will need to configure the module to be dependent on modules from within the Autopsy platform. Go to the "Libraries" area and choose "Add" in the "Module Dependencies" section. Choose the "Autopsy-core" library. You now have access to the Autopsy services.
If you later determine that you need to pull in external JAR files, then you will use the "Wrapped Jar" section to add them in.
Note, you will also need to come back to this section if you update the platform. You may need to add a new dependency for the version of the Autopsy-core that comes with the updated platform.
\subsubsection mod_dev_mod_config_restart Restarting
Autopsy requires that all modules restart Autopsy after they are installed -- otherwise the module might not be fully loaded and functional.
Configure your module this way
under Build -> Packaging. Check the box that says Needs Restart on Install.
\subsubsection mod_dev_mod_config_other Optional Settings
There are several optional things in the Properties section. You can add a description and specify the version. You can do all of this later though and it does not need to be done before you start development.
TODO: @@@ Add link here about NetBeans versioning scheme.
TODO: @@@ Add mention somwhere in the docs about Autopsy's versioning scheme
\subsection mod_dev_mod_other Other Links
For general NetBeans module information, refer to <a href="http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html">this guide from NetBeans.org</a>.
\section mod_dev_aut Creating Autopsy Modules
You can now add Autopsy modules into the NetBeans container module. There are other pages that focus on that and are listed on the main page. The rest of this document contains info that you will eventually want to come back to though.
As you will read in the later sections about the different module types, each Autopsy Module is a java class that extends an interface (the interface depends on the type of module).
\subsection mod_dev_aut_run1 Running Your Module During Development
When you are developing your Autopsy module, you can simply choose "Run" on the module and it will launch the Autopsy platform with the module enabled in it. This is also how you can debug the module.
\subsection mod_dev_aut_deploy Deploying Your Module
When you are ready to share your module, create an NBM file by right clicking on the module and selecting "Create NBM".
\subsection mod_dev_aut_install Installing Your Module
To install the module on a non-development environment, launch Autopsy and choose Plugins under the Tools menu. Open the Downloaded tab and click Add Plugins. Navigate to the NBM file and open it. Next, click Install and follow the wizard.
\section mod_dev_other Other Useful Information
This section contains other information that will be useful when developing any type of Autopsy module.
\subsection mod_dev_other_services Autopsy Services
Autopsy provides basic services to its modules. These were created to make it easier to write modules. Currently, the following
services are provided:
- FileManager: the org.sleuthkit.autopsy.casemodule.services.FileManager service provides an API to access any file in the case. You can access FileManager by calling org.sleuthkit.autopsy.casemodule.services.Services.getFileManager().
\subsection mod_dev_other_utilities Autopsy Utilities
Autopsy-Core module contains the core Autopsy application and also the framework the application is built upon that other modules can use.
Among the Core APIs there are general utilities available to the Autopsy modules. The relevant packages include:
- org.sleuthkit.autopsy.casemodule.Case class - for the module to access Case data (TSK database) and subscribe to Case change events
- org.sleuthkit.autopsy.coreutils package has classes providing utilities for getting access to Autopsy loggers, configuration persistance API,
getting information about the Platform (such as locations of files and folders, info about the runtime environment),
extracting default settings files from the jar file to a user settings folder, etc.
Relevant service classes are org.sleuthkit.autopsy.coreutils.Version,
org.sleuthkit.autopsy.coreutils.PlatformUtil, org.sleuthkit.autopsy.coreutils.ModuleSettings,
org.sleuthkit.autopsy.coreutils.Logger and org.sleuthkit.autopsy.coreutils.FileUtil.
TODO: Add additional info about utility classes (log, Case, database, etc.) Similar to the C++ section about services (http://sleuthkit.org/sleuthkit/docs/framework-docs/mod_devpage.html)
TODO: Move the log content from the wiki (http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Logging_and_Error_Checking) to here.
Note: org.sleuthkit.autopsy.ingest.IngestServices provides services specifically for the ingest modules.
\section mod_dev_adv Advanced Concepts
These aren't really advanced, but you don't need to know them in detail when you start your first module. You'll want to refer back to them after you get started and wonder, "how do I do X".
\section mod_dev_adv_bb Black Board
@@@ TODO
\section mod_dev_adv_inbox Ingest Inbox Messages
@@@ TODO: Sending messages, etc.
\section mod_dev_adv_options Option Panels
Some modules may have configuration settings that uses can change. We recommend that you use the infrastructure provided by Autopsy and NetBeans to do this so that all module condiguration is done in a single place.
To add a panel to the options menu, right click the module and choose New > Other. Under the Module Development category, select Options Panel and press Next.
Select Create Primary Panel, name the panel (preferably with the module's name), select an icon, and add keywords, then click Next and Finish. Note that NetBeans will automatically copy the selected icon to the module's directory if not already there.
NetBeans will generate two Java files for you, the panel and the controller. For now, we only need to focus on the panel.
First, use NetBeans' GUI builder to design the panel. Be sure to include all options, settings, preferences, etc for the module, as this is what the user will see. The recommended size of an options panel is about 675 x 500.
Second, in the source code of the panel, there are two important methods: \c load() and \c store(). When the options panel is opened via Tools > Options in Autopsy, the \c load() method will be called. Conversely, when the user presses OK after editing the options, the \c store() method will be called.
If one wishes to make any additional panels within the original options panel, or panels which the original opens, Autopsy provides the org.sleuthkit.autopsy.corecomponents.OptionsPanel interface to help. This interface requires the \c store() and \c load() functions also be provided in the separate panels, allowing for easier child storing and loading.
Any storing or loading of settings or properties should be done in the \c store() and \c load() methods. Continue to \ref mod_dev_properties for more details.
\subsection mod_dev_adv_properties Saving Settings and Properties
It is recommended to have the module settings persistent, so that when a change is made and Autopsy is re-opened
the user made changes remain effective and not reset back to defaults.
Use org.sleuthkit.autopsy.coreutils.ModuleSettings class for saving and reading back settings for your module.
\subsection mod_dev_adv_events Registering for Events
Autopsy will generate events as the application runs and modules may want to listen for those events so that they can change their state. There is not an exhaustive list of events, but here are some common ones to listen for:
- Case change events occur when a case is opened, closed, or changed. The org.sleuthkit.autopsy.casemodule.Case.addPropertyChangeListener() method can be used for this.
- IngestManager events occur when new results are available. The org.sleuthkit.autopsy.ingest.IngestManager.addPropertyChangeListener() method can be used for this.
*/

View File

@ -1,413 +1,412 @@
/*! \page mod_ingest_page Developing Ingest Modules
\section ingestmodule_modules Ingest Module Basics
Ingest modules analyze data from a disk image.
They typically focus on a specific type of data analysis.
The modules are loaded each time that Autopsy starts.
The user can choose to enable each module when they add an image to the case.
There are two types of ingest modules.
- Image-level modules are passed in a reference to an image and perform general analysis on it.
These modules may query the database for a small set of specific files, thus are generally quicker to execute.
- File-level modules are passed in a reference to each file.
The Ingest Manager chooses which files to pass and when.
These modules are intended to analyze most of the files on the system
or that want to examine the file content of all files
(i.e. to detect file type based on signature instead of file extension).
An example of Image-level module is a registry module, that extracts only the registry files.
An example of File-level module is a search module, that indexes and searches content of every file.
Modules post their results to the \ref platform_blackboard
(@@@ NEED REFERENCE FOR THIS -- org.sleuthkit.datamodel)
and can query the blackboard to get the results of previous modules.
For example, the hash database lookup module may want to query for a previously calculated hash value.
\section ingestmodule_relevant_api Relevant APIs
Relevant APIs to a ingest module writer are:
- The org.sleuthkit.autopsy.ingest.IngestServices class, which contains methods to post ingest results and
to get access to services in the framework (Case and blackboard, logging, configuration , and others).
- Interfaces org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile and org.sleuthkit.autopsy.ingest.IngestModuleImage, one of which needs to be implemented by the module.
There is also a parent interface, org.sleuthkit.autopsy.ingest.IngestModuleAbstract, common to all ingest modules.
- Additional utilities in the Autopsy \ref org.sleuthkit.autopsy.coreutils module for getting information about the platform,
versions and for file operations.
\section ingestmodule_making Making Ingest Modules
First, you will need to setup your environment and
make a new Autopsy module using Netbeans IDE. Refer to \ref mod_dev_page for general instructions.
Refer to org.sleuthkit.autopsy.ingest.example for sample source code of dummy modules.
\subsection ingestmodule_making_api Module Interface
The next step is to choose the correct module type and implement the correct interface.
Image-level modules will implement the org.sleuthkit.autopsy.ingest.IngestModuleImage interface
and file-level modules will implement the org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile interface.
The interfaces have several standard methods that need to be implemented:
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.init() is invoked every time an ingest session starts by the framework.
A module should support multiple invocations of init() throughout the application life-cycle.
In this method, module should reinitialize its internal objects and resources and get them ready
for a brand new ingest processing.
At minimum, the module should get a handle to the ingest services using
org.sleuthkit.autopsy.ingest.IngestServices.getDefault().
If the module posts results, then it needs the blackboard API; the module should get
an updated handle to the current Case database (and the blackboard API)
using org.sleuthkit.autopsy.ingest.IngestServices.getCurrentSleuthkitCaseDb().
This gives access to the underlying datamodel for the current Case.
Make sure not to store stale handles to Case objects across ingests,
because Case can likely be changed for the next ingest.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.complete() is invoked when an ingest session completes.
The module should perform any resource (files, handles, caches) cleanup in this method
and submit final results and post a final ingest inbox message, using org.sleuthkit.autopsy.ingest.IngestServices.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.stop() is invoked on a module when an ingest session is interrupted by the user or by the system.
The method implementation should be similar to complete() in that the module should perform any cleanup work.
If there is pending data to be processed or pending results to be reported by the module
then the results should be rejected and ignored if stop()
is invoked and the method should return as early as possible.
The main difference between complete() and stop() is that stop() does not need to worry about
finalizing and reporting final results, it can simply reject them.
The quicker it acts, the easier it will for the application to transition to the next state.
- process() method is invoked to analyze the data. The specific method depends on the module type; it is passed
either an Image or a File to process.
\subsubsection ingestmodule_making_process Process Method
The process method is where the work is done in each type of module, on the Image of File passed as an argument.
Once a result is found, in this method the module should post result to the blackboard
and it could post an inbox message to the user.
Some notes:
- File-level modules will be called on each file in an order determined by the org.sleuthkit.autopsy.ingest.IngestManager.
Each module is free to quickly ignore a file based on name, signature, etc.
- If a module wants to know the return value from a previously run module on this file,
it should use the org.sleuthkit.autopsy.ingest.IngestServices.getAbstractFileModuleResult() method.
- Image-level modules are expected not passed in specific files and are expected to query the database
to find the files that they are interested in. They can use the org.sleuthkit.datamodel.SleuthkitCase object handle (initialized in the init() method) to query the database.
- File-level module could be passed in files from different images in consecutive calls to process().
\subsubsection ingestmodule_making_process_controller Image Ingest Controller (Image-level modules only)
Image-level modules receive in org.sleuthkit.autopsy.ingest.IngestModuleImage.process() method
get a reference to org.sleuthkit.autopsy.ingest.IngestImageWorkerController object.
They should use this object to:
- report progress (number of work units processed),
- add thread cancellation support.
Example snippet of an ingest-level module process() method:
\code
@Override
public void process(Image image, IngestImageWorkerController controller) {
//we have some number workunits / sub-tasks to execute
//in this case, we know the number of total tasks in advance
final int totalTasks = 12;
//initialize the overall image ingest progress
controller.switchToDeterminate();
controller.progress(totalTasks);
for(int subTask = 0; subTask < totalTasks; ++subTask) {
//add cancellation support
if (controller.isCancelled() ) {
break; // break out early to let the thread terminate
}
//do the work
try {
//sub-task may add blackboard artifacts and create an inbox message
performSubTask(i);
} catch (Exception ex) {
logger.log(Level.WARNING, "Exception occurred in subtask " + subTask, ex);
}
//update progress
controller.progress(i+1);
}
}
\endcode
\subsection ingestmodule_module_lifecycle Module Lifecycle
File-level modules are singletons and are long-lived and image-level modules are short lived.
The same file-level module instance can be invoked again by the org.sleuthkit.autopsy.ingest.IngestManager when more work is enqueued or
when ingest is restarted. The same file-level ingest module instance can also be invoked for different Cases or files from different images in the Case.
Every file-level module should support multiple init() - process() - complete(), and init() - process() - stop() invocations.
New instances of image-level modules will be created when the second image is added.
Therefore, image-level modules can assume that the process() method will be called at most once after init() is called.
Every module (file or image) should also support multiple init() - complete() and init() - stop() invocations,
which can occur if ingest pipeline is started but no work is enqueued for the particular module.
\subsection ingestmodule_additional_method Additional Methods to Implement
Besides methods defined in the interfaces, you will need to implement
a public static getDefault() method (both for an image or a file module), which needs
to return a static instance of the module. This is required for proper module registration.
Presence of that method is validated when the module is loaded, and the module will fail validation
and will not be loaded if the method is not implemented.
The implementation of this method is very standard, example:
\code
public static synchronized MyIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new MyIngestModule();
}
return defaultInstance;
}
\endcode
File-level modules need to be singleton. To ensure this, make the constructor private.
Image-level modules require a public constructor.
\subsection ingestmodule_making_registration Module Registration
Modules are automatically discovered and registered when \ref mod_dev_plugin "added as a plugin to Autopsy".
Currently, a restart of Autopsy is required for the newly discovered ingest module to be fully registered and functional.
All you need to worry about is to implement the ingest module interface and the required methods and the module will be
automatically discovered by the framework.
\subsubsection ingestmodule_making_registration_pipeline_config Pipeline Configuration
Autopsy maintains an ordered list of autodiscovered modules. The order of a module in the pipeline determines
when it will be run relative to other modules. The order can be important for some modules and it can be adjusted.
When a module is installed using the plugin installer, it is automatically discovered and validated.
The validation process ensures that the module meets the inter-module dependencies, implements the right interfaces and methods
and meets constrains enforced by the schema. If the module is valid, it is registered and added to the right pipeline
based on the interfaces it implements, and the pipeline configuration is updated with the new module.
If the module is not already known to the pipeline configuration, it gets the default order assigned --
it is added to the end of the pipeline.
If the module is invalid, it will still be added to the pipeline configuration, but it will not be instantiated.
It will be re-validated again next time the module discovery runs. The validation process logs its results to the main
Autopsy log files.
The pipeline configuration is an XML file with currently discovered modules
and the modules that were discovered in the past but are not currently loaded.
Autopsy maintains that file in the Autopsy user configuration directory.
The XML file defines the module location, its place in the ingest pipeline, along with optional configuration arguments.
The example of the pipeline configuration is given below:
\code
<PIPELINE_CONFIG>
<PIPELINE type="FileAnalysis">
<MODULE order="1" type="plugin" location="org.sleuthkit.autopsy.hashdatabase.HashDbIngestModule" arguments="" />
<MODULE order="2" type="plugin" location="org.sleuthkit.autopsy.exifparser.ExifParserFileIngestModule"/>
</PIPELINE>
<PIPELINE type="ImageAnalysis">
<MODULE order="1" type="plugin" location="org.sleuthkit.autopsy.recentactivity.RAImageIngestModule" arguments=""/>
</PIPELINE>
</PIPELINE_CONFIG>
\endcode
Refer to http://sleuthkit.org/sleuthkit/docs/framework-docs/pipeline_config_page.html which is an official documentation
for the pipeline configuration schema.
The pipeline configuration file should not be directly edited by a regular user,
but it can be edited by a developer to test their module.
Autopsy will provide tools for reconfiguring the ingest pipeline in the near future,
and user/developer will be able to reload current view of discovered modules,
reorder modules in the pipeline and set their arguments using GUI.
\subsection ingestmodule_using_services Using Ingest Services
Class org.sleuthkit.autopsy.ingest.IngestModuleServices provides services specifically for the ingest modules
and a module developer should use these utilities.
The class has methods for ingest modules to:
- send ingest messages to the inbox,
- send new data events to registered listeners (such as viewers),
- check for errors in the file-level pipeline,
- getting access to org.sleuthkit.datamodel.SleuthkitCase database and the blackboard,
- getting loggers,
- getting and setting module settings.
To use it, a handle to org.sleuthkit.autopsy.ingest.IngestServices singleton object should be initialized
in the module's \c init() method. For example:
\code
services = IngestServices.getDefault()
\endcode
It is safe to store handle to services in your module private member variable.
However, DO NOT initialize the services handle statically in the member variable declaration.
Use the init() method to do that to ensure proper order of initialization of objects in the platform.
Module developers are encouraged to use Autopsy's org.sleuthkit.autopsy.coreutils.Logger
infrastructure to log errors to the Autopsy log.
The logger can also be accessed using the org.sleuthkit.autopsy.ingest.IngestServices class.
Certain modules may need need a persistant store (other than for storing results) for storing and reading
module configurations or state.
The ModuleSettings API can be used also via org.sleuthkit.autopsy.ingest.IngestServices class.
\subsection ingestmodule_making_results Posting Results
<!-- @@@ -->
NOTE: This needs to be made more in sync with the \ref platform_blackboard. This section (or one near this) needs to be the sole source of ingest inbox API information.
Users will see the results from ingest modules in one of two ways:
- Results are posted to the blackboard and will be displayed in the navigation tree
- For selected results, messages are sent to the Ingest Inbox to notify a user of what has recently been found.
\subsubsection ingestmodule_making_results_bb Posting Results to Blackboard
See the Blackboard (REFERENCE) documentation for posting results to it.
Modules are free to immediately post results when they find them
or they can wait until they are ready to post the results or until ingest is done.
An example of waiting to post results is the keyword search module.
It is resource intensive to commit the keyword index and do a keyword search.
Therefore, when its process() method is invoked,
it checks if it is internal timer and result posting frequency setting
to check if it is close to it since the last time it did a keyword search.
If it is, then it commits the index and performs the search.
When modules add data to the blackboard,
modules should notify listeners of the new data by
invoking IngestServices.fireModuleDataEvent() method.
Do so as soon as you have added an artifact to the blackboard.
This allows other modules (and the main UI) to know when to query the blackboard for the latest data.
However, if you are writing a larger number of blackboard artifacts in a loop, it is better to invoke
IngestServices.fireModuleDataEvent() only once after the bulk write, not to flood the system with events.
\subsubsection ingestmodule_making_results_inbox Posting Results to Message Inbox
Modules should post messages to the inbox when interesting data is found and has been posted to the blackboard.
A single message includes the module name, message subject, message details,
a unique message id (in the context of the originating module), and a uniqueness attribute.
The uniqueness attribute is used to group similar messages together
and to determine the overall importance priority of the message
(if the same message is seen repeatedly, it is considered lower priority).
For example, for a keyword search module, the uniqueness attribute would the keyword that was hit.
It is important though to not fill up the inbox with messages. Do not post an inbox message for every
result artifact written to the blackboard.
These messages should only be sent if the result has a low false positive rate and will likely be relevant.
For example, the hash lookup module will send messages if known bad (notable) files are found,
but not if known good (NSRL) files are found.
The keyword search module will send messages if a specific keyword matches,
but will not send messages (by default) if a regular expression match for a URL has matches
(because a lot of the URL hits will be false positives and can generate thousands of messages on a typical system).
Ingest messages have different types:
there are info messages, warning messages, error messages and data messages.
Modules will mostly post data messages about the most relevant results.
The data messages contain encapsulated blackboard artifacts and attributes.
The passed in data is used by the ingest inbox GUI widget to navigate
to the artifact view in the directory tree, if requested by the user.
Ingest message API is defined in IngestMessage class.
The class also contains factory methods to create new messages.
Messages are posted using IngestServices.postMessage() method,
which accepts a message object created using one of the factory methods.
Modules should post info messages (with no data) to the inbox
at minimum when stop() or complete() is invoked (refer to the examples).
It is recommended to populate the description field of the complete inbox message to provide feedback to the user
summarizing the module ingest run and if any errors were encountered.
Modules should also post high-level error messages (e.g. without flooding the inbox
when the same error encountered for a large number of files).
\subsection ingestmodule_making_configuration Module Configuration
<!-- @@@ -->
NOTE: Make sure we update this to reflect \ref mod_dev_properties and reduce duplicate comments.
Ingest modules may require user configuration. The framework
supports two levels of configuration: run-time and general. Run-time configuration
occurs when the user selects which ingest modules to run when an image is added. This level
of configuration should allow the user to enable or disable settings. General configuration is more in-depth and
may require an interface that is more powerful than simple check boxes.
As an example, the keyword search module uses both configuration methods. The run-time configuration allows the user
to choose which lists of keywords to search for. However, if the user wants to edit the lists or create lists, they
need to do go the general configuration window.
Module configuration is module-specific: every module maintains its own configuration state and is responsible for implementing the graphical interface. However, Autopsy does provide \ref mod_dev_configuration "a centralized location to display your settings to the user".
The run-time configuration (also called simple configuration), is achieved by each
ingest module providing a JPanel. The IngestModuleAbstract.hasSimpleConfiguration(),
IngestModuleAbstract.getSimpleConfiguration(), and IngestModuleAbstract.saveSimpleConfiguration()
methods should be used for run-time configuration.
The general configuration is also achieved by the module returning a JPanel. A link will be provided to the general configuration from the ingest manager if it exists.
The IngestModuleAbstract.hasAdvancedConfiguration(),
IngestModuleAbstract.getAdvancedConfiguration(), and IngestModuleAbstract.saveAdvancedConfiguration()
methods should be used for general configuration.
\section ingestmodule_events Getting Ingest Status and Events
<!-- @@@ -->
NOTE: Sync this up with \ref mod_dev_events.
Other modules and core Autopsy classes may want to get the overall ingest status from the ingest manager.
The IngestManager handle is obtained using org.sleuthkit.autopsy.ingest.IngestManager.getDefault().
The manager provides access to ingest status with the
org.sleuthkit.autopsy.ingest.IngestManager.isIngestRunning() method and related methods
that allow to query ingest status per specific module.
External modules (such as data viewers) can also register themselves as ingest module event listeners
and receive event notifications (when a module is started, stopped, completed or has new data).
Use the IngestManager.addPropertyChangeListener() method to register a module event listener.
Events types received are defined in IngestManager.IngestModuleEvent enum.
At the end of the ingest, IngestManager itself will notify all listeners of IngestModuleEvent.COMPLETED event.
The event is an indication for listeners to perform the final data refresh by quering the blackboard.
Module developers are encouraged to generate periodic IngestModuleEvent.DATA
ModuleDataEvent events when they post data to the blackboard,
but the IngestManager will make a final event to handle scenarios where the module did not notify listeners while it was running.
*/
/*! \page mod_ingest_page Developing Ingest Modules
\section ingestmodule_modules Ingest Module Basics
This section tells you how to make an Ingest Module.
Ingest modules analyze data from a disk image.
They typically focus on a specific type of data analysis.
The modules are loaded each time that Autopsy starts.
The user can choose to enable each module when they add an image to the case. It assumes you have already setup your development environment as described in \ref mod_dev_page.
First, you need to choose the type of Ingest Module.
- Image-level modules are passed in a reference to an image and perform general analysis on it.
These modules may query the database for a small set of specific files. For example, a Windows registry module that runs on the hive files. It is interested in only a small subset of the hard drive files.
- File-level modules are passed in a reference to each file.
The Ingest Manager chooses which files to pass and when.
These modules are intended to analyze most of the files on the system
For example, a hash calculation module that reads in the content of every file.
Refer to org.sleuthkit.autopsy.ingest.example for sample source code of dummy modules.
\section ingest_common Commonalities
There are several things about these module types that are common and we'll outline those here. For both modules, you will extend an interface and implement some methods.
Refer to the documentation for each method for its use.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.init() is invoked when an ingest session starts.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.complete() is invoked when an ingest session completes.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.stop() is invoked on a module when an ingest session is interrupted by the user or system.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.getName() returns the name of the module.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.getDescription() returns a short description of the module.
- org.sleuthkit.autopsy.ingest.IngestModuleAbstract.getVersion() returns the version of the module.
The process() method is invoked to analyze the data. This is where the analysis is done. The specific method depends on the module type; it is passed
either an Image or a File to process. We'll cover this in later sections. This method will post results to the blackboard
and with inbox messages to the user.
\section ingest_image Image-level Modules
To make an Image-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleImage". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the links above to fill in the details.
The org.sleuthkit.autopsy.ingest.IngestModuleImage.process() method gets several objects passed in.
get a reference to org.sleuthkit.autopsy.ingest.IngestImageWorkerController object.
They should use this object to:
- report progress (number of work units processed),
- add thread cancellation support.
New instances of image-level modules will be created when the second image is added.
Therefore, image-level modules can assume that the process() method will be called at most once after init() is called.
Example snippet of an ingest-level module process() method:
\code
@Override
public void process(Image image, IngestImageWorkerController controller) {
//we have some number workunits / sub-tasks to execute
//in this case, we know the number of total tasks in advance
final int totalTasks = 12;
//initialize the overall image ingest progress
controller.switchToDeterminate();
controller.progress(totalTasks);
for(int subTask = 0; subTask < totalTasks; ++subTask) {
//add cancellation support
if (controller.isCancelled() ) {
break; // break out early to let the thread terminate
}
//do the work
try {
//sub-task may add blackboard artifacts and create an inbox message
performSubTask(i);
} catch (Exception ex) {
logger.log(Level.WARNING, "Exception occurred in subtask " + subTask, ex);
}
//update progress
controller.progress(i+1);
}
}
\endcode
\section ingest_file File-level Modules
To make a File-level module, make a new Java class either manually or using the NetBeans wizards. Edit the class to extend "org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile". NetBeans will likely complain that you have not implemented the necessary methods and you can use its "hints" to automatically generate stubs for them. Use the links above to fill in the details.
File-level modules are singletons. Only a single instance is created for all files.
The same file-level module instance can be invoked again by the org.sleuthkit.autopsy.ingest.IngestManager when more work is enqueued or
when ingest is restarted. The same file-level ingest module instance can also be invoked for different Cases or files from different images in the Case.
Every file-level module should support multiple init() -> process() -> complete(), and init() -> process() -> stop() invocations. It shoudl also support init() -> complete() sequences.
------
\subsection ingestmodule_additional_method Additional Methods to Implement
MOVE THIS TO COMMON
Besides methods defined in the interfaces, you will need to implement
a public static getDefault() method (both for an image or a file module), which needs
to return a static instance of the module. This is required for proper module registration.
Presence of that method is validated when the module is loaded, and the module will fail validation
and will not be loaded if the method is not implemented.
The implementation of this method is very standard, example:
\code
public static synchronized MyIngestModule getDefault() {
//defaultInstance is a private static class variable
if (defaultInstance == null) {
defaultInstance = new MyIngestModule();
}
return defaultInstance;
}
\endcode
File-level modules need to be singleton. To ensure this, make the constructor private.
Image-level modules require a public constructor.
\subsection ingestmodule_making_registration Module Registration
Modules are automatically discovered and registered when \ref mod_dev_plugin "added as a plugin to Autopsy".
Currently, a restart of Autopsy is required for the newly discovered ingest module to be fully registered and functional.
All you need to worry about is to implement the ingest module interface and the required methods and the module will be
automatically discovered by the framework.
\subsubsection ingestmodule_making_registration_pipeline_config Pipeline Configuration
Autopsy maintains an ordered list of autodiscovered modules. The order of a module in the pipeline determines
when it will be run relative to other modules. The order can be important for some modules and it can be adjusted.
When a module is installed using the plugin installer, it is automatically discovered and validated.
The validation process ensures that the module meets the inter-module dependencies, implements the right interfaces and methods
and meets constrains enforced by the schema. If the module is valid, it is registered and added to the right pipeline
based on the interfaces it implements, and the pipeline configuration is updated with the new module.
If the module is not already known to the pipeline configuration, it gets the default order assigned --
it is added to the end of the pipeline.
If the module is invalid, it will still be added to the pipeline configuration, but it will not be instantiated.
It will be re-validated again next time the module discovery runs. The validation process logs its results to the main
Autopsy log files.
The pipeline configuration is an XML file with currently discovered modules
and the modules that were discovered in the past but are not currently loaded.
Autopsy maintains that file in the Autopsy user configuration directory.
The XML file defines the module location, its place in the ingest pipeline, along with optional configuration arguments.
The example of the pipeline configuration is given below:
\code
<PIPELINE_CONFIG>
<PIPELINE type="FileAnalysis">
<MODULE order="1" type="plugin" location="org.sleuthkit.autopsy.hashdatabase.HashDbIngestModule" arguments="" />
<MODULE order="2" type="plugin" location="org.sleuthkit.autopsy.exifparser.ExifParserFileIngestModule"/>
</PIPELINE>
<PIPELINE type="ImageAnalysis">
<MODULE order="1" type="plugin" location="org.sleuthkit.autopsy.recentactivity.RAImageIngestModule" arguments=""/>
</PIPELINE>
</PIPELINE_CONFIG>
\endcode
Refer to http://sleuthkit.org/sleuthkit/docs/framework-docs/pipeline_config_page.html which is an official documentation
for the pipeline configuration schema.
The pipeline configuration file should not be directly edited by a regular user,
but it can be edited by a developer to test their module.
Autopsy will provide tools for reconfiguring the ingest pipeline in the near future,
and user/developer will be able to reload current view of discovered modules,
reorder modules in the pipeline and set their arguments using GUI.
\subsection ingestmodule_using_services Using Ingest Services
Class org.sleuthkit.autopsy.ingest.IngestModuleServices provides services specifically for the ingest modules
and a module developer should use these utilities.
The class has methods for ingest modules to:
- send ingest messages to the inbox,
- send new data events to registered listeners (such as viewers),
- check for errors in the file-level pipeline,
- getting access to org.sleuthkit.datamodel.SleuthkitCase database and the blackboard,
- getting loggers,
- getting and setting module settings.
To use it, a handle to org.sleuthkit.autopsy.ingest.IngestServices singleton object should be initialized
in the module's \c init() method. For example:
\code
services = IngestServices.getDefault()
\endcode
It is safe to store handle to services in your module private member variable.
However, DO NOT initialize the services handle statically in the member variable declaration.
Use the init() method to do that to ensure proper order of initialization of objects in the platform.
Module developers are encouraged to use Autopsy's org.sleuthkit.autopsy.coreutils.Logger
infrastructure to log errors to the Autopsy log.
The logger can also be accessed using the org.sleuthkit.autopsy.ingest.IngestServices class.
Certain modules may need need a persistant store (other than for storing results) for storing and reading
module configurations or state.
The ModuleSettings API can be used also via org.sleuthkit.autopsy.ingest.IngestServices class.
\subsection ingestmodule_making_results Posting Results
<!-- @@@ -->
NOTE: This needs to be made more in sync with the \ref platform_blackboard. This section (or one near this) needs to be the sole source of ingest inbox API information.
Users will see the results from ingest modules in one of two ways:
- Results are posted to the blackboard and will be displayed in the navigation tree
- For selected results, messages are sent to the Ingest Inbox to notify a user of what has recently been found.
\subsubsection ingestmodule_making_results_bb Posting Results to Blackboard
See the Blackboard (REFERENCE) documentation for posting results to it.
Modules are free to immediately post results when they find them
or they can wait until they are ready to post the results or until ingest is done.
An example of waiting to post results is the keyword search module.
It is resource intensive to commit the keyword index and do a keyword search.
Therefore, when its process() method is invoked,
it checks if it is internal timer and result posting frequency setting
to check if it is close to it since the last time it did a keyword search.
If it is, then it commits the index and performs the search.
When modules add data to the blackboard,
modules should notify listeners of the new data by
invoking IngestServices.fireModuleDataEvent() method.
Do so as soon as you have added an artifact to the blackboard.
This allows other modules (and the main UI) to know when to query the blackboard for the latest data.
However, if you are writing a larger number of blackboard artifacts in a loop, it is better to invoke
IngestServices.fireModuleDataEvent() only once after the bulk write, not to flood the system with events.
\subsubsection ingestmodule_making_results_inbox Posting Results to Message Inbox
Modules should post messages to the inbox when interesting data is found and has been posted to the blackboard.
A single message includes the module name, message subject, message details,
a unique message id (in the context of the originating module), and a uniqueness attribute.
The uniqueness attribute is used to group similar messages together
and to determine the overall importance priority of the message
(if the same message is seen repeatedly, it is considered lower priority).
For example, for a keyword search module, the uniqueness attribute would the keyword that was hit.
It is important though to not fill up the inbox with messages. Do not post an inbox message for every
result artifact written to the blackboard.
These messages should only be sent if the result has a low false positive rate and will likely be relevant.
For example, the hash lookup module will send messages if known bad (notable) files are found,
but not if known good (NSRL) files are found.
The keyword search module will send messages if a specific keyword matches,
but will not send messages (by default) if a regular expression match for a URL has matches
(because a lot of the URL hits will be false positives and can generate thousands of messages on a typical system).
Ingest messages have different types:
there are info messages, warning messages, error messages and data messages.
Modules will mostly post data messages about the most relevant results.
The data messages contain encapsulated blackboard artifacts and attributes.
The passed in data is used by the ingest inbox GUI widget to navigate
to the artifact view in the directory tree, if requested by the user.
Ingest message API is defined in IngestMessage class.
The class also contains factory methods to create new messages.
Messages are posted using IngestServices.postMessage() method,
which accepts a message object created using one of the factory methods.
Modules should post info messages (with no data) to the inbox
at minimum when stop() or complete() is invoked (refer to the examples).
It is recommended to populate the description field of the complete inbox message to provide feedback to the user
summarizing the module ingest run and if any errors were encountered.
Modules should also post high-level error messages (e.g. without flooding the inbox
when the same error encountered for a large number of files).
\subsection ingestmodule_making_configuration Module Configuration
<!-- @@@ -->
NOTE: Make sure we update this to reflect \ref mod_dev_properties and reduce duplicate comments.
Ingest modules may require user configuration. The framework
supports two levels of configuration: run-time and general. Run-time configuration
occurs when the user selects which ingest modules to run when an image is added. This level
of configuration should allow the user to enable or disable settings. General configuration is more in-depth and
may require an interface that is more powerful than simple check boxes.
As an example, the keyword search module uses both configuration methods. The run-time configuration allows the user
to choose which lists of keywords to search for. However, if the user wants to edit the lists or create lists, they
need to do go the general configuration window.
Module configuration is module-specific: every module maintains its own configuration state and is responsible for implementing the graphical interface. However, Autopsy does provide \ref mod_dev_configuration "a centralized location to display your settings to the user".
The run-time configuration (also called simple configuration), is achieved by each
ingest module providing a JPanel. The IngestModuleAbstract.hasSimpleConfiguration(),
IngestModuleAbstract.getSimpleConfiguration(), and IngestModuleAbstract.saveSimpleConfiguration()
methods should be used for run-time configuration.
The general configuration is also achieved by the module returning a JPanel. A link will be provided to the general configuration from the ingest manager if it exists.
The IngestModuleAbstract.hasAdvancedConfiguration(),
IngestModuleAbstract.getAdvancedConfiguration(), and IngestModuleAbstract.saveAdvancedConfiguration()
methods should be used for general configuration.
\section ingestmodule_events Getting Ingest Status and Events
<!-- @@@ -->
NOTE: Sync this up with \ref mod_dev_events.
Other modules and core Autopsy classes may want to get the overall ingest status from the ingest manager.
The IngestManager handle is obtained using org.sleuthkit.autopsy.ingest.IngestManager.getDefault().
The manager provides access to ingest status with the
org.sleuthkit.autopsy.ingest.IngestManager.isIngestRunning() method and related methods
that allow to query ingest status per specific module.
External modules (such as data viewers) can also register themselves as ingest module event listeners
and receive event notifications (when a module is started, stopped, completed or has new data).
Use the IngestManager.addPropertyChangeListener() method to register a module event listener.
Events types received are defined in IngestManager.IngestModuleEvent enum.
At the end of the ingest, IngestManager itself will notify all listeners of IngestModuleEvent.COMPLETED event.
The event is an indication for listeners to perform the final data refresh by quering the blackboard.
Module developers are encouraged to generate periodic IngestModuleEvent.DATA
ModuleDataEvent events when they post data to the blackboard,
but the IngestManager will make a final event to handle scenarios where the module did not notify listeners while it was running.
---- MERGE THIS IN -----
\subsection mod_dev_configuration_ingest Ingest Dialog Panel
Each ingest module has a small configuration panel when the user
The ingest configuration dialog panel is displayed anytime ingest is to be started/restarted.
It provides framework for two-levels of settings: "simple panel" as well as an "advanced panel".
The simple panel is shown directly in the ingest configuration panel on the right-hand side when a specific module is selected.
The advanced panel is opened in a new window if the user presses the Advanced button in the ingest configuration dialog.
Both of these panels can be created as a standard \c JPanel, and returned by your ingest module using
of the the ingest module methods implemented, that are declared in the ingest module interface.
It is recommended when making an ingest module to have the advanced panel also be accessible also via the main Options panel,
allowing the user access to the settings from Tools > Options and not only via the ingest module configuration.
See \ref ingestmodule_making_configuration how to implement hooks for having your ingest module configurations registered.
----- MERGE THIS IN ----
When developing Ingest modules specifically - their life cycle is managed by ingest manager
and an ingest module does not need to listen for case change events
or other general system-wide events.
However, it should make sure that it gets a new handle to the current Case every time the module's init() is invoked.
---- MERGE
\section ingestmodule_relevant_api Relevant APIs
Relevant APIs to a ingest module writer are:
- The org.sleuthkit.autopsy.ingest.IngestServices class, which contains methods to post ingest results and
to get access to services in the framework (Case and blackboard, logging, configuration , and others).
- Interfaces org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile and org.sleuthkit.autopsy.ingest.IngestModuleImage, one of which needs to be implemented by the module.
There is also a parent interface, org.sleuthkit.autopsy.ingest.IngestModuleAbstract, common to all ingest modules.
- Additional utilities in the Autopsy \ref org.sleuthkit.autopsy.coreutils module for getting information about the platform,
versions and for file operations.
-------
Some notes:
- File-level modules will be called on each file in an order determined by the org.sleuthkit.autopsy.ingest.IngestManager.
Each module is free to quickly ignore a file based on name, signature, etc.
- If a module wants to know the return value from a previously run module on this file,
it should use the org.sleuthkit.autopsy.ingest.IngestServices.getAbstractFileModuleResult() method.
- Image-level modules are not passed in specific files and are expected to query the database
to find the files that they are interested in. They can use the org.sleuthkit.datamodel.SleuthkitCase object handle (initialized in the init() method) to query the database.
- File-level module could be passed in files from different images in consecutive calls to process().
*/

34
docs/doxygen/needs_a_home.dox Executable file
View File

@ -0,0 +1,34 @@
<!-- @@@ MOVE THIS SOMEWHERE ELSE -- the directory tree package maybe?? -->
The component is by default registered with the ingest manager as an ingest event listener.
The viewer first loads all the viewer-supported data currently in the blackboard when Autopsy starts.
During the ingest process the viewer receives events from ingest modules
(relayed by ingest manager) and it selectively refreshes parts of the tree providing real-time updates to the user.
When ingest is completed, the viewer responds to the final ingest data event generated by the ingest manager,
and performs a final refresh of all viewer-supported data in the blackboard.
Node content support capabilities are registered in the node's Lookup.
<!-- @@@ This is too detailed for here, but maybe should be broken up and put into the sections on making a result viewer and such…
-->
\section design_data_flow Data Flow
\subsection design_data_flow_create Creating Nodes in DataExplorer
Data flows between the UI zones using a NetBeans node. The DataExplorer modules create the NetBeans nodes. They query the SQLite database or do whatever they want to identify the set of files that are of interest. They create the NetBeans nodes based on Sleuthkit data model objects. See the org.sleuthkit.autopsy.datamodel package for more details on this.
\subsection design_data_flow_toResult Getting Nodes to DataResult
Each DataExplorer TopComponent is responsible for creating its own DataResult TopComponent to display its results. It can choose to re-use the same TopComponent for multiple searches (as DirectoryTree does) or it can choose to make a new one each time (as FileSearch does). The setNode() method on the DataResult object is used to set the root node to display. A dummy root node must be created as the parent if a parent does not already exist.
The DataExplorer is responsible for setting the double-click and right-click actions associated with the node. The default single click action is to pass data to DataContent. To override this, you must create a new DataResultViewer instance that overrides the propertyChange() method. The DataExplorer adds actions to wrapping the node in a FilterNode variant. The FilterNode then defines the actions for the node by overriding the getPreferredAction() and getActions() methods. As an example, org.sleuthkit.autopsy.directorytree.DataResultFilterNode and org.sleuthkit.autopsy.directorytree.DataResultFilterChildren wraps the nodes that are passed over by the DirectoryTree DataExplorer.
DataResult can send data back to its DataExplorer by making a custom action that looks up it's instance (DataExplorer.getInstance()).
\subsection design_data_flow_toContent Getting Nodes to DataContent
A default DataContent viewer is created when a case is opened. To display the contents of a node, it must be passed to a DataContent instance. The default single-click behavior of the DataResultViewers is to lookup the default DataContent TopComponent and pass the selected node to it. See org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer.propertyChange(PropertyChangeEvent) for details.

View File

@ -1,40 +1,42 @@
/*! \page platform_page Platform Concepts
\section platform_basics Basic Concepts
- <b>Central Database</b>: All data except for the disk image is stored in a SQLite database. This includes information about what files exist in the disk image and the output from modules. Access to this database can be found from the SleuthKitCase class. <!-- @@@ IS THAT CORRECT -->
- <b>Utilities</b>: There are core utilities that the platform provides to modules. See the \ref mod_dev_utilities section for more details.
- <b>Services</b>: There are services provided by the platform. See the \ref mod_dev_services section for more details.
- <b>Pipelines and Plug-in Modules:</b> The platform has several places where plug-in modules can be incorporated. This modular approach allows other developers to extend the functionality of the system. See the \ref platform_frameworks section for more details.
- <b>Blackboard:</b> The platform uses the blackboard to enable modules to communicate with each other and to display data in the GUI. See the \ref platform_blackboard section for more details.
- <b>Single tree:</b> Results from the various modules can generally be found in a single tree. This makes it easy for users to find their results.
- <b>Phases:</b> The platform has been design to support different phases in the investigation process:
- Case Creation: Use wizards to create a new case.
- File Extraction: Where files are identified and the basic metadata are added to the central database. This happens in the Add Image Wizard.
- Ingest Modules: A variety of analysis modules then run on the extracted files to perform specific tasks.
- Browsing and searching: User can manually browse and search the data using the user interface.
- Report: A final report is generated at the end of the case.
\section platform_frameworks Frameworks in the Platform
There are several places in the platform where plug-in modules can be applied.
- <b>Ingest Modules:</b> These modules are run when a new image is added to a case (and can be re-run afterwards too). See \ref mod_ingest_page for details on building these modules. These modules come in two forms:
- File Ingest Modules are called for every file in the image. Use this type of module if you want to examine the contents of all or most of the files. Examples include hash calculation, hash lookup, file type identification, and entropy calculation.
- Image Ingest Modules are called once for every image. These modules can use the database to query for one or more files and perform analysis on them. Examples include web artifact analysis and searches that can rely only file names and extensions.
- <b>Content Viewers:</b> These modules show information about a specific file. These are the modules in the lower right of the interface. The platform comes with viewers to view the file in hexadecimal, extract the strings from the file, and view images and movies. See \ref mod_content_page for details on creating these modules.
- <b>Result Viewers:</b> These modules show information about a set of files. These modules are in the upper right of the interface. The platform comes with viewers to view the set of files in a table and thumbnails. See \ref mod_result_page for details on creating these modules.
\section platform_blackboard The Blackboard
The blackboard allows modules to communicate. It has three main uses in Autopsy:
- Ingest modules can communicate with each other. For example, one module can calculate a MD5 hash of a file and post it to the blackboard. Then another module can retrieve the hash value from the blackboard and not need to calculate it again.
- The tree in the right-hand side of the UI uses the blackboard to populate its Results section. The bookmarks, hashset hits, etc. are all populated from Ingest modules that created blackboard entries.
- The report modules query the blackboard to identify what they should report on.
For more details on the blackboard, refer to the TSK Framework documentation at http://sleuthkit.org/sleuthkit/docs/framework-docs/mod_bbpage.html. These documents are about the C++ implementation of the blackboard, but it is the same concepts.
For details on the Java API, refer to the JNI docs:
http://sleuthkit.org/sleuthkit/docs/jni-docs/
*/
/*! \page platform_page Platform Concepts
\section platform_basics Basic Concepts
These are the basic concepts that you should be aware of before writing a module:
- <b>Phases:</b> The platform has been design to support different phases in the investigation process:
- Case Creation: Use wizards to create a new case.
- File Extraction: Where files are identified and the basic metadata are added to the central database. This happens in the Add Image Wizard.
- Ingest Modules: A variety of analysis modules then run on the extracted files to perform specific tasks.
- Browsing and searching: User can manually browse and search the data using the user interface.
- Report: A final report is generated at the end of the case.
- <b>Central Database</b>: All data except for the disk image is stored in a SQLite database. This includes information about what files exist in the disk image and the output from modules. Access to this database can be found from the SleuthKitCase class, but you'll probably never need to directly interact with it. <!-- @@@ IS THAT CORRECT -->
- <b>Utilities</b>: There are core utilities that the platform provides to modules. See the \ref mod_dev_utilities section for more details.
- <b>Services</b>: There are services provided by the platform. See the \ref mod_dev_services section for more details.
- <b>Blackboard:</b> The platform uses the blackboard to enable modules to communicate with each other and to display data in the GUI. See the \ref platform_blackboard section for more details.
- <b>Single tree:</b> Results from the various modules can generally be found in a single tree. This makes it easy for users to find their results.
\section platform_frameworks Frameworks in the Platform
There are several places in the platform where plug-in modules can be applied.
- <b>Ingest Modules:</b> These modules are run when a new image is added to a case (and can be re-run afterwards too). See \ref mod_ingest_page for details on building these modules. These modules come in two forms:
- File Ingest Modules are called for every file in the image. Use this type of module if you want to examine the contents of all or most of the files. Examples include hash calculation, hash lookup, file type identification, and entropy calculation.
- Image Ingest Modules are called once for every image. These modules can use the database to query for one or more files and perform analysis on them. Examples include web artifact analysis and searches that can rely only file names and extensions.
- <b>Content Viewers:</b> These modules show information about a specific file. These are the modules in the lower right of the interface. The platform comes with viewers to view the file in hexadecimal, extract the strings from the file, and view images and movies. See \ref mod_content_page for details on creating these modules.
- <b>Result Viewers:</b> These modules show information about a set of files. These modules are in the upper right of the interface. The platform comes with viewers to view the set of files in a table and thumbnails. See \ref mod_result_page for details on creating these modules.
\section platform_blackboard The Blackboard
The blackboard allows modules to communicate. It has three main uses in Autopsy:
- Ingest modules can communicate with each other. For example, one module can calculate a MD5 hash of a file and post it to the blackboard. Then another module can retrieve the hash value from the blackboard and not need to calculate it again.
- The tree in the right-hand side of the UI uses the blackboard to populate its Results section. The bookmarks, hashset hits, etc. are all populated from Ingest modules that created blackboard entries.
- The report modules query the blackboard to identify what they should report on.
For more details on the blackboard, refer to the TSK Framework documentation at http://sleuthkit.org/sleuthkit/docs/framework-docs/mod_bbpage.html. These documents are about the C++ implementation of the blackboard, but it is the same concepts.
For details on the Java API, refer to the JNI docs:
http://sleuthkit.org/sleuthkit/docs/jni-docs/
*/

View File

@ -1,98 +1,87 @@
/*! \page workflow_page General Workflow and Design
\section design_overview Overview
This section outlines Autopsy design from the typical analysis work flow perspective.
This page is organized based on these phases:
- A Case is created.
- Images are added to the case and ingest modules are run.
- Results are manually reviewed and searched.
- Reports are generated.
\section design_case Creating a Case
The first step in Autopsy work flow is creating a case. This is done in the org.sleuthkit.autopsy.casemodule package (see \ref casemodule_overview for details). This module contains the wizards needed and deals with how to store the information. You should not need to do much modifications in this package. But, you will want to use the org.sleuthkit.autopsy.casemodule.Case object to access all data related to this case.
\section design_image Adding an Image and Running Ingest Modules
After case is created, one or more disk images can be added to the case. There is a wizard to guide that process and it is located in the org.sleuthkit.autopsy.casemodule package. Refer to the package section \ref casemodule_add_image for more details on the wizard. Most developers will not need to touch this code though.
After image has been added to the case, the user can select one or more ingest modules to be executed on the image. Ingest modules focus on a specific type of analysis task and run in the background. The results from the ingest module can be found in the results tree and in the ingest inbox.
The org.sleuthkit.autopsy.ingest package provides the basic infrastructure for the ingest module management.
A list of standard ingest modules that come with Autopsy can be found in:
- org.sleuthkit.autopsy.keywordsearch
- org.sleuthkit.autopsy.recentactivity
- org.sleuthkit.autopsy.hashdatabase
- org.sleuthkit.autopsy.thunderbirdparser
See \ref mod_ingest_page for more details on making an ingest module.
\section design_view Viewing Results
The UI has three main areas. The tree on the left-hand side, the result viewers in the upper right, and the content viewers in the lower right. Data passes between these areas by encapsulating them in Netbeans Node objects (see org.openide.nodes.Node). These allow Autopsy to generically handle all types of data. The org.sleuthkit.autopsy.datamodel package details with wrapping the org.sleuthkit.datamodel objects as Netbeans Nodes.
Nodes are modeled in a parent-child hierarchy with other nodes. All data within a Case is represented in a hierarchy with the disk images being one level below the case and volumes and such below the image.
The tree on the left hand-side shows the analysis results.
Its contents are populated from the central database.
This is where you can browse the file system contents and see the results from the blackboard.
<!-- @@@(see \ref blackboard_page). -->
The tree is implemented in the org.sleuthkit.autopsy.directorytree package.
The area in the upper right is the result viewer area. When a node is selected from the tree, the node and its children are sent to this area. This area is used to view a set of nodes. The viewer is itself a framework with modules that display the data in different layouts. For example, the standard version comes with a table viewer and a thumbnail viewer. Refer to \ref mod_result_page for details on building a module.
When an item is selected from the result viewer area, it is passed to the bottom right content viewers. It too is a framework with many modules that know how to show information about a specific file in different ways. For example, there are viewers that show the data in a hex dump format, extract the strings, and display pictures and movies.
See \ref mod_content_page for details on building new content viewers.
\section design_report Report generation
When ingest is complete, the user can generate reports.
There is a reporting framework to enable many different formats. Autopsy currently comes with generic html, xml and Excel reports. See the org.sleuthkit.autopsy.report package for details on the framework and
\ref mod_report_page for details on building a new report module.
<!-- @@@ MOVE THIS SOMEWHERE ELSE -- the directory tree package maybe?? -->
The component is by default registered with the ingest manager as an ingest event listener.
The viewer first loads all the viewer-supported data currently in the blackboard when Autopsy starts.
During the ingest process the viewer receives events from ingest modules
(relayed by ingest manager) and it selectively refreshes parts of the tree providing real-time updates to the user.
When ingest is completed, the viewer responds to the final ingest data event generated by the ingest manager,
and performs a final refresh of all viewer-supported data in the blackboard.
Node content support capabilities are registered in the node's Lookup.
<!-- @@@ This is too detailed for here, but maybe should be broken up and put into the sections on making a result viewer and such…
-->
\section design_data_flow Data Flow
\subsection design_data_flow_create Creating Nodes in DataExplorer
Data flows between the UI zones using a NetBeans node. The DataExplorer modules create the NetBeans nodes. They query the SQLite database or do whatever they want to identify the set of files that are of interest. They create the NetBeans nodes based on Sleuthkit data model objects. See the org.sleuthkit.autopsy.datamodel package for more details on this.
\subsection design_data_flow_toResult Getting Nodes to DataResult
Each DataExplorer TopComponent is responsible for creating its own DataResult TopComponent to display its results. It can choose to re-use the same TopComponent for multiple searches (as DirectoryTree does) or it can choose to make a new one each time (as FileSearch does). The setNode() method on the DataResult object is used to set the root node to display. A dummy root node must be created as the parent if a parent does not already exist.
The DataExplorer is responsible for setting the double-click and right-click actions associated with the node. The default single click action is to pass data to DataContent. To override this, you must create a new DataResultViewer instance that overrides the propertyChange() method. The DataExplorer adds actions to wrapping the node in a FilterNode variant. The FilterNode then defines the actions for the node by overriding the getPreferredAction() and getActions() methods. As an example, org.sleuthkit.autopsy.directorytree.DataResultFilterNode and org.sleuthkit.autopsy.directorytree.DataResultFilterChildren wraps the nodes that are passed over by the DirectoryTree DataExplorer.
DataResult can send data back to its DataExplorer by making a custom action that looks up it's instance (DataExplorer.getInstance()).
\subsection design_data_flow_toContent Getting Nodes to DataContent
A default DataContent viewer is created when a case is opened. To display the contents of a node, it must be passed to a DataContent instance. The default single-click behavior of the DataResultViewers is to lookup the default DataContent TopComponent and pass the selected node to it. See org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer.propertyChange(PropertyChangeEvent) for details.
*/
/*! \page workflow_page General Workflow and Design
\section design_overview Overview
This section outlines the internal Autopsy design from the typical analysis work flow perspective.
This page is organized based on these phases:
- A Case is created.
- Images are added to the case and ingest modules are run.
- Results are manually reviewed and searched.
- Reports are generated.
\section design_case Creating a Case
The first step in Autopsy work flow is creating a case. This is done in the org.sleuthkit.autopsy.casemodule package (see \ref casemodule_overview for details). This module contains the wizards needed and deals with how to store the information. You should not need to do much modifications in this package. But, you will want to use the org.sleuthkit.autopsy.casemodule.Case object to access all data related to this case.
\section design_image Adding an Image and Running Ingest Modules
After case is created, one or more disk images can be added to the case. There is a wizard to guide that process and it is located in the org.sleuthkit.autopsy.casemodule package. Refer to the package section \ref casemodule_add_image for more details on the wizard. Most developers will not need to touch this code though. An important concept though is that adding an image to a case means that Autopsy uses The Sleuth Kit to enumerate all of the files in the file system and make a database entry for them in the embedded SQLite database that was created for the case. The database will be used for all further analysis.
After image has been added to the case, the user can select one or more ingest modules to be executed on the image. Ingest modules focus on a specific type of analysis task and run in the background. They either analyze the entire disk image or individual files. The user will see the results from the modules in the result tree and in the ingest inbox.
The org.sleuthkit.autopsy.ingest package provides the basic infrastructure for the ingest module management.
If you want to develop a module that analyzes drive data, then this is probably the type of module that you want to build. See \ref mod_ingest_page for more details on making an ingest module.
\section design_view Viewing Results
The UI has three main areas. The tree on the left-hand side, the result viewers in the upper right, and the content viewers in the lower right. Data passes between these areas by encapsulating them in Netbeans Node objects (see org.openide.nodes.Node). These allow Autopsy to generically handle all types of data. The org.sleuthkit.autopsy.datamodel package wraps the generic org.sleuthkit.datamodel Sleuth Kit objects as Netbeans Nodes.
Nodes are modeled in a parent-child hierarchy with other nodes. All data within a Case is represented in a hierarchy with the disk images being one level below the case and volumes and such below the image.
The tree on the left hand-side shows the analysis results.
Its contents are populated from the central database.
This is where you can browse the file system contents and see the results from the blackboard.
<!-- @@@(see \ref blackboard_page). -->
The tree is implemented in the org.sleuthkit.autopsy.directorytree package.
The area in the upper right is the result viewer area. When a node is selected from the tree, the node and its children are sent to this area. This area is used to view a set of nodes. The viewer is itself a framework with modules that display the data in different layouts. For example, the standard version comes with a table viewer and a thumbnail viewer. Refer to \ref mod_result_page for details on building a data result module.
When an item is selected from the result viewer area, it is passed to the bottom right content viewers. It too is a framework with many modules that know how to show information about a specific file in different ways. For example, there are viewers that show the data in a hex dump format, extract the strings, and display pictures and movies.
See \ref mod_content_page for details on building new content viewers.
\section design_report Report generation
When ingest is complete, the user can generate reports.
There is a reporting framework to enable many different formats. Autopsy currently comes with generic html, xml and Excel reports. See the org.sleuthkit.autopsy.report package for details on the framework and
\ref mod_report_page for details on building a new report module.
<!-- @@@ MOVE THIS SOMEWHERE ELSE -- the directory tree package maybe?? -->
The component is by default registered with the ingest manager as an ingest event listener.
The viewer first loads all the viewer-supported data currently in the blackboard when Autopsy starts.
During the ingest process the viewer receives events from ingest modules
(relayed by ingest manager) and it selectively refreshes parts of the tree providing real-time updates to the user.
When ingest is completed, the viewer responds to the final ingest data event generated by the ingest manager,
and performs a final refresh of all viewer-supported data in the blackboard.
Node content support capabilities are registered in the node's Lookup.
<!-- @@@ This is too detailed for here, but maybe should be broken up and put into the sections on making a result viewer and such…
-->
\section design_data_flow Data Flow
\subsection design_data_flow_create Creating Nodes in DataExplorer
Data flows between the UI zones using a NetBeans node. The DataExplorer modules create the NetBeans nodes. They query the SQLite database or do whatever they want to identify the set of files that are of interest. They create the NetBeans nodes based on Sleuthkit data model objects. See the org.sleuthkit.autopsy.datamodel package for more details on this.
\subsection design_data_flow_toResult Getting Nodes to DataResult
Each DataExplorer TopComponent is responsible for creating its own DataResult TopComponent to display its results. It can choose to re-use the same TopComponent for multiple searches (as DirectoryTree does) or it can choose to make a new one each time (as FileSearch does). The setNode() method on the DataResult object is used to set the root node to display. A dummy root node must be created as the parent if a parent does not already exist.
The DataExplorer is responsible for setting the double-click and right-click actions associated with the node. The default single click action is to pass data to DataContent. To override this, you must create a new DataResultViewer instance that overrides the propertyChange() method. The DataExplorer adds actions to wrapping the node in a FilterNode variant. The FilterNode then defines the actions for the node by overriding the getPreferredAction() and getActions() methods. As an example, org.sleuthkit.autopsy.directorytree.DataResultFilterNode and org.sleuthkit.autopsy.directorytree.DataResultFilterChildren wraps the nodes that are passed over by the DirectoryTree DataExplorer.
DataResult can send data back to its DataExplorer by making a custom action that looks up it's instance (DataExplorer.getInstance()).
\subsection design_data_flow_toContent Getting Nodes to DataContent
A default DataContent viewer is created when a case is opened. To display the contents of a node, it must be passed to a DataContent instance. The default single-click behavior of the DataResultViewers is to lookup the default DataContent TopComponent and pass the selected node to it. See org.sleuthkit.autopsy.corecomponents.AbstractDataResultViewer.propertyChange(PropertyChangeEvent) for details.
*/

View File

@ -9,11 +9,10 @@ app.name=autopsy
### Must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE
build.type=DEVELOPMENT
update_versions=false
#custom JVM options
#Note: can be higher on 64 bit systems, should be in sync with build.xml
run.args.extra=-J-Xms24m -J-Xmx512m -J-XX:MaxPermSize=128M -J-Xverify:none
run.args.extra=-J-Xms24m -J-Xmx768m -J-XX:MaxPermSize=256M -J-Xverify:none
auxiliary.org-netbeans-modules-apisupport-installer.license-type=apache.v2
auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=false
@ -31,8 +30,7 @@ modules=\
${project.org.sleuthkit.autopsy.core}:\
${project.org.sleuthkit.autopsy.corelibs}:\
${project.org.sleuthkit.autopsy.sevenzip}:\
${project.org.sleuthkit.autopsy.timeline}:\
${project.org.sleuthkit.autopsy.scalpel}
${project.org.sleuthkit.autopsy.timeline}
project.org.sleuthkit.autopsy.core=Core
project.org.sleuthkit.autopsy.corelibs=CoreLibs
project.org.sleuthkit.autopsy.hashdatabase=HashDatabase
@ -43,4 +41,4 @@ project.org.sleuthkit.autopsy.thunderbirdparser=thunderbirdparser
project.org.sleuthkit.autopsy.exifparser=ExifParser
project.org.sleuthkit.autopsy.sevenzip=SevenZip
project.org.sleuthkit.autopsy.timeline=Timeline
project.org.sleuthkit.autopsy.scalpel=ScalpelCarver

View File

@ -32,8 +32,6 @@ import java.util.logging.Level;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract.*;
import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
@ -52,12 +50,10 @@ import org.sleuthkit.autopsy.ingest.PipelineContext;
import org.sleuthkit.autopsy.ingest.IngestModuleInit;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
public class ThunderbirdMboxFileIngestModule implements IngestModuleAbstractFile {
public class ThunderbirdMboxFileIngestModule extends IngestModuleAbstractFile {
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
private static ThunderbirdMboxFileIngestModule instance = null;
@ -67,7 +63,6 @@ public class ThunderbirdMboxFileIngestModule implements IngestModuleAbstractFile
private static final String MODULE_NAME = "Thunderbird Parser";
private final String hashDBModuleName = "Hash Lookup";
final public static String MODULE_VERSION = "1.0";
private String args;
public static synchronized ThunderbirdMboxFileIngestModule getDefault() {
if (instance == null) {
@ -262,15 +257,6 @@ public class ThunderbirdMboxFileIngestModule implements IngestModuleAbstractFile
return MODULE_VERSION;
}
@Override
public String getArguments() {
return args;
}
@Override
public void setArguments(String args) {
this.args = args;
}
@Override
public void init(IngestModuleInit initContext) {
@ -288,41 +274,8 @@ public class ThunderbirdMboxFileIngestModule implements IngestModuleAbstractFile
//module specific cleanup due interruption here
}
@Override
public ModuleType getType() {
return ModuleType.AbstractFile;
}
@Override
public boolean hasSimpleConfiguration() {
return false;
}
@Override
public boolean hasAdvancedConfiguration() {
return false;
}
@Override
public javax.swing.JPanel getSimpleConfiguration() {
return null;
}
@Override
public javax.swing.JPanel getAdvancedConfiguration() {
return null;
}
@Override
public boolean hasBackgroundJobsRunning() {
return false;
}
@Override
public void saveAdvancedConfiguration() {
}
@Override
public void saveSimpleConfiguration() {
}
}