diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java index 5f47487f94..b1069ba5b9 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/AddEditCentralRepoCommentAction.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.centralrepository; import java.awt.event.ActionEvent; +import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; @@ -64,7 +65,13 @@ public final class AddEditCentralRepoCommentAction extends AbstractAction { correlationAttributeInstance = CorrelationAttributeUtil.getCorrAttrForFile(file); if (correlationAttributeInstance == null) { addToDatabase = true; - correlationAttributeInstance = CorrelationAttributeUtil.makeCorrAttrFromFile(file); + final List 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) { putValue(Action.NAME, Bundle.AddEditCentralRepoCommentAction_menuItemText_addEditCentralRepoCommentEmptyFile()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index 80e4ada388..643f5d5de7 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -53,7 +53,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.SleuthkitCase; @@ -116,7 +115,7 @@ public final class OtherOccurrences { // correlate on blackboard artifact attributes if they exist and supported BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); 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 diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED index a80f1f7d86..724758847b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Bundle.properties-MERGED @@ -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.nullName.message=Database name is null. CorrelationAttributeUtil.emailaddresses.text=Email Addresses -CorrelationType.DOMAIN.displayName=Domains -CorrelationType.EMAIL.displayName=Email Addresses -CorrelationType.FILES.displayName=Files +CorrelationType.DOMAIN.displayName=Domain +CorrelationType.EMAIL.displayName=Email Address +CorrelationType.FILES.displayName=File MD5 CorrelationType.ICCID.displayName=ICCID Number CorrelationType.IMEI.displayName=IMEI Number CorrelationType.IMSI.displayName=IMSI Number -CorrelationType.MAC.displayName=MAC Addresses +CorrelationType.MAC.displayName=MAC Address CorrelationType.OS_ACCOUNT.displayName=Os Account -CorrelationType.PHONE.displayName=Phone Numbers -CorrelationType.PROG_NAME.displayName=Installed Programs -CorrelationType.SSID.displayName=Wireless Networks -CorrelationType.USBID.displayName=USB Devices +CorrelationType.PHONE.displayName=Phone Number +CorrelationType.PROG_NAME.displayName=Installed Program +CorrelationType.SSID.displayName=Wireless Network +CorrelationType.USBID.displayName=USB Device EamArtifactInstances.knownStatus.bad=Bad EamArtifactInstances.knownStatus.known=Known EamArtifactInstances.knownStatus.unknown=Unknown diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java index 6d2ff51c01..5e64e3994b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeUtil.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2017-2020 Basis Technology Corp. + * Copyright 2017-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * 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.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; +import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -41,7 +42,6 @@ import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.OsAccount; -import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -55,7 +55,7 @@ public class CorrelationAttributeUtil { private static final List domainsToSkip = Arrays.asList("localhost", "127.0.0.1"); // artifact ids that specifically have a TSK_DOMAIN attribute that should be handled by CR - private static Set DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( + private static final Set DOMAIN_ARTIFACT_TYPE_IDS = new HashSet<>(Arrays.asList( ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID(), ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID(), ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID(), @@ -69,7 +69,7 @@ public class CorrelationAttributeUtil { * for the email address correlation attribute type. This string is * 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. */ @@ -78,56 +78,45 @@ public class CorrelationAttributeUtil { return Bundle.CorrelationAttributeUtil_emailaddresses_text(); } - // Defines which artifact types act as the sources for CR data. - // Most notably, does not include KEYWORD HIT, CALLLOGS, MESSAGES, CONTACTS - // TSK_INTERESTING_ARTIFACT_HIT (See JIRA-6129 for more details on the - // interesting artifact hit). - // IMPORTANT: This set should be updated for new artifacts types that need to - // be inserted into the CR. - private static final Set SOURCE_TYPES_FOR_CR_INSERT = new HashSet() { - { - 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()); + private static List makeCorrAttrsToSave(DataArtifact artifact) { + int artifactTypeID = artifact.getArtifactTypeID(); + //The account fields in these types are expected to be saved in a TSK_ACCOUNT artifact, which will be processed + if (artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() + || artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) { + return new ArrayList<>(); } - }; - - /** - * 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 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<>(); + 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 + * 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 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, * please use makeCorrAttrsToSave. An artifact that can have correlatable * 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 * 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 - * the artifact. + * the content. */ - public static List makeCorrAttrsForCorrelation(BlackboardArtifact artifact) { + public static List 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 makeCorrAttrsForSearch(AnalysisResult analysisResult) { List correlationAttrs = new ArrayList<>(); try { - BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); - if (sourceArtifact != null) { - - List attributes = sourceArtifact.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); + int artifactTypeID = analysisResult.getArtifactTypeID(); + if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { + BlackboardAttribute setNameAttr = analysisResult.getAttribute(BlackboardAttribute.Type.TSK_SET_NAME); + if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) { + makeCorrAttrFromArtifactAttr(correlationAttrs, analysisResult, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID, analysisResult.getAttributes()); } + } 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 makeCorrAttrsForSearch(DataArtifact artifact) { + List correlationAttrs = new ArrayList<>(); + try { + + List 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) { 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 corrAttrInstances, BlackboardArtifact artifact, List attributes) throws TskCoreException, CentralRepoException, CorrelationAttributeNormalizationException { - CorrelationAttributeInstance corrAttr = null; - /* * 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))) { value = getAttribute(attributes, new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString(); } - /* * Normalize the phone number. */ if (value != null && CorrelationAttributeNormalizer.isValidPhoneNumber(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) { 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. * @@ -506,21 +486,21 @@ public class CorrelationAttributeUtil { */ private static CorrelationAttributeInstance makeCorrAttr(BlackboardArtifact artifact, CorrelationAttributeInstance.Type correlationType, String value, Content sourceContent, Content dataSource) { + Content srcContent = sourceContent; + Content dataSrc = dataSource; try { - - if (sourceContent == null) { - sourceContent = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(artifact.getObjectID()); + if (srcContent == null) { + srcContent = 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}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID(), artifact.getId()}); // NON-NLS return null; } - - if (dataSource == null) { - dataSource = sourceContent.getDataSource(); + if (dataSrc == null) { + dataSrc = srcContent.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}", new Object[]{correlationType.getDisplayName(), artifact.getObjectID()}); // NON-NLS return null; @@ -532,24 +512,24 @@ public class CorrelationAttributeUtil { correlationType, value, correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc), "", "", TskData.FileKnown.UNKNOWN, - sourceContent.getId()); + srcContent.getId()); } 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", new Object[]{correlationType.getDisplayName(), artifact.getId()}); return null; } - AbstractFile bbSourceFile = (AbstractFile) sourceContent; + AbstractFile bbSourceFile = (AbstractFile) srcContent; return new CorrelationAttributeInstance( correlationType, value, correlationCase, - CorrelationDataSource.fromTSKDataSource(correlationCase, dataSource), + CorrelationDataSource.fromTSKDataSource(correlationCase, dataSrc), bbSourceFile.getParentPath() + bbSourceFile.getName(), "", 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. * @@ -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 * repository by this method. @@ -711,23 +696,23 @@ public class CorrelationAttributeUtil { * * @return The correlation attribute instance or null, if an error occurred. */ - public static CorrelationAttributeInstance makeCorrAttrFromFile(AbstractFile file) { - + private static List makeCorrAttrsForSearch(AbstractFile file) { + List fileTypeList = new ArrayList<>(); // will be an empty or single element list as was decided in 7852 if (!isSupportedAbstractFileType(file)) { - return null; + return fileTypeList; } // We need a hash to make the correlation artifact instance. String md5 = file.getMd5Hash(); if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) { - return null; + return fileTypeList; } try { CorrelationAttributeInstance.Type filesType = CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); CorrelationCase correlationCase = CentralRepository.getInstance().getCase(Case.getCurrentCaseThrows()); - return new CorrelationAttributeInstance( + fileTypeList.add(new CorrelationAttributeInstance( filesType, file.getMd5Hash(), correlationCase, @@ -735,21 +720,17 @@ public class CorrelationAttributeUtil { file.getParentPath() + file.getName(), "", TskData.FileKnown.UNKNOWN, - file.getId()); - + file.getId())); } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS - return null; } catch (CentralRepoException ex) { logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS - return null; } catch (CorrelationAttributeNormalizationException ex) { logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS - return null; } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Error getting current case", ex); // NON-NLS - return null; } + return fileTypeList; } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 474ac1cd85..1f1bd3923f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -311,18 +311,18 @@ public final class CaseEventListener implements PropertyChangeListener { * Sets the known status for the correlation attribute instance for the * given abstract file. * - * @param af The abstract file for which to set the correlation - * attribute instance. + * @param af The abstract file for which to set the correlation + * attribute instance. * @param knownStatus The new known status for the correlation attribute - * instance. + * instance. */ private void setContentKnownStatus(AbstractFile af, TskData.FileKnown knownStatus) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile(af); - - if (eamArtifact != null) { + final List md5CorrelationAttr = CorrelationAttributeUtil.makeCorrAttrsForSearch(af); + 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 // send update to Central Repository db try { - dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus); + dbManager.setAttributeInstanceKnownStatus(md5CorrelationAttr.get(0), knownStatus); } catch (CentralRepoException ex) { 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 * 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. */ 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 * 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. */ private void setArtifactKnownStatus(BlackboardArtifact bbArtifact, TskData.FileKnown knownStatus) { - List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbArtifact); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { try { dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus); @@ -528,7 +528,7 @@ public final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { //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 - List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbTag.getArtifact()); + List convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForSearch(bbTag.getArtifact()); for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); } @@ -566,9 +566,10 @@ public final class CaseEventListener implements PropertyChangeListener { if (!hasTagWithConflictingKnownStatus) { Content taggedContent = contentTag.getContent(); if (taggedContent instanceof AbstractFile) { - final CorrelationAttributeInstance eamArtifact = CorrelationAttributeUtil.makeCorrAttrFromFile((AbstractFile) taggedContent); - if (eamArtifact != null) { - CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); + final List eamArtifact = CorrelationAttributeUtil.makeCorrAttrsForSearch((AbstractFile) taggedContent); + if (!eamArtifact.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 + CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact.get(0), tagName.getKnownStatus()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 7aa229949e..04275f0e98 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -70,6 +70,7 @@ import org.sleuthkit.datamodel.Score; */ @NbBundle.Messages({"IngestEventsListener.ingestmodule.name=Central Repository"}) public class IngestEventsListener { + private static final Logger LOGGER = Logger.getLogger(CorrelationAttributeInstance.class.getName()); private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED); private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(DATA_ADDED); @@ -246,15 +247,15 @@ public class IngestEventsListener { originalArtifact.getArtifactID())); makeAndPostInterestingArtifact(originalArtifact, attributesForNewArtifact, Bundle.IngestEventsListener_prevExists_text()); } - - + /** * Make an interesting item artifact to flag the passed in artifact. * * @param originalArtifact Artifact in current case we want to flag * @param attributesForNewArtifact Attributes to assign to the new * 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 attributesForNewArtifact, String configuration) { try { @@ -263,8 +264,8 @@ public class IngestEventsListener { Blackboard blackboard = tskCase.getBlackboard(); // Create artifact if it doesn't already exist. if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_ARTIFACT_HIT, attributesForNewArtifact)) { - BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( - BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, + BlackboardArtifact newInterestingArtifact = abstractFile.newAnalysisResult( + BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT, Score.SCORE_LIKELY_NOTABLE, null, configuration, null, attributesForNewArtifact) .getAnalysisResult(); @@ -368,8 +369,8 @@ public class IngestEventsListener { try { dataSource = ((DataSourceAnalysisEvent) event).getDataSource(); /* - * We only care about Images for the purpose of - * updating hash values. + * We only care about Images for the purpose of updating hash + * values. */ if (!(dataSource instanceof Image)) { return; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java index ef623f44cf..b056eb11db 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentViewer.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.awt.Component; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; 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.NoCurrentCaseException; 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.DataFetchWorker; -import org.sleuthkit.datamodel.AnalysisResult; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.datamodel.AnalysisResultItem; 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) public class AnalysisResultsContentViewer implements DataContentViewer { private static final Logger logger = Logger.getLogger(AnalysisResultsContentPanel.class.getName()); - - // isPreferred value private static final int PREFERRED_VALUE = 3; - private final AnalysisResultsViewModel viewModel = new AnalysisResultsViewModel(); private final AnalysisResultsContentPanel panel = new AnalysisResultsContentPanel(); @@ -125,26 +123,24 @@ public class AnalysisResultsContentViewer implements DataContentViewer { @Override public boolean isSupported(Node node) { - if (node == null) { + if (Objects.isNull(node)) { return false; } - // There needs to either be a file with an AnalysisResult or an AnalysisResult in the lookup. - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content instanceof AnalysisResult) { - return true; - } - - if (content == null || content instanceof BlackboardArtifact) { - continue; - } + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + return true; + } + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + if (!Objects.isNull(contentItem)) { + Content content = contentItem.getTskContent(); try { if (Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard().hasAnalysisResults(content.getId())) { return true; } } 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) { return PREFERRED_VALUE; } + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 03720e0cbe..37e4114168 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -20,9 +20,8 @@ package org.sleuthkit.autopsy.contentviewers.analysisresults; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -31,14 +30,14 @@ import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; 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.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.TskCoreException; /** - * * Creates a representation of a list of analysis results gathered from a node. */ public class AnalysisResultsViewModel { @@ -72,7 +71,7 @@ public class AnalysisResultsViewModel { * @return The attributes to display. */ List> getAttributesToDisplay() { - return attributesToDisplay; + return Collections.unmodifiableList(attributesToDisplay); } /** @@ -118,7 +117,7 @@ public class AnalysisResultsViewModel { * @return The analysis results to be displayed. */ List 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()); } - Optional aggregateScore = Optional.empty(); - Optional nodeContent = Optional.empty(); - // maps id of analysis result to analysis result to prevent duplication - Map allAnalysisResults = new HashMap<>(); - Optional selectedResult = Optional.empty(); - - // Find first content that is not an artifact within node - for (Content content : node.getLookup().lookupAll(Content.class)) { - if (content == null || content instanceof BlackboardArtifact) { - continue; - } - - try { - nodeContent = Optional.of(content); - - // get the aggregate score of that content - aggregateScore = Optional.ofNullable(content.getAggregateScore()); - - // and add all analysis results to mapping - content.getAllAnalysisResults().stream() - .forEach((ar) -> allAnalysisResults.put(ar.getArtifactID(), ar)); - - break; - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Unable to get analysis results for content with obj id " + content.getId(), ex); + Content analyzedContent = null; + AnalysisResult selectedAnalysisResult = null; + Score aggregateScore = null; + List analysisResults = Collections.emptyList(); + long selectedObjectId = 0; + try { + AnalysisResultItem analysisResultItem = node.getLookup().lookup(AnalysisResultItem.class); + if (Objects.nonNull(analysisResultItem)) { + /* + * 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 + * as the source of the analysis results to display. + */ + selectedAnalysisResult = analysisResultItem.getAnalysisResult(); + selectedObjectId = selectedAnalysisResult.getId(); + analyzedContent = selectedAnalysisResult.getParent(); + } else { + /* + * The content represented by the Node is something other than + * an analysis result. Use it as the source of the analysis + * results to display. + */ + TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); + 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 analysisResults = node.getLookup().lookupAll(AnalysisResult.class); - if (analysisResults.size() > 0) { - - // get any items with a score - List 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 displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values()); - - return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent); + /* + * Use the data collected above to construct the view model. + */ + List displayAttributes = getOrderedDisplayAttributes(analysisResults); + return new NodeResults(displayAttributes, Optional.ofNullable(selectedAnalysisResult), Optional.ofNullable(aggregateScore), Optional.ofNullable(analyzedContent)); } + } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java b/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java index 77432b3ffe..3a3e853501 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/annotations/AnnotationUtils.java @@ -372,7 +372,7 @@ public class AnnotationUtils { return new ArrayList<>(); } - List> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact) + List> lookupKeys = CorrelationAttributeUtil.makeCorrAttrsForSearch(artifact) .stream() .map(cai -> Pair.of(cai.getCorrelationType(), cai.getCorrelationValue())) .collect(Collectors.toList()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java index 0a43d47102..daf8cd84da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentNode.java @@ -102,7 +102,7 @@ public abstract class AbstractContentNode extends ContentNode * @param content Underlying Content instances */ AbstractContentNode(T content) { - this(content, Lookups.singleton(content)); + this(content, Lookups.fixed(content, new TskContentItem(content))); } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java new file mode 100755 index 0000000000..442d070f5c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AnalysisResultItem.java @@ -0,0 +1,51 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 Basis Technology Corp. + * Contact: carrier sleuthkit 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()); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index e3bad44705..bf57a00caa 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -84,8 +84,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.Score; /** - * A BlackboardArtifactNode is an AbstractNode implementation that can be used - * to represent an artifact of any type. + * An AbstractNode implementation that can be used to represent an data artifact + * or analysis result of any type. */ public class BlackboardArtifactNode extends AbstractContentNode { @@ -219,17 +219,20 @@ public class BlackboardArtifactNode extends AbstractContentNode artifact.getSleuthkitCase().getContentById(objectID)); - if (content == null) { - return Lookups.fixed(artifact); + if (useAssociatedFile) { + content = getPathIdFile(artifact); } else { - return Lookups.fixed(artifact, content); + long srcObjectID = artifact.getObjectID(); + content = contentCache.get(srcObjectID, () -> artifact.getSleuthkitCase().getContentById(srcObjectID)); } } catch (ExecutionException ex) { - logger.log(Level.SEVERE, MessageFormat.format("Error getting source content (artifact objID={0}", artifact.getId()), ex); //NON-NLS - return Lookups.fixed(artifact); + logger.log(Level.SEVERE, MessageFormat.format("Error getting source/associated content (artifact object ID={0})", artifact.getId()), ex); //NON-NLS } - } - /** - * Creates a Lookup object for this node and populates it with both the - * artifact this node represents and its source content. - * - * @param artifact The artifact this node represents. - * @param lookupIsAssociatedFile True if the Content lookup should be made - * for the associated file instead of the - * parent file. - * - * @return The Lookup. - */ - 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); - } + /* + * Make an Autopsy Data Model wrapper for the artifact. + * + * NOTE: The creation of an Autopsy Data Model independent of the + * NetBeans nodes is a work in progress. At the time this comment is + * being written, this object is only used by the analysis content + * viewer. + */ + TskContentItem artifactItem; + if (artifact instanceof AnalysisResult) { + artifactItem = new AnalysisResultItem((AnalysisResult) artifact); } 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 sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,19 +22,13 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.List; -import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; -import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.Logger; 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.TskCoreException; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; /** @@ -46,7 +40,6 @@ class GetSCOTask implements Runnable { private final WeakReference> weakNodeRef; private final PropertyChangeListener listener; - private static final Logger logger = Logger.getLogger(GetSCOTask.class.getName()); GetSCOTask(WeakReference> weakContentRef, PropertyChangeListener listener) { this.weakNodeRef = weakContentRef; @@ -59,7 +52,7 @@ class GetSCOTask implements Runnable { public void run() { 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()) { 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 CorrelationAttributeInstance fileAttribute = contentNode.getCorrelationAttributeInstance(); scoData.setComment(contentNode.getCommentProperty(tags, fileAttribute)); - if (CentralRepository.isEnabled()) { Type type = null; String value = null; String description = Bundle.GetSCOTask_occurrences_defaultDescription(); - if (contentNode instanceof BlackboardArtifactNode) { - BlackboardArtifact bbArtifact = ((BlackboardArtifactNode) contentNode).getArtifact(); - //for specific artifact types we still want to display information for the file instance correlation attribute - if (bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID() - || bbArtifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID() - || 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 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); - } + List listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForSearch(contentNode.getContent()); + 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(); } scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(type, value, description)); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java new file mode 100755 index 0000000000..999474cc1d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TskContentItem.java @@ -0,0 +1,56 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2021-2021 Basis Technology Corp. + * Contact: carrier sleuthkit 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; + } + +} diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java index 9d36233407..85c13c6a1d 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ShellBagParser.java @@ -22,10 +22,12 @@ package org.sleuthkit.autopsy.recentactivity; import java.io.BufferedReader; -import java.io.FileReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -63,7 +65,7 @@ class 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(); while (line != null) { line = line.trim(); diff --git a/thirdparty/rr-full/plugins/shellbags.pl b/thirdparty/rr-full/plugins/shellbags.pl index f4400cb4f0..b0e71ec299 100644 --- a/thirdparty/rr-full/plugins/shellbags.pl +++ b/thirdparty/rr-full/plugins/shellbags.pl @@ -779,7 +779,7 @@ sub parseFolderEntry { $tag = 0; } else { - $str .= $s; + $str .= $s; $cnt++; } } @@ -799,7 +799,7 @@ sub parseFolderEntry { $tag = 0; } else { - $str .= $s; + $str .= $s; $cnt++; } } @@ -858,13 +858,12 @@ sub parseFolderEntry { my $str = substr($data,$ofs,length($data) - 30); my $longname = (split(/\00\00/,$str,2))[0]; - $longname =~ s/\00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = $shortname; + $item{name} = UTF16ToUtf8($shortname); } } return %item; @@ -957,7 +956,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\00\00/,$str,2))[0]; $item{name} =~ s/\13\20/\2D\00/; - $item{name} =~ s/\00//g; + $item{name} = Utf16ToUtf8($item{name}); return %item; } @@ -1024,7 +1023,7 @@ sub shellItem0x52 { $tag = 0; } else { - $item{name} .= $d; + $item{name} .= $d; $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; \ No newline at end of file diff --git a/thirdparty/rr-full/plugins/shellbags_test.pl b/thirdparty/rr-full/plugins/shellbags_test.pl index 7ff3a5a4d5..3b068ea3ac 100644 --- a/thirdparty/rr-full/plugins/shellbags_test.pl +++ b/thirdparty/rr-full/plugins/shellbags_test.pl @@ -100,7 +100,7 @@ sub traverse { my $type = unpack("C",substr($values{$v},2,1)); my $size = unpack("v",substr($values{$v},0,2)); # probe($values{$v}); - + # 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 if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) { @@ -411,12 +411,13 @@ sub parseFolderItem { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = $shortname; + $item{name} = Utf16ToUtf8($shortname); } return %item; } + 1; diff --git a/thirdparty/rr-full/plugins/shellbags_xp.pl b/thirdparty/rr-full/plugins/shellbags_xp.pl index ce90cc3e7f..4eaea3e58d 100644 --- a/thirdparty/rr-full/plugins/shellbags_xp.pl +++ b/thirdparty/rr-full/plugins/shellbags_xp.pl @@ -37,6 +37,9 @@ package shellbags_xp; use strict; use Time::Local; +require 'shellitems.pl'; + + my %config = (hive => "NTUSER\.DAT", hivemask => 32, output => "report", @@ -779,10 +782,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = $shortname; + $item{name} = _Utf16ToUtf8($shortname); } return %item; } @@ -871,7 +874,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} =~ s/\x00//g; + $item{name} = Utf16ToUtf8($item{name}); return %item; } @@ -931,4 +934,5 @@ sub printData { return @display; } + 1; diff --git a/thirdparty/rr-full/shellitems.pl b/thirdparty/rr-full/shellitems.pl index 5ec51cd6a2..93b71e7c20 100644 --- a/thirdparty/rr-full/shellitems.pl +++ b/thirdparty/rr-full/shellitems.pl @@ -27,6 +27,7 @@ # Author: H. Carvey, keydet89@yahoo.com #----------------------------------------------------------- use Time::Local; +use Encode::Unicode; my %guids = ("{bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6}" => "Action Center", "{7a979262-40ce-46ff-aeee-7884ac3b6136}" => "Add Hardware", @@ -634,10 +635,10 @@ sub parseFolderEntry { $longname =~ s/\x00//g; if ($longname ne "") { - $item{name} = $longname; + $item{name} = Utf16ToUtf8($longname); } else { - $item{name} = $shortname; + $item{name} = Utf16ToUtf8($shortname); } return %item; } @@ -716,7 +717,7 @@ sub parseFolderEntry2 { $item{name} = (split(/\x00\x00/,$str,2))[0]; $item{name} =~ s/\x13\x20/\x2D\x00/; - $item{name} =~ s/\x00//g; + $item{name} = Utf16ToUtf8($item{name}); 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;