Merge branch 'develop' of github.com:sleuthkit/autopsy into java11-upgrade

This commit is contained in:
esaunders 2020-11-20 11:51:29 -05:00
commit f211d22da5
70 changed files with 4081 additions and 706 deletions

12
.gitignore vendored
View File

@ -89,3 +89,15 @@ hs_err_pid*.log
*.img *.img
*.vhd *.vhd
*.E01 *.E01
/thirdparty/yara/yarabridge/yarabridge/x64/
/thirdparty/yara/yarabridge/yarabridge.VC.db
/thirdparty/yara/yarabridge/yarabridge.VC.VC.opendb
/thirdparty/yara/yarabridge/x64/
/thirdparty/yara/YaraWrapperTest/nbproject/private/
/thirdparty/yara/YaraWrapperTest/build/
/thirdparty/yara/YaraJNIWrapper/dist/
/thirdparty/yara/YaraJNIWrapper/build/
/thirdparty/yara/YaraJNIWrapper/nbproject/private/
/thirdparty/yara/yarabridge/.vs/

View File

@ -98,6 +98,11 @@
<copy file="${thirdparty.dir}/jdom/jdom-2.0.5.jar" todir="${ext.dir}" /> <copy file="${thirdparty.dir}/jdom/jdom-2.0.5.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/jdom/jdom-2.0.5-contrib.jar" todir="${ext.dir}" /> <copy file="${thirdparty.dir}/jdom/jdom-2.0.5-contrib.jar" todir="${ext.dir}" />
<copy file="${thirdparty.dir}/DatCon/3.6.9/DatCon.jar" todir="${ext.dir}" /> <copy file="${thirdparty.dir}/DatCon/3.6.9/DatCon.jar" todir="${ext.dir}" />
<!--Copy YARA to release-->
<copy todir="${basedir}/release/yara" >
<fileset dir="${thirdparty.dir}/yara/bin"/>
</copy>
<copy file="${thirdparty.dir}/yara/bin/YaraJNIWrapper.jar" todir="${ext.dir}" />
</target> </target>

View File

@ -121,6 +121,7 @@ file.reference.StixLib.jar=release\\modules\\ext\\StixLib.jar
file.reference.threetenbp-1.3.3.jar=release\\modules\\ext\\threetenbp-1.3.3.jar file.reference.threetenbp-1.3.3.jar=release\\modules\\ext\\threetenbp-1.3.3.jar
file.reference.webp-imageio-sejda-0.1.0.jar=release\\modules\\ext\\webp-imageio-sejda-0.1.0.jar file.reference.webp-imageio-sejda-0.1.0.jar=release\\modules\\ext\\webp-imageio-sejda-0.1.0.jar
file.reference.xmpcore-5.1.3.jar=release\\modules\\ext\\xmpcore-5.1.3.jar file.reference.xmpcore-5.1.3.jar=release\\modules\\ext\\xmpcore-5.1.3.jar
file.reference.YaraJNIWrapper.jar=release\\modules\\ext\\YaraJNIWrapper.jar
file.reference.zookeeper-3.4.6.jar=release\\modules\\ext\\zookeeper-3.4.6.jar file.reference.zookeeper-3.4.6.jar=release\\modules\\ext\\zookeeper-3.4.6.jar
javac.source=11 javac.source=11
javac.compilerargs=-Xlint -Xlint:-serial javac.compilerargs=-Xlint -Xlint:-serial

View File

@ -564,6 +564,10 @@
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path> <runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
<binary-origin>release\modules\ext\jsoup-1.10.3.jar</binary-origin> <binary-origin>release\modules\ext\jsoup-1.10.3.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/YaraJNIWrapper.jar</runtime-relative-path>
<binary-origin>release/modules/ext/YaraJNIWrapper.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/grpc-context-1.19.0.jar</runtime-relative-path> <runtime-relative-path>ext/grpc-context-1.19.0.jar</runtime-relative-path>
<binary-origin>release\modules\ext\grpc-context-1.19.0.jar</binary-origin> <binary-origin>release\modules\ext\grpc-context-1.19.0.jar</binary-origin>

View File

@ -383,6 +383,31 @@ public class CentralRepoDbManager {
saveNewCentralRepo(); saveNewCentralRepo();
} }
/**
* Set up a PostgresDb using the settings for the given database choice
* enum.
*
* @param choice Type of postgres DB to set up
* @throws CentralRepoException
*/
public void setupPostgresDb(CentralRepoDbChoice choice) throws CentralRepoException {
selectedDbChoice = choice;
DatabaseTestResult curStatus = testStatus();
if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
createDb();
curStatus = testStatus();
}
// the only successful setup status is tested ok
if (curStatus != DatabaseTestResult.TESTED_OK) {
throw new CentralRepoException("Unable to successfully create postgres database. Test failed with: " + curStatus);
}
// if successfully got here, then save the settings
CentralRepoDbUtil.setUseCentralRepo(true);
saveNewCentralRepo();
}
/** /**
* This method returns if changes to the central repository configuration * This method returns if changes to the central repository configuration
* were successfully applied. * were successfully applied.

View File

@ -121,10 +121,12 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbConnectiv
* @return * @return
*/ */
String getConnectionURL(boolean usePostgresDb) { String getConnectionURL(boolean usePostgresDb) {
StringBuilder url = new StringBuilder(); StringBuilder url = new StringBuilder()
url.append(getJDBCBaseURI()); .append(getJDBCBaseURI())
url.append(getHost()); .append(getHost())
url.append("/"); // NON-NLS .append(":") // NON-NLS
.append(getPort())
.append("/"); // NON-NLS
if (usePostgresDb) { if (usePostgresDb) {
url.append("postgres"); // NON-NLS url.append("postgres"); // NON-NLS
} else { } else {
@ -153,7 +155,7 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbConnectiv
} catch (ClassNotFoundException | SQLException ex) { } catch (ClassNotFoundException | SQLException ex) {
// TODO: Determine why a connection failure (ConnectionException) re-throws // TODO: Determine why a connection failure (ConnectionException) re-throws
// the SQLException and does not print this log message? // the SQLException and does not print this log message?
LOGGER.log(Level.SEVERE, "Failed to acquire ephemeral connection to postgresql."); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to acquire ephemeral connection to postgresql.", ex); // NON-NLS
conn = null; conn = null;
} }
return conn; return conn;

View File

@ -1,4 +1,10 @@
caseeventlistener.evidencetag=Evidence caseeventlistener.evidencetag=Evidence
CentralRepositoryNotificationDialog.bulletHeader=This data is used to:
CentralRepositoryNotificationDialog.bulletOne=Ignore common items (files, domains, and accounts)
CentralRepositoryNotificationDialog.bulletThree=Create personas that group accounts
CentralRepositoryNotificationDialog.bulletTwo=Identify where an item was previously seen
CentralRepositoryNotificationDialog.finalRemarks=To limit what is stored, use the Central Repository options panel.
CentralRepositoryNotificationDialog.header=Autopsy stores data about each case in its Central Repository.
IngestEventsListener.ingestmodule.name=Central Repository IngestEventsListener.ingestmodule.name=Central Repository
IngestEventsListener.prevCaseComment.text=Previous Case: IngestEventsListener.prevCaseComment.text=Previous Case:
# {0} - typeName # {0} - typeName
@ -7,6 +13,3 @@ IngestEventsListener.prevCount.text=Number of previous {0}: {1}
IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository) IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)
IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository) IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)
Installer.centralRepoUpgradeFailed.title=Central repository disabled Installer.centralRepoUpgradeFailed.title=Central repository disabled
Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. You can use this to ignore previously seen files and make connections between cases.
Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to enable it?
Installer.initialCreateSqlite.title=Enable Central Repository?

View File

@ -0,0 +1,73 @@
/*
* Central Repository
*
* Copyright 2020 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.centralrepository.eventlisteners;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.Version;
/**
* Notifies new installations or old upgrades that the central repository will
* be enabled by default.
*/
public class CentralRepositoryNotificationDialog {
/**
* This dialog should display iff the mode is RELEASE and the
* application is running with a GUI.
*/
static boolean shouldDisplay() {
return Version.getBuildType() == Version.Type.RELEASE
&& RuntimeProperties.runningWithGUI();
}
/**
* Displays an informational modal dialog to the user, which is dismissed by
* pressing 'OK'.
*/
@NbBundle.Messages({
"CentralRepositoryNotificationDialog.header=Autopsy stores data about each case in its Central Repository.",
"CentralRepositoryNotificationDialog.bulletHeader=This data is used to:",
"CentralRepositoryNotificationDialog.bulletOne=Ignore common items (files, domains, and accounts)",
"CentralRepositoryNotificationDialog.bulletTwo=Identify where an item was previously seen",
"CentralRepositoryNotificationDialog.bulletThree=Create personas that group accounts",
"CentralRepositoryNotificationDialog.finalRemarks=To limit what is stored, use the Central Repository options panel."
})
static void display() {
assert shouldDisplay();
MessageNotifyUtil.Message.info(
"<html>"
+ "<body>"
+ "<div>"
+ "<p>" + Bundle.CentralRepositoryNotificationDialog_header() + "</p>"
+ "<p>" + Bundle.CentralRepositoryNotificationDialog_bulletHeader() + "</p>"
+ "<ul>"
+ "<li>" + Bundle.CentralRepositoryNotificationDialog_bulletOne() + "</li>"
+ "<li>" + Bundle.CentralRepositoryNotificationDialog_bulletTwo() + "</li>"
+ "<li>" + Bundle.CentralRepositoryNotificationDialog_bulletThree() + "</li>"
+ "</ul>"
+ "<p>" + Bundle.CentralRepositoryNotificationDialog_finalRemarks() + "</p>"
+ "</div>"
+ "</body>"
+ "</html>"
);
}
}

View File

