mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 7949-annotationsMove
This commit is contained in:
commit
f0a9e3030a
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.centralrepository;
|
package org.sleuthkit.autopsy.centralrepository;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
@ -64,7 +65,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction {
|
|||||||
correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file);
|
correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file);
|
||||||
if (correlationAttributeInstance == null) {
|
if (correlationAttributeInstance == null) {
|
||||||
addToDatabase = true;
|
addToDatabase = true;
|
||||||
correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file);
|
final List<CorrelationAttributeInstance> md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(file);
|
||||||
|
if (!md5CorrelationAttr.isEmpty()) {
|
||||||
|
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||||
|
correlationAttributeInstance = md5CorrelationAttr.get(0);
|
||||||
|
} else {
|
||||||
|
correlationAttributeInstance = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (file.getSize() == 0) {
|
if (file.getSize() == 0) {
|
||||||
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile());
|
putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile());
|
||||||
|
@ -53,7 +53,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.DataSource;
|
|
||||||
import org.sleuthkit.datamodel.OsAccount;
|
import org.sleuthkit.datamodel.OsAccount;
|
||||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
import org.sleuthkit.datamodel.OsAccountInstance;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
@ -116,7 +115,7 @@ public final class OtherOccurrences {
|
|||||||
// correlate on blackboard artifact attributes if they exist and supported
|
// correlate on blackboard artifact attributes if they exist and supported
|
||||||
BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
|
BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
|
||||||
if (bbArtifact != null && CentralRepository.isEnabled()) {
|
if (bbArtifact != null && CentralRepository.isEnabled()) {
|
||||||
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact));
|
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can correlate based on the MD5 if it is enabled
|
// we can correlate based on the MD5 if it is enabled
|
||||||
|
@ -18,18 +18,18 @@ CentralRepositoryService.serviceName=Central Repository Service
|
|||||||
CorrelationAttributeInstance.invalidName.message=Invalid database table name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'.
|
CorrelationAttributeInstance.invalidName.message=Invalid database table name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'.
|
||||||
CorrelationAttributeInstance.nullName.message=Database name is null.
|
CorrelationAttributeInstance.nullName.message=Database name is null.
|
||||||
CorrelationAttributeUtil.emailaddresses.text=Email Addresses
|
CorrelationAttributeUtil.emailaddresses.text=Email Addresses
|
||||||
CorrelationType.DOMAIN.displayName=Domains
|
CorrelationType.DOMAIN.displayName=Domain
|
||||||
CorrelationType.EMAIL.displayName=Email Addresses
|
CorrelationType.EMAIL.displayName=Email Address
|
||||||
CorrelationType.FILES.displayName=Files
|
CorrelationType.FILES.displayName=File MD5
|
||||||
CorrelationType.ICCID.displayName=ICCID Number
|
CorrelationType.ICCID.displayName=ICCID Number
|
||||||
CorrelationType.IMEI.displayName=IMEI Number
|
CorrelationType.IMEI.displayName=IMEI Number
|
||||||
CorrelationType.IMSI.displayName=IMSI Number
|
CorrelationType.IMSI.displayName=IMSI Number
|
||||||
CorrelationType.MAC.displayName=MAC Addresses
|
CorrelationType.MAC.displayName=MAC Address
|
||||||
CorrelationType.OS_ACCOUNT.displayName=Os Account
|
CorrelationType.OS_ACCOUNT.displayName=Os Account
|
||||||
CorrelationType.PHONE.displayName=Phone Numbers
|
CorrelationType.PHONE.displayName=Phone Number
|
||||||
CorrelationType.PROG_NAME.displayName=Installed Programs
|
CorrelationType.PROG_NAME.displayName=Installed Program
|
||||||
CorrelationType.SSID.displayName=Wireless Networks
|
CorrelationType.SSID.displayName=Wireless Network
|
||||||
CorrelationType.USBID.displayName=USB Devices
|
CorrelationType.USBID.displayName=USB Device
|
||||||
EamArtifactInstances.knownStatus.bad=Bad
|
EamArtifactInstances.knownStatus.bad=Bad
|
||||||
EamArtifactInstances.knownStatus.known=Known
|
EamArtifactInstances.knownStatus.known=Known
|
||||||
EamArtifactInstances.knownStatus.unknown=Unknown
|
EamArtifactInstances.knownStatus.unknown=Unknown
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Central Repository
|
* Central Repository
|
||||||
*
|
*
|
||||||
* Copyright 2017-2020 Basis Technology Corp.
|
* Copyright 2017-2021 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");
|
||||||
@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.Cent
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.AnalysisResult;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -41,7 +42,6 @@ import org.sleuthkit.datamodel.DataArtifact;
|
|||||||
import org.sleuthkit.datamodel.HashUtility;
|
import org.sleuthkit.datamodel.HashUtility;
|
||||||
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
import org.sleuthkit.datamodel.InvalidAccountIDException;
|
||||||
import org.sleuthkit.datamodel.OsAccount;
|
import org.sleuthkit.datamodel.OsAccount;
|
||||||
import org.sleuthkit.datamodel.OsAccountInstance;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ public class CorrelationAttributeUtil {
|
|||||||
private static final List<String> domainsToSkip = Arrays.asList("localhost", "127.0.0.1");
|
private static final List<String> domainsToSkip = Arrays.asList("localhost", "127.0.0.1");
|
||||||
|
|
||||||
// artifact ids that specifically have a TSK_DOMAIN attribute that should be handled by CR
|
// artifact ids that specifically have a TSK_DOMAIN attribute that should be handled by CR
|
||||||
private static Set<Integer> DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList(
|
private static final Set<Integer> DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList(
|
||||||
ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID(),
|
ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID(),
|
||||||
ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID(),
|
ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID(),
|
||||||
ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(),
|
ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(),
|
||||||
@ -69,7 +69,7 @@ public class CorrelationAttributeUtil {
|
|||||||
* for the email address correlation attribute type. This string is
|
* for the email address correlation attribute type. This string is
|
||||||
* duplicated in the CorrelationAttributeInstance class.
|
* duplicated in the CorrelationAttributeInstance class.
|
||||||
*
|
*
|
||||||
* TODO (Jira-6088): We should not have multiple deifnitions of this string.
|
* TODO (Jira-6088): We should not have multiple definitions of this string.
|
||||||
*
|
*
|
||||||
* @return The display name of the email address correlation attribute type.
|
* @return The display name of the email address correlation attribute type.
|
||||||
*/
|
*/
|
||||||
@ -78,56 +78,45 @@ public class CorrelationAttributeUtil {
|
|||||||
return Bundle.CorrelationAttributeUtil_emailaddresses_text();
|
return Bundle.CorrelationAttributeUtil_emailaddresses_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines which artifact types act as the sources for CR data.
|
private static List<CorrelationAttributeInstance> makeCorrAttrsToSave(DataArtifact artifact) {
|
||||||
// Most notably, does not include KEYWORD HIT, CALLLOGS, MESSAGES, CONTACTS
|
int artifactTypeID = artifact.getArtifactTypeID();
|
||||||
// TSK_INTERESTING_ARTIFACT_HIT (See JIRA-6129 for more details on the
|
//The account fields in these types are expected to be saved in a TSK_ACCOUNT artifact, which will be processed
|
||||||
// interesting artifact hit).
|
if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||||
// IMPORTANT: This set should be updated for new artifacts types that need to
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()
|
||||||
// be inserted into the CR.
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
|
||||||
private static final Set<Integer> SOURCE_TYPES_FOR_CR_INSERT = new HashSet<Integer>() {
|
return new ArrayList<>();
|
||||||
{
|
|
||||||
addAll(DOMAIN_ARTIFACT_TYPE_IDS);
|
|
||||||
|
|
||||||
add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID());
|
|
||||||
add(ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID());
|
|
||||||
}
|
}
|
||||||
};
|
return CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact);
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes zero to many correlation attribute instances from the attributes of
|
|
||||||
* artifacts that have correlatable data. The intention of this method is to
|
|
||||||
* use the results to save to the CR, not to correlate with them. If you
|
|
||||||
* want to correlate, please use makeCorrAttrsForCorrelation. An artifact
|
|
||||||
* that can have correlatable data != An artifact that should be the source
|
|
||||||
* of data in the CR, so results may be un-necessarily incomplete.
|
|
||||||
*
|
|
||||||
* @param artifact An artifact.
|
|
||||||
*
|
|
||||||
* @return A list, possibly empty, of correlation attribute instances for
|
|
||||||
* the artifact.
|
|
||||||
*/
|
|
||||||
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(BlackboardArtifact artifact) {
|
|
||||||
if (SOURCE_TYPES_FOR_CR_INSERT.contains(artifact.getArtifactTypeID())) {
|
|
||||||
// Restrict the correlation attributes to use for saving.
|
|
||||||
// The artifacts which are suitable for saving are a subset of the
|
|
||||||
// artifacts that are suitable for correlating.
|
|
||||||
return makeCorrAttrsForCorrelation(artifact);
|
|
||||||
}
|
|
||||||
// Return an empty collection.
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes zero to many correlation attribute instances from the attributes of
|
* Makes zero to many correlation attribute instances from the attributes of
|
||||||
* artifacts that have correlatable data. The intention of this method is to
|
* content objects that have correlatable data. The intention of this method
|
||||||
|
* is to use the results to save to the CR, not to correlate with them. If
|
||||||
|
* you want to correlate, please use makeCorrAttrsForSearch. An artifact
|
||||||
|
* that can have correlatable data != An artifact that should be the source
|
||||||
|
* of data in the CR, so results may be un-necessarily incomplete.
|
||||||
|
*
|
||||||
|
* @param content A Content object.
|
||||||
|
*
|
||||||
|
* @return A list, possibly empty, of correlation attribute instances for
|
||||||
|
* the content.
|
||||||
|
*/
|
||||||
|
public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(Content content) {
|
||||||
|
if (content instanceof DataArtifact) {
|
||||||
|
return makeCorrAttrsToSave((DataArtifact) content);
|
||||||
|
} else if (content instanceof AnalysisResult) {
|
||||||
|
//AnalysisResults should already have the correlation attributes they are correlating on saved
|
||||||
|
//This check replaces the check explicitly excluding keyword hits and interesting items that existed prior to the AnalysisResult designation
|
||||||
|
return new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
return makeCorrAttrsForSearch(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes zero to many correlation attribute instances from the attributes of
|
||||||
|
* content that have correlatable data. The intention of this method is to
|
||||||
* use the results to correlate with, not to save. If you want to save,
|
* use the results to correlate with, not to save. If you want to save,
|
||||||
* please use makeCorrAttrsToSave. An artifact that can have correlatable
|
* please use makeCorrAttrsToSave. An artifact that can have correlatable
|
||||||
* data != An artifact that should be the source of data in the CR, so
|
* data != An artifact that should be the source of data in the CR, so
|
||||||
@ -144,96 +133,126 @@ public class CorrelationAttributeUtil {
|
|||||||
* whether receiving a null return value is an error or not, plus null
|
* whether receiving a null return value is an error or not, plus null
|
||||||
* checking is easy to forget, while catching exceptions is enforced.
|
* checking is easy to forget, while catching exceptions is enforced.
|
||||||
*
|
*
|
||||||
* @param artifact An artifact.
|
* @param Content A Content object.
|
||||||
*
|
*
|
||||||
* @return A list, possibly empty, of correlation attribute instances for
|
* @return A list, possibly empty, of correlation attribute instances for
|
||||||
* the artifact.
|
* the content.
|
||||||
*/
|
*/
|
||||||
public static List<CorrelationAttributeInstance> makeCorrAttrsForCorrelation(BlackboardArtifact artifact) {
|
public static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(Content content) {
|
||||||
|
if (content instanceof DataArtifact) {
|
||||||
|
return makeCorrAttrsForSearch((DataArtifact) content);
|
||||||
|
} else if (content instanceof AnalysisResult) {
|
||||||
|
return makeCorrAttrsForSearch((AnalysisResult) content);
|
||||||
|
} else if (content instanceof AbstractFile) {
|
||||||
|
return makeCorrAttrsForSearch((AbstractFile) content);
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AnalysisResult analysisResult) {
|
||||||
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact);
|
int artifactTypeID = analysisResult.getArtifactTypeID();
|
||||||
if (sourceArtifact != null) {
|
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||||
|
BlackboardAttribute setNameAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_SET_NAME);
|
||||||
List<BlackboardAttribute> attributes = sourceArtifact.getAttributes();
|
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, analysisResult, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, analysisResult.getAttributes());
|
||||||
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
|
||||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
|
||||||
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
|
||||||
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, attributes);
|
|
||||||
}
|
|
||||||
} else if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) {
|
|
||||||
BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN));
|
|
||||||
if ((domainAttr != null)
|
|
||||||
&& !domainsToSkip.contains(domainAttr.getValueString())) {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes);
|
|
||||||
}
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
|
||||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
|
||||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
|
||||||
Content dataSource = sourceContent.getDataSource();
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
|
||||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
|
||||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
|
||||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
|
||||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
|
||||||
Content dataSource = sourceContent.getDataSource();
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
|
||||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
|
||||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
|
||||||
Content dataSource = sourceContent.getDataSource();
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
|
||||||
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
|
||||||
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(sourceArtifact.getObjectID());
|
|
||||||
Content dataSource = sourceContent.getDataSource();
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID,
|
|
||||||
attributes, sourceContent, dataSource);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
|
||||||
makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact);
|
|
||||||
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) {
|
|
||||||
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH));
|
|
||||||
String pathAttrString = null;
|
|
||||||
if (setNameAttr != null) {
|
|
||||||
pathAttrString = setNameAttr.getValueString();
|
|
||||||
}
|
|
||||||
if (pathAttrString != null && !pathAttrString.isEmpty()) {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
|
||||||
} else {
|
|
||||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
|
||||||
}
|
|
||||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
|
||||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
|
||||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
|
||||||
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact, attributes);
|
|
||||||
}
|
}
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
|
||||||
|
BlackboardAttribute assocArtifactAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_ASSOCIATED_ARTIFACT);
|
||||||
|
if (assocArtifactAttr != null) {
|
||||||
|
BlackboardArtifact sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
|
||||||
|
return CorrelationAttributeUtil.makeCorrAttrsForSearch(sourceArtifact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
correlationAttrs.addAll(CorrelationAttributeUtil.makeCorrAttrsForSearch(analysisResult.getParent()));
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get information regarding correlation attributes from AnalysisResult", ex);
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Attempted to retrieve correlation attributes for search with no currently open case.", ex);
|
||||||
|
} catch (CentralRepoException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to get correlation type from central repository.", ex);
|
||||||
|
}
|
||||||
|
return correlationAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(DataArtifact artifact) {
|
||||||
|
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
||||||
|
|
||||||
|
int artifactTypeID = artifact.getArtifactTypeID();
|
||||||
|
if (DOMAIN_ARTIFACT_TYPE_IDS.contains(artifactTypeID)) {
|
||||||
|
BlackboardAttribute domainAttr = getAttribute(attributes, new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||||
|
if ((domainAttr != null)
|
||||||
|
&& !domainsToSkip.contains(domainAttr.getValueString())) {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID, attributes);
|
||||||
|
}
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
||||||
|
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||||
|
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||||
|
Content dataSource = sourceContent.getDataSource();
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID, CorrelationAttributeInstance.SSID_TYPE_ID, attributes);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()
|
||||||
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID()
|
||||||
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID, attributes);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
|
||||||
|
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||||
|
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||||
|
Content dataSource = sourceContent.getDataSource();
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMEI, CorrelationAttributeInstance.IMEI_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
||||||
|
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||||
|
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||||
|
Content dataSource = sourceContent.getDataSource();
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
||||||
|
// prefetch all the information as we will be calling makeCorrAttrFromArtifactAttr() multiple times
|
||||||
|
Content sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||||
|
Content dataSource = sourceContent.getDataSource();
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID,
|
||||||
|
attributes, sourceContent, dataSource);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
|
||||||
|
makeCorrAttrFromAcctArtifact(correlationAttrs, artifact);
|
||||||
|
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_INSTALLED_PROG.getTypeID()) {
|
||||||
|
BlackboardAttribute setNameAttr = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH));
|
||||||
|
String pathAttrString = null;
|
||||||
|
if (setNameAttr != null) {
|
||||||
|
pathAttrString = setNameAttr.getValueString();
|
||||||
|
}
|
||||||
|
if (pathAttrString != null && !pathAttrString.isEmpty()) {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||||
|
} else {
|
||||||
|
makeCorrAttrFromArtifactAttr(correlationAttrs, artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, CorrelationAttributeInstance.INSTALLED_PROGS_TYPE_ID, attributes);
|
||||||
|
}
|
||||||
|
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
||||||
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||||
|
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
||||||
|
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, artifact, attributes);
|
||||||
}
|
}
|
||||||
} catch (CorrelationAttributeNormalizationException ex) {
|
} catch (CorrelationAttributeNormalizationException ex) {
|
||||||
logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS
|
logger.log(Level.WARNING, String.format("Error normalizing correlation attribute (%s)", artifact), ex); // NON-NLS
|
||||||
@ -292,8 +311,6 @@ public class CorrelationAttributeUtil {
|
|||||||
*/
|
*/
|
||||||
private static void makeCorrAttrsFromCommunicationArtifacts(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact,
|
private static void makeCorrAttrsFromCommunicationArtifacts(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact,
|
||||||
List<BlackboardAttribute> attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException {
|
List<BlackboardAttribute> attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException {
|
||||||
CorrelationAttributeInstance corrAttr = null;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract the phone number from the artifact attribute.
|
* Extract the phone number from the artifact attribute.
|
||||||
*/
|
*/
|
||||||
@ -305,56 +322,19 @@ public class CorrelationAttributeUtil {
|
|||||||
} else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
} else if (null != getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
||||||
value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normalize the phone number.
|
* Normalize the phone number.
|
||||||
*/
|
*/
|
||||||
if (value != null
|
if (value != null
|
||||||
&& CorrelationAttributeNormalizer.isValidPhoneNumber(value)) {
|
&& CorrelationAttributeNormalizer.isValidPhoneNumber(value)) {
|
||||||
|
|
||||||
value = CorrelationAttributeNormalizer.normalizePhone(value);
|
value = CorrelationAttributeNormalizer.normalizePhone(value);
|
||||||
corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
CorrelationAttributeInstance corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
||||||
if (corrAttr != null) {
|
if (corrAttr != null) {
|
||||||
corrAttrInstances.add(corrAttr);
|
corrAttrInstances.add(corrAttr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the associated artifact of a "meta-artifact" such as an "interesting
|
|
||||||
* artifact hit" or "previously seen" artifact.
|
|
||||||
*
|
|
||||||
* @param artifact An artifact.
|
|
||||||
*
|
|
||||||
* @return The associated artifact if the input artifact is a
|
|
||||||
* "meta-artifact", otherwise the input artifact.
|
|
||||||
*
|
|
||||||
* @throws NoCurrentCaseException If there is no open case.
|
|
||||||
* @throws TskCoreException If there is an error querying thew case
|
|
||||||
* database.
|
|
||||||
*/
|
|
||||||
private static BlackboardArtifact getCorrAttrSourceArtifact(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException {
|
|
||||||
BlackboardArtifact sourceArtifact = null;
|
|
||||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() == artifact.getArtifactTypeID()) {
|
|
||||||
BlackboardAttribute assocArtifactAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
|
||||||
if (assocArtifactAttr != null) {
|
|
||||||
sourceArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(assocArtifactAttr.getValueLong());
|
|
||||||
}
|
|
||||||
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_SEEN.getTypeID() == artifact.getArtifactTypeID()
|
|
||||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE.getTypeID() == artifact.getArtifactTypeID()
|
|
||||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_UNSEEN.getTypeID() == artifact.getArtifactTypeID()) {
|
|
||||||
Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
|
||||||
if (content instanceof DataArtifact) {
|
|
||||||
sourceArtifact = (BlackboardArtifact) content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceArtifact == null) {
|
|
||||||
sourceArtifact = artifact;
|
|
||||||
}
|
|
||||||
return sourceArtifact;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a correlation attribute instance for an account artifact.
|
* Makes a correlation attribute instance for an account artifact.
|
||||||
*
|
*
|
||||||
@ -506,21 +486,21 @@ public class CorrelationAttributeUtil {
|
|||||||
*/
|
*/
|
||||||
private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value,
|
private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value,
|
||||||
Content sourceContent, Content dataSource) {
|
Content sourceContent, Content dataSource) {
|
||||||
|
Content srcContent = sourceContent;
|
||||||
|
Content dataSrc = dataSource;
|
||||||
try {
|
try {
|
||||||
|
if (srcContent == null) {
|
||||||
if (sourceContent == null) {
|
srcContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
||||||
sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID());
|
|
||||||
}
|
}
|
||||||
if (null == sourceContent) {
|
if (null == srcContent) {
|
||||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}",
|
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load content with ID: {1} associated with artifact with ID: {2}",
|
||||||
new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS
|
new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (dataSrc == null) {
|
||||||
if (dataSource == null) {
|
dataSrc = srcContent.getDataSource();
|
||||||
dataSource = sourceContent.getDataSource();
|
|
||||||
}
|
}
|
||||||
if (dataSource == null) {
|
if (dataSrc == null) {
|
||||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}",
|
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Failed to load data source for content with ID: {1}",
|
||||||
new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS
|
new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -532,24 +512,24 @@ public class CorrelationAttributeUtil {
|
|||||||
correlationType,
|
correlationType,
|
||||||
value,
|
value,
|
||||||
correlationCase,
|
correlationCase,
|
||||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource),
|
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
TskData.FileKnown.UNKNOWN,
|
TskData.FileKnown.UNKNOWN,
|
||||||
sourceContent.getId());
|
srcContent.getId());
|
||||||
} else {
|
} else {
|
||||||
if (!(sourceContent instanceof AbstractFile)) {
|
if (!(srcContent instanceof AbstractFile)) {
|
||||||
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile",
|
logger.log(Level.SEVERE, "Error creating artifact instance of type {0}. Source content of artifact with ID: {1} is not an AbstractFile",
|
||||||
new Object[]{correlationType.getDisplayName(), artifact.getId()});
|
new Object[]{correlationType.getDisplayName(), artifact.getId()});
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
AbstractFile bbSourceFile = (AbstractFile) sourceContent;
|
AbstractFile bbSourceFile = (AbstractFile) srcContent;
|
||||||
|
|
||||||
return new CorrelationAttributeInstance(
|
return new CorrelationAttributeInstance(
|
||||||
correlationType,
|
correlationType,
|
||||||
value,
|
value,
|
||||||
correlationCase,
|
correlationCase,
|
||||||
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource),
|
CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc),
|
||||||
bbSourceFile.getParentPath() + bbSourceFile.getName(),
|
bbSourceFile.getParentPath() + bbSourceFile.getName(),
|
||||||
"",
|
"",
|
||||||
TskData.FileKnown.UNKNOWN,
|
TskData.FileKnown.UNKNOWN,
|
||||||
@ -615,8 +595,12 @@ public class CorrelationAttributeUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @@@ BC: This seems like it should go into a DB-specific class because it is
|
||||||
|
// much different from the other methods in this class. It is going to the DB for data.
|
||||||
/**
|
/**
|
||||||
* Gets the correlation attribute instance for a file.
|
* Gets the correlation attribute instance for a file. This method goes to
|
||||||
|
* the CR to get an actual instance. It does not simply package the data
|
||||||
|
* from file into a generic instance object.
|
||||||
*
|
*
|
||||||
* @param file The file.
|
* @param file The file.
|
||||||
*
|
*
|
||||||
@ -694,7 +678,8 @@ public class CorrelationAttributeUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a correlation attribute instance for a file.
|
* Makes a correlation attribute instance for a file. Will include the
|
||||||
|
* specific object ID.
|
||||||
*
|
*
|
||||||
* IMPORTANT: The correlation attribute instance is NOT added to the central
|
* IMPORTANT: The correlation attribute instance is NOT added to the central
|
||||||
* repository by this method.
|
* repository by this method.
|
||||||
@ -711,23 +696,23 @@ public class CorrelationAttributeUtil {
|
|||||||
*
|
*
|
||||||
* @return The correlation attribute instance or null, if an error occurred.
|
* @return The correlation attribute instance or null, if an error occurred.
|
||||||
*/
|
*/
|
||||||
public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) {
|
private static List<CorrelationAttributeInstance> makeCorrAttrsForSearch(AbstractFile file) {
|
||||||
|
List<CorrelationAttributeInstance> fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852
|
||||||
if (!isSupportedAbstractFileType(file)) {
|
if (!isSupportedAbstractFileType(file)) {
|
||||||
return null;
|
return fileTypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need a hash to make the correlation artifact instance.
|
// We need a hash to make the correlation artifact instance.
|
||||||
String md5 = file.getMd5Hash();
|
String md5 = file.getMd5Hash();
|
||||||
if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) {
|
if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) {
|
||||||
return null;
|
return fileTypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CorrelationAttributeInstance.Type filesType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
|
CorrelationAttributeInstance.Type filesType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
|
||||||
|
|
||||||
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows());
|
||||||
return new CorrelationAttributeInstance(
|
fileTypeList.add(new CorrelationAttributeInstance(
|
||||||
filesType,
|
filesType,
|
||||||
file.getMd5Hash(),
|
file.getMd5Hash(),
|
||||||
correlationCase,
|
correlationCase,
|
||||||
@ -735,21 +720,17 @@ public class CorrelationAttributeUtil {
|
|||||||
file.getParentPath() + file.getName(),
|
file.getParentPath() + file.getName(),
|
||||||
"",
|
"",
|
||||||
TskData.FileKnown.UNKNOWN,
|
TskData.FileKnown.UNKNOWN,
|
||||||
file.getId());
|
file.getId()));
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS
|
logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS
|
||||||
return null;
|
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
|
||||||
return null;
|
|
||||||
} catch (CorrelationAttributeNormalizationException ex) {
|
} catch (CorrelationAttributeNormalizationException ex) {
|
||||||
logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS
|
logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS
|
||||||
return null;
|
|
||||||
} catch (NoCurrentCaseException ex) {
|
} catch (NoCurrentCaseException ex) {
|
||||||
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return fileTypeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -311,18 +311,18 @@ public final class CaseEventListener implements PropertyChangeListener {
|
|||||||
* Sets the known status for the correlation attribute instance for the
|
* Sets the known status for the correlation attribute instance for the
|
||||||
* given abstract file.
|
* given abstract file.
|
||||||
*
|
*
|
||||||
* @param af The abstract file for which to set the correlation
|
* @param af The abstract file for which to set the correlation
|
||||||
* attribute instance.
|
* attribute instance.
|
||||||
* @param knownStatus The new known status for the correlation attribute
|
* @param knownStatus The new known status for the correlation attribute
|
||||||
* instance.
|
* instance.
|
||||||
*/
|
*/
|
||||||
private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) {
|
private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) {
|
||||||
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af);
|
final List<CorrelationAttributeInstance> md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(af);
|
||||||
|
if (!md5CorrelationAttr.isEmpty()) {
|
||||||
if (eamArtifact != null) {
|
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||||
// send update to Central Repository db
|
// send update to Central Repository db
|
||||||
try {
|
try {
|
||||||
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
|
dbManager.setAttributeInstanceKnownStatus(md5CorrelationAttr.get(0), knownStatus);
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
|
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ public final class CaseEventListener implements PropertyChangeListener {
|
|||||||
* for the item. If there are, set known status as notable. If not set
|
* for the item. If there are, set known status as notable. If not set
|
||||||
* status as unknown.
|
* status as unknown.
|
||||||
*
|
*
|
||||||
* @param content The content for the tag that was added or deleted.
|
* @param content The content for the tag that was added or deleted.
|
||||||
* @param bbArtifact The artifact for the tag that was added or deleted.
|
* @param bbArtifact The artifact for the tag that was added or deleted.
|
||||||
*/
|
*/
|
||||||
private void handleTagChange(Content content, BlackboardArtifact bbArtifact) {
|
private void handleTagChange(Content content, BlackboardArtifact bbArtifact) {
|
||||||
@ -452,11 +452,11 @@ public final class CaseEventListener implements PropertyChangeListener {
|
|||||||
* Sets the known status of a blackboard artifact in the central
|
* Sets the known status of a blackboard artifact in the central
|
||||||
* repository.
|
* repository.
|
||||||
*
|
*
|
||||||
* @param bbArtifact The blackboard artifact to set known status.
|
* @param bbArtifact The blackboard artifact to set known status.
|
||||||
* @param knownStatus The new known status.
|
* @param knownStatus The new known status.
|
||||||
*/
|
*/
|
||||||
private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
|
private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) {
|
||||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
|
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact);
|
||||||
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
||||||
try {
|
try {
|
||||||
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
|
dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
|
||||||
@ -528,7 +528,7 @@ public final class CaseEventListener implements PropertyChangeListener {
|
|||||||
if (!hasTagWithConflictingKnownStatus) {
|
if (!hasTagWithConflictingKnownStatus) {
|
||||||
//Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
|
//Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
|
||||||
//with the initial set of correlation attributes this should be a single correlation attribute
|
//with the initial set of correlation attributes this should be a single correlation attribute
|
||||||
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbTag.getArtifact());
|
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbTag.getArtifact());
|
||||||
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
|
||||||
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
|
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
|
||||||
}
|
}
|
||||||
@ -566,9 +566,10 @@ public final class CaseEventListener implements PropertyChangeListener {
|
|||||||
if (!hasTagWithConflictingKnownStatus) {
|
if (!hasTagWithConflictingKnownStatus) {
|
||||||
Content taggedContent = contentTag.getContent();
|
Content taggedContent = contentTag.getContent();
|
||||||
if (taggedContent instanceof AbstractFile) {
|
if (taggedContent instanceof AbstractFile) {
|
||||||
final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile) taggedContent);
|
final List<CorrelationAttributeInstance> eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) taggedContent);
|
||||||
if (eamArtifact != null) {
|
if (!eamArtifact.isEmpty()) {
|
||||||
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
|
//for an abstract file the 'list' of attributes will be a single attribute or empty and is returning a list for consistancy with other makeCorrAttrsForSearch methods per 7852
|
||||||
|
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ import org.sleuthkit.datamodel.Score;
|
|||||||
*/
|
*/
|
||||||
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"})
|
@NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"})
|
||||||
public class IngestEventsListener {
|
public class IngestEventsListener {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName());
|
||||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
|
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED);
|
||||||
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
|
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED);
|
||||||
@ -246,15 +247,15 @@ public class IngestEventsListener {
|
|||||||
originalArtifact.getArtifactID()));
|
originalArtifact.getArtifactID()));
|
||||||
makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text());
|
makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make an interesting item artifact to flag the passed in artifact.
|
* Make an interesting item artifact to flag the passed in artifact.
|
||||||
*
|
*
|
||||||
* @param originalArtifact Artifact in current case we want to flag
|
* @param originalArtifact Artifact in current case we want to flag
|
||||||
* @param attributesForNewArtifact Attributes to assign to the new
|
* @param attributesForNewArtifact Attributes to assign to the new
|
||||||
* Interesting items artifact
|
* Interesting items artifact
|
||||||
* @param configuration The configuration to be specified for the new interesting artifact hit
|
* @param configuration The configuration to be specified for the
|
||||||
|
* new interesting artifact hit
|
||||||
*/
|
*/
|
||||||
private static void makeAndPostInterestingArtifact(BlackboardArtifact originalArtifact, Collection<BlackboardAttribute> attributesForNewArtifact, String configuration) {
|
private static void makeAndPostInterestingArtifact(BlackboardArtifact originalArtifact, Collection<BlackboardAttribute> attributesForNewArtifact, String configuration) {
|
||||||
try {
|
try {
|
||||||
@ -263,8 +264,8 @@ public class IngestEventsListener {
|
|||||||
Blackboard blackboard = tskCase.getBlackboard();
|
Blackboard blackboard = tskCase.getBlackboard();
|
||||||
// Create artifact if it doesn't already exist.
|
// Create artifact if it doesn't already exist.
|
||||||
if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) {
|
if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) {
|
||||||
BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult(
|
BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult(
|
||||||
BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE,
|
BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE,
|
||||||
null, configuration, null, attributesForNewArtifact)
|
null, configuration, null, attributesForNewArtifact)
|
||||||
.getAnalysisResult();
|
.getAnalysisResult();
|
||||||
|
|
||||||
@ -368,8 +369,8 @@ public class IngestEventsListener {
|
|||||||
try {
|
try {
|
||||||
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
|
dataSource = ((DataSourceAnalysisEvent) event).getDataSource();
|
||||||
/*
|
/*
|
||||||
* We only care about Images for the purpose of
|
* We only care about Images for the purpose of updating hash
|
||||||
* updating hash values.
|
* values.
|
||||||
*/
|
*/
|
||||||
if (!(dataSource instanceof Image)) {
|
if (!(dataSource instanceof Image)) {
|
||||||
return;
|
return;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
@ -28,24 +29,21 @@ import org.openide.util.lookup.ServiceProvider;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
|
||||||
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
|
||||||
import org.sleuthkit.datamodel.AnalysisResult;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a list of analysis results as a content viewer.
|
* A content viewer that displays the analysis results for a Content object.
|
||||||
*/
|
*/
|
||||||
@ServiceProvider(service = DataContentViewer.class, position = 7)
|
@ServiceProvider(service = DataContentViewer.class, position = 7)
|
||||||
public class AnalysisResultsContentViewer implements DataContentViewer {
|
public class AnalysisResultsContentViewer implements DataContentViewer {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName());
|
||||||
|
|
||||||
// isPreferred value
|
|
||||||
private static final int PREFERRED_VALUE = 3;
|
private static final int PREFERRED_VALUE = 3;
|
||||||
|
|
||||||
private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel();
|
private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel();
|
||||||
private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel();
|
private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel();
|
||||||
|
|
||||||
@ -125,26 +123,24 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSupported(Node node) {
|
public boolean isSupported(Node node) {
|
||||||
if (node == null) {
|
if (Objects.isNull(node)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup.
|
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
if (Objects.nonNull(analysisResultItem)) {
|
||||||
if (content instanceof AnalysisResult) {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (content == null || content instanceof BlackboardArtifact) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||||
|
if (!Objects.isNull(contentItem)) {
|
||||||
|
Content content = contentItem.getTskContent();
|
||||||
try {
|
try {
|
||||||
if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) {
|
if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Unable to get analysis results for file with obj id " + content.getId(), ex);
|
logger.log(Level.SEVERE, String.format("Error getting analysis results for Content (object ID = %d)", content.getId()), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,4 +151,5 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
|
|||||||
public int isPreferred(Node node) {
|
public int isPreferred(Node node) {
|
||||||
return PREFERRED_VALUE;
|
return PREFERRED_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -31,14 +30,14 @@ import java.util.stream.Stream;
|
|||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AnalysisResultItem;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.TskContentItem;
|
||||||
import org.sleuthkit.datamodel.AnalysisResult;
|
import org.sleuthkit.datamodel.AnalysisResult;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.Score;
|
import org.sleuthkit.datamodel.Score;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Creates a representation of a list of analysis results gathered from a node.
|
* Creates a representation of a list of analysis results gathered from a node.
|
||||||
*/
|
*/
|
||||||
public class AnalysisResultsViewModel {
|
public class AnalysisResultsViewModel {
|
||||||
@ -72,7 +71,7 @@ public class AnalysisResultsViewModel {
|
|||||||
* @return The attributes to display.
|
* @return The attributes to display.
|
||||||
*/
|
*/
|
||||||
List<Pair<String, String>> getAttributesToDisplay() {
|
List<Pair<String, String>> getAttributesToDisplay() {
|
||||||
return attributesToDisplay;
|
return Collections.unmodifiableList(attributesToDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,7 +117,7 @@ public class AnalysisResultsViewModel {
|
|||||||
* @return The analysis results to be displayed.
|
* @return The analysis results to be displayed.
|
||||||
*/
|
*/
|
||||||
List<ResultDisplayAttributes> getAnalysisResults() {
|
List<ResultDisplayAttributes> getAnalysisResults() {
|
||||||
return analysisResults;
|
return Collections.unmodifiableList(analysisResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -238,58 +237,44 @@ public class AnalysisResultsViewModel {
|
|||||||
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
|
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Score> aggregateScore = Optional.empty();
|
Content analyzedContent = null;
|
||||||
Optional<Content> nodeContent = Optional.empty();
|
AnalysisResult selectedAnalysisResult = null;
|
||||||
// maps id of analysis result to analysis result to prevent duplication
|
Score aggregateScore = null;
|
||||||
Map<Long, AnalysisResult> allAnalysisResults = new HashMap<>();
|
List<AnalysisResult> analysisResults = Collections.emptyList();
|
||||||
Optional<AnalysisResult> selectedResult = Optional.empty();
|
long selectedObjectId = 0;
|
||||||
|
try {
|
||||||
// Find first content that is not an artifact within node
|
AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class);
|
||||||
for (Content content : node.getLookup().lookupAll(Content.class)) {
|
if (Objects.nonNull(analysisResultItem)) {
|
||||||
if (content == null || content instanceof BlackboardArtifact) {
|
/*
|
||||||
continue;
|
* The content represented by the Node is an analysis result.
|
||||||
}
|
* Set this analysis result as the analysis result to be
|
||||||
|
* selected in the content viewer and get the analyzed content
|
||||||
try {
|
* as the source of the analysis results to display.
|
||||||
nodeContent = Optional.of(content);
|
*/
|
||||||
|
selectedAnalysisResult = analysisResultItem.getAnalysisResult();
|
||||||
// get the aggregate score of that content
|
selectedObjectId = selectedAnalysisResult.getId();
|
||||||
aggregateScore = Optional.ofNullable(content.getAggregateScore());
|
analyzedContent = selectedAnalysisResult.getParent();
|
||||||
|
} else {
|
||||||
// and add all analysis results to mapping
|
/*
|
||||||
content.getAllAnalysisResults().stream()
|
* The content represented by the Node is something other than
|
||||||
.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
* an analysis result. Use it as the source of the analysis
|
||||||
|
* results to display.
|
||||||
break;
|
*/
|
||||||
} catch (TskCoreException ex) {
|
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class);
|
||||||
logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex);
|
analyzedContent = contentItem.getTskContent();
|
||||||
|
selectedObjectId = analyzedContent.getId();
|
||||||
}
|
}
|
||||||
|
aggregateScore = analyzedContent.getAggregateScore();
|
||||||
|
analysisResults = analyzedContent.getAllAnalysisResults();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, String.format("Error getting analysis result data for selected Content (object ID=%d)", selectedObjectId), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find any analysis results in the node
|
/*
|
||||||
Collection<? extends AnalysisResult> analysisResults = node.getLookup().lookupAll(AnalysisResult.class);
|
* Use the data collected above to construct the view model.
|
||||||
if (analysisResults.size() > 0) {
|
*/
|
||||||
|
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(analysisResults);
|
||||||
// get any items with a score
|
return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent));
|
||||||
List<AnalysisResult> filteredResults = analysisResults.stream()
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// add them to the map to display
|
|
||||||
filteredResults.forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar));
|
|
||||||
|
|
||||||
// the selected result will be the highest scored analysis result in the node.
|
|
||||||
selectedResult = filteredResults.stream()
|
|
||||||
.max((a, b) -> a.getScore().compareTo(b.getScore()));
|
|
||||||
|
|
||||||
// if no aggregate score determined at this point, use the selected result score.
|
|
||||||
if (!aggregateScore.isPresent()) {
|
|
||||||
aggregateScore = selectedResult.flatMap(selectedRes -> Optional.ofNullable(selectedRes.getScore()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get view model representation
|
|
||||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values());
|
|
||||||
|
|
||||||
return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ public class AnnotationUtils {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact)
|
List<Pair<CorrelationAttributeInstance.Type, String>> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact)
|
||||||
.stream()
|
.stream()
|
||||||
.map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
|
.map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -102,7 +102,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
|||||||
* @param content Underlying Content instances
|
* @param content Underlying Content instances
|
||||||
*/
|
*/
|
||||||
AbstractContentNode(T content) {
|
AbstractContentNode(T content) {
|
||||||
this(content, Lookups.singleton(content));
|
this(content, Lookups.fixed(content, new TskContentItem(content)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
51
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
51
Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021-2021 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.datamodel;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.sleuthkit.datamodel.AnalysisResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Autopsy Data Model item with an underlying analysis result Sleuth Kit Data
|
||||||
|
* Model object.
|
||||||
|
*/
|
||||||
|
public class AnalysisResultItem extends TskContentItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an Autopsy Data Model item with an underlying AnalysisResult
|
||||||
|
* Sleuth Kit Data Model object.
|
||||||
|
*
|
||||||
|
* @param analysisResult The analysis result.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
AnalysisResultItem(AnalysisResult analysisResult) {
|
||||||
|
super(analysisResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying analysis result.
|
||||||
|
*
|
||||||
|
* @return The analysis result.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public AnalysisResult getAnalysisResult() {
|
||||||
|
return (AnalysisResult) (getTskContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -84,8 +84,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category;
|
|||||||
import org.sleuthkit.datamodel.Score;
|
import org.sleuthkit.datamodel.Score;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A BlackboardArtifactNode is an AbstractNode implementation that can be used
|
* An AbstractNode implementation that can be used to represent an data artifact
|
||||||
* to represent an artifact of any type.
|
* or analysis result of any type.
|
||||||
*/
|
*/
|
||||||
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
|
||||||
|
|
||||||
@ -219,17 +219,20 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
* Constructs an AbstractNode implementation that can be used to represent a
|
||||||
* can be used to represent an artifact of any type.
|
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||||
|
* contain the data artifact or analysis result and its parent content as
|
||||||
|
* its source content.
|
||||||
*
|
*
|
||||||
* @param artifact The artifact to represent.
|
* @param artifact The data artifact or analysis result.
|
||||||
* @param iconPath The path to the icon for the artifact type.
|
* @param iconPath The path to the icon for the data artifact or analysis
|
||||||
|
* result type.
|
||||||
*/
|
*/
|
||||||
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
|
public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
|
||||||
super(artifact, createLookup(artifact, false));
|
super(artifact, createLookup(artifact, false));
|
||||||
this.artifact = artifact;
|
this.artifact = artifact;
|
||||||
this.artifactType = getType(artifact);
|
this.artifactType = getType(artifact);
|
||||||
|
|
||||||
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
|
||||||
if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
|
if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
|
||||||
srcContent = lookupContent;
|
srcContent = lookupContent;
|
||||||
@ -259,26 +262,28 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
* Constructs an AbstractNode implementation that can be used to represent a
|
||||||
* can be used to represent an artifact of any type.
|
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||||
|
* contain the data artifact or analysis result and its source content,
|
||||||
|
* either the parent content or the associated file.
|
||||||
*
|
*
|
||||||
* @param artifact The artifact to represent.
|
* @param artifact The data artifact or analysis result.
|
||||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
* @param useAssociatedFileInLookup True if the source content in the Lookup
|
||||||
* for the associated file instead of the
|
* should be the associated file instead of
|
||||||
* parent file.
|
* the parent content.
|
||||||
*/
|
*/
|
||||||
@Beta
|
@Beta
|
||||||
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
public BlackboardArtifactNode(BlackboardArtifact artifact, boolean useAssociatedFileInLookup) {
|
||||||
super(artifact, createLookup(artifact, lookupIsAssociatedFile));
|
super(artifact, createLookup(artifact, useAssociatedFileInLookup));
|
||||||
this.artifact = artifact;
|
this.artifact = artifact;
|
||||||
this.artifactType = getType(artifact);
|
this.artifactType = getType(artifact);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//The lookup for a file may or may not exist so we define the srcContent as the parent.
|
|
||||||
srcContent = artifact.getParent();
|
srcContent = artifact.getParent();
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, MessageFormat.format("Error getting the parent of the artifact for (artifact objID={0})", artifact.getId()), ex);
|
logger.log(Level.WARNING, MessageFormat.format("Error getting the parent of the artifact for (artifact objID={0})", artifact.getId()), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcContent != null) {
|
if (srcContent != null) {
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
@ -294,6 +299,7 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
throw new IllegalArgumentException(MessageFormat.format("Artifact missing source content (artifact objID={0})", artifact));
|
||||||
}
|
}
|
||||||
|
|
||||||
setName(Long.toString(artifact.getArtifactID()));
|
setName(Long.toString(artifact.getArtifactID()));
|
||||||
String displayName = srcContent.getName();
|
String displayName = srcContent.getName();
|
||||||
setDisplayName(displayName);
|
setDisplayName(displayName);
|
||||||
@ -304,18 +310,22 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a BlackboardArtifactNode, an AbstractNode implementation that
|
* Constructs an AbstractNode implementation that can be used to represent a
|
||||||
* can be used to represent an artifact of any type.
|
* data artifact or analysis result of any type. The Lookup of the Node will
|
||||||
|
* contain the data artifact or analysis result and its parent content as
|
||||||
|
* its source content.
|
||||||
*
|
*
|
||||||
* @param artifact The artifact to represent.
|
* @param artifact The data artifact or analysis result.
|
||||||
*/
|
*/
|
||||||
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
public BlackboardArtifactNode(BlackboardArtifact artifact) {
|
||||||
this(artifact, IconsUtil.getIconFilePath(artifact.getArtifactTypeID()));
|
this(artifact, IconsUtil.getIconFilePath(artifact.getArtifactTypeID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the artifact type of the artifact.
|
* Returns the artifact type of the artifact.
|
||||||
|
*
|
||||||
* @param artifact The artifact.
|
* @param artifact The artifact.
|
||||||
|
*
|
||||||
* @return The artifact type or null if no type could be retrieved.
|
* @return The artifact type or null if no type could be retrieved.
|
||||||
*/
|
*/
|
||||||
private static BlackboardArtifact.Type getType(BlackboardArtifact artifact) {
|
private static BlackboardArtifact.Type getType(BlackboardArtifact artifact) {
|
||||||
@ -331,54 +341,52 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
* Creates a Lookup object for this node and populates it with both the
|
* Creates a Lookup object for this node and populates it with both the
|
||||||
* artifact this node represents and its source content.
|
* artifact this node represents and its source content.
|
||||||
*
|
*
|
||||||
* @param artifact The artifact this node represents.
|
* @param artifact The artifact this node represents.
|
||||||
|
* @param useAssociatedFile True if the source content in the Lookup should
|
||||||
|
* be the associated file instead of the parent
|
||||||
|
* content.
|
||||||
*
|
*
|
||||||
* @return The Lookup.
|
* @return The Lookup.
|
||||||
*/
|
*/
|
||||||
private static Lookup createLookup(BlackboardArtifact artifact) {
|
private static Lookup createLookup(BlackboardArtifact artifact, boolean useAssociatedFile) {
|
||||||
final long objectID = artifact.getObjectID();
|
/*
|
||||||
|
* Get the source content.
|
||||||
|
*/
|
||||||
|
Content content = null;
|
||||||
try {
|
try {
|
||||||
Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
|
if (useAssociatedFile) {
|
||||||
if (content == null) {
|
content = getPathIdFile(artifact);
|
||||||
return Lookups.fixed(artifact);
|
|
||||||
} else {
|
} else {
|
||||||
return Lookups.fixed(artifact, content);
|
long srcObjectID = artifact.getObjectID();
|
||||||
|
content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID));
|
||||||
}
|
}
|
||||||
} catch (ExecutionException ex) {
|
} catch (ExecutionException ex) {
|
||||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS
|
||||||
return Lookups.fixed(artifact);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Creates a Lookup object for this node and populates it with both the
|
* Make an Autopsy Data Model wrapper for the artifact.
|
||||||
* artifact this node represents and its source content.
|
*
|
||||||
*
|
* NOTE: The creation of an Autopsy Data Model independent of the
|
||||||
* @param artifact The artifact this node represents.
|
* NetBeans nodes is a work in progress. At the time this comment is
|
||||||
* @param lookupIsAssociatedFile True if the Content lookup should be made
|
* being written, this object is only used by the analysis content
|
||||||
* for the associated file instead of the
|
* viewer.
|
||||||
* parent file.
|
*/
|
||||||
*
|
TskContentItem artifactItem;
|
||||||
* @return The Lookup.
|
if (artifact instanceof AnalysisResult) {
|
||||||
*/
|
artifactItem = new AnalysisResultItem((AnalysisResult) artifact);
|
||||||
private static Lookup createLookup(BlackboardArtifact artifact, boolean lookupIsAssociatedFile) {
|
|
||||||
Content content = null;
|
|
||||||
if (lookupIsAssociatedFile) {
|
|
||||||
try {
|
|
||||||
content = getPathIdFile(artifact);
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS
|
|
||||||
content = null;
|
|
||||||
}
|
|
||||||
if (content == null) {
|
|
||||||
return Lookups.fixed(artifact);
|
|
||||||
} else {
|
|
||||||
return Lookups.fixed(artifact, content);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return createLookup(artifact);
|
artifactItem = new TskContentItem(artifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the Lookup.
|
||||||
|
*/
|
||||||
|
if (content == null) {
|
||||||
|
return Lookups.fixed(artifact, artifactItem);
|
||||||
|
} else {
|
||||||
|
return Lookups.fixed(artifact, artifactItem, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -447,10 +455,10 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
|
|||||||
* action to view it in the timeline.
|
* action to view it in the timeline.
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact) &&
|
if (ViewArtifactInTimelineAction.hasSupportedTimeStamp(artifact)
|
||||||
// don't show ViewArtifactInTimelineAction for AnalysisResults.
|
&& // don't show ViewArtifactInTimelineAction for AnalysisResults.
|
||||||
(!(this.artifact instanceof AnalysisResult))) {
|
(!(this.artifact instanceof AnalysisResult))) {
|
||||||
|
|
||||||
actionsList.add(new ViewArtifactInTimelineAction(artifact));
|
actionsList.add(new ViewArtifactInTimelineAction(artifact));
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2019-2020 Basis Technology Corp.
|
* Copyright 2019-2021 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");
|
||||||
@ -22,19 +22,13 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.Tag;
|
import org.sleuthkit.datamodel.Tag;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,7 +40,6 @@ class GetSCOTask implements Runnable {
|
|||||||
|
|
||||||
private final WeakReference<AbstractContentNode<?>> weakNodeRef;
|
private final WeakReference<AbstractContentNode<?>> weakNodeRef;
|
||||||
private final PropertyChangeListener listener;
|
private final PropertyChangeListener listener;
|
||||||
private static final Logger logger = Logger.getLogger(GetSCOTask.class.getName());
|
|
||||||
|
|
||||||
GetSCOTask(WeakReference<AbstractContentNode<?>> weakContentRef, PropertyChangeListener listener) {
|
GetSCOTask(WeakReference<AbstractContentNode<?>> weakContentRef, PropertyChangeListener listener) {
|
||||||
this.weakNodeRef = weakContentRef;
|
this.weakNodeRef = weakContentRef;
|
||||||
@ -59,7 +52,7 @@ class GetSCOTask implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
AbstractContentNode<?> contentNode = weakNodeRef.get();
|
AbstractContentNode<?> contentNode = weakNodeRef.get();
|
||||||
|
|
||||||
//Check for stale reference or if columns are disabled
|
//Check for stale reference or if columns are disabled
|
||||||
if (contentNode == null || UserPreferences.getHideSCOColumns()) {
|
if (contentNode == null || UserPreferences.getHideSCOColumns()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -72,49 +65,18 @@ class GetSCOTask implements Runnable {
|
|||||||
//because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless
|
//because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless
|
||||||
CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance();
|
CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance();
|
||||||
scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute));
|
scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute));
|
||||||
|
|
||||||
if (CentralRepository.isEnabled()) {
|
if (CentralRepository.isEnabled()) {
|
||||||
Type type = null;
|
Type type = null;
|
||||||
String value = null;
|
String value = null;
|
||||||
String description = Bundle.GetSCOTask_occurrences_defaultDescription();
|
String description = Bundle.GetSCOTask_occurrences_defaultDescription();
|
||||||
if (contentNode instanceof BlackboardArtifactNode) {
|
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(contentNode.getContent());
|
||||||
BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact();
|
if (listOfPossibleAttributes.size() > 1) {
|
||||||
//for specific artifact types we still want to display information for the file instance correlation attribute
|
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know
|
||||||
if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()
|
description = Bundle.GetSCOTask_occurrences_multipleProperties();
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID()
|
} else if (!listOfPossibleAttributes.isEmpty()) {
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID()
|
//there should only be one item in the list
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()
|
type = listOfPossibleAttributes.get(0).getCorrelationType();
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
|
value = listOfPossibleAttributes.get(0).getCorrelationValue();
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID()
|
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()
|
|
||||||
|| bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
|
|
||||||
try {
|
|
||||||
if (bbArtifact.getParent() instanceof AbstractFile) {
|
|
||||||
type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
|
|
||||||
value = ((AbstractFile) bbArtifact.getParent()).getMd5Hash();
|
|
||||||
}
|
|
||||||
} catch (TskCoreException | CentralRepoException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
|
|
||||||
if (listOfPossibleAttributes.size() > 1) {
|
|
||||||
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know
|
|
||||||
description = Bundle.GetSCOTask_occurrences_multipleProperties();
|
|
||||||
} else if (!listOfPossibleAttributes.isEmpty()) {
|
|
||||||
//there should only be one item in the list
|
|
||||||
type = listOfPossibleAttributes.get(0).getCorrelationType();
|
|
||||||
value = listOfPossibleAttributes.get(0).getCorrelationValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (contentNode.getContent() instanceof AbstractFile) {
|
|
||||||
//use the file instance correlation attribute if the node is not a BlackboardArtifactNode
|
|
||||||
try {
|
|
||||||
type = CorrelationAttributeInstance.getDefaultCorrelationTypes().get(CorrelationAttributeInstance.FILES_TYPE_ID);
|
|
||||||
value = ((AbstractFile) contentNode.getContent()).getMd5Hash();
|
|
||||||
} catch (CentralRepoException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get correlation type to determine value for O column for file", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description));
|
scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description));
|
||||||
}
|
}
|
||||||
|
56
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
56
Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2021-2021 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.datamodel;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Autopsy Data Model item with an underlying Sleuth Kit Data Model object
|
||||||
|
* that implements the Sleuth Kit Data Model's Content interface.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public class TskContentItem {
|
||||||
|
|
||||||
|
private final Content tskContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data
|
||||||
|
* Model object that implements the Sleuth Kit Data Model's Content
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @param content The underlying Sleuth Kit Data Model object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
TskContentItem(Content sleuthKitContent) {
|
||||||
|
this.tskContent = sleuthKitContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying Sleuth Kit Data Model object.
|
||||||
|
*
|
||||||
|
* @return The Sleuth Kit Data Model object.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public Content getTskContent() {
|
||||||
|
return tskContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,10 +22,12 @@
|
|||||||
package org.sleuthkit.autopsy.recentactivity;
|
package org.sleuthkit.autopsy.recentactivity;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -63,7 +65,7 @@ class ShellBagParser {
|
|||||||
|
|
||||||
ShellBagParser sbparser = new ShellBagParser();
|
ShellBagParser sbparser = new ShellBagParser();
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(regfile), StandardCharsets.UTF_8))) {
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
while (line != null) {
|
while (line != null) {
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
|
24
thirdparty/rr-full/plugins/shellbags.pl
vendored
24
thirdparty/rr-full/plugins/shellbags.pl
vendored
@ -779,7 +779,7 @@ sub parseFolderEntry {
|
|||||||
$tag = 0;
|
$tag = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$str .= $s;
|
$str .= $s;
|
||||||
$cnt++;
|
$cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -799,7 +799,7 @@ sub parseFolderEntry {
|
|||||||
$tag = 0;
|
$tag = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$str .= $s;
|
$str .= $s;
|
||||||
$cnt++;
|
$cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,13 +858,12 @@ sub parseFolderEntry {
|
|||||||
|
|
||||||
my $str = substr($data,$ofs,length($data) - 30);
|
my $str = substr($data,$ofs,length($data) - 30);
|
||||||
my $longname = (split(/\00\00/,$str,2))[0];
|
my $longname = (split(/\00\00/,$str,2))[0];
|
||||||
$longname =~ s/\00//g;
|
|
||||||
|
|
||||||
if ($longname ne "") {
|
if ($longname ne "") {
|
||||||
$item{name} = $longname;
|
$item{name} = Utf16ToUtf8($longname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item{name} = $shortname;
|
$item{name} = UTF16ToUtf8($shortname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return %item;
|
return %item;
|
||||||
@ -957,7 +956,7 @@ sub parseFolderEntry2 {
|
|||||||
|
|
||||||
$item{name} = (split(/\00\00/,$str,2))[0];
|
$item{name} = (split(/\00\00/,$str,2))[0];
|
||||||
$item{name} =~ s/\13\20/\2D\00/;
|
$item{name} =~ s/\13\20/\2D\00/;
|
||||||
$item{name} =~ s/\00//g;
|
$item{name} = Utf16ToUtf8($item{name});
|
||||||
|
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
@ -1024,7 +1023,7 @@ sub shellItem0x52 {
|
|||||||
$tag = 0;
|
$tag = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item{name} .= $d;
|
$item{name} .= $d;
|
||||||
$cnt += 2;
|
$cnt += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1119,4 +1118,15 @@ sub getNum48 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Utf16ToUtf8()
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
sub Utf16ToUtf8 {
|
||||||
|
my $str = $_[0];
|
||||||
|
Encode::from_to($str,'UTF-16LE','utf8');
|
||||||
|
$str = Encode::decode_utf8($str);
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
7
thirdparty/rr-full/plugins/shellbags_test.pl
vendored
7
thirdparty/rr-full/plugins/shellbags_test.pl
vendored
@ -100,7 +100,7 @@ sub traverse {
|
|||||||
my $type = unpack("C",substr($values{$v},2,1));
|
my $type = unpack("C",substr($values{$v},2,1));
|
||||||
my $size = unpack("v",substr($values{$v},0,2));
|
my $size = unpack("v",substr($values{$v},0,2));
|
||||||
# probe($values{$v});
|
# probe($values{$v});
|
||||||
|
|
||||||
# Need to first check to see if the parent of the item was a zip folder
|
# Need to first check to see if the parent of the item was a zip folder
|
||||||
# and if the 'zipsubfolder' value is set to 1
|
# and if the 'zipsubfolder' value is set to 1
|
||||||
if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) {
|
if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) {
|
||||||
@ -411,12 +411,13 @@ sub parseFolderItem {
|
|||||||
$longname =~ s/\x00//g;
|
$longname =~ s/\x00//g;
|
||||||
|
|
||||||
if ($longname ne "") {
|
if ($longname ne "") {
|
||||||
$item{name} = $longname;
|
$item{name} = Utf16ToUtf8($longname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item{name} = $shortname;
|
$item{name} = Utf16ToUtf8($shortname);
|
||||||
}
|
}
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
10
thirdparty/rr-full/plugins/shellbags_xp.pl
vendored
10
thirdparty/rr-full/plugins/shellbags_xp.pl
vendored
@ -37,6 +37,9 @@ package shellbags_xp;
|
|||||||
use strict;
|
use strict;
|
||||||
use Time::Local;
|
use Time::Local;
|
||||||
|
|
||||||
|
require 'shellitems.pl';
|
||||||
|
|
||||||
|
|
||||||
my %config = (hive => "NTUSER\.DAT",
|
my %config = (hive => "NTUSER\.DAT",
|
||||||
hivemask => 32,
|
hivemask => 32,
|
||||||
output => "report",
|
output => "report",
|
||||||
@ -779,10 +782,10 @@ sub parseFolderEntry {
|
|||||||
$longname =~ s/\x00//g;
|
$longname =~ s/\x00//g;
|
||||||
|
|
||||||
if ($longname ne "") {
|
if ($longname ne "") {
|
||||||
$item{name} = $longname;
|
$item{name} = Utf16ToUtf8($longname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item{name} = $shortname;
|
$item{name} = _Utf16ToUtf8($shortname);
|
||||||
}
|
}
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
@ -871,7 +874,7 @@ sub parseFolderEntry2 {
|
|||||||
|
|
||||||
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
||||||
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
||||||
$item{name} =~ s/\x00//g;
|
$item{name} = Utf16ToUtf8($item{name});
|
||||||
|
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
@ -931,4 +934,5 @@ sub printData {
|
|||||||
return @display;
|
return @display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
17
thirdparty/rr-full/shellitems.pl
vendored
17
thirdparty/rr-full/shellitems.pl
vendored
@ -27,6 +27,7 @@
|
|||||||
# Author: H. Carvey, keydet89@yahoo.com
|
# Author: H. Carvey, keydet89@yahoo.com
|
||||||
#-----------------------------------------------------------
|
#-----------------------------------------------------------
|
||||||
use Time::Local;
|
use Time::Local;
|
||||||
|
use Encode::Unicode;
|
||||||
|
|
||||||
my %guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center",
|
my %guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center",
|
||||||
"{7a979262-40ce-46ff-aeee-7884ac3b6136}" => "Add Hardware",
|
"{7a979262-40ce-46ff-aeee-7884ac3b6136}" => "Add Hardware",
|
||||||
@ -634,10 +635,10 @@ sub parseFolderEntry {
|
|||||||
$longname =~ s/\x00//g;
|
$longname =~ s/\x00//g;
|
||||||
|
|
||||||
if ($longname ne "") {
|
if ($longname ne "") {
|
||||||
$item{name} = $longname;
|
$item{name} = Utf16ToUtf8($longname);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$item{name} = $shortname;
|
$item{name} = Utf16ToUtf8($shortname);
|
||||||
}
|
}
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
@ -716,7 +717,7 @@ sub parseFolderEntry2 {
|
|||||||
|
|
||||||
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
$item{name} = (split(/\x00\x00/,$str,2))[0];
|
||||||
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
$item{name} =~ s/\x13\x20/\x2D\x00/;
|
||||||
$item{name} =~ s/\x00//g;
|
$item{name} = Utf16ToUtf8($item{name});
|
||||||
|
|
||||||
return %item;
|
return %item;
|
||||||
}
|
}
|
||||||
@ -837,4 +838,14 @@ sub getNum48 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Utf16ToUtf8()
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
sub Utf16ToUtf8 {
|
||||||
|
my $str = $_[0];
|
||||||
|
Encode::from_to($str,'UTF-16LE','utf8');
|
||||||
|
$str = Encode::decode_utf8($str);
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user