4961 initial integration of RejView library into autopsy

This commit is contained in:
William Schaefer 2019-05-10 11:06:13 -04:00
parent cc92182522
commit 7bd569b665
17 changed files with 1147 additions and 7 deletions

View File

@ -65,7 +65,6 @@
<!--Copy other jars-->
<copy file="${thirdparty.dir}/rejistry/Rejistry-1.1-SNAPSHOT.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/rejView/RejView.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/sevenzip/sevenzipjbinding.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/sevenzip/sevenzipjbinding-AllPlatforms.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/stix/StixLib.jar" todir="${ext.dir}" />

View File

@ -61,7 +61,6 @@ file.reference.pdfbox-2.0.13.jar=release\\modules\\ext\\pdfbox-2.0.13.jar
file.reference.pdfbox-tools-2.0.13.jar=release\\modules\\ext\\pdfbox-tools-2.0.13.jar
file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar
file.reference.Rejistry-1.1-SNAPSHOT.jar=release/modules/ext/Rejistry-1.1-SNAPSHOT.jar
file.reference.RejView.jar=release/modules/ext/RejView.jar
file.reference.rome-1.12.0.jar=release\\modules\\ext\\rome-1.12.0.jar
file.reference.sentiment-analysis-parser-0.1.jar=release\\modules\\ext\\sentiment-analysis-parser-0.1.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar

View File

@ -685,10 +685,6 @@
<runtime-relative-path>ext/Rejistry-1.1-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.1-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/RejView.jar</runtime-relative-path>
<binary-origin>release/modules/ext/RejView.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/dd-plist-1.20.jar</runtime-relative-path>
<binary-origin>release/modules/ext/dd-plist-1.20.jar</binary-origin>

View File

@ -21,7 +21,7 @@
*/
package org.sleuthkit.autopsy.contentviewers;
import com.williballenthin.RejistryView.RejView;
import com.williballenthin.rejistry.RegistryHive;
import com.williballenthin.rejistry.RegistryHiveBuffer;
import com.williballenthin.rejistry.RegistryParseException;
@ -33,6 +33,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JPanel;
import org.sleuthkit.autopsy.rejview.RejView;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;

View File