@ -25,14 +25,13 @@ import javax.swing.JOptionPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.openide.modules.ModuleInstall; import org.openide.modules.ModuleInstall;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.Version;
/** /**
* Adds/removes application event listeners responsible for adding data to the * Adds/removes application event listeners responsible for adding data to the
@ -81,20 +80,11 @@ public class Installer extends ModuleInstall {
* the org.sleuthkit.autopsy.core package when the already installed * the org.sleuthkit.autopsy.core package when the already installed
* Autopsy-Core module is restored (during application startup). * Autopsy-Core module is restored (during application startup).
*/ */
@NbBundle.Messages({
"Installer.initialCreateSqlite.title=Enable Central Repository?",
"Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to enable it?",
"Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. "
+ "You can use this to ignore previously seen files and make connections between cases."
})
@Override @Override
public void restored() { public void restored() {
addApplicationEventListeners(); addApplicationEventListeners();
if (Version.getBuildType() == Version.Type.RELEASE) {
setupDefaultCentralRepository(); setupDefaultCentralRepository();
} }
}
/** /**
* Adds the application event listeners responsible for adding data to the * Adds the application event listeners responsible for adding data to the
@ -107,9 +97,9 @@ public class Installer extends ModuleInstall {
/** /**
* Checks if the central repository has been set up and configured. If not, * Checks if the central repository has been set up and configured. If not,
* either offers to perform set up (running with a GUI) or does the set up * does the set up unconditionally. If the application is running with a
* unconditionally (not running with a GUI, e.g., in an automated ingest * GUI, a notification will be displayed to the user if the mode is RELEASE
* node). * (in other words, developers are exempt from seeing the notification).
*/ */
private void setupDefaultCentralRepository() { private void setupDefaultCentralRepository() {
Map<String, String> centralRepoSettings = ModuleSettings.getConfigSettings("CentralRepository"); Map<String, String> centralRepoSettings = ModuleSettings.getConfigSettings("CentralRepository");
@ -128,62 +118,30 @@ public class Installer extends ModuleInstall {
} }
} }
// if central repository hasn't been previously initialized, initialize it if(initialized) {
if (!initialized) { return; // Nothing to do
// if running with a GUI, prompt the user }
if (RuntimeProperties.runningWithGUI()) {
try {
SwingUtilities.invokeAndWait(() -> {
try {
String dialogText
= "<html><body>"
+ "<div style='width: 400px;'>"
+ "<p>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageHeader") + "</p>"
+ "<p style='margin-top: 10px'>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageDesc") + "</p>"
+ "</div>"
+ "</body></html>";
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), if (CentralRepositoryNotificationDialog.shouldDisplay()) {
dialogText, CentralRepositoryNotificationDialog.display();
NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.title"), }
JOptionPane.YES_NO_OPTION)) {
setupDefaultSqliteCentralRepo(); try {
CentralRepoDbManager manager = new CentralRepoDbManager();
if (UserPreferences.getIsMultiUserModeEnabled()) {
// Set up using existing multi-user settings.
manager.setupPostgresDb(CentralRepoDbChoice.POSTGRESQL_MULTIUSER);
} else {
manager.setupDefaultSqliteDb();
} }
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.SEVERE, "There was an error while initializing the central repository database", ex); logger.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
doMessageBoxIfRunningInGUI(ex); doMessageBoxIfRunningInGUI(ex);
} }
});
} catch (InterruptedException | InvocationTargetException ex) {
logger.log(Level.SEVERE, "There was an error while running the swing utility invoke later while creating the central repository database", ex);
}
} // if no GUI, just initialize
else {
try {
setupDefaultSqliteCentralRepo();
} catch (CentralRepoException ex) {
logger.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
doMessageBoxIfRunningInGUI(ex);
}
}
ModuleSettings.setConfigSetting("CentralRepository", "initialized", "true"); ModuleSettings.setConfigSetting("CentralRepository", "initialized", "true");
} }
}
/**
* Sets up a default single-user SQLite central repository.
*
* @throws CentralRepoException If there is an error setting up teh central
* repository.
*/
private void setupDefaultSqliteCentralRepo() throws CentralRepoException {
CentralRepoDbManager manager = new CentralRepoDbManager();
manager.setupDefaultSqliteDb();
}
/** /**
* Display a central repository exception in a message box if running with a * Display a central repository exception in a message box if running with a

View File

@ -28,10 +28,11 @@ import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.stream.Collectors;
import java.util.TreeMap; import org.apache.commons.lang.StringUtils;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -93,13 +94,53 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
return ARTIFACT_UPDATE_TYPE_IDS; return ARTIFACT_UPDATE_TYPE_IDS;
} }
/**
* Removes fileDetails entries with redundant paths, sorts by date
* descending and limits to the limit provided.
*
* @param fileDetails The file details list.
* @param limit The maximum number of entries to return.
* @return The sorted limited list with unique paths.
*/
private <T extends RecentFileDetails> List<T> getSortedLimited(List<T> fileDetails, int limit) {
Map<String, T> fileDetailsMap = fileDetails.stream()
.filter(details -> details != null)
.collect(Collectors.toMap(
d -> d.getPath().toUpperCase(),
d -> d,
(d1, d2) -> Long.compare(d1.getDateAsLong(), d2.getDateAsLong()) > 0 ? d1 : d2));
return fileDetailsMap.values().stream()
.sorted((a, b) -> -Long.compare(a.getDateAsLong(), b.getDateAsLong()))
.limit(limit)
.collect(Collectors.toList());
}
/**
* Returns a RecentFileDetails object as derived from the recent document
* artifact or null if no appropriate object can be made.
*
* @param artifact The artifact.
* @return The derived object or null if artifact is invalid.
*/
private RecentFileDetails getRecentlyOpenedDocument(BlackboardArtifact artifact) {
String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
Long lastOpened = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ATT);
if (StringUtils.isBlank(path) || lastOpened == null || lastOpened == 0) {
return null;
} else {
return new RecentFileDetails(path, lastOpened);
}
}
/** /**
* Return a list of the most recently opened documents based on the * Return a list of the most recently opened documents based on the
* TSK_RECENT_OBJECT artifact. * TSK_RECENT_OBJECT artifact.
* *
* @param dataSource The data source to query. * @param dataSource The data source to query.
* @param maxCount The maximum number of results to return, pass 0 to get * @param maxCount The maximum number of results to return, pass 0 to get a
* a list of all results. * list of all results.
* *
* @return A list RecentFileDetails representing the most recently opened * @return A list RecentFileDetails representing the most recently opened
* documents or an empty list if none were found. * documents or an empty list if none were found.
@ -112,38 +153,47 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
return Collections.emptyList(); return Collections.emptyList();
} }
List<BlackboardArtifact> artifactList throwOnNonPositiveCount(maxCount);
= DataSourceInfoUtilities.getArtifacts(provider.get(),
new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_RECENT_OBJECT),
dataSource,
DATETIME_ATT,
DataSourceInfoUtilities.SortOrder.DESCENDING,
maxCount);
List<RecentFileDetails> fileDetails = new ArrayList<>(); List<RecentFileDetails> details = provider.get().getBlackboard()
for (BlackboardArtifact artifact : artifactList) { .getArtifacts(ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID(), dataSource.getId()).stream()
Long accessedTime = null; .map(art -> getRecentlyOpenedDocument(art))
String path = ""; .filter(d -> d != null)
.collect(Collectors.toList());
// Get all the attributes in one call. return getSortedLimited(details, maxCount);
List<BlackboardAttribute> attributeList = artifact.getAttributes(); }
for (BlackboardAttribute attribute : attributeList) {
if (attribute.getAttributeType().equals(DATETIME_ATT)) { /**
accessedTime = attribute.getValueLong(); * Returns a RecentDownloadDetails object as derived from the recent
} else if (attribute.getAttributeType().equals(PATH_ATT)) { * download artifact or null if no appropriate object can be made.
path = attribute.getValueString(); *
* @param artifact The artifact.
* @return The derived object or null if artifact is invalid.
*/
private RecentDownloadDetails getRecentDownload(BlackboardArtifact artifact) {
Long accessedTime = DataSourceInfoUtilities.getLongOrNull(artifact, DATETIME_ACCESSED_ATT);
String domain = DataSourceInfoUtilities.getStringOrNull(artifact, DOMAIN_ATT);
String path = DataSourceInfoUtilities.getStringOrNull(artifact, PATH_ATT);
if (StringUtils.isBlank(path) || accessedTime == null || accessedTime == 0) {
return null;
} else {
return new RecentDownloadDetails(path, accessedTime, domain);
} }
} }
if (accessedTime != null && accessedTime != 0) { /**
fileDetails.add(new RecentFileDetails(path, accessedTime)); * Throws an IllegalArgumentException if count is less than 1.
*
* @param count The count.
*/
private void throwOnNonPositiveCount(int count) {
if (count < 1) {
throw new IllegalArgumentException("Invalid count: value must be greater than 0.");
} }
} }
return fileDetails;
}
/** /**
* Return a list of the most recent downloads based on the value of the the * Return a list of the most recent downloads based on the value of the the
* artifact TSK_DATETIME_ACCESSED attribute. * artifact TSK_DATETIME_ACCESSED attribute.
@ -163,38 +213,15 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
return Collections.emptyList(); return Collections.emptyList();
} }
List<BlackboardArtifact> artifactList throwOnNonPositiveCount(maxCount);
= DataSourceInfoUtilities.getArtifacts(provider.get(),
new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD),
dataSource,
DATETIME_ACCESSED_ATT,
DataSourceInfoUtilities.SortOrder.DESCENDING,
maxCount);
List<RecentDownloadDetails> fileDetails = new ArrayList<>(); List<RecentDownloadDetails> details = provider.get().getBlackboard()
for (BlackboardArtifact artifact : artifactList) { .getArtifacts(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), dataSource.getId()).stream()
// Get all the attributes in one call. .map(art -> getRecentDownload(art))
Long accessedTime = null; .filter(d -> d != null)
String domain = ""; .collect(Collectors.toList());
String path = "";
List<BlackboardAttribute> attributeList = artifact.getAttributes(); return getSortedLimited(details, maxCount);
for (BlackboardAttribute attribute : attributeList) {
if (attribute.getAttributeType().equals(DATETIME_ACCESSED_ATT)) {
accessedTime = attribute.getValueLong();
} else if (attribute.getAttributeType().equals(DOMAIN_ATT)) {
domain = attribute.getValueString();
} else if (attribute.getAttributeType().equals(PATH_ATT)) {
path = attribute.getValueString();
}
}
if (accessedTime != null && accessedTime != 0L) {
fileDetails.add(new RecentDownloadDetails(path, accessedTime, domain));
}
}
return fileDetails;
} }
/** /**
@ -214,109 +241,66 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
return Collections.emptyList(); return Collections.emptyList();
} }
if (maxCount < 0) { throwOnNonPositiveCount(maxCount);
throw new IllegalArgumentException("Invalid maxCount passed to getRecentAttachments, value must be equal to or greater than 0");
SleuthkitCase skCase = provider.get();
List<BlackboardArtifact> associatedArtifacts = skCase.getBlackboard()
.getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId());
List<RecentAttachmentDetails> details = new ArrayList<>();
for (BlackboardArtifact artifact : associatedArtifacts) {
RecentAttachmentDetails thisDetails = getRecentAttachment(artifact, skCase);
if (thisDetails != null) {
details.add(thisDetails);
}
} }
return createListFromMap(buildAttachmentMap(dataSource), maxCount); return getSortedLimited(details, maxCount);
} }
/** /**
* Build a map of all of the message attachment sorted in date order. * Creates a RecentAttachmentDetails object from the associated object
* artifact or null if no RecentAttachmentDetails object can be derived.
* *
* @param dataSource Data source to query. * @param artifact The associated object artifact.
* * @param skCase The current case.
* @return Returns a SortedMap of details objects returned in descending * @return The derived object or null.
* order.
*
* @throws SleuthkitCaseProviderException
* @throws TskCoreException * @throws TskCoreException
*/ */
private SortedMap<Long, List<RecentAttachmentDetails>> buildAttachmentMap(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException { private RecentAttachmentDetails getRecentAttachment(BlackboardArtifact artifact, SleuthkitCase skCase) throws TskCoreException {
SleuthkitCase skCase = provider.get(); // get associated artifact or return no result
TreeMap<Long, List<RecentAttachmentDetails>> sortedMap = new TreeMap<>();
List<BlackboardArtifact> associatedArtifacts = skCase.getBlackboard().getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId());
for (BlackboardArtifact artifact : associatedArtifacts) {
BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT); BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT);
if (attribute == null) { if (attribute == null) {
continue; return null;
} }
// get associated message artifact if exists or return no result
BlackboardArtifact messageArtifact = skCase.getBlackboardArtifact(attribute.getValueLong()); BlackboardArtifact messageArtifact = skCase.getBlackboardArtifact(attribute.getValueLong());
if (messageArtifact != null && isMessageArtifact(messageArtifact)) { if (messageArtifact == null || !isMessageArtifact(messageArtifact)) {
Content content = artifact.getParent(); return null;
if (content instanceof AbstractFile) {
String sender;
Long date = null;
String path;
BlackboardAttribute senderAttribute = messageArtifact.getAttribute(EMAIL_FROM_ATT);
if (senderAttribute != null) {
sender = senderAttribute.getValueString();
} else {
sender = "";
} }
senderAttribute = messageArtifact.getAttribute(MSG_DATEIME_SENT_ATT);
if (senderAttribute != null) { // get abstract file if exists or return no result
date = senderAttribute.getValueLong(); Content content = artifact.getParent();
if (!(content instanceof AbstractFile)) {
return null;
} }
AbstractFile abstractFile = (AbstractFile) content; AbstractFile abstractFile = (AbstractFile) content;
path = Paths.get(abstractFile.getParentPath(), abstractFile.getName()).toString(); // get the path, sender, and date
String path = Paths.get(abstractFile.getParentPath(), abstractFile.getName()).toString();
String sender = DataSourceInfoUtilities.getStringOrNull(messageArtifact, EMAIL_FROM_ATT);
Long date = DataSourceInfoUtilities.getLongOrNull(messageArtifact, MSG_DATEIME_SENT_ATT);
if (date != null && date != 0) { if (date == null || date == 0 || StringUtils.isBlank(path)) {
List<RecentAttachmentDetails> list = sortedMap.get(date); return null;
if (list == null) {
list = new ArrayList<>();
sortedMap.put(date, list);
}
RecentAttachmentDetails details = new RecentAttachmentDetails(path, date, sender);
if (!list.contains(details)) {
list.add(details);
}
}
}
}
}
return sortedMap.descendingMap();
}
/**
* Create a list of detail objects from the given sorted map of the max
* size.
*
* @param sortedMap A Map of attachment details sorted by date.
* @param maxCount Maximum number of values to return.
*
* @return A list of the details of the most recent attachments or empty
* list if none where found.
*/
private List<RecentAttachmentDetails> createListFromMap(SortedMap<Long, List<RecentAttachmentDetails>> sortedMap, int maxCount) {
List<RecentAttachmentDetails> fileList = new ArrayList<>();
for (List<RecentAttachmentDetails> mapList : sortedMap.values()) {
if (maxCount == 0 || fileList.size() + mapList.size() <= maxCount) {
fileList.addAll(mapList);
continue;
}
if (maxCount == fileList.size()) {
break;
}
for (RecentAttachmentDetails details : mapList) {
if (fileList.size() < maxCount) {
fileList.add(details);
} else { } else {
break; return new RecentAttachmentDetails(path, date, sender);
} }
} }
}
return fileList;
}
/** /**
* Is the given artifact a message. * Is the given artifact a message.
@ -330,6 +314,7 @@ public class RecentFilesSummary implements DefaultArtifactUpdateGovernor {
final int artifactTypeID = nodeArtifact.getArtifactTypeID(); final int artifactTypeID = nodeArtifact.getArtifactTypeID();
return artifactTypeID == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() return artifactTypeID == ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(); || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID();
} }
/** /**

View File

@ -280,9 +280,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
* @param dataSource The datasource. * @param dataSource The datasource.
* *
* @return A tuple where the first value is the latest web history accessed * @return A tuple where the first value is the latest web history accessed
* date in milliseconds and the second value maps normalized * date in milliseconds and the second value maps normalized (lowercase;
* (lowercase; trimmed) domain names to when those domains were * trimmed) domain names to when those domains were visited.
* visited.
* *
* @throws TskCoreException * @throws TskCoreException
* @throws SleuthkitCaseProviderException * @throws SleuthkitCaseProviderException
@ -364,8 +363,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
* term. * term.
* *
* @param dataSource The data source. * @param dataSource The data source.
* @param count The maximum number of records to be shown (must be > * @param count The maximum number of records to be shown (must be > 0).
* 0).
* *
* @return The list of most recent web searches where most recent search * @return The list of most recent web searches where most recent search
* appears first. * appears first.
@ -386,21 +384,22 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
.getArtifacts(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSource.getId()); .getArtifacts(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY.getTypeID(), dataSource.getId());
// group by search string (case insensitive) // group by search string (case insensitive)
Collection<List<TopWebSearchResult>> resultGroups = webSearchArtifacts Collection<TopWebSearchResult> resultGroups = webSearchArtifacts
.stream() .stream()
// get items where search string and date is not null // get items where search string and date is not null
.map(UserActivitySummary::getWebSearchResult) .map(UserActivitySummary::getWebSearchResult)
// remove null records // remove null records
.filter(result -> result != null) .filter(result -> result != null)
// get these messages grouped by search to string // get the latest message for each search string
.collect(Collectors.groupingBy((result) -> result.getSearchString().toUpperCase())) .collect(Collectors.toMap(
(result) -> result.getSearchString().toUpperCase(),
result -> result,
(result1, result2) -> TOP_WEBSEARCH_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
.values(); .values();
// get the most recent date for each search term // get the most recent date for each search term
List<TopWebSearchResult> results = resultGroups List<TopWebSearchResult> results = resultGroups
.stream() .stream()
// get the most recent access per search type
.map((list) -> list.stream().max(TOP_WEBSEARCH_RESULT_DATE_COMPARE).get())
// get most recent searches first // get most recent searches first
.sorted(TOP_WEBSEARCH_RESULT_DATE_COMPARE.reversed()) .sorted(TOP_WEBSEARCH_RESULT_DATE_COMPARE.reversed())
.limit(count) .limit(count)
@ -448,12 +447,31 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
return translated; return translated;
} }
/**
* Gives the most recent TopDeviceAttachedResult. If one is null, the other
* is returned.
*
* @param r1 A result.
* @param r2 Another result.
* @return The most recent one with a non-null date.
*/
private TopDeviceAttachedResult getMostRecentDevice(TopDeviceAttachedResult r1, TopDeviceAttachedResult r2) {
if (r2.getDateAccessed() == null) {
return r1;
}
if (r1.getDateAccessed() == null) {
return r2;
}
return r1.getDateAccessed().compareTo(r2.getDateAccessed()) >= 0 ? r1 : r2;
}
/** /**
* Retrieves most recent devices used by most recent date attached. * Retrieves most recent devices used by most recent date attached.
* *
* @param dataSource The data source. * @param dataSource The data source.
* @param count The maximum number of records to be shown (must be > * @param count The maximum number of records to be shown (must be > 0).
* 0).
* *
* @return The list of most recent devices attached where most recent device * @return The list of most recent devices attached where most recent device
* attached appears first. * attached appears first.
@ -469,7 +487,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
return Collections.emptyList(); return Collections.emptyList();
} }
return DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED, Collection<TopDeviceAttachedResult> results = DataSourceInfoUtilities.getArtifacts(caseProvider.get(), TYPE_DEVICE_ATTACHED,
dataSource, TYPE_DATETIME, DataSourceInfoUtilities.SortOrder.DESCENDING, 0) dataSource, TYPE_DATETIME, DataSourceInfoUtilities.SortOrder.DESCENDING, 0)
.stream() .stream()
.map(artifact -> { .map(artifact -> {
@ -482,9 +500,14 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
}) })
// remove Root Hub identifier // remove Root Hub identifier
.filter(result -> { .filter(result -> {
return result.getDeviceModel() == null return result.getDeviceId() == null
|| result.getDeviceModel() == null
|| !DEVICE_EXCLUDE_LIST.contains(result.getDeviceModel().trim().toUpperCase()); || !DEVICE_EXCLUDE_LIST.contains(result.getDeviceModel().trim().toUpperCase());
}) })
.collect(Collectors.toMap(result -> result.getDeviceId(), result -> result, (r1, r2) -> getMostRecentDevice(r1, r2)))
.values();
return results.stream()
.limit(count) .limit(count)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -538,8 +561,7 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
* sent. * sent.
* *
* @param dataSource The data source. * @param dataSource The data source.
* @param count The maximum number of records to be shown (must be > * @param count The maximum number of records to be shown (must be > 0).
* 0).
* *
* @return The list of most recent accounts used where the most recent * @return The list of most recent accounts used where the most recent
* account by last message sent occurs first. * account by last message sent occurs first.
@ -585,18 +607,19 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
Stream<TopAccountResult> allResults = Stream.concat(messageResults, Stream.concat(emailResults, calllogResults)); Stream<TopAccountResult> allResults = Stream.concat(messageResults, Stream.concat(emailResults, calllogResults));
// get them grouped by account type // get them grouped by account type
Collection<List<TopAccountResult>> groupedResults = allResults Collection<TopAccountResult> groupedResults = allResults
// remove null records // remove null records
.filter(result -> result != null) .filter(result -> result != null)
// get these messages grouped by account type // get these messages grouped by account type and get the most recent of each type
.collect(Collectors.groupingBy(TopAccountResult::getAccountType)) .collect(Collectors.toMap(
result -> result.getAccountType(),
result -> result,
(result1, result2) -> TOP_ACCOUNT_RESULT_DATE_COMPARE.compare(result1, result2) >= 0 ? result1 : result2))
.values(); .values();
// get account type sorted by most recent date // get account type sorted by most recent date
return groupedResults return groupedResults
.stream() .stream()
// get the most recent access per account type
.map((accountGroup) -> accountGroup.stream().max(TOP_ACCOUNT_RESULT_DATE_COMPARE).get())
// get most recent accounts accessed // get most recent accounts accessed
.sorted(TOP_ACCOUNT_RESULT_DATE_COMPARE.reversed()) .sorted(TOP_ACCOUNT_RESULT_DATE_COMPARE.reversed())
// limit to count // limit to count
@ -721,7 +744,6 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
return longNum != null && longNum > 0; return longNum != null && longNum > 0;
} }
/** /**
* Retrieves the top programs results for the given data source limited to * Retrieves the top programs results for the given data source limited to
* the count provided as a parameter. The highest run times are at the top * the count provided as a parameter. The highest run times are at the top
@ -732,8 +754,8 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
* *
* @param dataSource The datasource. If the datasource is null, an empty * @param dataSource The datasource. If the datasource is null, an empty
* list will be returned. * list will be returned.
* @param count The number of results to return. This value must be > 0 * @param count The number of results to return. This value must be > 0 or
* or an IllegalArgumentException will be thrown. * an IllegalArgumentException will be thrown.
* *
* @return The sorted list and limited to the count if last run or run count * @return The sorted list and limited to the count if last run or run count
* information is available on any item. * information is available on any item.
@ -759,7 +781,9 @@ public class UserActivitySummary implements DefaultArtifactUpdateGovernor {
// The value will be a TopProgramsResult with the max run times // The value will be a TopProgramsResult with the max run times
// and most recent last run date for each program name / program path pair. // and most recent last run date for each program name / program path pair.
.collect(Collectors.toMap( .collect(Collectors.toMap(
res -> Pair.of(res.getProgramName(), res.getProgramPath()), res -> Pair.of(
res.getProgramName() == null ? null : res.getProgramName().toUpperCase(),
res.getProgramPath() == null ? null : res.getProgramPath().toUpperCase()),
res -> res, res -> res,
(res1, res2) -> { (res1, res2) -> {
return new TopProgramsResult( return new TopProgramsResult(

View File

@ -0,0 +1,51 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.guicomponeontutils;
import javax.swing.Icon;
import org.sleuthkit.autopsy.guiutils.CheckBoxJList;
/**
* An abstract implementation of CheckBoxJList.CheckboxListItem so that
* implementing classes have default implementation.
*/
public abstract class AbstractCheckboxListItem implements CheckBoxJList.CheckboxListItem {
private boolean checked = false;
@Override
public boolean isChecked() {
return checked;
}
@Override
public void setChecked(boolean checked) {
this.checked = checked;
}
@Override
public boolean hasIcon() {
return false;
}
@Override
public Icon getIcon() {
return null;
}
}

View File

