diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java index 2ca2893ac8..396480cd50 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java @@ -44,10 +44,10 @@ public final class FilesSet implements Serializable { private final String description; private final boolean ignoreKnownFiles; private final boolean ignoreUnallocatedSpace; - - private final boolean readOnly; + + private final boolean standardSet; private final int versionNumber; - + private final Map rules = new HashMap<>(); /** @@ -65,7 +65,7 @@ public final class FilesSet implements Serializable { public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map rules) { this(name, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, false, 0); } - + /** * Constructs an interesting files set. * @@ -75,24 +75,27 @@ public final class FilesSet implements Serializable { * the set. * @param ignoreUnallocatedSpace Whether or not to exclude unallocated space * from the set. - * @param readOnly Whether or not the FilesSet should be read only (if not it is editable). - * @param versionNumber The versionNumber for the FilesSet so that older versions can be replaced with newer versions. + * @param standardSet Whether or not the FilesSet is considered a + * standard interesting set file. + * @param versionNumber The versionNumber for the FilesSet so that + * older versions can be replaced with newer + * versions. * @param rules The rules that define the set. May be null, * but a set with no rules is the empty set. */ public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map rules, - boolean readOnly, int versionNumber) { + boolean standardSet, int versionNumber) { if ((name == null) || (name.isEmpty())) { throw new IllegalArgumentException("Interesting files set name cannot be null or empty"); } - + if (versionNumber < 0) { throw new IllegalArgumentException("version number must be >= 0"); } - - this.readOnly = readOnly; + + this.standardSet = standardSet; this.versionNumber = versionNumber; - + this.name = name; this.description = (description != null ? description : ""); this.ignoreKnownFiles = ignoreKnownFiles; @@ -103,23 +106,21 @@ public final class FilesSet implements Serializable { } /** - * Returns whether or not the file set is read only. - * @return Whether or not the file set is read only. + * @return Whether or not the FilesSet is considered a standard interesting + * set file. */ - boolean isReadOnly() { - return readOnly; + boolean isStandardSet() { + return standardSet; } /** - * Returns he versionNumber for the FilesSet so that older versions can be replaced with newer versions. - * @return The versionNumber for the FilesSet so that older versions can be replaced with newer versions. + * @return The versionNumber for the FilesSet so that older versions can be + * replaced with newer versions. */ int getVersionNumber() { return versionNumber; } - - /** * Gets the name of this interesting files set. * @@ -673,7 +674,6 @@ public final class FilesSet implements Serializable { * To ensure compatibility with existing serialized configuration * settings, this class cannot have a 'serialVersionUID'. */ - private final TextMatcher textMatcher; /** @@ -697,10 +697,10 @@ public final class FilesSet implements Serializable { AbstractTextCondition(Pattern regex) { this.textMatcher = new FilesSet.Rule.RegexMatcher(regex); } - + /** * Construct a case-insensitive multi-value text condition. - * + * * @param values The list of values in which to look for a match. */ AbstractTextCondition(List values) { @@ -832,7 +832,6 @@ public final class FilesSet implements Serializable { * To ensure compatibility with existing serialized configuration * settings, this class cannot have a 'serialVersionUID'. */ - private final static long SECS_PER_DAY = 60 * 60 * 24; private int daysIncluded; @@ -883,8 +882,8 @@ public final class FilesSet implements Serializable { // AbstractFile.getFileNameExtension() returns just the // extension chars and not the dot. super(normalize(extension), false); - } - + } + /** * Construct a case-insensitive file name extension condition. * @@ -911,29 +910,29 @@ public final class FilesSet implements Serializable { public boolean passes(AbstractFile file) { return this.textMatches(file.getNameExtension()); } - + /** * Strip "." from the start of extensions in the provided list. - * + * * @param extensions The list of extensions to be processed. - * + * * @return A post-processed list of extensions. */ private static List normalize(List extensions) { List values = new ArrayList<>(extensions); - - for (int i=0; i < values.size(); i++) { + + for (int i = 0; i < values.size(); i++) { values.set(i, normalize(values.get(i))); } - + return values; } - + /** * Strip "." from the start of the provided extension. - * + * * @param extension The extension to be processed. - * + * * @return A post-processed extension. */ private static String normalize(String extension) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cloud Storage.xml b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cloud Storage.xml new file mode 100644 index 0000000000..fd7e30e553 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cloud Storage.xml @@ -0,0 +1,33 @@ + + + + CloudMe.exe + Resilio Sync.exe + pcloud.exe + slack.exe + iCloudDrive.exe + GoogleDriveFS.exe + goodsync.exe + synqion.exe + nextcloud.exe + microsoft.microsoftskydrive.exe + CloudScheduler.exe + googledrivesync.exe + dropbox.exe + sugarsync.exe + carboniteUI.exe + owncloud.exe + creative cloud.exe + DropboxUniversal.exe + MegaApp.exe + yandexdisk2.exe + efcClient.exe + amazonphotos.exe + zohodocs.exe + MEGAsync.exe + SpiderOakONE.exe + box.exe + onedrive.exe + sync-taskbar.exe + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cryptocurrency Wallets.xml b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cryptocurrency Wallets.xml new file mode 100644 index 0000000000..865aef1c51 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Cryptocurrency Wallets.xml @@ -0,0 +1,39 @@ + + + + ^electrum(.*)portable.exe + jaxx liberty.exe + ^electron-cash(.*).exe$ + exodus.exe + bitcoin-qt.exe + dogecoin-qt.exe + Zecwallet Fullnode.exe + litecoin-qt.exe + zelcore.exe + bitpay.exe + verge-qt.exe + atomic wallet.exe + armoryqt.exe + eidoo.exe + ^electron-cash(.*)portable.exe$ + monero-wallet-gui.exe + coinomi.exe + electron-cash.exe + zelcore-portable.exe + qtum-qt.exe + dash-qt.exe + Zecwallet Lite.exe + copay.exe + multidoge.exe + neon.exe + ^electrum-dash(.*).exe$ + lisk.exe + stargazer.exe + GreenAddress Wallet.exe + ^electrum(.*).exe + ^Qtum-electrum-win-(.*).exe$ + BitherWinLauncher.exe + toastwallet.exe + guarda.exe + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Encryption Programs.xml b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Encryption Programs.xml new file mode 100644 index 0000000000..2c33ba06c6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/Encryption Programs.xml @@ -0,0 +1,25 @@ + + + + cexpertcmd.exe + aescrypt.exe + 7z.exe + gdbus.exe + AxCrypt.exe + Encrypto.exe + Cryptomator.exe + KeePass.exe + certainsafe.exe + Tutanota Desktop.exe + BitLockerDeviceEncryption.exe + EncFSMP.exe + HTTPS Everywhere + Tor Browser + cexpert_gui.exe + gpg.exe + Folder Lock.exe + GFileEncryption.exe + VeraCrypt.exe + Desktop-Bridge.exe + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/README.txt b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/README.txt new file mode 100644 index 0000000000..ad539f6d39 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingFileSetRules/README.txt @@ -0,0 +1,2 @@ + +Whenever files are added or removed from this folder, StandardInterestingFilesSetsLoader.INTERESTING_FILESETS_RULES_NAMES needs to be altered accordingly. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemsFilesSetSettings.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemsFilesSetSettings.java index 68e3e6c581..2f10567c22 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemsFilesSetSettings.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/InterestingItemsFilesSetSettings.java @@ -80,7 +80,7 @@ class InterestingItemsFilesSetSettings implements Serializable { private static final Logger logger = Logger.getLogger(InterestingItemsFilesSetSettings.class.getName()); private static final String TYPE_FILTER_ATTR = "typeFilter"; //NON-NLS private static final String EXTENSION_RULE_TAG = "EXTENSION"; //NON-NLS - private static final String READONLY = "readOnly"; + private static final String STANDARD_SET = "standardSet"; private static final String VERSION_NUMBER = "versionNumber"; private Map filesSets; @@ -382,15 +382,15 @@ class InterestingItemsFilesSetSettings implements Serializable { ignoreUnallocatedSpace = Boolean.parseBoolean(ignoreUnallocated); } - String isReadonlyString = setElem.getAttribute(READONLY); - boolean isReadOnly = false; - if (StringUtils.isNotBlank(isReadonlyString)) { - isReadOnly = Boolean.parseBoolean(isReadonlyString); + String isStandardSetString = setElem.getAttribute(STANDARD_SET); + boolean isStandardSet = false; + if (StringUtils.isNotBlank(isStandardSetString)) { + isStandardSet = Boolean.parseBoolean(isStandardSetString); } String versionNumberString = setElem.getAttribute(VERSION_NUMBER); int versionNumber = 0; - if (StringUtils.isNotBlank(isReadonlyString)) { + if (StringUtils.isNotBlank(isStandardSetString)) { try { versionNumber = Integer.parseInt(versionNumberString); } @@ -424,7 +424,7 @@ class InterestingItemsFilesSetSettings implements Serializable { // Make the files set. Note that degenerate sets with no rules are // allowed to facilitate the separation of set definition and rule // definitions. A set without rules is simply the empty set. - FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isReadOnly, versionNumber); + FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isStandardSet, versionNumber); filesSets.put(set.getName(), set); } // Note: This method takes a file path to support the possibility of @@ -479,7 +479,7 @@ class InterestingItemsFilesSetSettings implements Serializable { } Document doc = XMLUtil.loadDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath()); - return readDefinitionsXML(doc, xmlFile); + return readDefinitionsXML(doc, xmlFile.getPath()); } /** @@ -495,25 +495,25 @@ class InterestingItemsFilesSetSettings implements Serializable { * @throws * org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager.FilesSetsManagerException */ - static Map readDefinitionsXML(Document doc, File xmlFile) throws FilesSetsManager.FilesSetsManagerException { + static Map readDefinitionsXML(Document doc, String resourceName) throws FilesSetsManager.FilesSetsManagerException { // Parse the XML in the file. Map filesSets = new HashMap<>(); if (doc == null) { - logger.log(Level.SEVERE, "FilesSet definition file at {0}", (xmlFile == null) ? "" : xmlFile.getPath()); // NON-NLS + logger.log(Level.SEVERE, "FilesSet definition file at {0}", resourceName); // NON-NLS return filesSets; } // Get the root element. Element root = doc.getDocumentElement(); if (root == null) { logger.log(Level.SEVERE, "Failed to get root {0} element tag of FilesSet definition file at {1}", - new Object[]{FILE_SETS_ROOT_TAG, (xmlFile == null) ? "" : xmlFile.getPath()}); // NON-NLS + new Object[]{FILE_SETS_ROOT_TAG, resourceName}); // NON-NLS return filesSets; } // Read in the files set definitions. NodeList setElems = root.getElementsByTagName(FILE_SET_TAG); for (int i = 0; i < setElems.getLength(); ++i) { - readFilesSet((Element) setElems.item(i), filesSets, xmlFile.getPath()); + readFilesSet((Element) setElems.item(i), filesSets, resourceName); } return filesSets; } @@ -561,7 +561,7 @@ class InterestingItemsFilesSetSettings implements Serializable { setElement.setAttribute(NAME_ATTR, set.getName()); setElement.setAttribute(DESC_ATTR, set.getDescription()); setElement.setAttribute(IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles())); - setElement.setAttribute(READONLY, Boolean.toString(set.isReadOnly())); + setElement.setAttribute(STANDARD_SET, Boolean.toString(set.isStandardSet())); setElement.setAttribute(VERSION_NUMBER, Integer.toString(set.getVersionNumber())); // Add the child elements for the set membership rules. // All conditions of a rule will be written as a single element in the xml diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/StandardInterestingFilesSetsLoader.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/StandardInterestingFilesSetsLoader.java index 820f4a707e..a5a9442c7f 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/StandardInterestingFilesSetsLoader.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/StandardInterestingFilesSetsLoader.java @@ -18,28 +18,24 @@ */ package org.sleuthkit.autopsy.modules.interestingitems; +import com.google.common.collect.ImmutableList; import java.io.File; -import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import java.util.logging.Level; -import org.apache.commons.io.FileUtils; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.openide.modules.OnStart; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; -import org.openide.util.io.NbObjectOutputStream; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; /** * When the interesting items module loads, this runnable loads standard @@ -48,6 +44,14 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; @OnStart public class StandardInterestingFilesSetsLoader implements Runnable { + // The list of class resources representing the standard interesting files sets + // NOTE: This list must be updated to correspond to the standard interesting files sets in 'InterestingFileSetRules' + private final static List INTERESTING_FILESETS_RULES_NAMES = ImmutableList.of( + "Cloud Storage.xml", + "Cryptocurrency Wallets.xml", + "Encryption Programs.xml" + ); + private static final Logger LOGGER = Logger.getLogger(StandardInterestingFilesSetsLoader.class.getName()); private static final String CONFIG_DIR = "InterestingFileSetRules"; @@ -115,43 +119,6 @@ public class StandardInterestingFilesSetsLoader implements Runnable { } return standardInterestingFileSets; } - - - private static List getResourceFolderContents(String directory) { - // taken from https://stackoverflow.com/questions/11012819/how-can-i-get-a-resource-folder-from-inside-my-jar-file - final File jarFile = new File(StandardInterestingFilesSetsLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath()); - List toRet = new ArrayList<>(); - - if(jarFile.isFile()) { - JarFile jar = null; - try { - jar = new JarFile(jarFile); - final Enumeration entries = jar.entries(); //gives ALL entries in jar - while(entries.hasMoreElements()) { - final String name = entries.nextElement().getName(); - if (name.startsWith(directory + "/")) { //filter according to the path - toRet.add(name); - } - } - jar.close(); - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, "There was an error reading contents of jar file.", ex); - } finally { - if (jar != null) { - try { - jar.close(); - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, "There was an error closing jar resources while loading contents.", ex); - } - } - } - } else { - LOGGER.log(Level.WARNING, "Jar file could not be opened. No standard interesting files sets will be loaded."); - } - - return toRet; - } - /** * Add the InterestingFileSetRules directory to the user’s app data config @@ -162,14 +129,14 @@ public class StandardInterestingFilesSetsLoader implements Runnable { * non-null. */ private static void copyRulesDirectory(File rulesConfigDir) { - - try { - for (String resourceFile : getResourceFolderContents(DEFAULT_XML_FILTER)) { - updateStandardFilesSetConfigFile(rulesConfigDir, resourceFile); + for (String resourceFile : INTERESTING_FILESETS_RULES_NAMES) { + String resourcePath = "./" + CONFIG_DIR + "/" + resourceFile; + if (StandardInterestingFilesSetsLoader.class.getResource(resourcePath) == null) { + LOGGER.log(Level.SEVERE, String.format("Expected resource: %s could not be found at %s.", resourceFile, resourcePath)); + } else { + InputStream fileSetStream = StandardInterestingFilesSetsLoader.class.getResourceAsStream(resourcePath); + updateStandardFilesSetConfigFile(rulesConfigDir, fileSetStream, resourceFile); } - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, String.format("There was an error copying %s to %s.", - resourceDirectory.getAbsolutePath(), rulesConfigDir.getAbsolutePath()), ex); } } @@ -178,21 +145,26 @@ public class StandardInterestingFilesSetsLoader implements Runnable { * corresponding files set on disk or the files set on disk has an older * version. * - * @param rulesConfigDir The directory for standard interesting files sets. - * @param resourceInputStream The standard interesting files set resource file - * located within the jar. + * @param rulesConfigDir The directory for standard interesting files + * sets. + * @param resourceInputStream The standard interesting files set resource + * file located within the jar. + * @param resourceName The filename of the resource to be copied. */ private static void updateStandardFilesSetConfigFile(File rulesConfigDir, InputStream resourceInputStream, String resourceName) { File configDirFile = new File(rulesConfigDir, resourceName); - + Map resourceFilesSet = null; + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); try { - resourceFilesSet = InterestingItemsFilesSetSettings.readDefinitionsXML(resourceFile); - } catch (FilesSetsManager.FilesSetsManagerException ex) { + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + Document xmlDoc = builder.parse(resourceInputStream); + resourceFilesSet = InterestingItemsFilesSetSettings.readDefinitionsXML(xmlDoc, resourceName); + } catch (ParserConfigurationException | SAXException | IOException | FilesSetsManager.FilesSetsManagerException ex) { LOGGER.log(Level.SEVERE, "Unable to read FilesSet data from resource file: " + resourceName, ex); return; } - + if (configDirFile.exists()) { Map configDirFilesSet = null; try { @@ -243,8 +215,8 @@ public class StandardInterestingFilesSetsLoader implements Runnable { if (destFileSet != null) { // If and only if there is a naming conflict with a user-defined rule set, append “(Custom)” // to the user-defined rule set and add it back to the Map. - if (appendCustom && srcFileSet.isReadOnly() != destFileSet.isReadOnly()) { - if (srcFileSet.isReadOnly()) { + if (appendCustom && srcFileSet.isStandardSet() != destFileSet.isStandardSet()) { + if (srcFileSet.isStandardSet()) { addCustomFile(dest, key, destFileSet); } else { addCustomFile(dest, key, srcFileSet); @@ -280,8 +252,8 @@ public class StandardInterestingFilesSetsLoader implements Runnable { "StandardInterestingFileSetsLoader.customSuffixed={0} (Custom)" }) private static void addCustomFile(Map dest, String key, FilesSet srcFilesSet) { - if (srcFilesSet.isReadOnly()) { - LOGGER.log(Level.SEVERE, "An attempt to create a custom file that was not readonly"); + if (srcFilesSet.isStandardSet()) { + LOGGER.log(Level.SEVERE, "An attempt to create a custom file that was a standard set."); return; }