This commit is contained in:
Devin148 2012-12-03 08:57:53 -05:00
commit 7c655956e3
15 changed files with 470 additions and 153 deletions

View File

@ -20,6 +20,10 @@ needed even if you have a 64-bit system).
Note: Netbeans IDE is not required to build and run Autopsy, Note: Netbeans IDE is not required to build and run Autopsy,
but it is a recommended IDE to use for development of Autopsy modules. but it is a recommended IDE to use for development of Autopsy modules.
1d) (opetional) If you are going to package Autopsy, then you'll also
need to set JRE_HOME to the root JRE directory.
2) Get Sleuth Kit Setup 2) Get Sleuth Kit Setup
2a) Download and build the release version of Libewf2 (20120304 or 2a) Download and build the release version of Libewf2 (20120304 or

View File

@ -53,6 +53,7 @@ final class AddImageVisualPanel2 extends JPanel {
infoPanel.add(progressLabel); infoPanel.add(progressLabel);
infoPanel.add(Box.createRigidArea(new Dimension(10, 10))); //spacer infoPanel.add(Box.createRigidArea(new Dimension(10, 10))); //spacer
this.jScrollPane1.setBorder(null); this.jScrollPane1.setBorder(null);
this.TextArea_CurrentDirectory.setBackground(this.getBackground());
} }
void resetInfoPanel() { void resetInfoPanel() {
@ -108,7 +109,15 @@ final class AddImageVisualPanel2 extends JPanel {
* @param dir the text to update with * @param dir the text to update with
*/ */
public void changeCurrentDir(String dir){ public void changeCurrentDir(String dir){
this.TextArea_CurrentDirectory.setText(dir.trim().isEmpty() ? "Folder Information Unavailable" : dir); this.TextArea_CurrentDirectory.setText(dir);
}
/**
* Sets the CurrentlyProcessing tag and text area to be invisible
*/
public void setProcessInvis(){
this.Label_CurrentDirectory_Static.setVisible(false);
this.TextArea_CurrentDirectory.setVisible(false);
} }

View File

@ -41,8 +41,8 @@ import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
/** /**
* The "Add Image" wizard panel3. Presents the * The "Add Image" wizard panel3. Presents the options to finish/cancel
* options to finish/cancel image-add and run ingest. * image-add and run ingest.
*/ */
class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> { class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
@ -53,10 +53,9 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* component from this class, just use getComponent(). * component from this class, just use getComponent().
*/ */
private Component component = null; private Component component = null;
private Image newImage = null; private volatile Image newImage = null;
private boolean ingested = false; private boolean ingested = false;
private boolean readyToIngest = false; private boolean readyToIngest = false;
// the paths of the image files to be added // the paths of the image files to be added
private String imgPath; private String imgPath;
// the time zone where the image is added // the time zone where the image is added
@ -67,7 +66,6 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings() private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings()
// flag to control the availiablity of next action // flag to control the availiablity of next action
private boolean imgAdded; // initalized to false in readSettings() private boolean imgAdded; // initalized to false in readSettings()
private CurrentDirectoryFetcher fetcher; private CurrentDirectoryFetcher fetcher;
private AddImageProcess process; private AddImageProcess process;
private AddImageAction action; private AddImageAction action;
@ -85,7 +83,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* but never displayed, or not all panels are displayed, it is better to * but never displayed, or not all panels are displayed, it is better to
* create only those which really need to be visible. * create only those which really need to be visible.
* *
* @return component the UI component of this wizard panel * @return component the UI component of this wizard panel
*/ */
@Override @Override
public Component getComponent() { public Component getComponent() {
@ -99,7 +97,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* Help for this panel. When the panel is active, this is used as the help * Help for this panel. When the panel is active, this is used as the help
* for the wizard dialog. * for the wizard dialog.
* *
* @return HelpCtx.DEFAULT_HELP the help for this panel * @return HelpCtx.DEFAULT_HELP the help for this panel
*/ */
@Override @Override
public HelpCtx getHelp() { public HelpCtx getHelp() {
@ -113,7 +111,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* Tests whether the panel is finished. If the panel is valid, the "Finish" * Tests whether the panel is finished. If the panel is valid, the "Finish"
* button will be enabled. * button will be enabled.
* *
* @return true the finish button should be always enabled at this point * @return true the finish button should be always enabled at this point
*/ */
@Override @Override
public boolean isValid() { public boolean isValid() {
@ -129,7 +127,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
/** /**
* Adds a listener to changes of the panel's validity. * Adds a listener to changes of the panel's validity.
* *
* @param l the change listener to add * @param l the change listener to add
*/ */
@Override @Override
public final void addChangeListener(ChangeListener l) { public final void addChangeListener(ChangeListener l) {
@ -138,7 +136,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
/** /**
* Removes a listener to changes of the panel's validity. * Removes a listener to changes of the panel's validity.
* *
* @param l the change listener to move * @param l the change listener to move
*/ */
@Override @Override
public final void removeChangeListener(ChangeListener l) { public final void removeChangeListener(ChangeListener l) {
@ -154,7 +152,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* buttons. This method can be called multiple times on one instance of * buttons. This method can be called multiple times on one instance of
* WizardDescriptor.Panel. * WizardDescriptor.Panel.
* *
* @param settings the setting to be read from * @param settings the setting to be read from
*/ */
@Override @Override
public void readSettings(WizardDescriptor settings) { public void readSettings(WizardDescriptor settings) {
@ -171,12 +169,12 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
/** /**
* Provides the wizard panel with the opportunity to update the settings * Provides the wizard panel with the opportunity to update the settings
* with its current customized state. Rather than updating its settings * with its current customized state. Rather than updating its settings with
* with every change in the GUI, it should collect them, and then only save * every change in the GUI, it should collect them, and then only save them
* them when requested to by this method. This method can be called multiple * when requested to by this method. This method can be called multiple
* times on one instance of WizardDescriptor.Panel. * times on one instance of WizardDescriptor.Panel.
* *
* @param settings the setting to be stored to * @param settings the setting to be stored to
*/ */
@Override @Override
public void storeSettings(WizardDescriptor settings) { public void storeSettings(WizardDescriptor settings) {
@ -188,8 +186,8 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
} }
/** /**
* Start ingest after verifying we have a new image, we are * Start ingest after verifying we have a new image, we are ready to ingest,
* ready to ingest, and we haven't already ingested. * and we haven't already ingested.
*/ */
private void startIngest() { private void startIngest() {
if (newImage != null && readyToIngest && !ingested) { if (newImage != null && readyToIngest && !ingested) {
@ -200,16 +198,21 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
} }
} }
/** /**
* Class for getting the currently processing directory. * Class for getting the currently processing directory.
* *
*/ */
private class CurrentDirectoryFetcher extends SwingWorker<Integer,Integer> { private static class CurrentDirectoryFetcher extends SwingWorker<Integer,Integer> {
AddImgTask task; AddImgTask task;
JProgressBar prog;
AddImageVisualPanel2 wiz;
AddImageProcess proc;
CurrentDirectoryFetcher(AddImgTask task){ CurrentDirectoryFetcher(JProgressBar prog, AddImageVisualPanel2 wiz, AddImageProcess proc){
this.task = task; this.wiz = wiz;
this.proc = proc;
this.prog = prog;
} }
/** /**
@ -218,28 +221,34 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
@Override @Override
protected Integer doInBackground(){ protected Integer doInBackground(){
try{ try{
while(task.progressBar.getValue() < 100 || task.progressBar.isIndeterminate()){ while(prog.getValue() < 100 || prog.isIndeterminate()){ //TODO Rely on state variable in AddImgTask class
EventQueue.invokeLater(new Runnable() { EventQueue.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
wizPanel.getComponent().changeCurrentDir(process.currentDirectory()); wiz.changeCurrentDir(proc.currentDirectory());
} }
}); });
Thread.sleep(2 * 1000); Thread.sleep(2 * 1000);
} }
return 1; return 1;
} } catch (InterruptedException ie) {
catch(InterruptedException ie){
return -1; return -1;
} }
} }
/**
* When done, set the Wizards processing tags to be invisible
*/
@Override
protected void done() {
wiz.setProcessInvis();
}
} }
/** /**
* Thread that will make the JNI call to ingest the image. * Thread that will make the JNI call to ingest the image.
*/ */
@ -251,9 +260,9 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
private boolean interrupted = false; private boolean interrupted = false;
private boolean hasCritError = false; private boolean hasCritError = false;
private String errorString = null; private String errorString = null;
private long start; private long start;
private WizardDescriptor settings; private WizardDescriptor settings;
private Logger logger = Logger.getLogger(AddImgTask.class.getName());
protected AddImgTask(WizardDescriptor settings) { protected AddImgTask(WizardDescriptor settings) {
this.progressBar = wizPanel.getComponent().getCrDbProgressBar(); this.progressBar = wizPanel.getComponent().getCrDbProgressBar();
@ -304,7 +313,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
fetcher = new CurrentDirectoryFetcher(this); fetcher = new CurrentDirectoryFetcher(this.progressBar, wizPanel.getComponent(), process);
cancelledWhileRunning.enable(); cancelledWhileRunning.enable();
try { try {
wizPanel.setStateStarted(); wizPanel.setStateStarted();
@ -321,15 +330,26 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
} finally { } finally {
// process is over, doesn't need to be dealt with if cancel happens // process is over, doesn't need to be dealt with if cancel happens
cancelledWhileRunning.disable(); cancelledWhileRunning.disable();
//enqueue what would be in done() to EDT thread
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
postProcessImage();
}
});
} }
this.setProgress(100);
return 0; return 0;
} }
/** /**
* Commit the finished AddImageProcess, and cancel the CleanupTask that * Commit the finished AddImageProcess, and cancel the CleanupTask that
* would have reverted it. * would have reverted it.
* @param settings property set to get AddImageProcess and CleanupTask from *
* @param settings property set to get AddImageProcess and CleanupTask
* from
* @throws Exception if commit or adding the image to the case failed * @throws Exception if commit or adding the image to the case failed
*/ */
private void commitImage(WizardDescriptor settings) throws Exception { private void commitImage(WizardDescriptor settings) throws Exception {
@ -341,11 +361,9 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
long imageId = 0; long imageId = 0;
try { try {
imageId = process.commit(); imageId = process.commit();
} } catch (TskException e) {
catch (TskException e) {
logger.log(Level.WARNING, "Errors occured while committing the image", e); logger.log(Level.WARNING, "Errors occured while committing the image", e);
} } finally {
finally {
//commit done, unlock db write in EWT thread //commit done, unlock db write in EWT thread
//before doing anything else //before doing anything else
SleuthkitCase.dbWriteUnlock(); SleuthkitCase.dbWriteUnlock();
@ -366,37 +384,28 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
* *
* (called by EventDispatch Thread after doInBackground finishes) * (called by EventDispatch Thread after doInBackground finishes)
*/ */
@Override protected void postProcessImage() {
protected void done() {
progressBar.setIndeterminate(false); progressBar.setIndeterminate(false);
setProgress(100);
// attempt actions that might fail and force the process to stop // attempt actions that might fail and force the process to stop
try { if (interrupted || hasCritError) {
//get() will block until doInBackground done and throw any exceptions logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
//that were thrown in the background task revert();
//if process was stopped, stop should have been complete (otherwise, unsafe to revert() ) if (hasCritError) {
get(); //core error
logger.log(Level.INFO, "Adding image took " + (System.currentTimeMillis() - start) + " ms."); wizPanel.getComponent().setErrors(errorString, true);
} catch (InterruptedException e) {
} catch (ExecutionException e) {
} finally {
if (interrupted || hasCritError) {
logger.log(Level.INFO, "Handling errors or interruption that occured in add image process");
revert();
if (hasCritError) {
//core error
wizPanel.getComponent().setErrors(errorString, true);
}
return;
} else if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
wizPanel.getComponent().setErrors(errorString, false);
} }
return;
} else if (errorString != null) {
//data error (non-critical)
logger.log(Level.INFO, "Handling non-critical errors that occured in add image process");
wizPanel.getComponent().setErrors(errorString, false);
} }
try { try {
// When everything happens without an error: // When everything happens without an error:
@ -431,6 +440,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
// Commit the image // Commit the image
if (newImage != null) //already commited if (newImage != null) //already commited
{ {
logger.log(Level.INFO, "Assuming image already committed, will not commit.");
return; return;
} }
@ -457,7 +467,7 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
wizPanel.getComponent().changeProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message wizPanel.getComponent().changeProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message
// Log error/display warning // Log error/display warning
Logger logger = Logger.getLogger(AddImgTask.class.getName());
logger.log(Level.SEVERE, "Error adding image to case", ex); logger.log(Level.SEVERE, "Error adding image to case", ex);
} finally { } finally {
} }

View File

@ -173,11 +173,13 @@ public class Case {
String oldCaseName = oldCase != null ? oldCase.name : ""; String oldCaseName = oldCase != null ? oldCase.name : "";
doCaseChange(null); //closes windows, etc
pcs.firePropertyChange(CASE_CURRENT_CASE, oldCase, null); pcs.firePropertyChange(CASE_CURRENT_CASE, oldCase, null);
doCaseChange(null);
pcs.firePropertyChange(CASE_NAME, oldCaseName, "");
doCaseNameChange(""); doCaseNameChange("");
pcs.firePropertyChange(CASE_NAME, oldCaseName, "");
@ -827,14 +829,16 @@ public class Case {
Case.runAddImageAction(); Case.runAddImageAction();
} }
} else { // case is closed } else { // case is closed
// close all top components first
CoreComponentControl.closeCoreWindows();
// disable these menus // disable these menus
CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu CallableSystemAction.get(AddImageAction.class).setEnabled(false); // Add Image menu
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu CallableSystemAction.get(CaseCloseAction.class).setEnabled(false); // Case Close menu
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false); // Case Properties menu
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false); // Delete Case menu
// close all top components
CoreComponentControl.closeCoreWindows();
Frame f = WindowManager.getDefault().getMainWindow(); Frame f = WindowManager.getDefault().getMainWindow();
f.setTitle(Case.getAppName()); // set the window name to just application name f.setTitle(Case.getAppName()); // set the window name to just application name

View File

@ -6,9 +6,9 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- definition of simple elements --> <!-- definition of simple elements -->
<xs:element name="Name" type="xs:string"/> <xs:element name="Name" type="String"/>
<xs:element name="Number" type="Integer" nillable="true"/> <xs:element name="Number" type="String" nillable="true"/>
<xs:element name="Examiner" type="String" nillable="true"/> <xs:element name="Examiner" type="String" nillable="true"/>

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
import javax.swing.Action; import javax.swing.Action;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.directorytree.ExtractUnallocAction;
import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.Volume;
/** /**
@ -66,6 +67,7 @@ public class VolumeNode extends AbstractContentNode<Volume> {
public Action[] getActions(boolean popup) { public Action[] getActions(boolean popup) {
return new Action[]{ //new ShowDetailAction("Volume Details", this.getName(), this), return new Action[]{ //new ShowDetailAction("Volume Details", this.getName(), this),
//new ShowDetailAction("File System Details", this.getName(), this) //new ShowDetailAction("File System Details", this.getName(), this)
//new ExtractUnallocAction("Extract Unallocated Files to single Single", this)
}; };
} }

View File

@ -160,7 +160,6 @@ public class DataResultFilterNode extends FilterNode {
List<Action> actions = new ArrayList<Action>(); List<Action> actions = new ArrayList<Action>();
actions.add(new NewWindowViewAction("View in New Window", vol)); actions.add(new NewWindowViewAction("View in New Window", vol));
actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class))); actions.addAll(ShowDetailActionVisitor.getActions(vol.getLookup().lookup(Content.class)));
return actions; return actions;
} }

View File

@ -0,0 +1,279 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.VolumeNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.LayoutDirectory;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Volume;
/**
* Extracts all the unallocated space as a single file
*/
public final class ExtractUnallocAction extends AbstractAction{
private List<LayoutFile> llf;
long VolumeId;
String ImageName;
long ImageId;
volatile static boolean running = false;
private static final Logger logger = Logger.getLogger(ExtractUnallocAction.class.getName());
public ExtractUnallocAction(String title, Volume volu){
super(title);
VolumeId = volu.getId();
try{
ImageName = volu.getImage().getName();
ImageId = volu.getImage().getId();
} catch(TskCoreException tce){
logger.log(Level.WARNING, "Unable to properly create ExtractUnallocAction, extraction may be incomplete", tce);
ImageName = "";
ImageId = 0;
}
llf = getUnallocFiles(volu);
Collections.sort(llf, new SortObjId());
}
/**
* Writes the unallocated files to $CaseDir/Export/ImgName-Unalloc-ImgObjectID-VolumeID.dat
* @param e
*/
@Override
public void actionPerformed(ActionEvent e) {
if (llf != null && llf.size() > 0) {
String UnallocName = ImageName + "-Unalloc-" + ImageId + "-" + VolumeId + ".dat";
//Format for single Unalloc File is ImgName-Unalloc-ImgObjectID-VolumeID.dat
File unalloc = new File(Case.getCurrentCase().getCaseDirectory() + File.separator + "Export" + File.separator + UnallocName);
if(running){
JOptionPane.showMessageDialog(new Frame(), "Unallocated Space is already running on this volume. Please select a different volume.");
return;
}
if (unalloc.exists()) {
int res = JOptionPane.showConfirmDialog(new Frame(), "The Unalloc File for this volume, " + UnallocName + " already exists, do you want to replace it?");
if (res == JOptionPane.YES_OPTION) {
unalloc.delete();
} else {
return;
}
}
ExtractUnallocWorker uw = new ExtractUnallocWorker(unalloc);
uw.execute();
} else {
logger.log(Level.WARNING, "Tried to get unallocated content from volume ID " + VolumeId + ", but its list of unallocated files was empty or null");
}
}
private List<LayoutFile> getUnallocFiles(Content c) {
UnallocVisitor uv = new UnallocVisitor();
logger.log(Level.INFO, "Sending out Unallocated File Visitor");
try {
return c.getChildren().get(0).accept(uv); //Launching it on the root directory
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
}
return null;
}
/**
* Private class for dispatching the file IO in a background thread.
*/
private class ExtractUnallocWorker extends SwingWorker<Integer, Integer> {
File path;
private ProgressHandle progress;
private boolean canceled = false;
ExtractUnallocWorker(File path) {
this.path = path;
running = true;
}
@Override
protected Integer doInBackground() {
try {
progress = ProgressHandleFactory.createHandle("Extracting " + path.getName(), new Cancellable() {
@Override
public boolean cancel() {
logger.log(Level.INFO, "Canceling extraction of Unalloc file " + path.getName());
canceled = true;
if (progress != null) {
progress.setDisplayName(path.getName() + " (Cancelling...)");
}
return true;
}
});
FileOutputStream fos = new FileOutputStream(path);
int MAX_BYTES = 8192;
byte[] buf = new byte[MAX_BYTES]; //read 8k at a time
logger.log(Level.INFO, "Writing Unalloc file to " + path.getPath());
progress.start(llf.size());
int count = 0;
for (LayoutFile f : llf) {
long offset = 0L;
while (offset != f.getSize() && !canceled) {
offset += f.read(buf, offset, MAX_BYTES); //Offset + Bytes read
fos.write(buf);
}
progress.progress(count++);
}
progress.finish();
fos.flush();
fos.close();
if(canceled){
path.delete();
logger.log(Level.INFO, "Canceled extraction of " + path.getName() + " and deleted file");
}
else{
logger.log(Level.INFO, "Finished writing unalloc file");
}
} catch (IOException ioe) {
logger.log(Level.WARNING, "Could not create Unalloc File; error writing file", ioe);
return -1;
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Could not create Unalloc File; error getting image info", tce);
return -1;
}finally{
running = false;
}
return 1;
}
}
private static class UnallocVisitor extends ContentVisitor.Default<List<LayoutFile>> {
/**
* If the volume has no FileSystem, then it will call this method to return the single instance of unallocated space.
* @param lf the LayoutFile the visitor encountered
* @return A list<LayoutFile> of size 1, returns null if it fails
*/
@Override
public List<LayoutFile> visit(final org.sleuthkit.datamodel.LayoutFile lf) {
return new ArrayList<LayoutFile>() {
{
add(lf);
}
};
}
/**
* If the visitor finds a FileSystem, it will filter the results for directories and return on the Root Dir.
* @param fs the FileSystem the visitor encountered
* @return A list<LayoutFile> containing the layout files from subsequent Visits(), returns null if it fails
*/
@Override
public List<LayoutFile> visit(FileSystem fs) {
try {
for (Content c : fs.getChildren()){
if(((AbstractFile)c).isRoot()){
return c.accept(this);
}
}
} catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting FileSystem " + fs.getId(), tce);
}
return null;
}
/**
* LayoutDirectory has all the Layout(Unallocated) files
* @param ld LayoutDirectory the visitor encountered
* @return A list<LayoutFile> containing all the LayoutFile in ld, returns null if it fails
*/
@Override
public List<LayoutFile> visit(LayoutDirectory ld){
try{
List<LayoutFile> lflst = new ArrayList<LayoutFile>();
for(Content layout : ld.getChildren()){
lflst.add((LayoutFile)layout);
}
return lflst;
} catch(TskCoreException tce){
logger.log(Level.WARNING, "Could not get list of Layout Files, failed at visiting Layout Directory", tce);
}
return null;
}
/**
* The only time this visitor should ever encounter a directory is when parsing over Root
* @param dir the directory this visitor encountered
* @return A list<LayoutFile> containing LayoutFiles encountered during subsequent Visits(), returns null if it fails
*/
@Override
public List<LayoutFile> visit(Directory dir) {
try {
for (Content c : dir.getChildren()) {
if(c instanceof LayoutDirectory){
return c.accept(this);
}
}
}catch (TskCoreException tce) {
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at visiting Directory " + dir.getId(), tce);
}
return null;
}
@Override
protected List<LayoutFile> defaultVisit(Content cntnt) {
return null;
}
}
private class SortObjId implements Comparator<LayoutFile>{
@Override
public int compare(LayoutFile o1, LayoutFile o2) {
if(o1.getId() == o2.getId()){
return 0;
}
if(o1.getId() > o2.getId()){
return -1;
}
else{
return 1;
}
}
}
}

View File

@ -44,11 +44,7 @@ import org.sleuthkit.datamodel.FileSystem;
import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.Volume;
/**
*
*
* @author jantonius
*/
class ShowDetailActionVisitor extends ContentVisitor.Default<List<? extends Action>> { class ShowDetailActionVisitor extends ContentVisitor.Default<List<? extends Action>> {
private static ShowDetailActionVisitor instance = new ShowDetailActionVisitor(); private static ShowDetailActionVisitor instance = new ShowDetailActionVisitor();
@ -231,11 +227,32 @@ class ShowDetailActionVisitor extends ContentVisitor.Default<List<? extends Acti
@Override @Override
public List<? extends Action> visit(final Volume vol) { public List<? extends Action> visit(final Volume vol) {
final String title = "Volume Details"; List<AbstractAction> lst = new ArrayList<AbstractAction>();
lst.add(new VolumeDetailsAction("Volume Details", vol));
lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single File", vol));
return lst;
}
return Collections.singletonList(new AbstractAction(title) {
@Override @Override
protected List<? extends Action> defaultVisit(Content di) {
return new ArrayList<Action>();
}
}
class VolumeDetailsAction extends AbstractAction{
String title;
Volume vol;
VolumeDetailsAction(String title, Volume vol){
super(title);
this.title = title;
this.vol = vol;
}
@Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Logger.noteAction(ShowDetailActionVisitor.class); Logger.noteAction(ShowDetailActionVisitor.class);
@ -289,11 +306,4 @@ class ShowDetailActionVisitor extends ContentVisitor.Default<List<? extends Acti
popUpWindow.setVisible(true); popUpWindow.setVisible(true);
} }
}); }
}
@Override
protected List<? extends Action> defaultVisit(Content di) {
return new ArrayList<Action>();
}
}

View File

@ -371,7 +371,7 @@ public class IngestManager {
try { try {
s.stop(); s.stop();
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "Exception while stopping module: " + s.getName(), e); logger.log(Level.WARNING, "Unexpected exception while stopping module: " + s.getName(), e);
} }
} }
@ -379,10 +379,11 @@ public class IngestManager {
//stop fs ingester thread //stop fs ingester thread
boolean cancelled = abstractFileIngester.cancel(true); boolean cancelled = abstractFileIngester.cancel(true);
if (!cancelled) { if (!cancelled) {
logger.log(Level.WARNING, "Unable to cancel file ingest worker"); logger.log(Level.INFO, "Unable to cancel file ingest worker, likely already stopped");
} else {
abstractFileIngester = null;
} }
abstractFileIngester = null;
} }
List<IngestImageThread> toStop = new ArrayList<IngestImageThread>(); List<IngestImageThread> toStop = new ArrayList<IngestImageThread>();

View File

@ -70,6 +70,8 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
private Map<Integer, HashDb> knownBadSets = new HashMap<Integer, HashDb>(); private Map<Integer, HashDb> knownBadSets = new HashMap<Integer, HashDb>();
private HashDbManagementPanel panel; private HashDbManagementPanel panel;
private final Hash hasher = new Hash();
private HashDbIngestModule() { private HashDbIngestModule() {
count = 0; count = 0;
} }
@ -323,8 +325,7 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
ProcessResult ret = ProcessResult.OK; ProcessResult ret = ProcessResult.OK;
boolean processFile = true; boolean processFile = true;
if (fsContent.getSize() == 0 if (fsContent.getKnown().equals(TskData.FileKnown.BAD)) {
|| fsContent.getKnown().equals(TskData.FileKnown.BAD)) {
processFile = false; processFile = false;
} }
if (processFile && (nsrlIsSet || knownBadIsSet)) { if (processFile && (nsrlIsSet || knownBadIsSet)) {
@ -333,7 +334,7 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
String md5Hash = fsContent.getMd5Hash(); String md5Hash = fsContent.getMd5Hash();
if (md5Hash == null || md5Hash.isEmpty()) { if (md5Hash == null || md5Hash.isEmpty()) {
long calcstart = System.currentTimeMillis(); long calcstart = System.currentTimeMillis();
md5Hash = Hash.calculateMd5(fsContent); md5Hash = hasher.calculateMd5(fsContent);
calctime += (System.currentTimeMillis() - calcstart); calctime += (System.currentTimeMillis() - calcstart);
} }
TskData.FileKnown status = TskData.FileKnown.UKNOWN; TskData.FileKnown status = TskData.FileKnown.UKNOWN;
@ -375,7 +376,7 @@ public class HashDbIngestModule implements IngestModuleAbstractFile {
String md5Hash = fsContent.getMd5Hash(); String md5Hash = fsContent.getMd5Hash();
if (md5Hash == null || md5Hash.isEmpty()) { if (md5Hash == null || md5Hash.isEmpty()) {
long calcstart = System.currentTimeMillis(); long calcstart = System.currentTimeMillis();
Hash.calculateMd5(fsContent); hasher.calculateMd5(fsContent);
calctime += (System.currentTimeMillis() - calcstart); calctime += (System.currentTimeMillis() - calcstart);
} }
ret = ProcessResult.OK; ret = ProcessResult.OK;

View File

@ -32,13 +32,13 @@ import org.sleuthkit.datamodel.FsContent;
/** /**
* Searches for FsContent Files with the same MD5 hash as the given Node's * Searches for FsContent Files with the same MD5 hash as the given Node's
* FsContent's MD5 hash. This action should only be available from Nodes with * FsContent's MD5 hash. This action should only be available from Nodes with
* specific Content attached; it is manually programmed into a Node's available actions. * specific Content attached; it is manually programmed into a Node's available
* actions.
*/ */
public class HashDbSearchAction extends CallableSystemAction implements HashSearchProvider { public class HashDbSearchAction extends CallableSystemAction implements HashSearchProvider {
private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor(); private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor();
private FsContent fsContent; private FsContent fsContent;
private static HashDbSearchAction instance = null; private static HashDbSearchAction instance = null;
HashDbSearchAction() { HashDbSearchAction() {
@ -46,7 +46,7 @@ public class HashDbSearchAction extends CallableSystemAction implements HashSear
} }
public static HashDbSearchAction getDefault() { public static HashDbSearchAction getDefault() {
if(instance == null){ if (instance == null) {
instance = new HashDbSearchAction(); instance = new HashDbSearchAction();
} }
return instance; return instance;
@ -82,25 +82,18 @@ public class HashDbSearchAction extends CallableSystemAction implements HashSear
} }
/** /**
* Find all files with the same MD5 hash as this' fsContent. fsContent should * Find all files with the same MD5 hash as this' fsContent. fsContent
* be previously set by calling the search function, which in turn calls performAction. * should be previously set by calling the search function, which in turn
* calls performAction.
*/ */
@Override @Override
public void performAction() { public void performAction() {
// Make sure all files have an md5 hash // Make sure at least 1 file has an md5 hash
if(HashDbSearcher.allFilesMd5Hashed()) { if (HashDbSearcher.countFilesMd5Hashed() > 0) {
doSearch(); doSearch();
// and if not, warn the user
} else if(HashDbSearcher.countFilesMd5Hashed() > 0) {
Object selected = JOptionPane.showConfirmDialog(null, "Not all files have MD5 hashes. "
+ "Search results will be incomplete.\n"
+ "Would you like to search anyway?", "File Search by MD5 Hash", JOptionPane.YES_NO_OPTION);
if(selected.equals(JOptionPane.YES_OPTION)) {
doSearch();
}
} else { } else {
JOptionPane.showMessageDialog(null, "No files currently have an MD5 hash.", JOptionPane.showMessageDialog(null, "No files currently have an MD5 hash calculated, run HashDB ingest first.",
"File Search by MD5 Hash", JOptionPane.ERROR_MESSAGE); "File Search by MD5 Hash", JOptionPane.ERROR_MESSAGE);
} }
} }

View File

@ -292,20 +292,9 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe
boolean search() { boolean search() {
// Check if any hashed have been entered // Check if any hashed have been entered
if(hashTable.getRowCount()!=0) { if(hashTable.getRowCount()!=0) {
// Make sure all files have an md5 hash // Make sure at least 1 file has an md5 hash
if(HashDbSearcher.allFilesMd5Hashed()) { if(HashDbSearcher.countFilesMd5Hashed() > 0) {
return doSearch(); return doSearch();
// and if not, warn the user
} else if(HashDbSearcher.countFilesMd5Hashed() > 0) {
errorField.setVisible(false);
Object selected = JOptionPane.showConfirmDialog(null, "Not all files have MD5 hashes. "
+ "Search results will be incomplete.\n"
+ "Would you like to search anyway?", "File Search by MD5 Hash", JOptionPane.YES_NO_OPTION);
if(selected.equals(JOptionPane.YES_OPTION)) {
return doSearch();
} else {
return false;
}
} else { } else {
JOptionPane.showMessageDialog(null, "No files currently have an MD5 hash.", JOptionPane.showMessageDialog(null, "No files currently have an MD5 hash.",
"File Search by MD5 Hash", JOptionPane.ERROR_MESSAGE); "File Search by MD5 Hash", JOptionPane.ERROR_MESSAGE);

View File

@ -25,6 +25,7 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
@ -39,6 +40,7 @@ import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.HTMLEditorKit.HTMLFactory; import javax.swing.text.html.HTMLEditorKit.HTMLFactory;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.progress.ProgressHandleFactory;
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.TextUtil; import org.sleuthkit.autopsy.coreutils.TextUtil;
/** /**
@ -320,7 +322,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
*/ */
void setSources(List<MarkupSource> sources) { void setSources(List<MarkupSource> sources) {
sourceComboBox.removeAllItems(); sourceComboBox.removeAllItems();
setPanelText(null); setPanelText(null, false);
for (MarkupSource ms : sources) { for (MarkupSource ms : sources) {
sourceComboBox.addItem(ms); sourceComboBox.addItem(ms);
@ -351,13 +353,28 @@ class ExtractedContentPanel extends javax.swing.JPanel {
return (MarkupSource) sourceComboBox.getSelectedItem(); return (MarkupSource) sourceComboBox.getSelectedItem();
} }
private void setPanelText(String text) { private void setPanelText(String text, boolean detectDirection) {
if (text == null ) { if (text == null) {
text = ""; text = "";
} }
//detect text direction and set it if (detectDirection) {
extractedTextPane.applyComponentOrientation(TextUtil.getTextDirection(text)); //detect text direction using first 1024 chars and set it
//get first up to 1024 chars, strip <pre> tag and unescape html to get the string on which to detect
final int len = text.length();
final int prefixLen = "<pre>".length();
if (len > prefixLen) {
final int maxOrientChars = Math.min(len, 1024);
final String orientDetectText = EscapeUtil.unEscapeHtml(text.substring(prefixLen, maxOrientChars));
ComponentOrientation direction = TextUtil.getTextDirection(orientDetectText);
//logger.log(Level.INFO, "ORIENTATION LEFT TO RIGHT: " + direction.isLeftToRight());
extractedTextPane.applyComponentOrientation(direction);
} else {
extractedTextPane.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
}
} else {
extractedTextPane.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
}
extractedTextPane.setText(text); extractedTextPane.setText(text);
extractedTextPane.setCaretPosition(0); extractedTextPane.setCaretPosition(0);
@ -570,13 +587,12 @@ class ExtractedContentPanel extends javax.swing.JPanel {
} }
} }
/** /**
* Gets and sets new markup. Updates GUI in GUI thread and gets markup in background thread. * Gets and sets new markup. Updates GUI in GUI thread and gets markup in
* To be invoked from GUI thread only. * background thread. To be invoked from GUI thread only.
*/ */
private void setMarkup(MarkupSource source) { private void setMarkup(MarkupSource source) {
setPanelText("<span style='font-style:italic'>Loading text... Please wait</span>"); setPanelText("<span style='font-style:italic'>Loading text... Please wait</span>", false);
new SetMarkup(source).execute(); new SetMarkup(source).execute();
} }
@ -611,9 +627,9 @@ class ExtractedContentPanel extends javax.swing.JPanel {
//super.done(); //super.done();
progress.finish(); progress.finish();
if (markup != null) { if (markup != null) {
setPanelText(markup); setPanelText(markup, true);
} else { } else {
setPanelText(""); setPanelText("", false);
} }
updateControls(source); updateControls(source);

View File

@ -283,7 +283,7 @@ public class Firefox extends Extract implements IngestModuleImage {
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString())))); //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", (Long.valueOf(result.get("startTime").toString())))); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", (Long.valueOf(result.get("startTime").toString()))));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID(), "RecentActivity", Util.findID(urldecodedtarget))); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID(), "RecentActivity", Util.findID(urldecodedtarget)));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), "RecentActivity", urldecodedtarget)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), "RecentActivity", ((result.get("target").toString() != null) ? result.get("target").toString() : "")));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", "FireFox")); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", "FireFox"));
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "RecentActivity", (Util.extractDomain((result.get("source").toString() != null) ? result.get("source").toString() : "")))); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "RecentActivity", (Util.extractDomain((result.get("source").toString() != null) ? result.get("source").toString() : ""))));
this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, FFSqlitedb.get(j), bbattributes); this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, FFSqlitedb.get(j), bbattributes);