@ -32,8 +32,10 @@ import javax.swing.ListSelectionModel;
/** /**
* A JList that renders the list items as check boxes. * A JList that renders the list items as check boxes.
*
* @param <T> An object that implements CheckboxListItem
*/ */
final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JList<T> { public final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JList<T> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -42,7 +44,7 @@ final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JLis
* a checkbox in CheckBoxJList. * a checkbox in CheckBoxJList.
* *
*/ */
interface CheckboxListItem { public interface CheckboxListItem {
/** /**
* Returns the checkbox state. * Returns the checkbox state.
@ -83,7 +85,7 @@ final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JLis
/** /**
* Construct a new JCheckBoxList. * Construct a new JCheckBoxList.
*/ */
CheckBoxJList() { public CheckBoxJList() {
initalize(); initalize();
} }
@ -134,12 +136,15 @@ final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JLis
checkbox.setSelected(value.isChecked()); checkbox.setSelected(value.isChecked());
checkbox.setBackground(list.getBackground()); checkbox.setBackground(list.getBackground());
checkbox.setEnabled(list.isEnabled()); checkbox.setEnabled(list.isEnabled());
checkbox.setOpaque(list.isOpaque());
label.setText(value.getDisplayName()); label.setText(value.getDisplayName());
label.setEnabled(list.isEnabled()); label.setEnabled(list.isEnabled());
label.setOpaque(list.isOpaque());
if (value.hasIcon()) { if (value.hasIcon()) {
label.setIcon(value.getIcon()); label.setIcon(value.getIcon());
} }
setOpaque(list.isOpaque());
setEnabled(list.isEnabled()); setEnabled(list.isEnabled());
return this; return this;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,6 +1,6 @@
DATExtractor_process_message=Processing DJI DAT file: %s DATExtractor_process_message=Processing DJI DAT file: %s
DATFileExtractor_Extractor_Name=DAT File Extractor DATFileExtractor_Extractor_Name=DAT File Extractor
DroneIngestModule_Description=Analyzes files generated by drones. DroneIngestModule_Description=Analyzes files generated by some DJI drones.
DroneIngestModule_Name=Drone Analyzer DroneIngestModule_Name=DJI Drone Analyzer
# {0} - AbstractFileName # {0} - AbstractFileName
DroneIngestModule_process_start=Started {0} DroneIngestModule_process_start=Started {0}

View File

@ -33,8 +33,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
public class DroneIngestModuleFactory extends IngestModuleFactoryAdapter { public class DroneIngestModuleFactory extends IngestModuleFactoryAdapter {
@Messages({ @Messages({
"DroneIngestModule_Name=Drone Analyzer", "DroneIngestModule_Name=DJI Drone Analyzer",
"DroneIngestModule_Description=Analyzes files generated by drones." "DroneIngestModule_Description=Analyzes files generated by some DJI drones."
}) })
/** /**

View File

@ -1,3 +1,4 @@
ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}.
ILeappAnalyzerIngestModule.processing.file=Processing file {0} ILeappAnalyzerIngestModule.processing.file=Processing file {0}
ILeappAnalyzerIngestModule.parsing.file=Parsing file {0} ILeappAnalyzerIngestModule.parsing.file=Parsing file {0}
ILeappAnalyzerIngestModule.processing.filesystem=Processing filesystem

View File

@ -8,6 +8,7 @@ ILeappAnalyzerIngestModule.iLeapp.cancelled=iLeapp run was canceled
ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}. ILeappAnalyzerIngestModule.init.exception.msg=Unable to find {0}.
ILeappAnalyzerIngestModule.processing.file=Processing file {0} ILeappAnalyzerIngestModule.processing.file=Processing file {0}
ILeappAnalyzerIngestModule.parsing.file=Parsing file {0} ILeappAnalyzerIngestModule.parsing.file=Parsing file {0}
ILeappAnalyzerIngestModule.processing.filesystem=Processing filesystem
ILeappAnalyzerIngestModule.report.name=iLeapp Html Report ILeappAnalyzerIngestModule.report.name=iLeapp Html Report
ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows. ILeappAnalyzerIngestModule.requires.windows=iLeapp module requires windows.
ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp ILeappAnalyzerIngestModule.running.iLeapp=Running iLeapp

View File

@ -18,8 +18,10 @@
*/ */
package org.sleuthkit.autopsy.modules.ileappanalyzer; package org.sleuthkit.autopsy.modules.ileappanalyzer;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.file.Files; import java.nio.file.Files;
@ -32,14 +34,17 @@ import java.util.Locale;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.commons.io.FilenameUtils;
import org.openide.modules.InstalledFileLocator; import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.casemodule.Case.getCurrentCase; import static org.sleuthkit.autopsy.casemodule.Case.getCurrentCase;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ExecUtil; import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
@ -50,6 +55,7 @@ import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.LocalFilesDataSource; import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -61,7 +67,9 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
private static final String MODULE_NAME = ILeappAnalyzerModuleFactory.getModuleName(); private static final String MODULE_NAME = ILeappAnalyzerModuleFactory.getModuleName();
private static final String ILEAPP = "iLeapp"; //NON-NLS private static final String ILEAPP = "iLeapp"; //NON-NLS
private static final String ILEAPP_FS = "fs_"; //NON-NLS
private static final String ILEAPP_EXECUTABLE = "ileapp.exe";//NON-NLS private static final String ILEAPP_EXECUTABLE = "ileapp.exe";//NON-NLS
private static final String ILEAPP_PATHS_FILE = "iLeapp_paths.txt"; //NON-NLS
private File iLeappExecutable; private File iLeappExecutable;
@ -87,7 +95,7 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
try { try {
iLeappFileProcessor = new ILeappFileProcessor(); iLeappFileProcessor = new ILeappFileProcessor();
} catch (IOException | IngestModuleException ex) { } catch (IOException | IngestModuleException | NoCurrentCaseException ex) {
throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_error_ileapp_file_processor_init(), ex); throw new IngestModuleException(Bundle.ILeappAnalyzerIngestModule_error_ileapp_file_processor_init(), ex);
} }
@ -112,59 +120,50 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
@Override @Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) { public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
if (!(context.getDataSource() instanceof LocalFilesDataSource)) { Case currentCase = Case.getCurrentCase();
return ProcessResult.OK; Path tempOutputPath = Paths.get(currentCase.getTempDirectory(), ILEAPP, ILEAPP_FS + dataSource.getId());
try {
Files.createDirectories(tempOutputPath);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", tempOutputPath.toString()), ex);
return ProcessResult.ERROR;
}
List<String> iLeappPathsToProcess = new ArrayList<>();
ProcessBuilder iLeappCommand = buildiLeappListCommand(tempOutputPath);
try {
int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
if (result != 0) {
logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
return ProcessResult.ERROR;
}
iLeappPathsToProcess = loadIleappPathFile(tempOutputPath);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program getting file paths to search"), ex);
return ProcessResult.ERROR;
} }
statusHelper.progress(Bundle.ILeappAnalyzerIngestModule_starting_iLeapp(), 0); statusHelper.progress(Bundle.ILeappAnalyzerIngestModule_starting_iLeapp(), 0);
List<AbstractFile> iLeappFilesToProcess = findiLeappFilesToProcess(dataSource); List<AbstractFile> iLeappFilesToProcess = new ArrayList<>();
if (!(context.getDataSource() instanceof LocalFilesDataSource)) {
extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
} else {
iLeappFilesToProcess = findiLeappFilesToProcess(dataSource);
statusHelper.switchToDeterminate(iLeappFilesToProcess.size()); statusHelper.switchToDeterminate(iLeappFilesToProcess.size());
Integer filesProcessedCount = 0; Integer filesProcessedCount = 0;
Case currentCase = Case.getCurrentCase();
for (AbstractFile iLeappFile : iLeappFilesToProcess) { for (AbstractFile iLeappFile : iLeappFilesToProcess) {
processILeappFile(dataSource, currentCase, statusHelper, filesProcessedCount, iLeappFile);
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
try {
Files.createDirectories(moduleOutputPath);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
return ProcessResult.ERROR;
}
statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.file", iLeappFile.getName()), filesProcessedCount);
ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, iLeappFile.getLocalAbsPath(), iLeappFile.getNameExtension());
try {
int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
if (result != 0) {
// ignore if there is an error and continue to try and process the next file if there is one
continue;
}
addILeappReportToReports(moduleOutputPath, currentCase);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file %s", iLeappFile.getLocalAbsPath()), ex);
return ProcessResult.ERROR;
}
if (context.dataSourceIngestIsCancelled()) {
logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
return ProcessResult.OK;
}
ProcessResult fileProcessorResult = iLeappFileProcessor.processFiles(dataSource, moduleOutputPath, iLeappFile);
if (fileProcessorResult == ProcessResult.ERROR) {
return ProcessResult.ERROR;
}
filesProcessedCount++; filesProcessedCount++;
} }
// Process the logical image as a fs in iLeapp to make sure this is not a logical fs that was added
extractFilesFromImage(dataSource, iLeappPathsToProcess, tempOutputPath);
processILeappFs(dataSource, currentCase, statusHelper, tempOutputPath.toString());
}
IngestMessage message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, IngestMessage message = IngestMessage.createMessage(IngestMessage.MessageType.DATA,
Bundle.ILeappAnalyzerIngestModule_has_run(), Bundle.ILeappAnalyzerIngestModule_has_run(),
@ -173,6 +172,99 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
return ProcessResult.OK; return ProcessResult.OK;
} }
/**
* Process each tar/zip file that is found in a logical image that contains xLeapp data
* @param dataSource Datasource where the file has been found
* @param currentCase current case
* @param statusHelper Progress bar for messages to show user
* @param filesProcessedCount count that is incremented for progress bar
* @param iLeappFile abstract file that will be processed
*/
private void processILeappFile(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, int filesProcessedCount,
AbstractFile iLeappFile) {
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
try {
Files.createDirectories(moduleOutputPath);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
return;
}
statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.file", iLeappFile.getName()), filesProcessedCount);
ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, iLeappFile.getLocalAbsPath(), iLeappFile.getNameExtension());
try {
int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
if (result != 0) {
logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
return;
}
addILeappReportToReports(moduleOutputPath, currentCase);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file %s", iLeappFile.getLocalAbsPath()), ex);
return;
}
if (context.dataSourceIngestIsCancelled()) {
logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
return;
}
ProcessResult fileProcessorResult = iLeappFileProcessor.processFiles(dataSource, moduleOutputPath, iLeappFile);
if (fileProcessorResult == ProcessResult.ERROR) {
return;
}
}
/**
* Process extracted files from a disk image using xLeapp
* @param dataSource Datasource where the file has been found
* @param currentCase current case
* @param statusHelper Progress bar for messages to show user
* @param directoryToProcess
*/
private void processILeappFs(Content dataSource, Case currentCase, DataSourceIngestModuleProgress statusHelper, String directoryToProcess) {
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss z", Locale.US).format(System.currentTimeMillis());//NON-NLS
Path moduleOutputPath = Paths.get(currentCase.getModuleDirectory(), ILEAPP, currentTime);
try {
Files.createDirectories(moduleOutputPath);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error creating iLeapp output directory %s", moduleOutputPath.toString()), ex);
return;
}
statusHelper.progress(NbBundle.getMessage(this.getClass(), "ILeappAnalyzerIngestModule.processing.filesystem"));
ProcessBuilder iLeappCommand = buildiLeappCommand(moduleOutputPath, directoryToProcess, "fs");
try {
int result = ExecUtil.execute(iLeappCommand, new DataSourceIngestModuleProcessTerminator(context, true));
if (result != 0) {
logger.log(Level.WARNING, String.format("Error when trying to execute iLeapp program getting file paths to search for result is %d", result));
return;
}
addILeappReportToReports(moduleOutputPath, currentCase);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Error when trying to execute iLeapp program against file system"), ex);
return;
}
if (context.dataSourceIngestIsCancelled()) {
logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
return;
}
ProcessResult fileProcessorResult = iLeappFileProcessor.processFileSystem(dataSource, moduleOutputPath);
if (fileProcessorResult == ProcessResult.ERROR) {
return;
}
}
/** /**
* Find the files that will be processed by the iLeapp program * Find the files that will be processed by the iLeapp program
* *
@ -208,6 +300,13 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
return iLeappFilesToProcess; return iLeappFilesToProcess;
} }
/**
* Build the command to run xLeapp
* @param moduleOutputPath output path for xLeapp
* @param sourceFilePath path where the xLeapp file is
* @param iLeappFileSystem type of file to process tar/zip/fs
* @return process to run
*/
private ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType) { private ProcessBuilder buildiLeappCommand(Path moduleOutputPath, String sourceFilePath, String iLeappFileSystemType) {
ProcessBuilder processBuilder = buildProcessWithRunAsInvoker( ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
@ -221,10 +320,26 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
return processBuilder; return processBuilder;
} }
/**
* Command to run xLeapp using the path option
* @param moduleOutputPath path where the file paths output will reside
* @return process to run
*/
private ProcessBuilder buildiLeappListCommand(Path moduleOutputPath) {
ProcessBuilder processBuilder = buildProcessWithRunAsInvoker(
"\"" + iLeappExecutable + "\"", //NON-NLS
"-p"
);
processBuilder.redirectError(moduleOutputPath.resolve("iLeapp_paths_error.txt").toFile()); //NON-NLS
processBuilder.redirectOutput(moduleOutputPath.resolve("iLeapp_paths.txt").toFile()); //NON-NLS
return processBuilder;
}
static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) { static private ProcessBuilder buildProcessWithRunAsInvoker(String... commandLine) {
ProcessBuilder processBuilder = new ProcessBuilder(commandLine); ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
/* /*
* Add an environment variable to force log2timeline/psort to run with * Add an environment variable to force iLeapp to run with
* the same permissions Autopsy uses. * the same permissions Autopsy uses.
*/ */
processBuilder.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS processBuilder.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS
@ -254,8 +369,13 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
.filter(f -> f.toLowerCase().endsWith("index.html")).collect(Collectors.toList()); .filter(f -> f.toLowerCase().endsWith("index.html")).collect(Collectors.toList());
if (!allIndexFiles.isEmpty()) { if (!allIndexFiles.isEmpty()) {
// Check for existance of directory that holds report data if does not exist then report contains no data
String filePath = FilenameUtils.getFullPathNoEndSeparator(allIndexFiles.get(0));
File dataFilesDir = new File(Paths.get(filePath, "_TSV Exports").toString());
if (dataFilesDir.exists()) {
currentCase.addReport(allIndexFiles.get(0), MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_report_name()); currentCase.addReport(allIndexFiles.get(0), MODULE_NAME, Bundle.ILeappAnalyzerIngestModule_report_name());
} }
}
} catch (IOException | UncheckedIOException | TskCoreException ex) { } catch (IOException | UncheckedIOException | TskCoreException ex) {
// catch the error and continue on as report is not added // catch the error and continue on as report is not added
@ -264,4 +384,129 @@ public class ILeappAnalyzerIngestModule implements DataSourceIngestModule {
} }
/*
* Reads the iLeapp paths file to get the paths that we want to extract
*
* @param moduleOutputPath path where the file paths output will reside
*/
private List<String> loadIleappPathFile(Path moduleOutputPath) throws FileNotFoundException, IOException {
List<String> iLeappPathsToProcess = new ArrayList<>();
Path filePath = Paths.get(moduleOutputPath.toString(), ILEAPP_PATHS_FILE);
try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toString()))) {
String line = reader.readLine();
while (line != null) {
if (line.contains("path list generation") || line.length() < 2) {
line = reader.readLine();
continue;
}
iLeappPathsToProcess.add(line.trim());
line = reader.readLine();
}
}
return iLeappPathsToProcess;
}
/**
* Extract files from a disk image to process with xLeapp
* @param dataSource Datasource of the image
* @param iLeappPathsToProcess List of paths to extract content from
* @param moduleOutputPath path to write content to
*/
private void extractFilesFromImage(Content dataSource, List<String> iLeappPathsToProcess, Path moduleOutputPath) {
FileManager fileManager = getCurrentCase().getServices().getFileManager();
for (String fullFilePath : iLeappPathsToProcess) {
if (context.dataSourceIngestIsCancelled()) {
logger.log(Level.INFO, "ILeapp Analyser ingest module run was canceled"); //NON-NLS
break;
}
String ffp = fullFilePath.replaceAll("\\*", "%");
ffp = FilenameUtils.normalize(ffp, true);
String fileName = FilenameUtils.getName(ffp);
String filePath = FilenameUtils.getPath(ffp);
List<AbstractFile> iLeappFiles = new ArrayList<>();
try {
if (filePath.isEmpty()) {
iLeappFiles = fileManager.findFiles(dataSource, fileName); //NON-NLS
} else {
iLeappFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "No files found to process"); //NON-NLS
return;
}
for (AbstractFile iLeappFile : iLeappFiles) {
Path parentPath = Paths.get(moduleOutputPath.toString(), iLeappFile.getParentPath());
File fileParentPath = new File(parentPath.toString());
extractFileToOutput(dataSource, iLeappFile, fileParentPath, parentPath);
}
}
}
/**
* Create path and file from datasource in temp
* @param dataSource datasource of the image
* @param iLeappFile abstract file to write out
* @param fileParentPath parent file path
* @param parentPath parent file
*/
private void extractFileToOutput(Content dataSource, AbstractFile iLeappFile, File fileParentPath, Path parentPath) {
if (fileParentPath.exists()) {
if (!iLeappFile.isDir()) {
writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
} else {
try {
Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
} catch (IOException ex) {
logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
}
}
} else {
try {
Files.createDirectories(parentPath);
} catch (IOException ex) {
logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
}
if (!iLeappFile.isDir()) {
writeiLeappFile(dataSource, iLeappFile, fileParentPath.toString());
} else {
try {
Files.createDirectories(Paths.get(parentPath.toString(), iLeappFile.getName()));
} catch (IOException ex) {
logger.log(Level.INFO, String.format("Error creating iLeapp output directory %s", parentPath.toString()), ex);
}
}
}
}
/**
* Write out file to output
* @param dataSource datasource of disk image
* @param iLeappFile acstract file to write out
* @param parentPath path to write file to
*/
private void writeiLeappFile(Content dataSource, AbstractFile iLeappFile, String parentPath) {
String fileName = iLeappFile.getName().replace(":", "-");
if (!fileName.matches(".") && !fileName.matches("..") && !fileName.toLowerCase().endsWith("-slack")) {
Path filePath = Paths.get(parentPath, fileName);
File localFile = new File(filePath.toString());
try {
ContentUtils.writeToFile(iLeappFile, localFile, context::dataSourceIngestIsCancelled);
} catch (ReadContentInputStream.ReadContentInputStreamException ex) {
logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).",
iLeappFile.getName(), iLeappFile.getId()), ex); //NON-NLS
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Error writing file local file '%s' (id=%d).",
filePath.toString(), iLeappFile.getId()), ex); //NON-NLS
}
}
}
} }

View File