@ -0,0 +1,269 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.nio.ByteBuffer;
/**
* HexView is a standard three-paned hex editor widget that displays binary data.
*
* Note, this does not do any intelligent paging of the data. You should estimate it to load three strings
* with length equal to the given ByteBuffer. So its probably not good to use this view with large files.
*/
public class HexView extends JPanel implements CaretListener {
private final static int DEFAULT_BYTES_PER_LINE = 0x10;
private final static char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private final int _bytesPerLine;
private final ByteBuffer _buf;
private final JTextComponent _offsetView;
private final JTextComponent _hexView;
private final JTextComponent _asciiView;
private final JLabel _statusLabel;
private final Color _highlightColor;
private final DefaultHighlighter.DefaultHighlightPainter _highlighterPainter;
/**
* Uses the default 0x10 bytes per line.
*
* @param buf The binary data to display within this hex view.
*/
public HexView(ByteBuffer buf) {
this(buf, DEFAULT_BYTES_PER_LINE);
}
/**
* @param buf The binary data to display within this hex view.
* @param bytesPerLine The number of bytes to display per line.
*/
public HexView(ByteBuffer buf, int bytesPerLine) {
super(new BorderLayout());
this._buf = buf;
this._bytesPerLine = bytesPerLine;
Font font = new Font("Monospaced", Font.PLAIN, 12);
this._offsetView = new JTextArea();
this._hexView = new JTextArea();
this._asciiView = new JTextArea();
JPanel _statusView = new JPanel();
// status bar
_statusView.setBorder(new BevelBorder(BevelBorder.LOWERED));
this.add(_statusView, BorderLayout.SOUTH);
_statusView.setPreferredSize(new Dimension(this.getWidth(), 18));
_statusView.setLayout(new BoxLayout(_statusView, BoxLayout.X_AXIS));
this._statusLabel = new JLabel("");
this._statusLabel.setHorizontalAlignment(SwingConstants.LEFT);
_statusView.add(this._statusLabel);
// right panes are split
JSplitPane _splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this._hexView, this._asciiView);
_splitPane.setResizeWeight(0.5);
_splitPane.setOneTouchExpandable(true);
_splitPane.setContinuousLayout(true);
// three panes sitting together
JPanel panes = new JPanel(new BorderLayout());
panes.add(this._offsetView, BorderLayout.WEST);
panes.add(_splitPane, BorderLayout.CENTER);
JScrollPane scroller = new JScrollPane(panes);
this.add(scroller, BorderLayout.CENTER);
_offsetView.setFont(font);
_hexView.setFont(font);
_asciiView.setFont(font);
StringBuilder offsetSB = new StringBuilder();
StringBuilder hexSB = new StringBuilder();
StringBuilder asciiSB = new StringBuilder();
buf.position(0x0);
for (int i = 0; i < buf.limit(); i++) {
if (i % this._bytesPerLine == 0x0) {
offsetSB.append(String.format("0x%x \n", i));
}
byte b = buf.get();
char[] hex = new char[3];
hex[0] = HEX_DIGITS[(b >>> 4) & 0x0F];
hex[1] = HEX_DIGITS[b & 0x0F];
hex[2] = ' ';
hexSB.append(hex);
if (b >= ' ' && b <= '~') {
asciiSB.append((char)b);
} else {
asciiSB.append('.');
}
if (i % this._bytesPerLine == this._bytesPerLine - 1) {
hexSB.append("\n");
asciiSB.append("\n");
}
}
this._offsetView.setText(offsetSB.toString());
this._hexView.setText(hexSB.toString());
this._asciiView.setText(asciiSB.toString());
this._hexView.addCaretListener(this);
this._asciiView.addCaretListener(this);
this._asciiView.setSelectedTextColor(this._asciiView.getForeground());
this._hexView.setSelectedTextColor(this._asciiView.getForeground());
this._highlightColor = this._hexView.getSelectionColor();
this._highlighterPainter = new DefaultHighlighter.DefaultHighlightPainter(this._highlightColor);
}
/**
* clearHighlight removes any colors applied to the text views.
*/
private void clearHighlight() {
this._asciiView.getHighlighter().removeAllHighlights();
this._hexView.getHighlighter().removeAllHighlights();
}
/**
* setHighlight colors the given byte range.
* @param startByte The starting byte index of the selection.
* @param endByte The ending byte index of the selection.
*/
private void setHighlight(int startByte, int endByte) {
int startRows = (startByte - (startByte % this._bytesPerLine)) / this._bytesPerLine;
int endRows = (endByte - (endByte % this._bytesPerLine)) / this._bytesPerLine;
this.clearHighlight();
try {
this._asciiView.getHighlighter().addHighlight(startByte + startRows, endByte + endRows, this._highlighterPainter);
this._hexView.getHighlighter().addHighlight((startByte * 3) + startRows, (endByte * 3) + endRows, this._highlighterPainter);
} catch (BadLocationException e1) {
System.out.println("bad location");
}
}
/**
* setSelection sets the given byte range as "selected", which from a GUI perspective means the
* bytes are highlighted, and the status bar updated.
* @param startByte The starting byte index of the selection.
* @param endByte The ending byte index of the selection.
*/
private void setSelection(int startByte, int endByte) {
this.setHighlight(startByte, endByte);
if (startByte != endByte) {
/**
* @param 1 Start
* @param 2 End
* @param 3 Len
*/
String statusTemplate = "Selection: %1$d to %2$d (len: %3$d) [0x%1$x to 0x%2$x (len: 0x%3$x)]";
this._statusLabel.setText(String.format(statusTemplate, startByte, endByte, endByte - startByte));
} else {
/**
* @param 1 Start
*/
String statusTemplate = "Position: %1$d [0x%1$x]";
this._statusLabel.setText(String.format(statusTemplate, startByte));
}
}
// these flags are used to ensure we don't end up in a circular event loop where
// one component fires an event on the other, who volley's it back.
private int _hexLastSelectionStart = 0;
private int _hexLastSelectionEnd = 0;
private int _asciiLastSelectionStart = 0;
private int _asciiLastSelectionEnd = 0;
@Override
public void caretUpdate(CaretEvent e) {
if (e.getMark() == e.getDot()) {
this.clearHighlight();
}
if (e.getSource() == this._asciiView) {
int startByte = e.getMark();
int endByte = e.getDot();
if (startByte > endByte) {
int t = endByte;
endByte = startByte;
startByte = t;
}
// the number of line endings before the start,end points
int startRows = (startByte - (startByte % this._bytesPerLine)) / this._bytesPerLine;
int endRows = (endByte - (endByte % this._bytesPerLine)) / this._bytesPerLine;
// the byte index of the start,end points in the ASCII view
startByte = startByte - startRows;
endByte = endByte - endRows;
// avoid the loop
if (_asciiLastSelectionStart == startByte && _asciiLastSelectionEnd == endByte) {
return;
}
_asciiLastSelectionStart = startByte;
_asciiLastSelectionEnd = endByte;
this.setSelection(startByte, endByte);
} else if (e.getSource() == this._hexView) {
int startByte = e.getMark();
int endByte = e.getDot();
if (startByte > endByte) {
int t = endByte;
endByte = startByte;
startByte = t;
}
// the number of line endings before the start,end points
int startRows = (startByte - (startByte % this._bytesPerLine)) / (3 * this._bytesPerLine);
int endRows = (endByte - (endByte % this._bytesPerLine)) / (3 * this._bytesPerLine);
// the byte index of the start,end points in the ASCII view
startByte = startByte - startRows;
startByte = startByte / 3;
endByte = endByte - endRows;
endByte = endByte / 3;
if (_hexLastSelectionStart == startByte && _hexLastSelectionEnd == endByte) {
return;
}
_hexLastSelectionStart = startByte;
_hexLastSelectionEnd = endByte;
this.setSelection(startByte, endByte);
} else {
System.out.println("from unknown");
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.HexDump;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.ValueData;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Iterator;
/**
* Formats a ValueData to a string similar to Regedit.exe on Windows.
* For an example, see the nice sample here:
* http://raja5.files.wordpress.com/2009/08/wincleanup_regedit.jpg
*/
public class RegeditExeValueFormatter {
public static String format(ValueData val) throws UnsupportedEncodingException, RegistryParseException {
StringBuilder sb = new StringBuilder();
switch(val.getValueType()) {
case REG_SZ:
case REG_EXPAND_SZ:{
String valString = val.getAsString();
if (valString.length() == 0) {
sb.append("(value not set)");
} else {
sb.append(valString);
}
if (sb.length() > 48) {
sb.setLength(45);
sb.append("...");
}
break;
}
case REG_MULTI_SZ: {
Iterator<String> it = val.getAsStringList().iterator();
while (it.hasNext()) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(", ");
}
}
if (sb.length() > 48) {
sb.setLength(45);
sb.append("...");
}
break;
}
case REG_DWORD:
case REG_BIG_ENDIAN: {
sb.append(String.format("0x%08x (%d)", val.getAsNumber(), val.getAsNumber()));
break;
}
case REG_QWORD: {
sb.append(String.format("0x%016x (%d)", val.getAsNumber(), val.getAsNumber())); // can you even do %016x?
break;
}
default: {
ByteBuffer valData = val.getAsRawData();
valData.position(0x0);
for (int i = 0; i < Math.min(16, valData.limit()); i++) {
byte b = valData.get();
sb.append(HexDump.toHexString(b));
if (i != 15) { // magic number, sorry.
sb.append(' ');
}
}
if (valData.limit() > 16) {
sb.append("...");
}
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,95 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryKey;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.RegistryValue;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class RejTreeKeyNode implements RejTreeNode {
private final RegistryKey _key;
public RejTreeKeyNode(RegistryKey key) {
this._key = key;
}
@Override
public String toString() {
try {
return this._key.getName();
} catch (UnsupportedEncodingException e) {
System.err.println("Failed to parse key name");
return "PARSE FAILED.";
}
}
@Override
public boolean hasChildren() {
try {
return this._key.getValueList().size() > 0 || this._key.getSubkeyList().size() > 0;
} catch (RegistryParseException e) {
System.err.println("Failed to parse key children.");
return false;
}
}
@Override
public List<RejTreeNode> getChildren() {
LinkedList<RejTreeNode> children = new LinkedList<RejTreeNode>();
try {
Iterator<RegistryKey> keyit = this._key.getSubkeyList().iterator();
while (keyit.hasNext()) {
children.add(new RejTreeKeyNode(keyit.next()));
}
Iterator<RegistryValue> valueit = this._key.getValueList().iterator();
while (valueit.hasNext()) {
children.add(new RejTreeValueNode(valueit.next()));
}
} catch (RegistryParseException e) {
System.err.println("Failed to parse key children.");
}
return children;
}
/**
* @scope: package-protected
*/
RegistryKey getKey() {
return this._key;
}
/**
* TODO(wb): this isn't exactly MVC...
*/
public RejTreeNodeView getView() {
return new RejTreeKeyView(this);
}
}

View File

@ -0,0 +1,143 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.RegistryValue;
import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
public class RejTreeKeyView extends RejTreeNodeView {
private final RejTreeKeyNode _node;
public RejTreeKeyView(RejTreeKeyNode node) {
super(new BorderLayout());
this._node = node;
/**
* @param 1 Name
* @param 2 Number of subkeys
* @param 3 Number of values
*/
String metadataTemplate = "" +
"<html>" +
"<i>Name:</i> <b>%1$s</b><br/>" +
"<i>Number of subkeys:</i> %2$d<br/>" +
"<i>Number values:</i> %3$d<br/>" +
"</html>";
String keyName;
int numSubkeys;
int numValues;
try {
keyName = this._node.getKey().getName();
} catch (UnsupportedEncodingException e) {
keyName = "FAILED TO PARSE KEY NAME";
}
try {
numSubkeys = this._node.getKey().getSubkeyList().size();
} catch (RegistryParseException e) {
numSubkeys = -1;
}
try {
numValues = this._node.getKey().getValueList().size();
} catch (RegistryParseException e) {
numValues = -1;
}
JLabel metadataLabel = new JLabel(String.format(metadataTemplate, keyName, numSubkeys, numValues), JLabel.LEFT);
metadataLabel.setBorder(BorderFactory.createTitledBorder("Metadata"));
metadataLabel.setVerticalAlignment(SwingConstants.TOP);
String[] columnNames = {"Name", "Type", "Value"};
Object[][] data = new Object[numValues][3];
try {
Iterator<RegistryValue> valit = this._node.getKey().getValueList().iterator();
int i = 0;
while (valit.hasNext()) {
RegistryValue val = valit.next();
if (val.getName().length() == 0) {
data[i][0] = "(Default)";
} else {
data[i][0] = val.getName();
}
data[i][1] = val.getValueType().toString();
data[i][2] = RegeditExeValueFormatter.format(val.getValue());
i++;
}
} catch (RegistryParseException e) {
// TODO(wb): need to add some warning here...
// not sure how to do it, though, since some data may have already been added
// but not necessarily all of it
}
catch (UnsupportedEncodingException e) {
// TODO(wb): need to add some warning here...
}
JTable table = new JTable(data, columnNames);
table.setAutoCreateRowSorter(true);
table.setCellSelectionEnabled(false);
table.setRowSelectionAllowed(true);
table.setIntercellSpacing(new Dimension(10, 1));
// inspiration for packing the columns from:
// http://jroller.com/santhosh/entry/packing_jtable_columns
if (table.getColumnCount() > 0) {
int width[] = new int[table.getColumnCount()];
int total = 0;
for (int j = 0; j < width.length; j++) {
TableColumn column = table.getColumnModel().getColumn(j);
int w = (int)table.getTableHeader().getDefaultRenderer().getTableCellRendererComponent(table, column.getIdentifier(), false, false, -1, j).getPreferredSize().getWidth();
if (table.getRowCount() > 0) {
for (int i = 0; i < table.getRowCount(); i++) {
int pw = (int)table.getCellRenderer(i, j).getTableCellRendererComponent(table, table.getValueAt(i, j), false, false, i, j).getPreferredSize().getWidth();
w = Math.max(w, pw);
}
}
width[j] += w + table.getIntercellSpacing().width;
total += w + table.getIntercellSpacing().width;
}
width[width.length - 1] += table.getVisibleRect().width - total;
TableColumnModel columnModel = table.getColumnModel();
for (int j = 0; j < width.length; j++) {
TableColumn column = columnModel.getColumn(j);
table.getTableHeader().setResizingColumn(column);
column.setWidth(width[j]);
}
}
JScrollPane valuesPane = new JScrollPane(table);
valuesPane.setBorder(BorderFactory.createTitledBorder("Values"));
this.add(metadataLabel, BorderLayout.NORTH);
this.add(valuesPane, BorderLayout.CENTER);
}
}

View File

@ -0,0 +1,35 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import java.util.List;
/**
* RejTreeNode is the adaptor between the Registry structure model and the JTree model.
* It may describe both the contents of the node, and how it should be displayed.
*/
public interface RejTreeNode {
public abstract String toString();
public abstract boolean hasChildren();
public abstract List<RejTreeNode> getChildren();
public abstract RejTreeNodeView getView();
}

View File

@ -0,0 +1,33 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
public class RejTreeNodeSelectionEvent {
private final RejTreeNode _node;
public RejTreeNodeSelectionEvent(RejTreeNode n) {
this._node = n;
}
public RejTreeNode getNode() {
return this._node;
}
}

View File

@ -0,0 +1,26 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
public interface RejTreeNodeSelectionListener {
public abstract void nodeSelected(RejTreeNodeSelectionEvent e);
}

View File

@ -0,0 +1,35 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import javax.swing.*;
import java.awt.*;
public class RejTreeNodeView extends JPanel {
public RejTreeNodeView() {
super();
}
public RejTreeNodeView(LayoutManager lm) {
super(lm);
}
}

View File

@ -0,0 +1,75 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryValue;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
public class RejTreeValueNode implements RejTreeNode {
private final RegistryValue _value;
public RejTreeValueNode(RegistryValue value) {
this._value = value;
}
@Override
public String toString() {
try {
String valueName = this._value.getName();
if (valueName == "") {
return "(Default)";
}
return valueName;
} catch (UnsupportedEncodingException e) {
System.err.println("Failed to parse _value name");
return "PARSE FAILED.";
}
}
@Override
public boolean hasChildren() {
return false;
}
@Override
public List<RejTreeNode> getChildren() {
return new LinkedList<RejTreeNode>();
}
/**
* @scope: package-protected
*/
RegistryValue getValue() {
return this._value;
}
/**
* TODO(wb): this isn't exactly MVC...
*/
public RejTreeNodeView getView() {
return new RejTreeValueView(this);
}
}

View File

@ -0,0 +1,136 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryParseException;
import com.williballenthin.rejistry.ValueData;
import javax.swing.*;
import java.awt.*;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
public class RejTreeValueView extends RejTreeNodeView {
private final RejTreeValueNode _node;
public RejTreeValueView(RejTreeValueNode node) {
super(new BorderLayout());
this._node = node;
/**
* @param 1 Name
* @param 2 Type
*/
String metadataTemplate = "" +
"<html>" +
"<i>Name:</i> <b>%1$s</b><br/>" +
"<i>Type:</i> %2$s" +
"</html>";
String valueName;
String valueType;
/**
* @param 1 Value
*/
String valueTemplate = "" +
"<html>" +
"%1$s" +
"</html>";
try {
valueName = this._node.getValue().getName();
} catch (UnsupportedEncodingException e) {
valueName = "FAILED TO DECODE VALUE NAME";
}
try {
valueType = this._node.getValue().getValueType().toString();
} catch (RegistryParseException e ) {
valueType = "FAILED TO PARSE VALUE TYPE";
}
JLabel metadataLabel = new JLabel(String.format(metadataTemplate, valueName, valueType), JLabel.LEFT);
metadataLabel.setBorder(BorderFactory.createTitledBorder("Metadata"));
metadataLabel.setVerticalAlignment(SwingConstants.TOP);
// this valueComponent must be set in the follow try/catch block.
JComponent valueComponent;
try {
ValueData data = this._node.getValue().getValue();
// the case statements are a bit repetitive, but i think make more sense than confusingly-nested if/elses
switch(data.getValueType()) {
case REG_SZ:
case REG_EXPAND_SZ: {
String valueValue = data.getAsString();
JLabel valueLabel = new JLabel(String.format(valueTemplate, valueValue), JLabel.LEFT);
valueLabel.setBorder(BorderFactory.createTitledBorder("Value"));
valueLabel.setVerticalAlignment(SwingConstants.TOP);
valueComponent = valueLabel;
break;
}
case REG_MULTI_SZ: {
StringBuilder sb = new StringBuilder();
for (String s : data.getAsStringList()) {
sb.append(s);
sb.append("<br />");
}
String valueValue = sb.toString();
JLabel valueLabel = new JLabel(String.format(valueTemplate, valueValue), JLabel.LEFT);
valueLabel.setBorder(BorderFactory.createTitledBorder("Value"));
valueLabel.setVerticalAlignment(SwingConstants.TOP);
valueComponent = valueLabel;
break;
}
case REG_DWORD:
case REG_QWORD:
case REG_BIG_ENDIAN: {
String valueValue = String.format("0x%x", data.getAsNumber());
JLabel valueLabel = new JLabel(String.format(valueTemplate, valueValue), JLabel.LEFT);
valueLabel.setBorder(BorderFactory.createTitledBorder("Value"));
valueLabel.setVerticalAlignment(SwingConstants.TOP);
valueComponent = valueLabel;
break;
}
default: {
HexView hexView = new HexView(data.getAsRawData());
hexView.setBorder(BorderFactory.createTitledBorder("Value"));
valueComponent = hexView;
break;
}
}
} catch (RegistryParseException e) {
JLabel valueLabel = new JLabel(String.format(valueTemplate, "FAILED TO PARSE VALUE VALUE"), JLabel.LEFT);
valueLabel.setBorder(BorderFactory.createTitledBorder("Value"));
valueLabel.setVerticalAlignment(SwingConstants.TOP);
valueComponent = valueLabel;
} catch (UnsupportedEncodingException e) {
JLabel valueLabel = new JLabel(String.format(valueTemplate, "FAILED TO PARSE VALUE VALUE"), JLabel.LEFT);
valueLabel.setBorder(BorderFactory.createTitledBorder("Value"));
valueLabel.setVerticalAlignment(SwingConstants.TOP);
valueComponent = valueLabel;
}
this.add(metadataLabel, BorderLayout.NORTH);
this.add(new JScrollPane(valueComponent), BorderLayout.CENTER);
}
}

View File

@ -0,0 +1,122 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryHive;
import com.williballenthin.rejistry.RegistryParseException;
import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class RejTreeView extends JScrollPane implements TreeExpansionListener, TreeSelectionListener {
private final DefaultTreeModel _tree_model;
private JTree _tree;
private final RegistryHive _hive;
private final CopyOnWriteArrayList<RejTreeNodeSelectionListener> _nodeSelectionListeners;
public RejTreeView(RegistryHive hive) {
this._hive = hive;
DefaultMutableTreeNode rootNode;
this._nodeSelectionListeners = new CopyOnWriteArrayList<RejTreeNodeSelectionListener>();
try {
rootNode = getTreeNode(new RejTreeKeyNode(this._hive.getRoot()));
} catch (RegistryParseException e) {
System.err.println("Failed to parse root key");
rootNode = new DefaultMutableTreeNode("PARSE FAILED");
}
this._tree_model = new DefaultTreeModel(rootNode);
this._tree_model.setAsksAllowsChildren(true);
this._tree = new JTree(this._tree_model);
this._tree.addTreeExpansionListener(this);
this._tree.addTreeSelectionListener(this);
// here's a bit of a hack to force the children to be loaded and shown
this._tree.collapsePath(new TreePath(rootNode.getPath()));
this._tree.expandPath(new TreePath(rootNode.getPath()));
setViewportView(this._tree);
setPreferredSize(new Dimension(250, 400));
}
/**
* getTreeNode creates a TreeNode from a RejTreeNode, settings the appropriate fields.
*/
private DefaultMutableTreeNode getTreeNode(RejTreeNode node) {
DefaultMutableTreeNode ret;
ret = new DefaultMutableTreeNode(node);
ret.setAllowsChildren(node.hasChildren());
return ret;
}
@Override
public void treeExpanded(TreeExpansionEvent event) {
TreePath path = event.getPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
if (node.getChildCount() == 0) {
RejTreeNode n = (RejTreeNode)node.getUserObject();
for (RejTreeNode rejTreeNode : n.getChildren()) {
node.add(getTreeNode(rejTreeNode));
}
this._tree_model.nodeStructureChanged(node);
}
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
}
@Override
public void valueChanged(TreeSelectionEvent e) {
TreePath path = e.getPath();
System.out.println("Selected: " + path);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
this.triggerRejTreeNodeSelection((RejTreeNode)node.getUserObject());
}
public void addRejTreeNodeSelectionListener(RejTreeNodeSelectionListener l) {
this._nodeSelectionListeners.add(l);
}
public void removeRejTreeNodeSelectionListener(RejTreeNodeSelectionListener l ) {
this._nodeSelectionListeners.remove(l);
}
private void triggerRejTreeNodeSelection(RejTreeNode n) {
RejTreeNodeSelectionEvent e = new RejTreeNodeSelectionEvent(n);
for (RejTreeNodeSelectionListener listener : this._nodeSelectionListeners) {
listener.nodeSelected(e);
}
}
}

View File

@ -0,0 +1,79 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Copyright 2013 Willi Ballenthin
* Contact: willi.ballenthin <at> gmail <dot> com
*
* 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.rejview;
import com.williballenthin.rejistry.RegistryHive;
import com.williballenthin.rejistry.RegistryHiveBuffer;
import javax.swing.*;
import java.awt.*;
import java.nio.ByteBuffer;
public class RejView extends JPanel implements RejTreeNodeSelectionListener {
private final RegistryHive _hive;
private final RejTreeView _tree_view;
private final JSplitPane _splitPane;
public RejView(RegistryHive hive) {
super(new BorderLayout());
this._hive = hive;
// have to do these cause they're final
this._tree_view = new RejTreeView(this._hive);
this._splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
this._tree_view, new JPanel());
this.setupUI();
}
public RejView(ByteBuffer buf) {
super(new BorderLayout());
this._hive = new RegistryHiveBuffer(buf);
// have to do these cause they're final
this._tree_view = new RejTreeView(this._hive);
this._splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
this._tree_view, new JPanel());
this.setupUI();
}
private void setupUI() {
this._splitPane.setResizeWeight(0);
this._splitPane.setOneTouchExpandable(true);
this._splitPane.setContinuousLayout(true);
this.add(this._splitPane, BorderLayout.CENTER);
this.setPreferredSize(new Dimension(800, 600));
this._tree_view.addRejTreeNodeSelectionListener(this);
}
@Override
public void nodeSelected(RejTreeNodeSelectionEvent e) {
RejTreeNodeView v = e.getNode().getView();
int curDividerLocation = this._splitPane.getDividerLocation();
this._splitPane.setRightComponent(v);
this._splitPane.setDividerLocation(curDividerLocation);
}
}

Binary file not shown.