@ -44,6 +44,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException; import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
@ -76,12 +77,16 @@ public final class ILeappFileProcessor {
private final Map<String, String> tsvFileArtifactComments; private final Map<String, String> tsvFileArtifactComments;
private final Map<String, List<List<String>>> tsvFileAttributes; private final Map<String, List<List<String>>> tsvFileAttributes;
public ILeappFileProcessor() throws IOException, IngestModuleException { Blackboard blkBoard;
public ILeappFileProcessor() throws IOException, IngestModuleException, NoCurrentCaseException {
this.tsvFiles = new HashMap<>(); this.tsvFiles = new HashMap<>();
this.tsvFileArtifacts = new HashMap<>(); this.tsvFileArtifacts = new HashMap<>();
this.tsvFileArtifactComments = new HashMap<>(); this.tsvFileArtifactComments = new HashMap<>();
this.tsvFileAttributes = new HashMap<>(); this.tsvFileAttributes = new HashMap<>();
blkBoard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
configExtractor(); configExtractor();
loadConfigFile(); loadConfigFile();
@ -110,6 +115,19 @@ public final class ILeappFileProcessor {
return ProcessResult.OK; return ProcessResult.OK;
} }
public ProcessResult processFileSystem(Content dataSource, Path moduleOutputPath) {
try {
List<String> iLeappTsvOutputFiles = findTsvFiles(moduleOutputPath);
processiLeappFiles(iLeappTsvOutputFiles, dataSource);
} catch (IOException | IngestModuleException ex) {
logger.log(Level.SEVERE, String.format("Error trying to process iLeapp output files in directory %s. ", moduleOutputPath.toString()), ex); //NON-NLS
return ProcessResult.ERROR;
}
return ProcessResult.OK;
}
/** /**
* Find the tsv files in the iLeapp output directory and match them to files * Find the tsv files in the iLeapp output directory and match them to files
* we know we want to process and return the list to process those files. * we know we want to process and return the list to process those files.
@ -124,7 +142,7 @@ public final class ILeappFileProcessor {
.filter(f -> f.toLowerCase().endsWith(".tsv")).collect(Collectors.toList()); .filter(f -> f.toLowerCase().endsWith(".tsv")).collect(Collectors.toList());
for (String tsvFile : allTsvFiles) { for (String tsvFile : allTsvFiles) {
if (tsvFiles.containsKey(FilenameUtils.getName(tsvFile))) { if (tsvFiles.containsKey(FilenameUtils.getName(tsvFile.toLowerCase()))) {
foundTsvFiles.add(tsvFile); foundTsvFiles.add(tsvFile);
} }
} }
@ -160,7 +178,41 @@ public final class ILeappFileProcessor {
processFile(iLeappFile, attrList, fileName, artifactType, bbartifacts, iLeappImageFile); processFile(iLeappFile, attrList, fileName, artifactType, bbartifacts, iLeappImageFile);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
// check this throw new IngestModuleException(String.format("Error getting Blackboard Artifact Type for %s", tsvFileArtifacts.get(fileName)), ex);
}
}
}
if (!bbartifacts.isEmpty()) {
postArtifacts(bbartifacts);
}
}
/**
* Process the iLeapp files that were found that match the xml mapping file
*
* @param iLeappFilesToProcess List of files to process
* @param iLeappImageFile Abstract file to create artifact for
*
* @throws FileNotFoundException
* @throws IOException
*/
private void processiLeappFiles(List<String> iLeappFilesToProcess, Content dataSource) throws FileNotFoundException, IOException, IngestModuleException {
List<BlackboardArtifact> bbartifacts = new ArrayList<>();
for (String iLeappFileName : iLeappFilesToProcess) {
String fileName = FilenameUtils.getName(iLeappFileName);
File iLeappFile = new File(iLeappFileName);
if (tsvFileAttributes.containsKey(fileName)) {
List<List<String>> attrList = tsvFileAttributes.get(fileName);
try {
BlackboardArtifact.Type artifactType = Case.getCurrentCase().getSleuthkitCase().getArtifactType(tsvFileArtifacts.get(fileName));
processFile(iLeappFile, attrList, fileName, artifactType, bbartifacts, dataSource);
} catch (TskCoreException ex) {
throw new IngestModuleException(String.format("Error getting Blackboard Artifact Type for %s", tsvFileArtifacts.get(fileName)), ex); throw new IngestModuleException(String.format("Error getting Blackboard Artifact Type for %s", tsvFileArtifacts.get(fileName)), ex);
} }
} }
@ -174,7 +226,8 @@ public final class ILeappFileProcessor {
} }
private void processFile(File iLeappFile, List<List<String>> attrList, String fileName, BlackboardArtifact.Type artifactType, private void processFile(File iLeappFile, List<List<String>> attrList, String fileName, BlackboardArtifact.Type artifactType,
List<BlackboardArtifact> bbartifacts, AbstractFile iLeappImageFile) throws FileNotFoundException, IOException, IngestModuleException { List<BlackboardArtifact> bbartifacts, Content dataSource) throws FileNotFoundException, IOException, IngestModuleException,
TskCoreException {
try (BufferedReader reader = new BufferedReader(new FileReader(iLeappFile))) { try (BufferedReader reader = new BufferedReader(new FileReader(iLeappFile))) {
String line = reader.readLine(); String line = reader.readLine();
// Check first line, if it is null then no heading so nothing to match to, close and go to next file. // Check first line, if it is null then no heading so nothing to match to, close and go to next file.
@ -183,8 +236,8 @@ public final class ILeappFileProcessor {
line = reader.readLine(); line = reader.readLine();
while (line != null) { while (line != null) {
Collection<BlackboardAttribute> bbattributes = processReadLine(line, columnNumberToProcess, fileName); Collection<BlackboardAttribute> bbattributes = processReadLine(line, columnNumberToProcess, fileName);
if (!bbattributes.isEmpty()) { if (!bbattributes.isEmpty() && !blkBoard.artifactExists(dataSource, BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactType.getTypeID()), bbattributes)) {
BlackboardArtifact bbartifact = createArtifactWithAttributes(artifactType.getTypeID(), iLeappImageFile, bbattributes); BlackboardArtifact bbartifact = createArtifactWithAttributes(artifactType.getTypeID(), dataSource, bbattributes);
if (bbartifact != null) { if (bbartifact != null) {
bbartifacts.add(bbartifact); bbartifacts.add(bbartifact);
} }
@ -340,7 +393,7 @@ public final class ILeappFileProcessor {
for (int i = 0; i < nlist.getLength(); i++) { for (int i = 0; i < nlist.getLength(); i++) {
NamedNodeMap nnm = nlist.item(i).getAttributes(); NamedNodeMap nnm = nlist.item(i).getAttributes();
tsvFiles.put(nnm.getNamedItem("filename").getNodeValue(), nnm.getNamedItem("description").getNodeValue()); tsvFiles.put(nnm.getNamedItem("filename").getNodeValue().toLowerCase(), nnm.getNamedItem("description").getNodeValue());
} }
@ -393,16 +446,17 @@ public final class ILeappFileProcessor {
} }
} }
/** /**
* Generic method for creating a blackboard artifact with attributes * Generic method for creating a blackboard artifact with attributes
* *
* @param type is a blackboard.artifact_type enum to determine * @param type is a blackboard.artifact_type enum to determine which
* which type the artifact should be * type the artifact should be
* @param abstractFile is the AbstractFile object that needs to have the * @param abstractFile is the AbstractFile object that needs to have the
* artifact added for it * artifact added for it
* @param bbattributes is the collection of blackboard attributes that * @param bbattributes is the collection of blackboard attributes that need
* need to be added to the artifact after the * to be added to the artifact after the artifact has
* artifact has been created * been created
* *
* @return The newly-created artifact, or null on error * @return The newly-created artifact, or null on error
*/ */
@ -417,6 +471,30 @@ public final class ILeappFileProcessor {
return null; return null;
} }
/**
* Generic method for creating a blackboard artifact with attributes
*
* @param type is a blackboard.artifact_type enum to determine which
* type the artifact should be
* @param datasource is the Content object that needs to have the artifact
* added for it
* @param bbattributes is the collection of blackboard attributes that need
* to be added to the artifact after the artifact has
* been created
*
* @return The newly-created artifact, or null on error
*/
private BlackboardArtifact createArtifactWithAttributes(int type, Content dataSource, Collection<BlackboardAttribute> bbattributes) {
try {
BlackboardArtifact bbart = dataSource.newArtifact(type);
bbart.addAttributes(bbattributes);
return bbart;
} catch (TskException ex) {
logger.log(Level.WARNING, Bundle.ILeappFileProcessor_error_creating_new_artifacts(), ex); //NON-NLS
}
return null;
}
/** /**
* Method to post a list of BlackboardArtifacts to the blackboard. * Method to post a list of BlackboardArtifacts to the blackboard.
* *

View File

@ -47,6 +47,15 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="App Snapshots.tsv" description="App Snapshots (screenshots)">
<ArtifactName artifactname="TSK_SCREEN_SHOTS" comment="null">
<AttributeName attributename="TSK_PROG_NAME" columnName="App Name" required="yes" />
<AttributeName attributename="TSK_PATH" columnName="SOurce Path" required="yes" />
<AttributeName attributename="TSK_DATETIME" columnName="Date Modified" required="yes" />
<AttributeName attributename="null" columnName="Source File Located" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Bluetooth Other.tsv" description="Bluetooth Other"> <FileName filename="Bluetooth Other.tsv" description="Bluetooth Other">
<ArtifactName artifactname="TSK_BLUETOOTH_ADAPTER" comment="Bluetooth Other"> <ArtifactName artifactname="TSK_BLUETOOTH_ADAPTER" comment="Bluetooth Other">
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" /> <AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
@ -120,6 +129,13 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="DHCP Received List.tsv" description="DHCP Received List" >
<ArtifactName artifactname="TSK_IP_DHCP" comment="null">
<AttributeName attributename="TSK_NAME" columnName="Key" required="yes" />
<AttributeName attributename="TSK_VALUE" columnName="Value" required="yes" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC App Activity.tsv" description="KnowledgeC App Activity"> <FileName filename="KnowledgeC App Activity.tsv" description="KnowledgeC App Activity">
<ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC App Activity"> <ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC App Activity">
<AttributeName attributename="TSK_DATETIME" columnName="Entry Creation" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Entry Creation" required="yes" />
@ -189,6 +205,36 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="KnowledgeC Device is Backlit.tsv" description="KnowledgeC Device is Backlit">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Device Backlit">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Screen is Backlit" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Start" required="no" />
<AttributeName attributename="null" columnName="End" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="ZOBJECT Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Battery Level.tsv" description="KnowledgeC Battery Level">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Battery Level">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Battery Level" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Day of the Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName=" ZOBJECT Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Bluetooth Connections.tsv" description="KnowledgeC Bluetooth Connections"> <FileName filename="KnowledgeC Bluetooth Connections.tsv" description="KnowledgeC Bluetooth Connections">
<ArtifactName artifactname="TSK_BLUETOOTH_PAIRING" comment="KnowledgeC Bluetooth Connections"> <ArtifactName artifactname="TSK_BLUETOOTH_PAIRING" comment="KnowledgeC Bluetooth Connections">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" /> <AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
@ -207,15 +253,61 @@
<FileName filename="KnowledgeC Car Play Connections.tsv" description="KnowledgeC Car Play Connections"> <FileName filename="KnowledgeC Car Play Connections.tsv" description="KnowledgeC Car Play Connections">
<ArtifactName artifactname="TSK_DEVICE_INFO" comment="KnowledgeC Car Play Connections"> <ArtifactName artifactname="TSK_DEVICE_INFO" comment="KnowledgeC Car Play Connections">
<AttributeName attributename="TSK_DATETIME" columnName="Start" required="no" /> <AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" />
<AttributeName attributename="null" columnName="End" required="no" /> <AttributeName attributename="null" columnName="End" required="no" />
<AttributeName attributename="null" columnName="Car Play Connected" required="no" /> <AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Car Play Connected" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" /> <AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" /> <AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" /> <AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" /> <AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" /> <AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="TSK_DEVICE_ID" columnName="UUID" required="no" /> <AttributeName attributename="TSK_DEVICE_ID" columnName="UUID" required="yes" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Disk Subsystem Access.tsv" description="KnowledgeC Disk Subsystem Access">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="disk Subsystem">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Value String" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Do Not Disturb.tsv" description="KnowledgeC Do Not Disturb">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Do Not Disturb">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Value" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Inferred Motion.tsv" description="KnowledgeC Inferred Motion">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Inferred Motion">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Value" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" /> <AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName> </ArtifactName>
</FileName> </FileName>
@ -248,6 +340,19 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="KnowledgeC Device Locked.tsv" description="KnowledgeC Device Locked">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Device Locked">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Is Locked?" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Day of the Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName=" ZOBJECT Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Media Playing.tsv" description="KnowledgeC Media Playing"> <FileName filename="Media Playing.tsv" description="KnowledgeC Media Playing">
<ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Media Playing"> <ArtifactName artifactname="TSK_RECENT_OBJ" comment="KnowledgeC Media Playing">
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" /> <AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
@ -288,6 +393,36 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="KnowledgeC Screen Orientation.tsv" description="KnowledgeC Screen Orientation">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Screen Orientation">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Orientation" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Usage in Minutes" required="no" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Plugged In.tsv" description="KnowledgeC Plugged In">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Plugged In">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Is Plugged In?" required="yes" />
<AttributeName attributename="null" columnName="Usage in Seconds" required="no" />
<AttributeName attributename="null" columnName="Day of the Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Start" required="no" />
<AttributeName attributename="null" columnName="End" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName=" ZOBJECT Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Safari Browsing.tsv" description="KnowledgeC Safari Browsing"> <FileName filename="KnowledgeC Safari Browsing.tsv" description="KnowledgeC Safari Browsing">
<ArtifactName artifactname="TSK_WEB_HISTORY" comment="KnowledgeC Safari Browsing"> <ArtifactName artifactname="TSK_WEB_HISTORY" comment="KnowledgeC Safari Browsing">
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" /> <AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
@ -302,6 +437,18 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="KnowledgeC Siri Usage.tsv" description="KnowledgeC Siri Usage">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Siri Usage">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="App Name" required="yes" />
<AttributeName attributename="null" columnName="Weekday" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="ZOBJECT Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC App Usage.tsv" description="KnowledgeC App Usage"> <FileName filename="KnowledgeC App Usage.tsv" description="KnowledgeC App Usage">
<ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC App Usage"> <ArtifactName artifactname="TSK_PROG_RUN" comment="KnowledgeC App Usage">
<AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Start" required="yes" />
@ -318,6 +465,18 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="KnowledgeC User Waking Events.tsv" description="KnowledgeC User Waking Event">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="User Waking">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="null" columnName="Day of Week" required="no" />
<AttributeName attributename="null" columnName="GMT Offset" required="no" />
<AttributeName attributename="null" columnName="Entry Creation" required="no" />
<AttributeName attributename="null" columnName="UUID" required="no" />
<AttributeName attributename="null" columnName="Zobject Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="KnowledgeC Web Usage.tsv" description="KnowledgeC Web Usage"> <FileName filename="KnowledgeC Web Usage.tsv" description="KnowledgeC Web Usage">
<ArtifactName artifactname="TSK_WEB_HISTORY" comment="KnowledgeC Web Usage"> <ArtifactName artifactname="TSK_WEB_HISTORY" comment="KnowledgeC Web Usage">
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" /> <AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Start" required="yes" />
@ -433,6 +592,102 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
--> -->
<FileName filename="Notifications.tsv" description="iOS Notificatons">
<ArtifactName artifactname="TSK_PROG_NOTIFICATIONS" comment="iOS Notificatons">
<AttributeName attributename="TSK_DATETIME" columnName="Creation Time" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName=" Bundle" required="yes" />
<AttributeName attributename="TSK_TITLE" columnName=" Title[Subtitle]" required="yes" />
<AttributeName attributename="TSK_VALUE" columnName=" Message" required="yes" />
<AttributeName attributename="null" columnName=" Other Details" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Agg Bulletins.tsv" description="Powerlog Aggregate Bulletins">
<ArtifactName artifactname="TSK_PROG_NOTIFICATIONS" comment="Powerlog Aggregate Bulletins">
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="Bulletin Bundle ID" required="yes" />
<AttributeName attributename="null" columnName="Time Interval in Seconds" required="no" />
<AttributeName attributename="null" columnName="Count" required="no" />
<AttributeName attributename="null" columnName="Post Type" required="no" />
<AttributeName attributename="null" columnName="Aggregate Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Agg Notifications.tsv" description="Powerlog Aggregate Notifications">
<ArtifactName artifactname="TSK_PROG_NOTIFICATIONS" comment="Powerlog Aggregate Notifications">
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="Notification Bundle ID" required="yes" />
<AttributeName attributename="null" columnName="Time Interval in Seconds" required="no" />
<AttributeName attributename="null" columnName="Count" required="no" />
<AttributeName attributename="null" columnName="Notification Type" required="no" />
<AttributeName attributename="null" columnName="Aggregate Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Backup Info.tsv" description="Powerlog Backup Info">
<ArtifactName artifactname="TSK_BACKUP_EVENT" comment="null">
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_DATETIME_START" columnName="Start" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End" required="yes" />
<AttributeName attributename="null" columnName="State" required="no" />
<AttributeName attributename="null" columnName="Finished" required="no" />
<AttributeName attributename="null" columnName="Has error" required="no" />
<AttributeName attributename="null" columnName="Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Deleted Apps.tsv" description="Powerlog Deleted Apps">
<ArtifactName artifactname="TSK_DELETED_PROG" comment="Powerlog Deleted Apps">
<AttributeName attributename="TSK_DATETIME_DELETED" columnName="App Deleted Date" required="yes" />
<AttributeName attributename="TSK_DATETIME" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="App Name" required="yes" />
<AttributeName attributename="null" columnName="App Executable Name" required="no" />
<AttributeName attributename="TSK_PATH" columnName="Bundle ID" required="yes" />
<AttributeName attributename="null" columnName="Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Lightning Connector.tsv" description="Powerlog Lightning Connector Status">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Powerlog Lightning Connector Status">
<AttributeName attributename="TSK_DATETIME" columnName="Adjusted Timestamp" required="yes" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Accesory Power Mode" required="yes" />
<AttributeName attributename="null" columnName="Original Lightnint Connector Timestamp" required="no" />
<AttributeName attributename="null" columnName="Offset Timestamp" required="no" />
<AttributeName attributename="null" columnName="Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Push Message Received.tsv" description="Powerlog Push Message Received">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Powerlog Push Message Received">
<AttributeName attributename="TSK_DATETIME" columnName="Adjusted Timestamp" required="yes" />
<AttributeName attributename="TSK_PROG_NAME" columnName="Bundle ID" required="yes" />
<AttributeName attributename="TSK_VALUE" columnName="Connection Type" required="yes" />
<AttributeName attributename="null" columnName="Is Dropped" required="no" />
<AttributeName attributename="null" columnName="Link Quality" required="no" />
<AttributeName attributename="null" columnName="Priority" required="no" />
<AttributeName attributename="null" columnName="Topic" required="no" />
<AttributeName attributename="null" columnName="Server Hostname" required="no" />
<AttributeName attributename="null" columnName="Server IP" required="no" />
<AttributeName attributename="null" columnName="Original Timestamp" required="no" />
<AttributeName attributename="null" columnName="Offset Timestamp" required="no" />
<AttributeName attributename="null" columnName="Time Offset" required="no" />
<AttributeName attributename="null" columnName="Aggregate Table ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Torch.tsv" description="Powerlog Torch">
<ArtifactName artifactname="TSK_USER_DEVICE_EVENT" comment="Powerlog Torch">
<AttributeName attributename="TSK_DATETIME" columnName="Adjusted Timestamp" required="yes" />
<AttributeName attributename="null" columnName="Bundle ID" required="no" />
<AttributeName attributename="TSK_USER_DEVICE_EVENT_TYPE" columnName="Status" required="yes" />
<AttributeName attributename="null" columnName="Original Torch Timestamp" required="no" />
<AttributeName attributename="null" columnName="Offset Timestamp" required="no" />
<AttributeName attributename="null" columnName="Time Offset" required="no" />
<AttributeName attributename="null" columnName="Torch ID" required="no" />
</ArtifactName>
</FileName>
<FileName filename="Powerlog Wifi Network Connections.tsv" description="Powerlog WiFi Network Connections"> <FileName filename="Powerlog Wifi Network Connections.tsv" description="Powerlog WiFi Network Connections">
<ArtifactName artifactname="TSK_WIFI_NETWORK" comment="Powerlog WiFi Network Connections"> <ArtifactName artifactname="TSK_WIFI_NETWORK" comment="Powerlog WiFi Network Connections">
<AttributeName attributename="TSK_DATETIME" columnName="Adjusted Timestamp" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Adjusted Timestamp" required="yes" />

View File

@ -0,0 +1,5 @@
Yara_Module_Description=With the YARA ingest module you use YARA rule files to search files for textual or binary patterns.
Yara_Module_Name=YARA
YaraIngestModule_no_ruleSets=Unable to run YARA ingest, list of YARA rule sets was empty.
YaraIngestModule_windows_error_msg=The YARA ingest module is only available on 64bit Windows.
YaraIngestModule_yarac_not_found=Unable to compile YARA rules files. Unable to find executable at.

View File

@ -0,0 +1,258 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
import org.sleuthkit.autopsy.yara.YaraJNIWrapper;
import org.sleuthkit.autopsy.yara.YaraWrapperException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_RULE;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Methods for scanning files for yara rule matches.
*/
final class YaraIngestHelper {
private static final String YARA_DIR = "yara";
private static final String YARA_C_EXE = "yarac64.exe";
private static final String MODULE_NAME = YaraIngestModuleFactory.getModuleName();
private YaraIngestHelper() {
}
/**
* Uses the yarac tool to compile the rules in the given rule sets.
*
* @param ruleSetNames List of names of the selected rule sets.
* @param tempDir Path of the directory to put the compiled rule files.
*
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/
static void compileRules(List<String> ruleSetNames, Path outputDir) throws IngestModuleException {
if (ruleSetNames == null || ruleSetNames.isEmpty()) {
throw new IngestModule.IngestModuleException(Bundle.YaraIngestModule_no_ruleSets());
}
// Find javac
File exeFile = InstalledFileLocator.getDefault().locate(
Paths.get(YARA_DIR, YARA_C_EXE).toString(),
YaraIngestModule.class.getPackage().getName(), false);
if (exeFile == null) {
throw new IngestModuleException(Bundle.YaraIngestModule_yarac_not_found());
}
for (RuleSet set : getRuleSetsForNames(ruleSetNames)) {
compileRuleSet(set, outputDir, exeFile);
}
}
/**
* Scan the given AbstractFile for yara rule matches from the rule sets in
* the given directory creating a blackboard artifact for each matching
* rule.
*
* The baseDirectory should contain a series of directories one for each
* rule set.
*
* @param file The file to scan.
* @param baseRuleSetDirectory Base directory for the compiled rule sets.
*
* @throws TskCoreException
*/
static List<BlackboardArtifact> scanFileForMatches(AbstractFile file, File baseRuleSetDirectory, byte[] fileData, int fileDataSize, int timeout) throws TskCoreException, YaraWrapperException {
List<BlackboardArtifact> artifacts = new ArrayList<>();
File[] ruleSetDirectories = baseRuleSetDirectory.listFiles();
for (File ruleSetDirectory : ruleSetDirectories) {
List<String> ruleMatches = YaraIngestHelper.scanFileForMatches(fileData, fileDataSize, ruleSetDirectory, timeout);
if (!ruleMatches.isEmpty()) {
artifacts.addAll(YaraIngestHelper.createArtifact(file, ruleSetDirectory.getName(), ruleMatches));
}
}
return artifacts;
}
/**
*
* @param file The Abstract File being processed.
* @param baseRuleSetDirectory Base directory of the compiled rule sets.
* @param localFile Local copy of file.
* @param timeout Yara file scan timeout in seconds.
*
* @return
*
* @throws TskCoreException
* @throws YaraWrapperException
*/
static List<BlackboardArtifact> scanFileForMatches(AbstractFile file, File baseRuleSetDirectory, File localFile, int timeout) throws TskCoreException, YaraWrapperException {
List<BlackboardArtifact> artifacts = new ArrayList<>();
File[] ruleSetDirectories = baseRuleSetDirectory.listFiles();
for (File ruleSetDirectory : ruleSetDirectories) {
List<String> ruleMatches = YaraIngestHelper.scanFileForMatch(localFile, ruleSetDirectory, timeout);
if (!ruleMatches.isEmpty()) {
artifacts.addAll(YaraIngestHelper.createArtifact(file, ruleSetDirectory.getName(), ruleMatches));
}
}
return artifacts;
}
/**
* Scan the given file byte array for rule matches using the YaraJNIWrapper
* API.
*
* @param fileBytes
* @param ruleSetDirectory
*
* @return List of rules that match from the given file from the given rule
* set. Empty list is returned if no matches where found.
*
* @throws TskCoreException
*/
private static List<String> scanFileForMatches(byte[] fileBytes, int fileSize, File ruleSetDirectory, int timeout) throws YaraWrapperException {
List<String> matchingRules = new ArrayList<>();
File[] ruleSetCompiledFileList = ruleSetDirectory.listFiles();
for (File ruleFile : ruleSetCompiledFileList) {
matchingRules.addAll(YaraJNIWrapper.findRuleMatch(ruleFile.getAbsolutePath(), fileBytes, fileSize, timeout));
}
return matchingRules;
}
private static List<String> scanFileForMatch(File scanFile, File ruleSetDirectory, int timeout) throws YaraWrapperException {
List<String> matchingRules = new ArrayList<>();
File[] ruleSetCompiledFileList = ruleSetDirectory.listFiles();
for (File ruleFile : ruleSetCompiledFileList) {
matchingRules.addAll(YaraJNIWrapper.findRuleMatchFile(ruleFile.getAbsolutePath(), scanFile.getAbsolutePath(), timeout));
}
return matchingRules;
}
/**
* Create a list of Blackboard Artifacts, one for each matching rule.
*
* @param abstractFile File to add artifact to.
* @param ruleSetName Name rule set with matching rule.
* @param matchingRules Matching rule.
*
* @return List of artifacts or empty list if none were found.
*
* @throws TskCoreException
*/
private static List<BlackboardArtifact> createArtifact(AbstractFile abstractFile, String ruleSetName, List<String> matchingRules) throws TskCoreException {
List<BlackboardArtifact> artifacts = new ArrayList<>();
for (String rule : matchingRules) {
BlackboardArtifact artifact = abstractFile.newArtifact(TSK_YARA_HIT);
List<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(TSK_SET_NAME, MODULE_NAME, ruleSetName));
attributes.add(new BlackboardAttribute(TSK_RULE, MODULE_NAME, rule));
artifact.addAttributes(attributes);
artifacts.add(artifact);
}
return artifacts;
}
@NbBundle.Messages({
"YaraIngestModule_yarac_not_found=Unable to compile YARA rules files. Unable to find executable at.",
"YaraIngestModule_no_ruleSets=Unable to run YARA ingest, list of YARA rule sets was empty."
})
/**
* Compiles the rule files in the given rule set.
*
* The compiled rule files are created in outputDir\RuleSetName.
*
* @param set RuleSet for which to compile files.
* @param outputDir Output directory for the compiled rule files.
* @param yarac yarac executeable file.
*
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/
static private void compileRuleSet(RuleSet set, Path outputDir, File yarac) throws IngestModuleException {
File tempFolder = Paths.get(outputDir.toString(), set.getName()).toFile();
if (!tempFolder.exists()) {
tempFolder.mkdir();
}
List<File> fileList = set.getRuleFiles();
for (File file : fileList) {
List<String> commandList = new ArrayList<>();
commandList.add(String.format("\"%s\"", yarac.toString()));
commandList.add(String.format("\"%s\"", file.toString()));
commandList.add(String.format("\"%s\"", Paths.get(tempFolder.getAbsolutePath(), "compiled_" + file.getName())));
ProcessBuilder builder = new ProcessBuilder(commandList);
try {
ExecUtil.execute(builder);
} catch (SecurityException | IOException ex) {
throw new IngestModuleException(String.format("Failed to compile Yara rules file", file.toString()), ex);
}
}
}
/**
* Returns a list of RuleSet objects for the given list of RuleSet names.
*
* @param names List of RuleSet names.
*
* @return List of RuleSet or empty list if none of the names matched
* existing rules.
*/
private static List<RuleSet> getRuleSetsForNames(List<String> names) {
List<RuleSet> ruleSetList = new ArrayList<>();
RuleSetManager manager = new RuleSetManager();
for (RuleSet set : manager.getRuleSetList()) {
if (names.contains(set.getName())) {
ruleSetList.add(set);
}
}
return ruleSetList;
}
}

View File

@ -0,0 +1,106 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
/**
* IngestJobSettings for the YARA ingest module.
*/
public final class YaraIngestJobSettings implements IngestModuleIngestJobSettings {
private static final long serialVersionUID = 1L;
private List<String> selectedRuleSetNames;
private boolean onlyExecutableFiles;
// Default constructor.
YaraIngestJobSettings() {
onlyExecutableFiles = true;
selectedRuleSetNames = new ArrayList<>();
}
/**
* Constructor.
*
* @param selected List of selected rules.
* @param onlyExecutableFiles Process only executable files.
*/
public YaraIngestJobSettings(List<RuleSet> selected, boolean onlyExecutableFiles) {
this.selectedRuleSetNames = new ArrayList<>();
for (RuleSet set : selected) {
selectedRuleSetNames.add(set.getName());
}
this.onlyExecutableFiles = onlyExecutableFiles;
}
/**
* Return the list of rule name sets that were selected in the ingest
* settings panel.
*
* @return List of selected RuleSet names.
*/
public List<String> getSelectedRuleSetNames() {
return Collections.unmodifiableList(selectedRuleSetNames);
}
/**
* Set the list of selected rule names.
*
* @param selected List of selected rule Sets.
*/
void setSelectedRuleSetNames(List<RuleSet> selected) {
this.selectedRuleSetNames = new ArrayList<>();
for (RuleSet set : selected) {
selectedRuleSetNames.add(set.getName());
}
}
/**
* Process only executable Files.
*
* @return If true the ingest module should process only executable files,
* if false process all files.
*/
public boolean onlyExecutableFiles() {
return onlyExecutableFiles;
}
/**
* Set whether to process only executable files or all files.
*
* @param onlyExecutableFiles True if the ingest module should only process
* executable files.
*/
void setOnlyExecuteableFile(boolean onlyExecutableFiles) {
this.onlyExecutableFiles = onlyExecutableFiles;
}
@Override
public long getVersionNumber() {
return serialVersionUID;
}
}

View File

@ -0,0 +1,224 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.apache.commons.lang3.RandomStringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
import org.sleuthkit.autopsy.yara.YaraWrapperException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* An ingest module that runs the yara against the given files.
*
*/
public class YaraIngestModule extends FileIngestModuleAdapter {
// 15MB
private static final int FILE_SIZE_THRESHOLD_MB = 100;
private static final int FILE_SIZE_THRESHOLD_BYTE = FILE_SIZE_THRESHOLD_MB * 1024 * 1024;
private static final int YARA_SCAN_TIMEOUT_SEC = 30 * 60 * 60; // 30 minutes.
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private final static Logger logger = Logger.getLogger(YaraIngestModule.class.getName());
private static final String YARA_DIR = "yara";
private static final Map<Long, Path> pathsByJobId = new ConcurrentHashMap<>();
private static final String RULESET_DIR = "RuleSets";
private final YaraIngestJobSettings settings;
private IngestJobContext context = null;
private Long jobId;
/**
* Constructor.
*
* @param settings
*/
YaraIngestModule(YaraIngestJobSettings settings) {
this.settings = settings;
}
@Messages({
"YaraIngestModule_windows_error_msg=The YARA ingest module is only available on 64bit Windows.",})
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
this.jobId = context.getJobId();
if (!PlatformUtil.isWindowsOS() || !PlatformUtil.is64BitOS()) {
throw new IngestModule.IngestModuleException(Bundle.YaraIngestModule_windows_error_msg());
}
if (refCounter.incrementAndGet(jobId) == 1) {
// compile the selected rules & put into temp folder based on jobID
Path tempDir = getTempDirectory(jobId);
Path tempRuleSetDir = Paths.get(tempDir.toString(), RULESET_DIR);
if(!tempRuleSetDir.toFile().exists()) {
tempRuleSetDir.toFile().mkdir();
}
YaraIngestHelper.compileRules(settings.getSelectedRuleSetNames(), tempRuleSetDir);
}
}
@Override
public void shutDown() {
if (context != null && refCounter.decrementAndGet(jobId) == 0) {
// do some clean up.
Path jobPath = pathsByJobId.get(jobId);
if (jobPath != null) {
jobPath.toFile().delete();
pathsByJobId.remove(jobId);
}
}
}
@Override
public ProcessResult process(AbstractFile file) {
if (settings.onlyExecutableFiles()) {
String extension = file.getNameExtension();
if (!extension.equals("exe")) {
return ProcessResult.OK;
}
}
// Skip the file if its 0 in length or a directory.
if (file.getSize() == 0 ||
file.isDir() ||
file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
return ProcessResult.OK;
}
try {
List<BlackboardArtifact> artifacts = new ArrayList<>();
File ruleSetsDir = Paths.get(getTempDirectory(jobId).toString(), RULESET_DIR).toFile();
// If the file size is less than FILE_SIZE_THRESHOLD_BYTE read the file
// into a buffer, else make a local copy of the file.
if(file.getSize() < FILE_SIZE_THRESHOLD_BYTE) {
byte[] fileBuffer = new byte[(int)file.getSize()];
int dataRead = file.read(fileBuffer, 0, file.getSize());
if(dataRead != 0) {
artifacts.addAll( YaraIngestHelper.scanFileForMatches(file, ruleSetsDir, fileBuffer, dataRead, YARA_SCAN_TIMEOUT_SEC));
}
} else {
File tempCopy = createLocalCopy(file);
artifacts.addAll( YaraIngestHelper.scanFileForMatches(file, ruleSetsDir, tempCopy, YARA_SCAN_TIMEOUT_SEC));
tempCopy.delete();
}
if(!artifacts.isEmpty()) {
Blackboard blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
blackboard.postArtifacts(artifacts, YaraIngestModuleFactory.getModuleName());
}
} catch (BlackboardException | NoCurrentCaseException | IngestModuleException | TskCoreException | YaraWrapperException ex) {
logger.log(Level.SEVERE, String.format("YARA ingest module failed to process file id %d", file.getId()), ex);
return ProcessResult.ERROR;
} catch(IOException ex) {
logger.log(Level.SEVERE, String.format("YARA ingest module failed to make a local copy of given file id %d", file.getId()), ex);
return ProcessResult.ERROR;
}
return ProcessResult.OK;
}
/**
* Return the temp directory for this jobId. If the folder does not exit it
* will be created.
*
* @param jobId The current jobId
*
* @return The path of the temporary directory for the given jobId.
*
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/
private synchronized Path getTempDirectory(long jobId) throws IngestModuleException {
Path jobPath = pathsByJobId.get(jobId);
if (jobPath != null) {
return jobPath;
}
Path baseDir;
try {
baseDir = Paths.get(Case.getCurrentCaseThrows().getTempDirectory(), YARA_DIR);
} catch (NoCurrentCaseException ex) {
throw new IngestModuleException("Failed to create YARA ingest model temp directory, no open case.", ex);
}
// Make the base yara directory, as needed
if (!baseDir.toFile().exists()) {
baseDir.toFile().mkdirs();
}
String randomDirName = String.format("%s_%d", RandomStringUtils.randomAlphabetic(8), jobId);
jobPath = Paths.get(baseDir.toString(), randomDirName);
jobPath.toFile().mkdir();
pathsByJobId.put(jobId, jobPath);
return jobPath;
}
/**
* Create a local copy of the given AbstractFile.
*
* @param file AbstractFile to make a copy of.
*
* @return A File object representation of the local copy.
*
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
* @throws IOException
*/
protected File createLocalCopy(AbstractFile file) throws IngestModuleException, IOException {
String tempFileName = RandomStringUtils.randomAlphabetic(15) + file.getId() + ".temp";
File tempFile = Paths.get(getTempDirectory(context.getJobId()).toString(), tempFileName).toFile();
ContentUtils.writeToFile(file, tempFile, context::dataSourceIngestIsCancelled);
return tempFile;
}
}

View File

@ -0,0 +1,92 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara;
import java.util.ArrayList;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
import org.sleuthkit.autopsy.modules.yara.ui.YaraIngestSettingsPanel;
/**
* A factory that creates ingest modules that use the Yara rule set definitions
* to identify files that may be of interest to the user.
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class YaraIngestModuleFactory extends IngestModuleFactoryAdapter {
@Messages({
"Yara_Module_Name=YARA",
"Yara_Module_Description=With the YARA ingest module you use YARA rule files to search files for textual or binary patterns."
})
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return Bundle.Yara_Module_Description();
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public boolean hasIngestJobSettingsPanel() {
return true;
}
@Override
public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
return new YaraIngestSettingsPanel((YaraIngestJobSettings)settings);
}
@Override
public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
return new YaraIngestJobSettings(new ArrayList<>(), true);
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
return new YaraIngestModule((YaraIngestJobSettings) settings);
}
/**
* Return the name of the ingest module.
*
* @return Ingest module name.
*/
static String getModuleName() {
return Bundle.Yara_Module_Name();
}
}

View File

@ -0,0 +1,84 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.rules;
import java.io.File;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
/**
* Represents a yara rule set which is a collection of yara rule files.
*/
public class RuleSet implements Comparable<RuleSet>, Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final Path path;
/**
* Construct a new RuleSet.
*
* @param name Name of the rule set.
* @param path Directory path to the rule set.
*/
RuleSet(String name, Path path) {
this.name = name;
this.path = path;
}
/**
* Returns the name of the rule set.
*
* @return Name of rule set.
*/
public String getName() {
return name;
}
/**
* Returns location if the rule set files.
*
* @return The path for this rule set.
*/
public Path getPath() {
return path;
}
/**
* Returns a list of the rule files in this rule set.
*
* @return List of Files in current directory.
*/
public List<File> getRuleFiles() {
return Arrays.asList(path.toFile().listFiles());
}
@Override
public String toString() {
return getName();
}
@Override
public int compareTo(RuleSet ruleSet) {
return getName().compareTo(ruleSet.getName());
}
}

View File

@ -0,0 +1,47 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.rules;
/**
*
* An exception class for yara rule sets.
*/
public class RuleSetException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Construct a RuleSetException with the given message.
*
* @param msg Exception message.
*/
RuleSetException(String msg) {
super(msg);
}
/**
* Construct a RuleSetException with the given message and exception.
*
* @param msg Exception message.
* @param ex Exception.
*/
RuleSetException(String msg, Exception ex) {
super(msg, ex);
}
}

View File

@ -0,0 +1,109 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 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.modules.yara.rules;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
*
* Yara Rule Set Manager. Manages the creation, deletion of yara rule sets.
*/
public class RuleSetManager {
private final static String BASE_FOLDER = "yara";
private final static String RULE_SET_FOLDER = "ruleSets";
/**
* Create a new Yara rule set with the given set name.
*
* @param name Name of new rule set
*
* @return Newly created RuleSet
*
* @throws RuleSetException RuleSet with given name already exists.
*/
public RuleSet createRuleSet(String name) throws RuleSetException {
if (isRuleSetExists(name)) {
throw new RuleSetException(String.format("Yara rule set with name %s already exits.", name));
}
Path basePath = getRuleSetPath();
Path setPath = Paths.get(basePath.toString(), name);
setPath.toFile().mkdir();
return new RuleSet(name, setPath);
}
/**
* Returns a list of all of the existing yara rule sets.
*
* @return
*/
public List<RuleSet> getRuleSetList() {
List<RuleSet> ruleSets = new ArrayList<>();
Path basePath = getRuleSetPath();
String[] ruleSetNames = basePath.toFile().list();
for (String setName : ruleSetNames) {
ruleSets.add(new RuleSet(setName, Paths.get(basePath.toString(), setName)));
}
return ruleSets;
}
/**
* Check if a yara rule set of the given name exists.
*
* @param name Yara rule set name
*
* @return True if the rule set exist.
*/
public boolean isRuleSetExists(String name) {
Path basePath = getRuleSetPath();
Path setPath = Paths.get(basePath.toString(), name);
return setPath.toFile().exists();
}
/**
* Returns the Path to get RuleSet directory. If it does not exist it is
* created.
*
* @return Yara rule set directory path.
*/
private Path getRuleSetPath() {
Path basePath = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), BASE_FOLDER, RULE_SET_FOLDER);
File baseFile = basePath.toFile();
if (!baseFile.exists()) {
baseFile.mkdirs();
}
return basePath;
}
}

View File

@ -0,0 +1,15 @@
OptionCategory_Name_YaraRuleSetOption=Yara Rule Sets
OptionCategory_Keywords_YaraRuleSetOption=YaraRuleSets
RuleSetPanel.newButton.text=New Set
RuleSetPanel.deleteButton.text=Delete Set
RuleSetPanel.ruleSetListLabel.text=Rule Sets:
RuleSetDetailsPanel.ruleSetListLabel.text=The folder currently contains the following rule files:
RuleSetDetailsPanel.setDetailsLabel.text=Set Details
RuleSetDetailsPanel.openFolderButton.text=Open Folder
RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files. A file need only match one rule in the set to be found.
RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
YaraIngestSettingsPanel.border.title=Select YARA rule sets to enable during ingest:
YaraIngestSettingsPanel.allFilesButton.text=All Files
YaraIngestSettingsPanel.allFilesButton.toolTipText=
YaraIngestSettingsPanel.executableFilesButton.text=Only Executable Files
RuleSetDetailsPanel.refreshButton.text=Refresh File List

View File

@ -0,0 +1,22 @@
OptionCategory_Name_YaraRuleSetOption=Yara Rule Sets
OptionCategory_Keywords_YaraRuleSetOption=YaraRuleSets
RuleSetDetailsPanel_failed_to_open_folder_msg=Failed to open new window for rule set file.
RuleSetDetailsPanel_failed_to_open_folder_title=Open Error
RuleSetPanel.newButton.text=New Set
RuleSetPanel.deleteButton.text=Delete Set
RuleSetPanel.ruleSetListLabel.text=Rule Sets:
RuleSetDetailsPanel.ruleSetListLabel.text=The folder currently contains the following rule files:
RuleSetDetailsPanel.setDetailsLabel.text=Set Details
RuleSetDetailsPanel.openFolderButton.text=Open Folder
RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files. A file need only match one rule in the set to be found.
RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
YaraIngestSettingsPanel.border.title=Select YARA rule sets to enable during ingest:
YaraIngestSettingsPanel.allFilesButton.text=All Files
YaraIngestSettingsPanel.allFilesButton.toolTipText=
YaraIngestSettingsPanel.executableFilesButton.text=Only Executable Files
RuleSetDetailsPanel.refreshButton.text=Refresh File List
# {0} - rule set name
YaraRuleSetOptionPanel_badName_msg=Rule set name {0} already exists.\nRule set names must be unique.
YaraRuleSetOptionPanel_badName_title=Create Rule Set
YaraRuleSetOptionPanel_new_rule_set_name_msg=Supply a new unique rule set name:
YaraRuleSetOptionPanel_new_rule_set_name_title=Rule Set Name

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,-85"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="ruleSetListLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.ruleSetListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="16" insetsLeft="0" insetsBottom="3" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="setDetailsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.setDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="10" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="openFolderButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/folder-icon-16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.openFolderButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openFolderButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="openLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.openLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="4" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
<Component class="javax.swing.JButton" name="refreshButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/arrow-circle-double-135.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.refreshButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="14" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,228 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.ui;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
/**
* A panel for displaying the details of an individual yara rule set.
*/
public class RuleSetDetailsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(RuleSetDetailsPanel.class.getName());
private RuleSet currentRuleSet;
private final DefaultListModel<File> fileListModel;
private final JList<File> fileList;
/**
* Creates new form RuleSetDetailsPanel
*/
public RuleSetDetailsPanel() {
initComponents();
fileListModel = new DefaultListModel<>();
fileList = new JList<>();
fileList.setModel(fileListModel);
fileList.setCellRenderer(new FileRenderer());
openFolderButton.setEnabled(false);
scrollPane.setViewportView(fileList);
}
/**
* Update the panel to show the details of the given RuleSet.
*
* @param ruleSet New RuleSet to display
*/
void setRuleSet(RuleSet ruleSet) {
currentRuleSet = ruleSet;
fileListModel.clear();
if (ruleSet != null) {
List<File> files = currentRuleSet.getRuleFiles();
if(files != null) {
for (File file : files) {
fileListModel.addElement(file);
}
}
}
openFolderButton.setEnabled(ruleSet != null);
}
/**
* Simple ListCellRenderer for the file list.
*/
private final class FileRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof File) {
File file = (File) value;
setText(file.getName());
setToolTipText(file.getAbsolutePath());
}
return this;
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JLabel ruleSetListLabel = new javax.swing.JLabel();
javax.swing.JLabel setDetailsLabel = new javax.swing.JLabel();
openFolderButton = new javax.swing.JButton();
openLabel = new javax.swing.JLabel();
scrollPane = new javax.swing.JScrollPane();
javax.swing.JButton refreshButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(ruleSetListLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.ruleSetListLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(16, 0, 3, 0);
add(ruleSetListLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(setDetailsLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.setDetailsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 10, 0);
add(setDetailsLabel, gridBagConstraints);
openFolderButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/folder-icon-16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(openFolderButton, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.openFolderButton.text")); // NOI18N
openFolderButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openFolderButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 5;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
add(openFolderButton, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(openLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.openLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
add(openLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
add(scrollPane, gridBagConstraints);
refreshButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/arrow-circle-double-135.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.refreshButton.text")); // NOI18N
refreshButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
refreshButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 5;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
add(refreshButton, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@Messages({
"RuleSetDetailsPanel_failed_to_open_folder_msg=Failed to open new window for rule set file.",
"RuleSetDetailsPanel_failed_to_open_folder_title=Open Error"
})
private void openFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFolderButtonActionPerformed
if (currentRuleSet != null) {
File file = currentRuleSet.getPath().toFile();
if (file.exists()) {
try {
Desktop.getDesktop().open(file);
} catch (IOException ex) {
JOptionPane.showMessageDialog(this,
Bundle.RuleSetDetailsPanel_failed_to_open_folder_msg(),
Bundle.RuleSetDetailsPanel_failed_to_open_folder_title(),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.WARNING, String.format("Failed to open external file explorer for: %s", currentRuleSet.getPath().toString()), ex);
}
}
}
}//GEN-LAST:event_openFolderButtonActionPerformed
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
if (currentRuleSet != null) {
fileListModel.clear();
List<File> files = currentRuleSet.getRuleFiles();
if(files != null) {
for (File file : files) {
fileListModel.addElement(file);
}
}
}
}//GEN-LAST:event_refreshButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton openFolderButton;
private javax.swing.JLabel openLabel;
private javax.swing.JScrollPane scrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-114,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="descriptionField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
<LineBorder/>
</Border>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.descriptionField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="ruleSetListLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.ruleSetListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="10" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="buttonPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="0"/>
<Property name="horizontalGap" type="int" value="5"/>
<Property name="rows" type="int" value="1"/>
</Layout>
<SubComponents>
<Component class="javax.swing.JButton" name="newButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/add16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.newButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="deleteButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/images/delete16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.deleteButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,231 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.ui;
import java.awt.Component;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
/**
* Panel for managing yara rule sets.
*/
public final class RuleSetPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final DefaultListModel<RuleSet> listModel;
private final JList<RuleSet> ruleSetList;
public RuleSetPanel() {
initComponents();
// Creating and initializing JList here to better take
// advantace of JList use of generics.
ruleSetList = new JList<>();
listModel = new DefaultListModel<>();
scrollPane.setViewportView(ruleSetList);
ruleSetList.setModel(listModel);
ruleSetList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
ruleSetList.setCellRenderer(new RuleSetRenderer());
ruleSetList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
deleteButton.setEnabled(getSelectedRule() != null);
}
});
deleteButton.setEnabled(false);
}
/**
* Add the list of rule sets to the list model.
*
* @param ruleSetList Rule sets to add.
*/
void addSetList(List<RuleSet> newSetList) {
// Put the list into alphectical order.
List<RuleSet> list = new ArrayList<>();
list.addAll(newSetList);
Collections.sort(list);
listModel.clear();
for (RuleSet set : list) {
listModel.addElement(set);
}
}
/**
* Adds a new rule to the list.
*
* @param set
*/
void addRuleSet(RuleSet set) {
// This will assure that the new item
// appears in the correct location.
List<RuleSet> list = Collections.list(listModel.elements());
list.add(set);
addSetList(list);
ruleSetList.setSelectedValue(set, true);
}
/**
* Removes a rule set from the list.
*
* @param set
*/
void removeRuleSet(RuleSet set) {
listModel.removeElement(set);
}
/**
* Add a listener for the new rule set action.
*
* @param listener
*/
void addNewRuleListener(ActionListener listener) {
newButton.addActionListener(listener);
}
/**
* Add a listener for the delete rule set action.
*
* @param listener
*/
void addDeleteRuleListener(ActionListener listener) {
deleteButton.addActionListener(listener);
}
/**
* Add a listener for list selection change.
*
* @param listener
*/
void addListSelectionListener(ListSelectionListener listener) {
ruleSetList.addListSelectionListener(listener);
}
/**
* Returns the current selected rule set.
*
* @return Currently selected rule set or null if one is not selected.
*/
RuleSet getSelectedRule() {
return ruleSetList.getSelectedValue();
}
/**
* Simple ListCellRenderer for a RuleSet.
*/
private final class RuleSetRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof RuleSet) {
RuleSet set = (RuleSet) value;
setText(set.getName());
setToolTipText(set.getName());
}
return this;
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JTextPane descriptionField = new javax.swing.JTextPane();
javax.swing.JLabel ruleSetListLabel = new javax.swing.JLabel();
scrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
newButton = new javax.swing.JButton();
deleteButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
descriptionField.setEditable(false);
descriptionField.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
descriptionField.setText(org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.descriptionField.text")); // NOI18N
descriptionField.setOpaque(false);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
add(descriptionField, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(ruleSetListLabel, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.ruleSetListLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0);
add(ruleSetListLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 10, 0);
add(scrollPane, gridBagConstraints);
buttonPanel.setLayout(new java.awt.GridLayout(1, 0, 5, 0));
newButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newButton, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.newButton.text")); // NOI18N
buttonPanel.add(newButton);
deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.deleteButton.text")); // NOI18N
buttonPanel.add(deleteButton);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(buttonPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton deleteButton;
private javax.swing.JButton newButton;
private javax.swing.JScrollPane scrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="buttonGroup">
</Component>
</NonVisualComponents>
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Select YARA rule sets to enable during ingest:">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="buttonPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="allFilesButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.allFilesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.allFilesButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JRadioButton" name="executableFilesButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.executableFilesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,182 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.ui;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.DefaultListModel;
import org.sleuthkit.autopsy.guicomponeontutils.AbstractCheckboxListItem;
import org.sleuthkit.autopsy.guiutils.CheckBoxJList;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
import org.sleuthkit.autopsy.modules.yara.YaraIngestJobSettings;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
/**
* Yara Ingest settings panel.
*/
public class YaraIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
private static final long serialVersionUID = 1L;
private final CheckBoxJList<RuleSetListItem> checkboxList;
private final DefaultListModel<RuleSetListItem> listModel;
/**
* Creates new form YaraIngestSettingsPanel
*/
YaraIngestSettingsPanel() {
initComponents();
listModel = new DefaultListModel<>();
checkboxList = new CheckBoxJList<>();
scrollPane.setViewportView(checkboxList);
}
public YaraIngestSettingsPanel(YaraIngestJobSettings settings) {
this();
List<String> setNames = settings.getSelectedRuleSetNames();
checkboxList.setModel(listModel);
checkboxList.setOpaque(false);
RuleSetManager manager = new RuleSetManager();
List<RuleSet> ruleSetList = manager.getRuleSetList();
for (RuleSet set : ruleSetList) {
RuleSetListItem item = new RuleSetListItem(set);
item.setChecked(setNames.contains(set.getName()));
listModel.addElement(item);
}
allFilesButton.setSelected(!settings.onlyExecutableFiles());
executableFilesButton.setSelected(settings.onlyExecutableFiles());
}
@Override
public IngestModuleIngestJobSettings getSettings() {
List<RuleSet> selectedRules = new ArrayList<>();
Enumeration<RuleSetListItem> enumeration = listModel.elements();
while (enumeration.hasMoreElements()) {
RuleSetListItem item = enumeration.nextElement();
if (item.isChecked()) {
selectedRules.add(item.getRuleSet());
}
}
return new YaraIngestJobSettings(selectedRules, executableFilesButton.isSelected());
}
/**
* RuleSet wrapper class for Checkbox JList model.
*/
private final class RuleSetListItem extends AbstractCheckboxListItem {
private final RuleSet ruleSet;
/**
* RuleSetListItem constructor.
*
* @param set RuleSet object to display in list.
*/
RuleSetListItem(RuleSet set) {
this.ruleSet = set;
}
/**
* Returns the RuleSet.
*
* @return
*/
RuleSet getRuleSet() {
return ruleSet;
}
@Override
public String getDisplayName() {
return ruleSet.getName();
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
buttonGroup = new javax.swing.ButtonGroup();
scrollPane = new javax.swing.JScrollPane();
buttonPanel = new javax.swing.JPanel();
allFilesButton = new javax.swing.JRadioButton();
executableFilesButton = new javax.swing.JRadioButton();
setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.border.title"))); // NOI18N
setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
add(scrollPane, gridBagConstraints);
buttonPanel.setLayout(new java.awt.GridBagLayout());
buttonGroup.add(allFilesButton);
org.openide.awt.Mnemonics.setLocalizedText(allFilesButton, org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.allFilesButton.text")); // NOI18N
allFilesButton.setToolTipText(org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.allFilesButton.toolTipText")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
buttonPanel.add(allFilesButton, gridBagConstraints);
buttonGroup.add(executableFilesButton);
executableFilesButton.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(executableFilesButton, org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.executableFilesButton.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
buttonPanel.add(executableFilesButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
add(buttonPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton allFilesButton;
private javax.swing.ButtonGroup buttonGroup;
private javax.swing.JPanel buttonPanel;
private javax.swing.JRadioButton executableFilesButton;
private javax.swing.JScrollPane scrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
<LineBorder/>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,45"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="viewportPanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JSeparator" name="separator">
<Properties>
<Property name="orientation" type="int" value="1"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="-1" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel" name="ruleSetDetailsPanel">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[500, 97]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[500, 204]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="17" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel" name="ruleSetPanel">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 2147483647]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 107]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 214]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="17" weightX="0.0" weightY="1.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,207 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.ui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSetException;
import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
/**
*
* Yara Rule Set Option Panel.
*/
public class YaraRuleSetOptionPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(YaraRuleSetOptionPanel.class.getName());
private final RuleSetManager manager;
/**
* Creates new form YaraRuleSetOptionPanel
*/
public YaraRuleSetOptionPanel() {
initComponents();
manager = new RuleSetManager();
ruleSetPanel.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
handleSelectionChange();
}
});
ruleSetPanel.addDeleteRuleListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleDeleteRuleSet();
}
});
ruleSetPanel.addNewRuleListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleNewRuleSet();
}
});
}
/**
* Update the panel with the current rule set.
*/
void updatePanel() {
ruleSetPanel.addSetList(manager.getRuleSetList());
}
/**
* Handle the change in rule set selection. Update the detail panel with the
* selected rule.
*/
private void handleSelectionChange() {
ruleSetDetailsPanel.setRuleSet(ruleSetPanel.getSelectedRule());
}
@NbBundle.Messages({
"YaraRuleSetOptionPanel_new_rule_set_name_msg=Supply a new unique rule set name:",
"YaraRuleSetOptionPanel_new_rule_set_name_title=Rule Set Name",
"# {0} - rule set name",
"YaraRuleSetOptionPanel_badName_msg=Rule set name {0} already exists.\nRule set names must be unique.",
"YaraRuleSetOptionPanel_badName_title=Create Rule Set"
})
/**
* Handle the new rule set action. Prompt the user for a rule set name,
* create the new set and update the rule set list.
*/
private void handleNewRuleSet() {
String value = JOptionPane.showInputDialog(this,
Bundle.YaraRuleSetOptionPanel_new_rule_set_name_msg(),
Bundle.YaraRuleSetOptionPanel_new_rule_set_name_title());
try {
ruleSetPanel.addRuleSet(manager.createRuleSet(value));
} catch (RuleSetException ex) {
JOptionPane.showMessageDialog(this,
Bundle.YaraRuleSetOptionPanel_badName_msg(value),
Bundle.YaraRuleSetOptionPanel_badName_title(),
JOptionPane.ERROR_MESSAGE);
logger.log(Level.WARNING, "Failed to create new rule set, user provide existing name.", ex);
}
}
/**
* Handle the delete rule action. Delete the rule set and update the the
* rule set list.
*/
private void handleDeleteRuleSet() {
RuleSet ruleSet = ruleSetPanel.getSelectedRule();
ruleSetPanel.removeRuleSet(ruleSet);
deleteDirectory(ruleSet.getPath().toFile());
}
/**
* Recursively delete the given directory and its children.
*
* @param directoryToBeDeleted
*
* @return True if the delete was successful.
*/
private boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel viewportPanel = new javax.swing.JPanel();
javax.swing.JSeparator separator = new javax.swing.JSeparator();
ruleSetDetailsPanel = new org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel();
ruleSetPanel = new org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel();
setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
setLayout(new java.awt.BorderLayout());
scrollPane.setBorder(null);
viewportPanel.setLayout(new java.awt.GridBagLayout());
separator.setOrientation(javax.swing.SwingConstants.VERTICAL);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 1.0;
viewportPanel.add(separator, gridBagConstraints);
ruleSetDetailsPanel.setMinimumSize(new java.awt.Dimension(500, 97));
ruleSetDetailsPanel.setPreferredSize(new java.awt.Dimension(500, 204));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
viewportPanel.add(ruleSetDetailsPanel, gridBagConstraints);
ruleSetPanel.setMaximumSize(new java.awt.Dimension(400, 2147483647));
ruleSetPanel.setMinimumSize(new java.awt.Dimension(400, 107));
ruleSetPanel.setPreferredSize(new java.awt.Dimension(400, 214));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
viewportPanel.add(ruleSetPanel, gridBagConstraints);
scrollPane.setViewportView(viewportPanel);
add(scrollPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel ruleSetDetailsPanel;
private org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel ruleSetPanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,90 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.modules.yara.ui;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
/**
* Yara rule set option panel controller.
*
*/
@OptionsPanelController.TopLevelRegistration(
categoryName = "#OptionCategory_Name_YaraRuleSetOption",
iconBase = "org/sleuthkit/autopsy/images/yara_32.png",
keywords = "#OptionCategory_Keywords_YaraRuleSetOption",
keywordsCategory = "YaraRuleSets",
position = 20
)
public class YaraRuleSetsOptionPanelController extends OptionsPanelController {
private YaraRuleSetOptionPanel panel = null;
@Override
public void update() {
if (panel != null) {
panel.updatePanel();
}
}
@Override
public void applyChanges() {
}
@Override
public void cancel() {
}
@Override
public JComponent getComponent(Lookup masterLookup) {
panel = new YaraRuleSetOptionPanel();
return panel;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener pl) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener pl) {
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return false;
}
}

View File

@ -60,6 +60,7 @@ import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.autopsy.report.ReportProgressPanel;
import org.sleuthkit.caseuco.CaseUcoExporter; import org.sleuthkit.caseuco.CaseUcoExporter;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -983,10 +984,10 @@ public class PortableCaseReportModule implements ReportModule {
BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName()); BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
try { try {
BlackboardArtifact.Type newCustomType = portableSkCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName()); BlackboardArtifact.Type newCustomType = portableSkCase.getBlackboard().getOrAddArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID()); oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
return newCustomType.getTypeID(); return newCustomType.getTypeID();
} catch (TskDataException ex) { } catch (BlackboardException ex) {
throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex); // NON-NLS throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex); // NON-NLS
} }
} }
@ -1007,11 +1008,11 @@ public class PortableCaseReportModule implements ReportModule {
} }
try { try {
BlackboardAttribute.Type newCustomType = portableSkCase.addArtifactAttributeType(oldAttrType.getTypeName(), BlackboardAttribute.Type newCustomType = portableSkCase.getBlackboard().getOrAddAttributeType(oldAttrType.getTypeName(),
oldAttrType.getValueType(), oldAttrType.getDisplayName()); oldAttrType.getValueType(), oldAttrType.getDisplayName());
oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType); oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType);
return newCustomType; return newCustomType;
} catch (TskDataException ex) { } catch (BlackboardException ex) {
throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex); // NON-NLS throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex); // NON-NLS
} }
} }

View File

@ -292,6 +292,26 @@ public class RecentFilesSummaryTest {
} }
} }
@Test
public void getRecentlyOpenedDocuments_uniquePaths() throws SleuthkitCaseProviderException, TskCoreException {
DataSource dataSource = TskMockUtils.getDataSource(1);
BlackboardArtifact item1 = getRecentDocumentArtifact(dataSource, 1001, DAY_SECONDS, "/a/path");
BlackboardArtifact item2 = getRecentDocumentArtifact(dataSource, 1002, DAY_SECONDS + 1, "/a/path");
BlackboardArtifact item3 = getRecentDocumentArtifact(dataSource, 1003, DAY_SECONDS + 2, "/a/path");
List<BlackboardArtifact> artifacts = Arrays.asList(item2, item3, item1);
Pair<SleuthkitCase, Blackboard> casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts));
RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft());
List<RecentFileDetails> results = summary.getRecentlyOpenedDocuments(dataSource, 10);
// verify results (only successItem)
Assert.assertNotNull(results);
Assert.assertEquals(1, results.size());
Assert.assertEquals((Long) (DAY_SECONDS + 2), results.get(0).getDateAsLong());
Assert.assertTrue("/a/path".equalsIgnoreCase(results.get(0).getPath()));
}
@Test @Test
public void getRecentlyOpenedDocuments_filtersMissingData() throws SleuthkitCaseProviderException, TskCoreException { public void getRecentlyOpenedDocuments_filtersMissingData() throws SleuthkitCaseProviderException, TskCoreException {
DataSource dataSource = TskMockUtils.getDataSource(1); DataSource dataSource = TskMockUtils.getDataSource(1);
@ -368,6 +388,30 @@ public class RecentFilesSummaryTest {
} }
} }
@Test
public void getRecentDownloads_uniquePaths() throws SleuthkitCaseProviderException, TskCoreException {
DataSource dataSource = TskMockUtils.getDataSource(1);
BlackboardArtifact item1 = getRecentDownloadArtifact(dataSource, 1001, DAY_SECONDS, "domain1.com", "/a/path1");
BlackboardArtifact item1a = getRecentDownloadArtifact(dataSource, 10011, DAY_SECONDS + 1, "domain1.com", "/a/path1");
BlackboardArtifact item2 = getRecentDownloadArtifact(dataSource, 1002, DAY_SECONDS + 2, "domain2.com", "/a/path1");
BlackboardArtifact item3 = getRecentDownloadArtifact(dataSource, 1003, DAY_SECONDS + 3, "domain2a.com", "/a/path1");
List<BlackboardArtifact> artifacts = Arrays.asList(item2, item3, item1);
Pair<SleuthkitCase, Blackboard> casePair = DataSourceSummaryMockUtils.getArtifactsTSKMock(RandomizationUtils.getMixedUp(artifacts));
RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft());
// call method
List<RecentDownloadDetails> results = summary.getRecentDownloads(dataSource, 10);
// verify results
Assert.assertNotNull(results);
Assert.assertEquals(1, results.size());
Assert.assertEquals((Long) (DAY_SECONDS + 3), results.get(0).getDateAsLong());
Assert.assertTrue("/a/path1".equalsIgnoreCase(results.get(0).getPath()));
Assert.assertTrue("domain2a.com".equalsIgnoreCase(results.get(0).getWebDomain()));
}
@Test @Test
public void getRecentDownloads_filtersMissingData() throws SleuthkitCaseProviderException, TskCoreException { public void getRecentDownloads_filtersMissingData() throws SleuthkitCaseProviderException, TskCoreException {
DataSource dataSource = TskMockUtils.getDataSource(1); DataSource dataSource = TskMockUtils.getDataSource(1);
@ -410,16 +454,14 @@ public class RecentFilesSummaryTest {
* *
* @param messageArtifactTypeId The type id for the artifact or null if * @param messageArtifactTypeId The type id for the artifact or null if
* no message artifact to be created. * no message artifact to be created.
* @param emailFrom Who the message is from or null not to * @param emailFrom Who the message is from or null not to include
* include attribute. * attribute.
* @param messageTime Time in seconds from epoch or null not * @param messageTime Time in seconds from epoch or null not to include
* to include attribute. * attribute.
* @param fileParentPath The parent AbstractFile's path value. * @param fileParentPath The parent AbstractFile's path value.
* @param fileName The parent AbstractFile's filename * @param fileName The parent AbstractFile's filename value.
* value.
* @param associatedAttrFormed If false, the TSK_ASSOCIATED_OBJECT * @param associatedAttrFormed If false, the TSK_ASSOCIATED_OBJECT
* artifact has no attribute (even though * artifact has no attribute (even though it is required).
* it is required).
* @param hasParent Whether or not the artifact has a parent * @param hasParent Whether or not the artifact has a parent
* AbstractFile. * AbstractFile.
*/ */
@ -442,13 +484,12 @@ public class RecentFilesSummaryTest {
* *
* @param messageArtifactTypeId The type id for the artifact or null if * @param messageArtifactTypeId The type id for the artifact or null if
* no message artifact to be created. * no message artifact to be created.
* @param emailFrom Who the message is from or null not to * @param emailFrom Who the message is from or null not to include
* include attribute. * attribute.
* @param messageTime Time in seconds from epoch or null not * @param messageTime Time in seconds from epoch or null not to include
* to include attribute. * attribute.
* @param fileParentPath The parent AbstractFile's path value. * @param fileParentPath The parent AbstractFile's path value.
* @param fileName The parent AbstractFile's filename * @param fileName The parent AbstractFile's filename value.
* value.
*/ */
AttachmentArtifactItem(Integer messageArtifactTypeId, String emailFrom, Long messageTime, String fileParentPath, String fileName) { AttachmentArtifactItem(Integer messageArtifactTypeId, String emailFrom, Long messageTime, String fileParentPath, String fileName) {
this(messageArtifactTypeId, emailFrom, messageTime, fileParentPath, fileName, true, true); this(messageArtifactTypeId, emailFrom, messageTime, fileParentPath, fileName, true, true);
@ -678,4 +719,34 @@ public class RecentFilesSummaryTest {
.toString().equalsIgnoreCase(successItem2Details.getPath())); .toString().equalsIgnoreCase(successItem2Details.getPath()));
Assert.assertTrue(successItem2.getEmailFrom().equalsIgnoreCase(successItem2Details.getSender())); Assert.assertTrue(successItem2.getEmailFrom().equalsIgnoreCase(successItem2Details.getSender()));
} }
@Test
public void getRecentAttachments_uniquePath() throws SleuthkitCaseProviderException, TskCoreException {
// setup data
DataSource dataSource = TskMockUtils.getDataSource(1);
AttachmentArtifactItem item1 = new AttachmentArtifactItem(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
"person@sleuthkit.com", DAY_SECONDS, "/parent/path", "msg.pdf");
AttachmentArtifactItem item2 = new AttachmentArtifactItem(ARTIFACT_TYPE.TSK_MESSAGE.getTypeID(),
"person_on_skype", DAY_SECONDS + 1, "/parent/path", "msg.pdf");
AttachmentArtifactItem item3 = new AttachmentArtifactItem(ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(),
"person2@sleuthkit.com", DAY_SECONDS + 2, "/parent/path", "msg.pdf");
List<AttachmentArtifactItem> items = Arrays.asList(item1, item2, item3);
Pair<SleuthkitCase, Blackboard> casePair = getRecentAttachmentArtifactCase(items);
RecentFilesSummary summary = new RecentFilesSummary(() -> casePair.getLeft());
// get data
List<RecentAttachmentDetails> results = summary.getRecentAttachments(dataSource, 10);
// verify results
Assert.assertNotNull(results);
Assert.assertEquals(1, results.size());
Assert.assertEquals(results.get(0).getDateAsLong(), (Long) (DAY_SECONDS + 2));
Assert.assertTrue(Paths.get(item3.getFileParentPath(), item3.getFileName())
.toString().equalsIgnoreCase(results.get(0).getPath()));
Assert.assertTrue(results.get(0).getSender().equalsIgnoreCase(item3.getEmailFrom()));
}
} }

View File

@ -66,12 +66,16 @@ import org.sleuthkit.datamodel.TskCoreException;
* Tests for UserActivitySummary. * Tests for UserActivitySummary.
*/ */
public class UserActivitySummaryTest { public class UserActivitySummaryTest {
/** /**
* Function to retrieve data from UserActivitySummary with the provided arguments. * Function to retrieve data from UserActivitySummary with the provided
* arguments.
*/ */
private interface DataFunction<T> { private interface DataFunction<T> {
/** /**
* A UserActivitySummary method encapsulated in a uniform manner. * A UserActivitySummary method encapsulated in a uniform manner.
*
* @param userActivitySummary The UserActivitySummary class to use. * @param userActivitySummary The UserActivitySummary class to use.
* @param datasource The data source. * @param datasource The data source.
* @param count The count. * @param count The count.
@ -333,6 +337,28 @@ public class UserActivitySummaryTest {
} }
} }
@Test
public void getRecentDevices_uniqueByDeviceId()
throws TskCoreException, NoServiceProviderException, SleuthkitCaseProviderException, TskCoreException, TranslationException {
long dataSourceId = 1L;
DataSource dataSource = TskMockUtils.getDataSource(dataSourceId);
BlackboardArtifact item1 = getRecentDeviceArtifact(1001, dataSource, "ID1", "MAKE1", "MODEL1", DAY_SECONDS);
BlackboardArtifact item2 = getRecentDeviceArtifact(1002, dataSource, "ID1", "MAKE1", "MODEL1", DAY_SECONDS + 1);
BlackboardArtifact item3 = getRecentDeviceArtifact(1003, dataSource, "ID1", "MAKE1", "MODEL1", DAY_SECONDS + 2);
Pair<SleuthkitCase, Blackboard> tskPair = getArtifactsTSKMock(Arrays.asList(item1, item2, item3));
UserActivitySummary summary = getTestClass(tskPair.getLeft(), false, null);
List<TopDeviceAttachedResult> results = summary.getRecentDevices(dataSource, 10);
Assert.assertEquals(1, results.size());
Assert.assertEquals((long) (DAY_SECONDS + 2), results.get(0).getDateAccessed().getTime() / 1000);
Assert.assertTrue("ID1".equalsIgnoreCase(results.get(0).getDeviceId()));
Assert.assertTrue("MAKE1".equalsIgnoreCase(results.get(0).getDeviceMake()));
Assert.assertTrue("MODEL1".equalsIgnoreCase(results.get(0).getDeviceModel()));
}
private static BlackboardArtifact getWebSearchArtifact(long artifactId, DataSource dataSource, String query, Long date) { private static BlackboardArtifact getWebSearchArtifact(long artifactId, DataSource dataSource, String query, Long date) {
try { try {
return TskMockUtils.getArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY), artifactId, dataSource, return TskMockUtils.getArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY), artifactId, dataSource,
@ -797,8 +823,8 @@ public class UserActivitySummaryTest {
* @param dataSource The datasource to use as parameter. * @param dataSource The datasource to use as parameter.
* @param count The count to use as a parameter. * @param count The count to use as a parameter.
* @param retArtifacts The artifacts to return from * @param retArtifacts The artifacts to return from
* SleuthkitCase.getArtifacts. This method filters * SleuthkitCase.getArtifacts. This method filters based on artifact type
* based on artifact type from the call. * from the call.
* @param expectedResults The expected results. * @param expectedResults The expected results.
* *
* @throws TskCoreException * @throws TskCoreException

View File

@ -205,7 +205,9 @@ DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}...
DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}... DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}...
DeleteCaseTask.progress.startMessage=Starting deletion... DeleteCaseTask.progress.startMessage=Starting deletion...
DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes
# {0} - item count
DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0} DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}
# {0} - item count
DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0} DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}
DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service
# {0} - node path # {0} - node path

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2015 Basis Technology Corp. * Copyright 2015 - 2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -151,6 +151,8 @@ public class SharedConfiguration {
/** /**
* Upload the current multi-user ingest settings to a shared folder. * Upload the current multi-user ingest settings to a shared folder.
* *
* @return
*
* @throws SharedConfigurationException * @throws SharedConfigurationException
* @throws CoordinationServiceException * @throws CoordinationServiceException
* @throws InterruptedException * @throws InterruptedException
@ -208,6 +210,7 @@ public class SharedConfiguration {
uploadCentralRepositorySettings(remoteFolder); uploadCentralRepositorySettings(remoteFolder);
uploadObjectDetectionClassifiers(remoteFolder); uploadObjectDetectionClassifiers(remoteFolder);
uploadPythonModules(remoteFolder); uploadPythonModules(remoteFolder);
uploadYARASetting(remoteFolder);
try { try {
Files.deleteIfExists(uploadInProgress.toPath()); Files.deleteIfExists(uploadInProgress.toPath());
@ -222,6 +225,8 @@ public class SharedConfiguration {
/** /**
* Download the multi-user settings from a shared folder. * Download the multi-user settings from a shared folder.
* *
* @return
*
* @throws SharedConfigurationException * @throws SharedConfigurationException
* @throws InterruptedException * @throws InterruptedException
*/ */
@ -252,13 +257,16 @@ public class SharedConfiguration {
} }
try { try {
/* Make sure all recent changes are saved to the preference file. /*
This also releases open file handles to the preference files. If this * Make sure all recent changes are saved to the preference
is not done, then occasionally downloading of shared configuration * file. This also releases open file handles to the preference
fails silently, likely because Java/OS is still holding the file handle. * files. If this is not done, then occasionally downloading of
The problem manifests itself by some of the old/original configuration files * shared configuration fails silently, likely because Java/OS
sticking around after shared configuration has seemingly been successfully * is still holding the file handle. The problem manifests
updated. */ * itself by some of the old/original configuration files
* sticking around after shared configuration has seemingly been
* successfully updated.
*/
UserPreferences.saveToStorage(); UserPreferences.saveToStorage();
} catch (BackingStoreException ex) { } catch (BackingStoreException ex) {
throw new SharedConfigurationException("Failed to save shared configuration settings", ex); throw new SharedConfigurationException("Failed to save shared configuration settings", ex);
@ -275,6 +283,7 @@ public class SharedConfiguration {
downloadCentralRepositorySettings(remoteFolder); downloadCentralRepositorySettings(remoteFolder);
downloadObjectDetectionClassifiers(remoteFolder); downloadObjectDetectionClassifiers(remoteFolder);
downloadPythonModules(remoteFolder); downloadPythonModules(remoteFolder);
downloadYARASettings(remoteFolder);
// Download general settings, then restore the current // Download general settings, then restore the current
// values for the unshared fields // values for the unshared fields
@ -517,10 +526,12 @@ public class SharedConfiguration {
} }
/** /**
* Copy an entire local settings folder to the remote folder, deleting any existing files. * Copy an entire local settings folder to the remote folder, deleting any
* existing files.
* *
* @param localFolder The local folder to copy * @param localFolder The local folder to copy
* @param remoteBaseFolder The remote folder that will hold a copy of the original folder * @param remoteBaseFolder The remote folder that will hold a copy of the
* original folder
* *
* @throws SharedConfigurationException * @throws SharedConfigurationException
*/ */
@ -546,11 +557,12 @@ public class SharedConfiguration {
} }
/** /**
* Copy an entire remote settings folder to the local folder, deleting any existing files. * Copy an entire remote settings folder to the local folder, deleting any
* No error if the remote folder does not exist. * existing files. No error if the remote folder does not exist.
* *
* @param localFolder The local folder that will be overwritten. * @param localFolder The local folder that will be overwritten.
* @param remoteBaseFolder The remote folder holding the folder that will be copied * @param remoteBaseFolder The remote folder holding the folder that will be
* copied
* *
* @throws SharedConfigurationException * @throws SharedConfigurationException
*/ */
@ -1093,12 +1105,10 @@ public class SharedConfiguration {
Map<String, String> remoteVersions = readVersionsFromFile(remoteVersionFile); Map<String, String> remoteVersions = readVersionsFromFile(remoteVersionFile);
/* /*
Iterate through remote list * Iterate through remote list If local needs it, download
If local needs it, download *
* Download remote settings files to local Download remote versions file
Download remote settings files to local * to local HashDbManager reload
Download remote versions file to local
HashDbManager reload
*/ */
File localDb = new File(""); File localDb = new File("");
File sharedDb = new File(""); File sharedDb = new File("");
@ -1356,4 +1366,41 @@ public class SharedConfiguration {
throw new SharedConfigurationException(String.format("Failed to calculate CRC for %s", file.getAbsolutePath()), ex); throw new SharedConfigurationException(String.format("Failed to calculate CRC for %s", file.getAbsolutePath()), ex);
} }
} }
/**
* Copy the YARA settings directory from the local directory to the remote
* directory.
*
* @param remoteFolder Shared settings folder
*
* @throws
* org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException
*/
private void uploadYARASetting(File remoteFolder) throws SharedConfigurationException {
publishTask("Uploading YARA module configuration");
File localYara = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), "yara").toFile();
if (!localYara.exists()) {
return;
}
copyLocalFolderToRemoteFolder(localYara, remoteFolder);
}
/**
* Downloads the YARA settings folder from the remote directory to the local
* one.
*
* @param remoteFolder Shared settings folder
*
* @throws
* org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException
*/
private void downloadYARASettings(File remoteFolder) throws SharedConfigurationException {
publishTask("Downloading YARA module configuration");
File localYara = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), "yara").toFile();
copyRemoteFolderToLocalFolder(localYara, remoteFolder);
}
} }

View File

@ -61,6 +61,7 @@ ExtractOS_progressMessage=Checking for OS
ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files
ExtractPrefetch_module_name=Windows Prefetch Extractor ExtractPrefetch_module_name=Windows Prefetch Extractor
ExtractRecycleBin_module_name=Recycle Bin ExtractRecycleBin_module_name=Recycle Bin
ExtractRecycleBin_Recyle_Bin_Display_Name=Recycle Bin
ExtractSafari_Error_Getting_History=An error occurred while processing Safari history files. ExtractSafari_Error_Getting_History=An error occurred while processing Safari history files.
ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files
ExtractSafari_Error_Parsing_Cookies=An error occured while processing Safari Cookies files ExtractSafari_Error_Parsing_Cookies=An error occured while processing Safari Cookies files
@ -84,16 +85,9 @@ ExtractZone_progress_Msg=Extracting :Zone.Identifer files
ExtractZone_Restricted=Restricted Sites Zone ExtractZone_Restricted=Restricted Sites Zone
ExtractZone_Trusted=Trusted Sites Zone ExtractZone_Trusted=Trusted Sites Zone
OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\nThe module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy. OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n\The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy.
OpenIDE-Module-Name=RecentActivity OpenIDE-Module-Name=RecentActivity
OpenIDE-Module-Short-Description=Recent Activity finder ingest module OpenIDE-Module-Short-Description=Recent Activity finder ingest module
Browser.name.Microsoft.Edge=Microsoft Edge
Browser.name.Yandex=Yandex
Browser.name.Opera=Opera
Browser.name.SalamWeb=SalamWeb
Browser.name.UC.Browser=UC Browser
Browser.name.Brave=Brave
Browser.name.Google.Chrome=Google Chrome
Chrome.moduleName=Chromium Chrome.moduleName=Chromium
Chrome.getHistory.errMsg.errGettingFiles=Error when trying to get Chrome history files. Chrome.getHistory.errMsg.errGettingFiles=Error when trying to get Chrome history files.
Chrome.getHistory.errMsg.couldntFindAnyFiles=Could not find any allocated Chrome history files. Chrome.getHistory.errMsg.couldntFindAnyFiles=Could not find any allocated Chrome history files.

View File

@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -415,6 +416,9 @@ final class ExtractRecycleBin extends Extract {
return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID()))); return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID())));
} }
@Messages({
"ExtractRecycleBin_Recyle_Bin_Display_Name=Recycle Bin"
})
/** /**
* Create TSK_RECYCLE_BIN artifact type. * Create TSK_RECYCLE_BIN artifact type.
* *
@ -422,9 +426,9 @@ final class ExtractRecycleBin extends Extract {
*/ */
private void createRecycleBinArtifactType() throws TskCoreException { private void createRecycleBinArtifactType() throws TskCoreException {
try { try {
tskCase.addBlackboardArtifactType(RECYCLE_BIN_ARTIFACT_NAME, "Recycle Bin"); //NON-NLS tskCase.getBlackboard().getOrAddArtifactType(RECYCLE_BIN_ARTIFACT_NAME, Bundle.ExtractRecycleBin_Recyle_Bin_Display_Name()); //NON-NLS
} catch (TskDataException ex) { } catch (BlackboardException ex) {
logger.log(Level.INFO, String.format("%s may have already been defined for this case", RECYCLE_BIN_ARTIFACT_NAME)); throw new TskCoreException(String.format("An exception was thrown while defining artifact type %s", RECYCLE_BIN_ARTIFACT_NAME), ex);
} }
} }

View File

@ -68,6 +68,7 @@ import java.util.Set;
import java.util.HashSet; import java.util.HashSet;
import static java.util.Locale.US; import static java.util.Locale.US;
import static java.util.TimeZone.getTimeZone; import static java.util.TimeZone.getTimeZone;
import org.openide.util.Exceptions;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -77,6 +78,7 @@ import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.autopsy.recentactivity.ShellBagParser.ShellBag; import org.sleuthkit.autopsy.recentactivity.ShellBagParser.ShellBag;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT;
@ -1960,18 +1962,11 @@ class ExtractRegistry extends Extract {
* @throws TskCoreException * @throws TskCoreException
*/ */
private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException { private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException {
if (shellBagArtifactType == null) {
shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME);
if (shellBagArtifactType == null) { if (shellBagArtifactType == null) {
try { try {
tskCase.addBlackboardArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name()); //NON-NLS shellBagArtifactType = tskCase.getBlackboard().getOrAddArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name());
} catch (TskDataException ex) { } catch (BlackboardException ex) {
// Artifact already exists throw new TskCoreException(String.format("Failed to get shell bag artifact type", SHELLBAG_ARTIFACT_NAME), ex);
logger.log(Level.INFO, String.format("%s may have already been defined for this case", SHELLBAG_ARTIFACT_NAME));
}
shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME);
} }
} }
@ -1989,12 +1984,12 @@ class ExtractRegistry extends Extract {
private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException { private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException {
if (shellBagLastWriteAttributeType == null) { if (shellBagLastWriteAttributeType == null) {
try { try {
shellBagLastWriteAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE, shellBagLastWriteAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME,
Bundle.Shellbag_Last_Write_Attribute_Display_Name()); Bundle.Shellbag_Last_Write_Attribute_Display_Name());
} catch (TskDataException ex) { } catch (BlackboardException ex) {
// Attribute already exists get it from the case // Attribute already exists get it from the case
shellBagLastWriteAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE); throw new TskCoreException(String.format("Failed to get custom attribute %s", SHELLBAG_ATTRIBUTE_LAST_WRITE), ex);
} }
} }
return shellBagLastWriteAttributeType; return shellBagLastWriteAttributeType;
@ -2011,12 +2006,11 @@ class ExtractRegistry extends Extract {
private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException { private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException {
if (shellBagKeyAttributeType == null) { if (shellBagKeyAttributeType == null) {
try { try {
shellBagKeyAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_KEY, shellBagKeyAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_KEY,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
Bundle.Shellbag_Key_Attribute_Display_Name()); Bundle.Shellbag_Key_Attribute_Display_Name());
} catch (TskDataException ex) { } catch (BlackboardException ex) {
// The attribute already exists get it from the case throw new TskCoreException(String.format("Failed to get key attribute %s", SHELLBAG_ATTRIBUTE_KEY), ex);
shellBagKeyAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_KEY);
} }
} }
return shellBagKeyAttributeType; return shellBagKeyAttributeType;

View File

@ -76,6 +76,10 @@
<sysproperty key="solrPort" value="${solrPort}"/> <sysproperty key="solrPort" value="${solrPort}"/>
<sysproperty key="messageServiceHost" value="${messageServiceHost}"/> <sysproperty key="messageServiceHost" value="${messageServiceHost}"/>
<sysproperty key="messageServicePort" value="${messageServicePort}"/> <sysproperty key="messageServicePort" value="${messageServicePort}"/>
<sysproperty key="crHost" value="${crHost}"/>
<sysproperty key="crPort" value="${crPort}"/>
<sysproperty key="crUserName" value="${crUserName}"/>
<sysproperty key="crPassword" value="${crPassword}"/>
<sysproperty key="isMultiUser" value="${isMultiUser}"/> <sysproperty key="isMultiUser" value="${isMultiUser}"/>
<!--needed to have tests NOT to steal focus when running, works in latest apple jdk update only.--> <!--needed to have tests NOT to steal focus when running, works in latest apple jdk update only.-->
<sysproperty key="apple.awt.UIElement" value="@{disable.apple.ui}"/> <sysproperty key="apple.awt.UIElement" value="@{disable.apple.ui}"/>

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2018 Basis Technology Corp. * Copyright 2011-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -25,6 +25,9 @@ import junit.framework.Test;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.netbeans.jemmy.Timeouts; import org.netbeans.jemmy.Timeouts;
import org.netbeans.junit.NbModuleSuite; import org.netbeans.junit.NbModuleSuite;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
/** /**
* This test expects the following system properties to be set: img_path: The * This test expects the following system properties to be set: img_path: The
@ -100,6 +103,21 @@ public class RegressionTest extends TestCase {
public void setUp() { public void setUp() {
logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######"); logger.info("######## " + AutopsyTestCases.getEscapedPath(System.getProperty("img_path")) + " #######");
Timeouts.setDefault("ComponentOperator.WaitComponentTimeout", 1000000); Timeouts.setDefault("ComponentOperator.WaitComponentTimeout", 1000000);
try {
if (Boolean.parseBoolean(System.getProperty("isMultiUser"))) {
// Set up a custom postgres CR using the configuration passed
// to system properties.
CentralRepoDbManager manager = new CentralRepoDbManager();
manager.getDbSettingsPostgres().setHost(System.getProperty("crHost"));
manager.getDbSettingsPostgres().setPort(Integer.parseInt(System.getProperty("crPort")));
manager.getDbSettingsPostgres().setUserName(System.getProperty("crUserName"));
manager.getDbSettingsPostgres().setPassword(System.getProperty("crPassword"));
manager.setupPostgresDb(CentralRepoDbChoice.POSTGRESQL_CUSTOM);
}
} catch (CentralRepoException ex) {
throw new RuntimeException("Error setting up multi user CR", ex);
}
} }
/** /**

View File

@ -13,7 +13,7 @@ You should ensure that the database folder is backed up.
To install PostgreSQL, perform the following steps: To install PostgreSQL, perform the following steps:
1. Download a 64-bit PostgreSQL installer from http://www.enterprisedb.com/products-services-training/pgdownload#windows Choose the one that says _Win X86-64_. Autopsy has been tested with PostgreSQL version 9.5. 1. Download a 64-bit PostgreSQL installer from https://www.enterprisedb.com/downloads/postgres-postgresql-downloads Choose one under Windows x86-64. Autopsy has been tested with PostgreSQL version 9.5.
2. Run the installer. The name will be similar to _postgresql-9.5.3-1-windows-x64.exe_. 2. Run the installer. The name will be similar to _postgresql-9.5.3-1-windows-x64.exe_.

View File

@ -471,6 +471,10 @@ class TestRunner(object):
test_data.ant.append("-DsolrPort=" + str(test_config.solrPort)) test_data.ant.append("-DsolrPort=" + str(test_config.solrPort))
test_data.ant.append("-DmessageServiceHost=" + test_config.messageServiceHost) test_data.ant.append("-DmessageServiceHost=" + test_config.messageServiceHost)
test_data.ant.append("-DmessageServicePort=" + str(test_config.messageServicePort)) test_data.ant.append("-DmessageServicePort=" + str(test_config.messageServicePort))
test_data.ant.append("-DcrHost=" + str(test_config.crHost))
test_data.ant.append("-DcrPort=" + str(test_config.crPort))
test_data.ant.append("-DcrUserName=" + str(test_config.crUserName))
test_data.ant.append("-DcrPassword=" + str(test_config.crPassword))
if test_data.isMultiUser: if test_data.isMultiUser:
test_data.ant.append("-DisMultiUser=true") test_data.ant.append("-DisMultiUser=true")
# Note: test_data has autopys_version attribute, but we couldn't see it from here. It's set after run ingest. # Note: test_data has autopys_version attribute, but we couldn't see it from here. It's set after run ingest.
@ -854,6 +858,14 @@ class TestConfiguration(object):
self.messageServicePort = parsed_config.getElementsByTagName("messageServicePort")[0].getAttribute("value").encode().decode("utf_8") self.messageServicePort = parsed_config.getElementsByTagName("messageServicePort")[0].getAttribute("value").encode().decode("utf_8")
if parsed_config.getElementsByTagName("multiUser_outdir"): if parsed_config.getElementsByTagName("multiUser_outdir"):
self.multiUser_outdir = parsed_config.getElementsByTagName("multiUser_outdir")[0].getAttribute("value").encode().decode("utf_8") self.multiUser_outdir = parsed_config.getElementsByTagName("multiUser_outdir")[0].getAttribute("value").encode().decode("utf_8")
if parsed_config.getElementsByTagName("crHost"):
self.crHost = parsed_config.getElementsByTagName("crHost")[0].getAttribute("value").encode().decode("utf_8")
if parsed_config.getElementsByTagName("crPort"):
self.crPort = parsed_config.getElementsByTagName("crPort")[0].getAttribute("value").encode().decode("utf_8")
if parsed_config.getElementsByTagName("crUserName"):
self.crUserName = parsed_config.getElementsByTagName("crUserName")[0].getAttribute("value").encode().decode("utf_8")
if parsed_config.getElementsByTagName("crPassword"):
self.crPassword = parsed_config.getElementsByTagName("crPassword")[0].getAttribute("value").encode().decode("utf_8")
self._init_imgs(parsed_config) self._init_imgs(parsed_config)
self._init_build_info(parsed_config) self._init_build_info(parsed_config)

View File

@ -27,7 +27,7 @@ def make_os_path(platform, *dirs):
path += str(dir).replace('\\', '/') + '/' path += str(dir).replace('\\', '/') + '/'
return path_fix(path) return path_fix(path)
elif platform == "win32": elif platform == "win32":
return make_path(dirs) return make_path(*dirs)
else: else:
print("Couldn't make path, because we only support Windows and Cygwin at this time.") print("Couldn't make path, because we only support Windows and Cygwin at this time.")
sys.exit(1) sys.exit(1)

Binary file not shown.

View File

@ -1,7 +1,7 @@
This folder contains the projects you need for building and testing the yarabridge.dll and YaraJNIWrapper.jar. This folder contains the projects you need for building and testing the yarabridge.dll and YaraJNIWrapper.jar.
bin: bin:
Contains the built dll and jar. Contains the built jar and jarac64.exe. jarac64.exe is used to by the ingest module to compile the rule files.
yarabridge: yarabridge:
VS project to create the dll that wraps the the libyara library. VS project to create the dll that wraps the the libyara library.
@ -18,7 +18,8 @@ Steps for building yarabridge, YaraJNIWrapper and YaraWrapperTest.
- Build Release x64. - Build Release x64.
3. Open the yarabridge project and build Release x64. 3. Open the yarabridge project and build Release x64.
-If you have link issues, make sure you build release x64 in the previous step. -If you have link issues, make sure you build release x64 in the previous step.
-This project will automatically copy the built dll to the bin folder. -This project will automatically copy the built dll into the YaraJNIWrapper src\org\sleuthkit\autopsy\yara folder.
- This is where is needs to be so that its included into the jar file.
4. Build YaraJNIWrapper 4. Build YaraJNIWrapper
- Open in netbeans and select Build. - Open in netbeans and select Build.
- Manually move the newly build jar file to the bin folder. After building the jar file can be found in - Manually move the newly build jar file to the bin folder. After building the jar file can be found in

View File

@ -179,9 +179,7 @@ is divided into following sections:
</and> </and>
</condition> </condition>
<condition property="have.tests"> <condition property="have.tests">
<or> <or/>
<available file="${test.src.dir}"/>
</or>
</condition> </condition>
<condition property="have.sources"> <condition property="have.sources">
<or> <or>
@ -289,7 +287,6 @@ is divided into following sections:
</target> </target>
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check"> <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail> <fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail> <fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail> <fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail> <fail unless="build.classes.dir">Must set build.classes.dir</fail>
@ -588,9 +585,6 @@ is divided into following sections:
<j2seproject3:junit-prototype> <j2seproject3:junit-prototype>
<customizePrototype> <customizePrototype>
<batchtest todir="${build.test.results.dir}"> <batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
<fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}"> <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
<filename name="${test.binarytestincludes}"/> <filename name="${test.binarytestincludes}"/>
</fileset> </fileset>
@ -613,11 +607,7 @@ is divided into following sections:
<condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}"> <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
<isset property="test.method"/> <isset property="test.method"/>
</condition> </condition>
<union id="test.set"> <union id="test.set"/>
<fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</union>
<taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/> <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
<testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="YaraJNIWrapper" testname="TestNG tests" workingDir="${work.dir}"> <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="YaraJNIWrapper" testname="TestNG tests" workingDir="${work.dir}">
<xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/> <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
@ -1544,14 +1534,14 @@ is divided into following sections:
<!-- You can override this target in the ../build.xml file. --> <!-- You can override this target in the ../build.xml file. -->
</target> </target>
<target depends="-init-source-module-properties" if="named.module.internal" name="-init-test-javac-module-properties-with-module"> <target depends="-init-source-module-properties" if="named.module.internal" name="-init-test-javac-module-properties-with-module">
<j2seproject3:modulename property="test.module.name" sourcepath="${test.src.dir}"/> <j2seproject3:modulename property="test.module.name" sourcepath=""/>
<condition else="${empty.dir}" property="javac.test.sourcepath" value="${test.src.dir}"> <condition else="${empty.dir}" property="javac.test.sourcepath" value="">
<and> <and>
<isset property="test.module.name"/> <isset property="test.module.name"/>
<length length="0" string="${test.module.name}" when="greater"/> <length length="0" string="${test.module.name}" when="greater"/>
</and> </and>
</condition> </condition>
<condition else="--patch-module ${module.name}=${test.src.dir} --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED"> <condition else="--patch-module ${module.name}= --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED">
<and> <and>
<isset property="test.module.name"/> <isset property="test.module.name"/>
<length length="0" string="${test.module.name}" when="greater"/> <length length="0" string="${test.module.name}" when="greater"/>
@ -1592,17 +1582,15 @@ is divided into following sections:
</target> </target>
<target depends="-init-test-javac-module-properties-with-module,-init-test-module-properties-without-module" name="-init-test-module-properties"/> <target depends="-init-test-javac-module-properties-with-module,-init-test-module-properties-without-module" name="-init-test-module-properties"/>
<target if="do.depend.true" name="-compile-test-depend"> <target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/> <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir=""/>
</target> </target>
<target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test"> <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="${test.src.dir}"> <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="">
<customize> <customize>
<compilerarg line="${javac.test.compilerargs}"/> <compilerarg line="${javac.test.compilerargs}"/>
</customize> </customize>
</j2seproject3:javac> </j2seproject3:javac>
<copy todir="${build.test.classes.dir}"> <copy todir="${build.test.classes.dir}"/>
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target> </target>
<target name="-post-compile-test"> <target name="-post-compile-test">
<!-- Empty placeholder for easier customization. --> <!-- Empty placeholder for easier customization. -->
@ -1616,14 +1604,12 @@ is divided into following sections:
<target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single"> <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail> <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/> <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"> <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="" srcdir="">
<customize> <customize>
<compilerarg line="${javac.test.compilerargs}"/> <compilerarg line="${javac.test.compilerargs}"/>
</customize> </customize>
</j2seproject3:javac> </j2seproject3:javac>
<copy todir="${build.test.classes.dir}"> <copy todir="${build.test.classes.dir}"/>
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target> </target>
<target name="-post-compile-test-single"> <target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. --> <!-- Empty placeholder for easier customization. -->

View File

@ -1,4 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project-private xmlns="http://www.netbeans.org/ns/project-private/1"> <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group>
<file>file:/C:/Users/kelly/Workspace/autopsy/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/YaraJNIWrapper.java</file>
</group>
</open-files>
</project-private> </project-private>

View File

@ -1,9 +1,10 @@
annotation.processing.enabled=true annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false annotation.processing.enabled.in.editor=false
annotation.processing.processor.options=
annotation.processing.processors.list= annotation.processing.processors.list=
annotation.processing.run.all.processors=true annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
application.title=YaraJNIWrapper
application.vendor=kelly
build.classes.dir=${build.dir}/classes build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned: # This directory is removed when the project is cleaned:
@ -32,10 +33,13 @@ dist.jar=${dist.dir}/YaraJNIWrapper.jar
dist.javadoc.dir=${dist.dir}/javadoc dist.javadoc.dir=${dist.dir}/javadoc
dist.jlink.dir=${dist.dir}/jlink dist.jlink.dir=${dist.dir}/jlink
dist.jlink.output=${dist.jlink.dir}/YaraJNIWrapper dist.jlink.output=${dist.jlink.dir}/YaraJNIWrapper
endorsed.classpath=
excludes= excludes=
file.reference.yara-lib=src/org/sleuthkit/autopsy/yara/lib
includes=** includes=**
jar.compress=false jar.compress=false
javac.classpath= javac.classpath=\
${file.reference.yara-lib}
# Space-separated list of extra javac options # Space-separated list of extra javac options
javac.compilerargs= javac.compilerargs=
javac.deprecation=false javac.deprecation=false
@ -90,4 +94,3 @@ run.test.modulepath=\
${javac.test.modulepath} ${javac.test.modulepath}
source.encoding=UTF-8 source.encoding=UTF-8
src.dir=src src.dir=src
test.src.dir=test

View File

@ -7,9 +7,7 @@
<source-roots> <source-roots>
<root id="src.dir"/> <root id="src.dir"/>
</source-roots> </source-roots>
<test-roots> <test-roots/>
<root id="test.src.dir"/>
</test-roots>
</data> </data>
</configuration> </configuration>
</project> </project>

View File

@ -18,9 +18,11 @@
*/ */
package org.sleuthkit.autopsy.yara; package org.sleuthkit.autopsy.yara;
import java.net.URISyntaxException; import java.io.File;
import java.nio.file.Path; import java.io.FileOutputStream;
import java.nio.file.Paths; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -31,18 +33,12 @@ import java.util.logging.Logger;
*/ */
public class YaraJNIWrapper { public class YaraJNIWrapper {
// Load the yarabridge.dll which should be located in the same directory as
// the jar file. If we need to use this code for debugging the dll this
// code will need to be modified to add that support.
static { static {
Path directoryPath = null;
try { try {
directoryPath = Paths.get(YaraJNIWrapper.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent().toAbsolutePath(); extractAndLoadDll();
} catch (URISyntaxException ex) { } catch (IOException | YaraWrapperException ex) {
Logger.getLogger(YaraJNIWrapper.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(YaraJNIWrapper.class.getName()).log(Level.SEVERE, null, ex);
} }
String libraryPath = Paths.get(directoryPath != null ? directoryPath.toString() : "", "yarabridge.dll").toAbsolutePath().toString();
System.load(libraryPath);
} }
/** /**
@ -50,14 +46,60 @@ public class YaraJNIWrapper {
* *
* The rule path must be to a yara compile rule file. * The rule path must be to a yara compile rule file.
* *
* @param compiledRulesPath * @param compiledRulesPath Absolute path to a compiled YARA rule file.
* @param byteBuffer * @param byteBuffer File buffer.
* @param bufferSize Size of the byte to read in the given buffer
* @param timeoutSec Scan timeout value in seconds.
* *
* @return List of rules found rules. Null maybe returned if error occurred. * @return List of rules found rules. Null maybe returned if error occurred.
* *
* @throws YaraWrapperException * @throws YaraWrapperException
*/ */
static public native List<String> findRuleMatch(String compiledRulesPath, byte[] byteBuffer) throws YaraWrapperException; static public native List<String> findRuleMatch(String compiledRulesPath, byte[] byteBuffer, int bufferSize, int timeoutSec) throws YaraWrapperException;
/**
* Returns a list of matching YARA rules found in the given file.
*
* @param compiledRulePath Absolute path to a compiled YARA rule file.
* @param filePath Absolute path to the file to search.
* @param timeoutSec Scan timeout value in seconds.
*
* @return List of rules found rules. Null maybe returned if error occurred.
*
*
* @throws YaraWrapperException
*/
static public native List<String> findRuleMatchFile(String compiledRulePath, String filePath, int timeoutSec) throws YaraWrapperException;
/**
* Copy yarabridge.dll from inside the jar to a temp file that can be loaded
* with System.load.
*
* To make this work, the dll needs to be in the same folder as this source
* file. The dll needs to be located somewhere in the jar class path.
*
* @throws IOException
* @throws YaraWrapperException
*/
static private void extractAndLoadDll() throws IOException, YaraWrapperException {
File tempFile = File.createTempFile("lib", null);
tempFile.deleteOnExit();
try (InputStream in = YaraJNIWrapper.class.getResourceAsStream("yarabridge.dll")) {
if (in == null) {
throw new YaraWrapperException("native library was not found in jar file.");
}
try (OutputStream out = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[1024];
int lengthRead;
while ((lengthRead = in.read(buffer)) > 0) {
out.write(buffer, 0, lengthRead);
out.flush();
}
}
}
System.load(tempFile.getAbsolutePath());
}
/** /**
* private constructor. * private constructor.

View File

@ -35,7 +35,7 @@ dist.jlink.dir=${dist.dir}/jlink
dist.jlink.output=${dist.jlink.dir}/YaraWrapperTest dist.jlink.output=${dist.jlink.dir}/YaraWrapperTest
endorsed.classpath= endorsed.classpath=
excludes= excludes=
file.reference.YaraJNIWrapper.jar=../bin/YaraJNIWrapper.jar file.reference.YaraJNIWrapper.jar=../YaraJNIWrapper/dist/YaraJNIWrapper.jar
includes=** includes=**
jar.compress=false jar.compress=false
javac.classpath=\ javac.classpath=\

View File

@ -26,8 +26,6 @@ import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.sleuthkit.autopsy.yara.YaraJNIWrapper;
import org.sleuthkit.autopsy.yara.YaraWrapperException;
/** /**
* Tests the YaraJNIWrapper code. * Tests the YaraJNIWrapper code.
@ -43,6 +41,7 @@ public class YaraWrapperTest {
} }
testFileRuleMatch(args[0], args[1]); testFileRuleMatch(args[0], args[1]);
testFileRuleMatchFile(args[0], args[1]);
} }
/** /**
@ -58,7 +57,7 @@ public class YaraWrapperTest {
try { try {
byte[] data = Files.readAllBytes(path); byte[] data = Files.readAllBytes(path);
List<String> list = YaraJNIWrapper.findRuleMatch(compiledRulePath, data); List<String> list = YaraJNIWrapper.findRuleMatch(compiledRulePath, data, data.length, 100);
if (list != null) { if (list != null) {
if (list.isEmpty()) { if (list.isEmpty()) {
@ -78,4 +77,33 @@ public class YaraWrapperTest {
} }
} }
/**
* Test the call to findRuleMatchFile which takes a compiled rule file
* path and a path to a file.
*
* @param compiledRulePath
* @param filePath
*/
private static void testFileRuleMatchFile(String compiledRulePath, String filePath) {
try {
List<String> list = YaraJNIWrapper.findRuleMatchFile(compiledRulePath, filePath, 100);
if (list != null) {
if (list.isEmpty()) {
System.out.println("FindRuleMatch return an empty list");
} else {
System.out.println("Matching Rules:");
for (String s : list) {
System.out.println(s);
}
}
} else {
logger.log(Level.SEVERE, "FindRuleMatch return a null list");
}
} catch (YaraWrapperException ex) {
logger.log(Level.SEVERE, "Error thrown from yarabridge", ex);
}
}
} }

Binary file not shown.

Binary file not shown.

BIN
thirdparty/yara/bin/yarac64.exe vendored Executable file

Binary file not shown.

View File

@ -20,7 +20,6 @@
using std::string; using std::string;
using std::vector; using std::vector;
/* /*
Callback method to be passed to yr_rules_scan_mem method. Callback method to be passed to yr_rules_scan_mem method.
user_data is expected to be a pointer to a string vector. user_data is expected to be a pointer to a string vector.
@ -79,49 +78,85 @@ jobject createArrayList(JNIEnv *env, std::vector<std::string> vector) {
return list; return list;
} }
/*
Loads the compiled rules file returning a YARA error code.
Throws a java exeception if there are any issues.
*/
int loadRuleFile(JNIEnv * env, jstring compiledRulePath, YR_RULES **rules) {
char errorMessage[256];
const char *nativeString = env->GetStringUTFChars(compiledRulePath, 0);
int result = yr_rules_load(nativeString, rules);
if (result != ERROR_SUCCESS) {
sprintf_s(errorMessage, "Failed to load compiled yara rule %s (error code = %d)\n", nativeString, result);
throwException(env, errorMessage);
}
env->ReleaseStringUTFChars(compiledRulePath, nativeString);
return result;
}
/*
Initalize the YARA library, if needed. yr_initialize only needs to be called once.
*/
int initalizeYaraLibrary(JNIEnv * env) {
static int library_initalized = 0;
char errorMessage[256];
int result = ERROR_SUCCESS;
if (library_initalized == 0) {
if ((result = yr_initialize()) != ERROR_SUCCESS) {
sprintf_s(errorMessage, "libyara initialization error (%d)\n", result);
throwException(env, errorMessage);
}
library_initalized = 1;
}
return result;
}
/* /*
* Class: org_sleuthkit_autopsy_yara_YaraJNIWrapper * Class: org_sleuthkit_autopsy_yara_YaraJNIWrapper
* Method: FindRuleMatch * Method: FindRuleMatch
* Signature: (Ljava/lang/String;[B)Ljava/util/List; * Signature: (Ljava/lang/String;[B)Ljava/util/List;
*/ */
JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatch JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatch
(JNIEnv * env, jclass cls, jstring compiledRulePath, jbyteArray fileByteArray) { (JNIEnv * env, jclass cls, jstring compiledRulePath, jbyteArray fileByteArray, jint byteArrayLength, jint timeoutSec) {
char errorMessage[256]; char errorMessage[256];
const char *nativeString = env->GetStringUTFChars(compiledRulePath, 0);
jobject resultList = NULL; jobject resultList = NULL;
int result; int result;
if ((result = yr_initialize()) != ERROR_SUCCESS) { YR_RULES *rules = NULL;
sprintf_s(errorMessage, "libyara initialization error (%d)\n", result);
throwException(env, errorMessage); if ((result = initalizeYaraLibrary(env)) != ERROR_SUCCESS) {
return resultList; return resultList;
} }
while (1) { while (1) {
YR_RULES *rules = NULL; if((result = loadRuleFile(env, compiledRulePath, &rules)) != ERROR_SUCCESS) {
if ((result = yr_rules_load(nativeString, &rules)) != ERROR_SUCCESS) {
sprintf_s(errorMessage, "Failed to load compiled yara rules (%d)\n", result);
throwException(env, errorMessage);
break; break;
} }
boolean isCopy;
int byteArrayLength = env->GetArrayLength(fileByteArray);
if (byteArrayLength == 0) { if (byteArrayLength == 0) {
throwException(env, "Unable to scan for matches. File byte array size was 0."); throwException(env, "Unable to scan for matches. File byte array size was 0.");
break; break;
} }
boolean isCopy;
jbyte* nativeByteArray = env->GetByteArrayElements(fileByteArray, &isCopy); jbyte* nativeByteArray = env->GetByteArrayElements(fileByteArray, &isCopy);
int flags = 0;
std::vector<std::string> scanResults; std::vector<std::string> scanResults;
result = yr_rules_scan_mem(rules, (unsigned char*)nativeByteArray, byteArrayLength, flags, callback, &scanResults, 1000000); result = yr_rules_scan_mem(rules, (unsigned char*)nativeByteArray, byteArrayLength, 0, callback, &scanResults, timeoutSec);
env->ReleaseByteArrayElements(fileByteArray, nativeByteArray, 0); env->ReleaseByteArrayElements(fileByteArray, nativeByteArray, 0);
if (result != ERROR_SUCCESS) { if (result != ERROR_SUCCESS) {
if (result == ERROR_SCAN_TIMEOUT) {
sprintf_s(errorMessage, "Yara file scan timed out");
}
else {
sprintf_s(errorMessage, "Yara file scan failed (%d)\n", result); sprintf_s(errorMessage, "Yara file scan failed (%d)\n", result);
}
throwException(env, errorMessage); throwException(env, errorMessage);
break; break;
} }
@ -130,9 +165,60 @@ JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRul
break; break;
} }
env->ReleaseStringUTFChars(compiledRulePath, nativeString); if (rules != NULL) {
yr_finalize(); yr_rules_destroy(rules);
}
return resultList; return resultList;
} }
/*
* Class: org_sleuthkit_autopsy_yara_YaraJNIWrapper
* Method: findRuleMatchFile
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
*/
JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatchFile
(JNIEnv * env, jclass cls, jstring compiledRulePath, jstring filePath, jint timeoutSec) {
char errorMessage[256];
jobject resultList = NULL;
int result;
YR_RULES *rules = NULL;
if ((result = initalizeYaraLibrary(env)) != ERROR_SUCCESS) {
return resultList;
}
while (1) {
if ((result = loadRuleFile(env, compiledRulePath, &rules)) != ERROR_SUCCESS) {
break;
}
std::vector<std::string> scanResults;
const char *nativeString = env->GetStringUTFChars(filePath, 0);
result = yr_rules_scan_file(rules, nativeString, 0, callback, &scanResults, timeoutSec);
if (result != ERROR_SUCCESS) {
if (result == ERROR_SCAN_TIMEOUT) {
sprintf_s(errorMessage, "Yara file scan timed out on file %s", nativeString);
}
else {
sprintf_s(errorMessage, "Yara file scan failed (%d)\n", result);
}
throwException(env, errorMessage);
break;
}
resultList = createArrayList(env, scanResults);
break;
}
if (rules != NULL) {
yr_rules_destroy(rules);
}
return resultList;
}

View File

@ -13,7 +13,15 @@ extern "C" {
* Signature: (Ljava/lang/String;[B)Ljava/util/List; * Signature: (Ljava/lang/String;[B)Ljava/util/List;
*/ */
JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatch JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatch
(JNIEnv *, jclass, jstring, jbyteArray); (JNIEnv *, jclass, jstring, jbyteArray, jint, jint);
/*
* Class: org_sleuthkit_autopsy_yara_YaraJNIWrapper
* Method: findRuleMatchFile
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
*/
JNIEXPORT jobject JNICALL Java_org_sleuthkit_autopsy_yara_YaraJNIWrapper_findRuleMatchFile
(JNIEnv *, jclass, jstring, jstring, jint);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -113,7 +113,7 @@
<AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\bin\$(ProjectName).dll"</Command> <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\YaraJNIWrapper\src\org\sleuthkit\autopsy\yara\$(ProjectName).dll"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -153,7 +153,7 @@
<AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\bin\$(ProjectName).dll"</Command> <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\YaraJNIWrapper\src\org\sleuthkit\autopsy\yara\$(ProjectName).dll"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@ -53,6 +53,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.AccountFileInstance; import org.sleuthkit.datamodel.AccountFileInstance;
import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
@ -421,14 +422,16 @@ final class VcardParser {
if (attributeType == null) { if (attributeType == null) {
try{ try{
// Add this attribute type to the case database. // Add this attribute type to the case database.
attributeType = tskCase.addArtifactAttributeType(attributeTypeName, attributeType = tskCase.getBlackboard().getOrAddAttributeType(attributeTypeName,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
String.format("Phone Number (%s)", StringUtils.capitalize(splitType.toLowerCase()))); String.format("Phone Number (%s)", StringUtils.capitalize(splitType.toLowerCase())));
}catch (TskDataException ex) {
attributeType = tskCase.getAttributeType(attributeTypeName);
}
}
ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephoneText, attributeType, attributes); ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephoneText, attributeType, attributes);
}catch (BlackboardException ex) {
logger.log(Level.WARNING, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
}
}
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex); logger.log(Level.WARNING, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
} }
@ -474,14 +477,14 @@ final class VcardParser {
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName); BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
if (attributeType == null) { if (attributeType == null) {
// Add this attribute type to the case database. // Add this attribute type to the case database.
attributeType = tskCase.addArtifactAttributeType(attributeTypeName, attributeType = tskCase.getBlackboard().getOrAddAttributeType(attributeTypeName,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
String.format("Email (%s)", StringUtils.capitalize(splitType.toLowerCase()))); String.format("Email (%s)", StringUtils.capitalize(splitType.toLowerCase())));
} }
ThunderbirdMboxFileIngestModule.addArtifactAttribute(email.getValue(), attributeType, attributes); ThunderbirdMboxFileIngestModule.addArtifactAttribute(email.getValue(), attributeType, attributes);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex); logger.log(Level.SEVERE, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
} catch (TskDataException ex) { } catch (BlackboardException ex) {
logger.log(Level.SEVERE, String.format("Unable to add custom attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex); logger.log(Level.SEVERE, String.format("Unable to add custom attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
} }
} }