diff --git a/.gitignore b/.gitignore
index 0af92464ed9d7e63a2bcf826f2ab663ae3f8f9e3..9672ad8957e7daf883e47cc65cea3107bef250f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -89,3 +89,13 @@ hs_err_pid*.log
 *.img
 *.vhd
 *.E01
+
+/thirdparty/yara/yarabridge/yarabridge/x64/
+/thirdparty/yara/yarabridge/yarabridge.VC.db
+/thirdparty/yara/yarabridge/yarabridge.VC.VC.opendb
+/thirdparty/yara/yarabridge/x64/
+/thirdparty/yara/YaraWrapperTest/nbproject/private/
+/thirdparty/yara/YaraWrapperTest/build/
+/thirdparty/yara/YaraJNIWrapper/dist/
+/thirdparty/yara/YaraJNIWrapper/build/
+/thirdparty/yara/YaraJNIWrapper/nbproject/private/
diff --git a/Core/build.xml b/Core/build.xml
index bbf612c3d9e23105ecd7f708d94aee75e86b51a1..1ec2a3b481cd7a5dc6f84fba4861e77b9491ccc0 100644
--- a/Core/build.xml
+++ b/Core/build.xml
@@ -98,6 +98,10 @@
         <copy file="${thirdparty.dir}/jdom/jdom-2.0.5.jar" todir="${ext.dir}" />
         <copy file="${thirdparty.dir}/jdom/jdom-2.0.5-contrib.jar" todir="${ext.dir}" />
 		<copy file="${thirdparty.dir}/DatCon/3.6.9/DatCon.jar" todir="${ext.dir}" />
+        <!--Copy iLeapp to release-->
+        <copy todir="${basedir}/release/yara" >
+            <fileset dir="${thirdparty.dir}/yara/bin"/>
+        </copy>
     </target>
     
     
diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties
index 0c83dc776e24deec20e2c6c7473a94f2bffd515a..2b8155b7b20bcd3409fda1ca5ea19b027e09b6aa 100644
--- a/Core/nbproject/project.properties
+++ b/Core/nbproject/project.properties
@@ -118,6 +118,7 @@ file.reference.StixLib.jar=release\\modules\\ext\\StixLib.jar
 file.reference.threetenbp-1.3.3.jar=release\\modules\\ext\\threetenbp-1.3.3.jar
 file.reference.webp-imageio-sejda-0.1.0.jar=release\\modules\\ext\\webp-imageio-sejda-0.1.0.jar
 file.reference.xmpcore-5.1.3.jar=release\\modules\\ext\\xmpcore-5.1.3.jar
+file.reference.YaraJNIWrapper.jar=release/modules/ext/YaraJNIWrapper.jar
 file.reference.zookeeper-3.4.6.jar=release\\modules\\ext\\zookeeper-3.4.6.jar
 javac.source=1.8
 javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index 165c56ea2fa82a40dfbcafb50f5f29cb63be83a2..1cddbaa638a64e9bb94c8511031dd1388524b363 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -547,18 +547,10 @@
                 <runtime-relative-path>ext/checker-compat-qual-2.5.3.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\checker-compat-qual-2.5.3.jar</binary-origin>
             </class-path-extension>
-            <class-path-extension>
-                <runtime-relative-path>ext/sleuthkit-4.10.1.jar</runtime-relative-path>
-                <binary-origin>release/modules/ext/sleuthkit-4.10.1.jar</binary-origin>
-            </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/animal-sniffer-annotations-1.17.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\animal-sniffer-annotations-1.17.jar</binary-origin>
             </class-path-extension>
-            <class-path-extension>
-                <runtime-relative-path>ext/sleuthkit-caseuco-4.10.1.jar</runtime-relative-path>
-                <binary-origin>release/modules/ext/sleuthkit-caseuco-4.10.1.jar</binary-origin>
-            </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/gax-1.44.0.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\gax-1.44.0.jar</binary-origin>
@@ -567,6 +559,10 @@
                 <runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\jsoup-1.10.3.jar</binary-origin>
             </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/YaraJNIWrapper.jar</runtime-relative-path>
+                <binary-origin>release/modules/ext/YaraJNIWrapper.jar</binary-origin>
+            </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/grpc-context-1.19.0.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\grpc-context-1.19.0.jar</binary-origin>
@@ -671,6 +667,10 @@
                 <runtime-relative-path>ext/grpc-alts-1.19.0.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\grpc-alts-1.19.0.jar</binary-origin>
             </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/sleuthkit-caseuco-4.10.1.jar</runtime-relative-path>
+                <binary-origin>release/modules/ext/sleuthkit-caseuco-4.10.1.jar</binary-origin>
+            </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\jdom-2.0.5.jar</binary-origin>
@@ -795,6 +795,10 @@
                 <runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\sevenzipjbinding-AllPlatforms.jar</binary-origin>
             </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/sleuthkit-4.10.1.jar</runtime-relative-path>
+                <binary-origin>release/modules/ext/sleuthkit-4.10.1.jar</binary-origin>
+            </class-path-extension>
             <class-path-extension>
                 <runtime-relative-path>ext/jutf7-1.0.0.jar</runtime-relative-path>
                 <binary-origin>release\modules\ext\jutf7-1.0.0.jar</binary-origin>
diff --git a/Core/src/org/sleuthkit/autopsy/guicomponeontutils/AbstractCheckboxListItem.java b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/AbstractCheckboxListItem.java
new file mode 100755
index 0000000000000000000000000000000000000000..df0a00888f47daac4e76d13ef6f9b5ee2e1dbdd7
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/guicomponeontutils/AbstractCheckboxListItem.java
@@ -0,0 +1,51 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.guicomponeontutils;
+
+import javax.swing.Icon;
+import org.sleuthkit.autopsy.guiutils.CheckBoxJList;
+
+/**
+ * An abstract implementation of CheckBoxJList.CheckboxListItem so that
+ * implementing classes have default implementation.
+ */
+public abstract class AbstractCheckboxListItem implements CheckBoxJList.CheckboxListItem {
+
+    private boolean checked = false;
+
+    @Override
+    public boolean isChecked() {
+        return checked;
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        this.checked = checked;
+    }
+
+    @Override
+    public boolean hasIcon() {
+        return false;
+    }
+
+    @Override
+    public Icon getIcon() {
+        return null;
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/CheckBoxJList.java b/Core/src/org/sleuthkit/autopsy/guiutils/CheckBoxJList.java
index ab17187c4bcf667951c97514c8e8f0d49581475e..f59db1259f3365e4f38191468a17f41fc291ebb5 100755
--- a/Core/src/org/sleuthkit/autopsy/guiutils/CheckBoxJList.java
+++ b/Core/src/org/sleuthkit/autopsy/guiutils/CheckBoxJList.java
@@ -32,8 +32,10 @@
 
 /**
  * A JList that renders the list items as check boxes.
+ * 
+ * @param <T> An object that implements CheckboxListItem
  */
-final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JList<T> {
+public final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JList<T> {
 
     private static final long serialVersionUID = 1L;
 
@@ -42,7 +44,7 @@ final class CheckBoxJList<T extends CheckBoxJList.CheckboxListItem> extends JLis
      * a checkbox in CheckBoxJList.
      *
      */
-    interface CheckboxListItem {
+    public interface CheckboxListItem {
 
         /**
          * Returns the checkbox state.
@@ -83,7 +85,7 @@ interface CheckboxListItem {
     /**
      * Construct a new JCheckBoxList.
      */
-    CheckBoxJList() {
+    public CheckBoxJList() {
         initalize();
     }
     
@@ -134,12 +136,15 @@ public Component getListCellRendererComponent(
             checkbox.setSelected(value.isChecked());
             checkbox.setBackground(list.getBackground());
             checkbox.setEnabled(list.isEnabled());
+            checkbox.setOpaque(list.isOpaque());
             label.setText(value.getDisplayName());
             label.setEnabled(list.isEnabled());
+            label.setOpaque(list.isOpaque());
             if (value.hasIcon()) {
                 label.setIcon(value.getIcon());
             }
 
+            setOpaque(list.isOpaque());
             setEnabled(list.isEnabled());
             return this;
         }
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/yara/Bundle.properties-MERGED
new file mode 100755
index 0000000000000000000000000000000000000000..8f898ba1275eb07ff9a56dd1fc89e9bfebc83b2e
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/Bundle.properties-MERGED
@@ -0,0 +1,5 @@
+Yara_Module_Description=With the YARA ingest module you use YARA rule files to search files for textual or binary patterns.
+Yara_Module_Name=YARA
+YaraIngestModule_no_ruleSets=Unable to run YARA ingest, list of YARA rule sets was empty.
+YaraIngestModule_windows_error_msg=The YARA ingest module is only available on 64bit Windows.
+YaraIngestModule_yarac_not_found=Unable to compile YARA rules files. Unable to find executable at.
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestHelper.java b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestHelper.java
new file mode 100755
index 0000000000000000000000000000000000000000..9afcc9facddf61ed6e01383c572005ef9ed24f91
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestHelper.java
@@ -0,0 +1,207 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.sleuthkit.autopsy.modules.yara;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import org.openide.modules.InstalledFileLocator;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.coreutils.ExecUtil;
+import org.sleuthkit.autopsy.ingest.IngestModule;
+import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
+import org.sleuthkit.autopsy.yara.YaraJNIWrapper;
+import org.sleuthkit.autopsy.yara.YaraWrapperException;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.BlackboardArtifact;
+import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_YARA_HIT;
+import org.sleuthkit.datamodel.BlackboardAttribute;
+import org.sleuthkit.datamodel.TskCoreException;
+
+/**
+ * Methods for scanning files for yara rule matches.
+ */
+final class YaraIngestHelper {
+
+    private static final String YARA_DIR = "yara";
+    private static final String YARA_C_EXE = "yarac64.exe";
+    private static final String MODULE_NAME = YaraIngestModuleFactory.getModuleName();
+
+    private YaraIngestHelper() {
+    }
+
+    /**
+     * Uses the yarac tool to compile the rules in the given rule sets.
+     *
+     * @param ruleSetNames List of names of the selected rule sets.
+     * @param tempDir      Path of the directory to put the compiled rule files.
+     *
+     * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
+     */
+    static void compileRules(List<String> ruleSetNames, Path outputDir) throws IngestModuleException {
+        if (ruleSetNames == null || ruleSetNames.isEmpty()) {
+            throw new IngestModule.IngestModuleException(Bundle.YaraIngestModule_no_ruleSets());
+        }
+
+        // Find javac
+        File exeFile = InstalledFileLocator.getDefault().locate(
+                Paths.get(YARA_DIR, YARA_C_EXE).toString(),
+                YaraIngestModule.class.getPackage().getName(), false);
+
+        if (exeFile == null) {
+            throw new IngestModuleException(Bundle.YaraIngestModule_yarac_not_found());
+        }
+
+        for (RuleSet set : getRuleSetsForNames(ruleSetNames)) {
+            compileRuleSet(set, outputDir, exeFile);
+        }
+    }
+
+    /**
+     * Scan the given AbstractFile for yara rule matches from the rule sets in
+     * the given directory creating a blackboard artifact for each matching
+     * rule.
+     *
+     * The baseDirectory should contain a series of directories one for each
+     * rule set.
+     *
+     * @param file          The file to scan.
+     * @param baseDirectory Base directory for the compiled rule sets.
+     *
+     * @throws TskCoreException
+     */
+    static List<BlackboardArtifact> scanFileForMatches(AbstractFile file, File baseDirectory) throws TskCoreException, YaraWrapperException {
+        List<BlackboardArtifact> artifacts = new ArrayList<>();
+
+        byte[] fileBytes = new byte[(int) file.getSize()];
+        file.read(fileBytes, 0, fileBytes.length);
+
+        File[] ruleSetDirectories = baseDirectory.listFiles();
+        for (File ruleSetDirectory : ruleSetDirectories) {
+            List<String> ruleMatches = YaraIngestHelper.scanFileForMatches(fileBytes, ruleSetDirectory);
+            if (!ruleMatches.isEmpty()) {
+                artifacts.addAll(YaraIngestHelper.createArtifact(file, ruleSetDirectory.getName(), ruleMatches));
+            }
+        }
+
+        return artifacts;
+    }
+
+    /**
+     * Scan the given file byte array for rule matches using the YaraJNIWrapper
+     * API.
+     *
+     * @param fileBytes
+     * @param ruleSetDirectory
+     *
+     * @return List of rules that match from the given file from the given rule
+     *         set. Empty list is returned if no matches where found.
+     *
+     * @throws TskCoreException
+     */
+    private static List<String> scanFileForMatches(byte[] fileBytes, File ruleSetDirectory) throws TskCoreException, YaraWrapperException {
+        List<String> matchingRules = new ArrayList<>();
+
+        File[] ruleSetCompiledFileList = ruleSetDirectory.listFiles();
+
+        for (File ruleFile : ruleSetCompiledFileList) {
+            matchingRules.addAll(YaraJNIWrapper.findRuleMatch(ruleFile.getAbsolutePath(), fileBytes));
+        }
+
+        return matchingRules;
+    }
+
+    /**
+     * Create a list of Blackboard Artifacts, one for each matching rule.
+     *
+     * @param abstractFile  File to add artifact to.
+     * @param ruleSetName   Name rule set with matching rule.
+     * @param matchingRules Matching rule.
+     *
+     * @return List of artifacts or empty list if none were found.
+     *
+     * @throws TskCoreException
+     */
+    private static List<BlackboardArtifact> createArtifact(AbstractFile abstractFile, String ruleSetName, List<String> matchingRules) throws TskCoreException {
+        List<BlackboardArtifact> artifacts = new ArrayList<>();
+        for (String rule : matchingRules) {
+            BlackboardArtifact artifact = abstractFile.newArtifact(TSK_YARA_HIT);
+            List<BlackboardAttribute> attributes = new ArrayList<>();
+
+            attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName));
+            attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, rule));
+
+            artifact.addAttributes(attributes);
+            artifacts.add(artifact);
+        }
+        return artifacts;
+    }
+
+    @NbBundle.Messages({
+        "YaraIngestModule_yarac_not_found=Unable to compile YARA rules files. Unable to find executable at.",
+        "YaraIngestModule_no_ruleSets=Unable to run YARA ingest, list of YARA rule sets was empty."
+    })
+
+    /**
+     * Compiles the rule files in the given rule set.
+     *
+     * The compiled rule files are created in outputDir\RuleSetName.
+     *
+     * @param set       RuleSet for which to compile files.
+     * @param outputDir Output directory for the compiled rule files.
+     * @param yarac     yarac executeable file.
+     *
+     * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
+     */
+    static private void compileRuleSet(RuleSet set, Path outputDir, File yarac) throws IngestModuleException {
+        File tempFolder = Paths.get(outputDir.toString(), set.getName()).toFile();
+        if (!tempFolder.exists()) {
+            tempFolder.mkdir();
+        }
+
+        List<File> fileList = set.getRuleFiles();
+        for (File file : fileList) {
+            List<String> commandList = new ArrayList<>();
+            commandList.add(String.format("\"%s\"", yarac.toString()));
+            commandList.add(String.format("\"%s\"", file.toString()));
+            commandList.add(String.format("\"%s\"", Paths.get(tempFolder.getAbsolutePath(), "compiled_" + file.getName())));
+
+            ProcessBuilder builder = new ProcessBuilder(commandList);
+            try {
+                ExecUtil.execute(builder);
+            } catch (SecurityException | IOException ex) {
+                throw new IngestModuleException(String.format("Failed to compile Yara rules file", file.toString()), ex);
+            }
+
+        }
+    }
+
+    /**
+     * Returns a list of RuleSet objects for the given list of RuleSet names.
+     *
+     * @param names List of RuleSet names.
+     *
+     * @return List of RuleSet or empty list if none of the names matched
+     *         existing rules.
+     */
+    private static List<RuleSet> getRuleSetsForNames(List<String> names) {
+        List<RuleSet> ruleSetList = new ArrayList<>();
+
+        RuleSetManager manager = new RuleSetManager();
+        for (RuleSet set : manager.getRuleSetList()) {
+            if (names.contains(set.getName())) {
+                ruleSetList.add(set);
+            }
+        }
+
+        return ruleSetList;
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestJobSettings.java
new file mode 100755
index 0000000000000000000000000000000000000000..b115bba90f048d56cadfb33ab861afdb605c6cc7
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestJobSettings.java
@@ -0,0 +1,106 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
+
+/**
+ * IngestJobSettings for the YARA ingest module.
+ */
+public final class YaraIngestJobSettings implements IngestModuleIngestJobSettings {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<String> selectedRuleSetNames;
+    private boolean onlyExecutableFiles;
+
+    // Default constructor.
+    YaraIngestJobSettings() {
+        onlyExecutableFiles = true;
+        selectedRuleSetNames = new ArrayList<>();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param selected            List of selected rules.
+     * @param onlyExecutableFiles Process only executable files.
+     */
+    public YaraIngestJobSettings(List<RuleSet> selected, boolean onlyExecutableFiles) {
+        this.selectedRuleSetNames = new ArrayList<>();
+
+        for (RuleSet set : selected) {
+            selectedRuleSetNames.add(set.getName());
+        }
+
+        this.onlyExecutableFiles = onlyExecutableFiles;
+    }
+
+    /**
+     * Return the list of rule name sets that were selected in the ingest
+     * settings panel.
+     *
+     * @return List of selected RuleSet names.
+     */
+    public List<String> getSelectedRuleSetNames() {
+        return Collections.unmodifiableList(selectedRuleSetNames);
+    }
+
+    /**
+     * Set the list of selected rule names.
+     *
+     * @param selected List of selected rule Sets.
+     */
+    void setSelectedRuleSetNames(List<RuleSet> selected) {
+        this.selectedRuleSetNames = new ArrayList<>();
+        for (RuleSet set : selected) {
+            selectedRuleSetNames.add(set.getName());
+        }
+    }
+
+    /**
+     * Process only executable Files.
+     *
+     * @return If true the ingest module should process only executable files,
+     *         if false process all files.
+     */
+    public boolean onlyExecutableFiles() {
+        return onlyExecutableFiles;
+    }
+
+    /**
+     * Set whether to process only executable files or all files.
+     *
+     * @param onlyExecutableFiles True if the ingest module should only process
+     *                            executable files.
+     */
+    void setOnlyExecuteableFile(boolean onlyExecutableFiles) {
+        this.onlyExecutableFiles = onlyExecutableFiles;
+    }
+
+    @Override
+    public long getVersionNumber() {
+        return serialVersionUID;
+    }
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModule.java
new file mode 100755
index 0000000000000000000000000000000000000000..85a393d3467f0cf9734173267db2afd466599f84
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModule.java
@@ -0,0 +1,168 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.coreutils.PlatformUtil;
+import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter;
+import org.sleuthkit.autopsy.ingest.IngestJobContext;
+import org.sleuthkit.autopsy.ingest.IngestModule;
+import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
+import org.sleuthkit.autopsy.yara.YaraWrapperException;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.Blackboard;
+import org.sleuthkit.datamodel.Blackboard.BlackboardException;
+import org.sleuthkit.datamodel.BlackboardArtifact;
+import org.sleuthkit.datamodel.TskCoreException;
+
+/**
+ * An ingest module that runs the yara against the given files.
+ *
+ */
+public class YaraIngestModule extends FileIngestModuleAdapter {
+
+    private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
+    private final static Logger logger = Logger.getLogger(YaraIngestModule.class.getName());
+    private static final String YARA_DIR = "yara";
+    private static final Map<Long, Path> pathsByJobId = new ConcurrentHashMap<>();
+
+    private final YaraIngestJobSettings settings;
+
+    private IngestJobContext context = null;
+    private Long jobId;
+
+    /**
+     * Constructor.
+     *
+     * @param settings
+     */
+    YaraIngestModule(YaraIngestJobSettings settings) {
+        this.settings = settings;
+    }
+
+    @Messages({
+        "YaraIngestModule_windows_error_msg=The YARA ingest module is only available on 64bit Windows.",})
+
+    @Override
+    public void startUp(IngestJobContext context) throws IngestModuleException {
+        this.context = context;
+        this.jobId = context.getJobId();
+
+        if (!PlatformUtil.isWindowsOS() || !PlatformUtil.is64BitOS()) {
+            throw new IngestModule.IngestModuleException(Bundle.YaraIngestModule_windows_error_msg());
+        }
+
+        if (refCounter.incrementAndGet(jobId) == 1) {
+            // compile the selected rules & put into temp folder based on jobID
+            Path tempDir = getTempDirectory(jobId);
+
+            YaraIngestHelper.compileRules(settings.getSelectedRuleSetNames(), tempDir);
+        }
+    }
+
+    @Override
+    public void shutDown() {
+        if (context != null && refCounter.decrementAndGet(jobId) == 0) {
+            // do some clean up.
+            Path jobPath = pathsByJobId.get(jobId);
+            if (jobPath != null) {
+                jobPath.toFile().delete();
+                pathsByJobId.remove(jobId);
+            }
+        }
+    }
+
+    @Override
+    public ProcessResult process(AbstractFile file) {
+
+        if (settings.onlyExecutableFiles()) {
+            String extension = file.getNameExtension();
+            if (!extension.equals("exe")) {
+                return ProcessResult.OK;
+            }
+        }
+
+        // Skip the file if its 0 in length.
+        if (file.getSize() == 0) {
+            return ProcessResult.OK;
+        }
+
+        try {
+            List<BlackboardArtifact> artifacts = YaraIngestHelper.scanFileForMatches(file, getTempDirectory(jobId).toFile());
+            
+            if(!artifacts.isEmpty()) {
+                Blackboard blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
+                blackboard.postArtifacts(artifacts, YaraIngestModuleFactory.getModuleName());
+            }
+            
+        } catch (BlackboardException | NoCurrentCaseException | IngestModuleException | TskCoreException | YaraWrapperException ex) {
+            logger.log(Level.SEVERE, "YARA ingest module failed to process file.", ex);
+            return ProcessResult.ERROR;
+        } 
+        return ProcessResult.OK;
+    }
+
+    /**
+     * Return the temp directory for this jobId. If the folder does not exit it
+     * will be created.
+     *
+     * @param jobId The current jobId
+     *
+     * @return The path of the temporary directory for the given jobId.
+     *
+     * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
+     */
+    private synchronized Path getTempDirectory(long jobId) throws IngestModuleException {
+        Path jobPath = pathsByJobId.get(jobId);
+        if (jobPath != null) {
+            return jobPath;
+        }
+
+        Path baseDir;
+        try {
+            baseDir = Paths.get(Case.getCurrentCaseThrows().getTempDirectory(), YARA_DIR);
+        } catch (NoCurrentCaseException ex) {
+            throw new IngestModuleException("Failed to create YARA ingest model temp directory, no open case.", ex);
+        }
+
+        // Make the base yara directory, as needed
+        if (!baseDir.toFile().exists()) {
+            baseDir.toFile().mkdirs();
+        }
+
+        String randomDirName = String.format("%s_%d", RandomStringUtils.randomAlphabetic(8), jobId);
+        jobPath = Paths.get(baseDir.toString(), randomDirName);
+        jobPath.toFile().mkdir();
+
+        pathsByJobId.put(jobId, jobPath);
+
+        return jobPath;
+    }
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModuleFactory.java
new file mode 100755
index 0000000000000000000000000000000000000000..1abf8aaa0f9206bd1d0c5fb9a5bbe14cc64cb120
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/YaraIngestModuleFactory.java
@@ -0,0 +1,92 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara;
+
+import java.util.ArrayList;
+import org.openide.util.NbBundle.Messages;
+import org.openide.util.lookup.ServiceProvider;
+import org.sleuthkit.autopsy.coreutils.Version;
+import org.sleuthkit.autopsy.ingest.FileIngestModule;
+import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
+import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+import org.sleuthkit.autopsy.modules.yara.ui.YaraIngestSettingsPanel;
+
+/**
+ * A factory that creates ingest modules that use the Yara rule set definitions
+ * to identify files that may be of interest to the user.
+ */
+@ServiceProvider(service = IngestModuleFactory.class)
+public class YaraIngestModuleFactory extends IngestModuleFactoryAdapter {
+
+    @Messages({
+        "Yara_Module_Name=YARA",
+        "Yara_Module_Description=With the YARA ingest module you use YARA rule files to search files for textual or binary patterns."
+    })
+
+    @Override
+    public String getModuleDisplayName() {
+        return getModuleName();
+    }
+
+    @Override
+    public String getModuleDescription() {
+        return Bundle.Yara_Module_Description();
+    }
+
+    @Override
+    public String getModuleVersionNumber() {
+        return Version.getVersion();
+    }
+
+    @Override
+    public boolean hasIngestJobSettingsPanel() {
+        return true;
+    }
+
+    @Override
+    public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
+        return new YaraIngestSettingsPanel((YaraIngestJobSettings)settings);
+    }
+
+    @Override
+    public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
+        return new YaraIngestJobSettings(new ArrayList<>(), true);
+    }
+
+    @Override
+    public boolean isFileIngestModuleFactory() {
+        return true;
+    }
+
+    @Override
+    public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
+        return new YaraIngestModule((YaraIngestJobSettings) settings);
+    }
+
+    /**
+     * Return the name of the ingest module.
+     *
+     * @return Ingest module name.
+     */
+    static String getModuleName() {
+        return Bundle.Yara_Module_Name();
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java
index 12b383894428703f15938fcde11e518aa20a2619..112cf9206c66938aeaf79fecbab10cd4efa808ce 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java
@@ -19,6 +19,7 @@
 package org.sleuthkit.autopsy.modules.yara.rules;
 
 import java.io.File;
+import java.io.Serializable;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.List;
@@ -26,7 +27,9 @@
 /**
  * Represents a yara rule set which is a collection of yara rule files.
  */
-public class RuleSet implements Comparable<RuleSet> {
+public class RuleSet implements Comparable<RuleSet>, Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private final String name;
     private final Path path;
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties
index 5012f855b42dba159465977d5afb4cb7a3e9efaf..2ac49a54638f69bcec671603980c8886ff588867 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties
@@ -8,3 +8,7 @@ RuleSetDetailsPanel.setDetailsLabel.text=Set Details
 RuleSetDetailsPanel.openFolderButton.text=Open Folder
 RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files.  A file need only match one rule in the set to be found.
 RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
+YaraIngestSettingsPanel.border.title=Select YARA rule sets to enable during ingest:
+YaraIngestSettingsPanel.allFilesButton.text=All Files
+YaraIngestSettingsPanel.allFilesButton.toolTipText=
+YaraIngestSettingsPanel.executableFilesButton.text=Only Executable Files
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED
index a6b64a97c0cdb6b37cdd35efe706d5a6b53f855f..3fad865f4322f24ca849cc002a421a31b5e3fbbb 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED
@@ -10,6 +10,10 @@ RuleSetDetailsPanel.setDetailsLabel.text=Set Details
 RuleSetDetailsPanel.openFolderButton.text=Open Folder
 RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files.  A file need only match one rule in the set to be found.
 RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
+YaraIngestSettingsPanel.border.title=Select YARA rule sets to enable during ingest:
+YaraIngestSettingsPanel.allFilesButton.text=All Files
+YaraIngestSettingsPanel.allFilesButton.toolTipText=
+YaraIngestSettingsPanel.executableFilesButton.text=Only Executable Files
 # {0} - rule set name
 YaraRuleSetOptionPanel_badName_msg=Rule set name {0} already exists.\nRule set names must be unique.
 YaraRuleSetOptionPanel_badName_title=Create Rule Set
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.form
new file mode 100755
index 0000000000000000000000000000000000000000..d4832c66a16e9292e1be785387096bebcf8a98f9
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.form
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="buttonGroup">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+      <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+        <TitledBorder title="Select YARA rule sets to enable during ingest:">
+          <ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </TitledBorder>
+      </Border>
+    </Property>
+  </Properties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="1.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+    </Container>
+    <Container class="javax.swing.JPanel" name="buttonPanel">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JRadioButton" name="allFilesButton">
+          <Properties>
+            <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+              <ComponentRef name="buttonGroup"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.allFilesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.allFilesButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+        </Component>
+        <Component class="javax.swing.JRadioButton" name="executableFilesButton">
+          <Properties>
+            <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+              <ComponentRef name="buttonGroup"/>
+            </Property>
+            <Property name="selected" type="boolean" value="true"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="YaraIngestSettingsPanel.executableFilesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.java
new file mode 100755
index 0000000000000000000000000000000000000000..e68b11ccb232896ea73d1aefa7c62de611e47cb1
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraIngestSettingsPanel.java
@@ -0,0 +1,182 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.ui;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import javax.swing.DefaultListModel;
+import org.sleuthkit.autopsy.guicomponeontutils.AbstractCheckboxListItem;
+import org.sleuthkit.autopsy.guiutils.CheckBoxJList;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+import org.sleuthkit.autopsy.modules.yara.YaraIngestJobSettings;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
+
+/**
+ * Yara Ingest settings panel.
+ */
+public class YaraIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private final CheckBoxJList<RuleSetListItem> checkboxList;
+    private final DefaultListModel<RuleSetListItem> listModel;
+
+    /**
+     * Creates new form YaraIngestSettingsPanel
+     */
+    YaraIngestSettingsPanel() {
+        initComponents();
+        listModel = new DefaultListModel<>();
+        checkboxList = new CheckBoxJList<>();
+        scrollPane.setViewportView(checkboxList);
+    }
+    
+    public YaraIngestSettingsPanel(YaraIngestJobSettings settings) {
+        this();
+        
+        List<String> setNames = settings.getSelectedRuleSetNames();
+        
+        checkboxList.setModel(listModel);
+        checkboxList.setOpaque(false);
+        RuleSetManager manager = new RuleSetManager();
+        List<RuleSet> ruleSetList = manager.getRuleSetList();
+        for (RuleSet set : ruleSetList) {
+            RuleSetListItem item = new RuleSetListItem(set);
+            item.setChecked(setNames.contains(set.getName()));
+            listModel.addElement(item);
+        }
+        
+        allFilesButton.setSelected(!settings.onlyExecutableFiles());
+        executableFilesButton.setSelected(settings.onlyExecutableFiles());
+    }
+
+    @Override
+    public IngestModuleIngestJobSettings getSettings() {
+        List<RuleSet> selectedRules = new ArrayList<>();
+
+        Enumeration<RuleSetListItem> enumeration = listModel.elements();
+        while (enumeration.hasMoreElements()) {
+            RuleSetListItem item = enumeration.nextElement();
+            if (item.isChecked()) {
+                selectedRules.add(item.getRuleSet());
+            }
+        }
+
+        return new YaraIngestJobSettings(selectedRules, executableFilesButton.isSelected());
+    }
+
+    /**
+     * RuleSet wrapper class for Checkbox JList model.
+     */
+    private final class RuleSetListItem extends AbstractCheckboxListItem {
+
+        private final RuleSet ruleSet;
+
+        /**
+         * RuleSetListItem constructor.
+         *
+         * @param set RuleSet object to display in list.
+         */
+        RuleSetListItem(RuleSet set) {
+            this.ruleSet = set;
+        }
+
+        /**
+         * Returns the RuleSet.
+         *
+         * @return
+         */
+        RuleSet getRuleSet() {
+            return ruleSet;
+        }
+
+        @Override
+        public String getDisplayName() {
+            return ruleSet.getName();
+        }
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        buttonGroup = new javax.swing.ButtonGroup();
+        scrollPane = new javax.swing.JScrollPane();
+        buttonPanel = new javax.swing.JPanel();
+        allFilesButton = new javax.swing.JRadioButton();
+        executableFilesButton = new javax.swing.JRadioButton();
+
+        setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.border.title"))); // NOI18N
+        setLayout(new java.awt.GridBagLayout());
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.weighty = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
+        add(scrollPane, gridBagConstraints);
+
+        buttonPanel.setLayout(new java.awt.GridBagLayout());
+
+        buttonGroup.add(allFilesButton);
+        org.openide.awt.Mnemonics.setLocalizedText(allFilesButton, org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.allFilesButton.text")); // NOI18N
+        allFilesButton.setToolTipText(org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.allFilesButton.toolTipText")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        buttonPanel.add(allFilesButton, gridBagConstraints);
+
+        buttonGroup.add(executableFilesButton);
+        executableFilesButton.setSelected(true);
+        org.openide.awt.Mnemonics.setLocalizedText(executableFilesButton, org.openide.util.NbBundle.getMessage(YaraIngestSettingsPanel.class, "YaraIngestSettingsPanel.executableFilesButton.text")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 1;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        buttonPanel.add(executableFilesButton, gridBagConstraints);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 1;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.weightx = 1.0;
+        add(buttonPanel, gridBagConstraints);
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JRadioButton allFilesButton;
+    private javax.swing.ButtonGroup buttonGroup;
+    private javax.swing.JPanel buttonPanel;
+    private javax.swing.JRadioButton executableFilesButton;
+    private javax.swing.JScrollPane scrollPane;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/thirdparty/yara/YaraJNIWrapper/nbproject/build-impl.xml b/thirdparty/yara/YaraJNIWrapper/nbproject/build-impl.xml
index 38dd8d0c8708d143a8a41e2a3952c0c7b1aa7683..d5569a48c319371a3c730160092e3870f0f19c9c 100755
--- a/thirdparty/yara/YaraJNIWrapper/nbproject/build-impl.xml
+++ b/thirdparty/yara/YaraJNIWrapper/nbproject/build-impl.xml
@@ -179,9 +179,7 @@ is divided into following sections:
             </and>
         </condition>
         <condition property="have.tests">
-            <or>
-                <available file="${test.src.dir}"/>
-            </or>
+            <or/>
         </condition>
         <condition property="have.sources">
             <or>
@@ -289,7 +287,6 @@ is divided into following sections:
     </target>
     <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
         <fail unless="src.dir">Must set src.dir</fail>
-        <fail unless="test.src.dir">Must set test.src.dir</fail>
         <fail unless="build.dir">Must set build.dir</fail>
         <fail unless="dist.dir">Must set dist.dir</fail>
         <fail unless="build.classes.dir">Must set build.classes.dir</fail>
@@ -588,9 +585,6 @@ is divided into following sections:
                 <j2seproject3:junit-prototype>
                     <customizePrototype>
                         <batchtest todir="${build.test.results.dir}">
-                            <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
-                                <filename name="@{testincludes}"/>
-                            </fileset>
                             <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
                                 <filename name="${test.binarytestincludes}"/>
                             </fileset>
@@ -613,11 +607,7 @@ is divided into following sections:
                 <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
                     <isset property="test.method"/>
                 </condition>
-                <union id="test.set">
-                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
-                        <filename name="@{testincludes}"/>
-                    </fileset>
-                </union>
+                <union id="test.set"/>
                 <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
                 <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="YaraJNIWrapper" testname="TestNG tests" workingDir="${work.dir}">
                     <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
@@ -1544,14 +1534,14 @@ is divided into following sections:
         <!-- You can override this target in the ../build.xml file. -->
     </target>
     <target depends="-init-source-module-properties" if="named.module.internal" name="-init-test-javac-module-properties-with-module">
-        <j2seproject3:modulename property="test.module.name" sourcepath="${test.src.dir}"/>
-        <condition else="${empty.dir}" property="javac.test.sourcepath" value="${test.src.dir}">
+        <j2seproject3:modulename property="test.module.name" sourcepath=""/>
+        <condition else="${empty.dir}" property="javac.test.sourcepath" value="">
             <and>
                 <isset property="test.module.name"/>
                 <length length="0" string="${test.module.name}" when="greater"/>
             </and>
         </condition>
-        <condition else="--patch-module ${module.name}=${test.src.dir} --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED">
+        <condition else="--patch-module ${module.name}= --add-reads ${module.name}=ALL-UNNAMED" property="javac.test.compilerargs" value="--add-reads ${test.module.name}=ALL-UNNAMED">
             <and>
                 <isset property="test.module.name"/>
                 <length length="0" string="${test.module.name}" when="greater"/>
@@ -1592,17 +1582,15 @@ is divided into following sections:
     </target>
     <target depends="-init-test-javac-module-properties-with-module,-init-test-module-properties-without-module" name="-init-test-module-properties"/>
     <target if="do.depend.true" name="-compile-test-depend">
-        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir=""/>
     </target>
     <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
-        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="${test.src.dir}">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${javac.test.sourcepath}" srcdir="">
             <customize>
                 <compilerarg line="${javac.test.compilerargs}"/>
             </customize>
         </j2seproject3:javac>
-        <copy todir="${build.test.classes.dir}">
-            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
+        <copy todir="${build.test.classes.dir}"/>
     </target>
     <target name="-post-compile-test">
         <!-- Empty placeholder for easier customization. -->
@@ -1616,14 +1604,12 @@ is divided into following sections:
     <target depends="init,deps-jar,compile,-init-test-module-properties,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
         <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
         <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
-        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}, module-info.java" modulepath="${javac.test.modulepath}" processorpath="${javac.test.processorpath}" sourcepath="" srcdir="">
             <customize>
                 <compilerarg line="${javac.test.compilerargs}"/>
             </customize>
         </j2seproject3:javac>
-        <copy todir="${build.test.classes.dir}">
-            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
+        <copy todir="${build.test.classes.dir}"/>
     </target>
     <target name="-post-compile-test-single">
         <!-- Empty placeholder for easier customization. -->
diff --git a/thirdparty/yara/YaraJNIWrapper/nbproject/project.properties b/thirdparty/yara/YaraJNIWrapper/nbproject/project.properties
index a0ef4dac371c47ddecad7c1f688e878f2ea41cf0..0af470a2bf254dcdef638a273afed75fedc60e4c 100755
--- a/thirdparty/yara/YaraJNIWrapper/nbproject/project.properties
+++ b/thirdparty/yara/YaraJNIWrapper/nbproject/project.properties
@@ -1,9 +1,10 @@
 annotation.processing.enabled=true
 annotation.processing.enabled.in.editor=false
-annotation.processing.processor.options=
 annotation.processing.processors.list=
 annotation.processing.run.all.processors=true
 annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=YaraJNIWrapper
+application.vendor=kelly
 build.classes.dir=${build.dir}/classes
 build.classes.excludes=**/*.java,**/*.form
 # This directory is removed when the project is cleaned:
@@ -32,10 +33,13 @@ dist.jar=${dist.dir}/YaraJNIWrapper.jar
 dist.javadoc.dir=${dist.dir}/javadoc
 dist.jlink.dir=${dist.dir}/jlink
 dist.jlink.output=${dist.jlink.dir}/YaraJNIWrapper
+endorsed.classpath=
 excludes=
+file.reference.yara-lib=src/org/sleuthkit/autopsy/yara/lib
 includes=**
 jar.compress=false
-javac.classpath=
+javac.classpath=\
+    ${file.reference.yara-lib}
 # Space-separated list of extra javac options
 javac.compilerargs=
 javac.deprecation=false
@@ -90,4 +94,3 @@ run.test.modulepath=\
     ${javac.test.modulepath}
 source.encoding=UTF-8
 src.dir=src
-test.src.dir=test
diff --git a/thirdparty/yara/YaraJNIWrapper/nbproject/project.xml b/thirdparty/yara/YaraJNIWrapper/nbproject/project.xml
index df43138d7ec98c10c27e4ace6713295ed7a65033..89ae97a48ba44b29e1b31136a96418a7a22a2b06 100755
--- a/thirdparty/yara/YaraJNIWrapper/nbproject/project.xml
+++ b/thirdparty/yara/YaraJNIWrapper/nbproject/project.xml
@@ -7,9 +7,7 @@
             <source-roots>
                 <root id="src.dir"/>
             </source-roots>
-            <test-roots>
-                <root id="test.src.dir"/>
-            </test-roots>
+            <test-roots/>
         </data>
     </configuration>
 </project>
diff --git a/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/YaraJNIWrapper.java b/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/YaraJNIWrapper.java
index 0fc5e8f0f42805ea9fe170d47eecc2ee06b62ca6..1905d690cd56cfb30bd1b2ce7877092d23bb8a66 100755
--- a/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/YaraJNIWrapper.java
+++ b/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/YaraJNIWrapper.java
@@ -18,9 +18,11 @@
  */
 package org.sleuthkit.autopsy.yara;
 
-import java.net.URISyntaxException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -31,18 +33,12 @@
  */
 public class YaraJNIWrapper {
 
-    // Load the yarabridge.dll which should be located in the same directory as
-    // the jar file. If we need to use this code for debugging the dll this
-    // code will need to be modified to add that support.
     static {
-        Path directoryPath = null;
         try {
-            directoryPath = Paths.get(YaraJNIWrapper.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getParent().toAbsolutePath();
-        } catch (URISyntaxException ex) {
+            extractAndLoadDll();
+        } catch (IOException | YaraWrapperException ex) {
             Logger.getLogger(YaraJNIWrapper.class.getName()).log(Level.SEVERE, null, ex);
         }
-        String libraryPath = Paths.get(directoryPath != null ? directoryPath.toString() : "", "yarabridge.dll").toAbsolutePath().toString();
-        System.load(libraryPath);
     }
 
     /**
@@ -59,10 +55,40 @@ public class YaraJNIWrapper {
      */
     static public native List<String> findRuleMatch(String compiledRulesPath, byte[] byteBuffer) throws YaraWrapperException;
 
+    /**
+     * Copy yarabridge.dll from inside the jar to a temp file that can be loaded
+     * with System.load.
+     * 
+     * To make this work, the dll needs to be in the same folder as this source
+     * file. The dll needs to be located somewhere in the jar class path.
+     * 
+     * @throws IOException
+     * @throws YaraWrapperException 
+     */
+    static private void extractAndLoadDll() throws IOException, YaraWrapperException {
+        File tempFile = File.createTempFile("lib", null);
+        tempFile.deleteOnExit();
+        try (InputStream in = YaraJNIWrapper.class.getResourceAsStream("yarabridge.dll")) {
+            if (in == null) {
+                throw new YaraWrapperException("native library was not found in jar file.");
+            }
+            try (OutputStream out = new FileOutputStream(tempFile)) {
+                byte[] buffer = new byte[1024];
+                int lengthRead;
+                while ((lengthRead = in.read(buffer)) > 0) {
+                    out.write(buffer, 0, lengthRead);
+                    out.flush();
+                }
+            }
+        }
+
+        System.load(tempFile.getAbsolutePath());
+    }
+
     /**
      * private constructor.
      */
     private YaraJNIWrapper() {
     }
-    
+
 }
diff --git a/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/yarabridge.dll b/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/yarabridge.dll
new file mode 100755
index 0000000000000000000000000000000000000000..d6d3d75e1b715a82dcadb21b9a1b583f230dea92
Binary files /dev/null and b/thirdparty/yara/YaraJNIWrapper/src/org/sleuthkit/autopsy/yara/yarabridge.dll differ
diff --git a/thirdparty/yara/YaraWrapperTest/nbproject/project.properties b/thirdparty/yara/YaraWrapperTest/nbproject/project.properties
index c0126ab42a546b8f400e9d92f01fa8682d786fdd..b7874aae82fc7a569c538f4b1835eec8dddaf643 100755
--- a/thirdparty/yara/YaraWrapperTest/nbproject/project.properties
+++ b/thirdparty/yara/YaraWrapperTest/nbproject/project.properties
@@ -35,7 +35,7 @@ dist.jlink.dir=${dist.dir}/jlink
 dist.jlink.output=${dist.jlink.dir}/YaraWrapperTest
 endorsed.classpath=
 excludes=
-file.reference.YaraJNIWrapper.jar=../bin/YaraJNIWrapper.jar
+file.reference.YaraJNIWrapper.jar=../YaraJNIWrapper/dist/YaraJNIWrapper.jar
 includes=**
 jar.compress=false
 javac.classpath=\
diff --git a/thirdparty/yara/bin/YaraJNIWrapper.jar b/thirdparty/yara/bin/YaraJNIWrapper.jar
index 749d7a6ae7d81e95727a742cd97f703b6099829d..f10842d973cfe1d9666b113f73febf20a24080bd 100755
Binary files a/thirdparty/yara/bin/YaraJNIWrapper.jar and b/thirdparty/yara/bin/YaraJNIWrapper.jar differ
diff --git a/thirdparty/yara/bin/yarabridge.dll b/thirdparty/yara/bin/yarabridge.dll
deleted file mode 100755
index c74062a626e30902f5917efe1e327f476f92e043..0000000000000000000000000000000000000000
Binary files a/thirdparty/yara/bin/yarabridge.dll and /dev/null differ
diff --git a/thirdparty/yara/bin/yarac64.exe b/thirdparty/yara/bin/yarac64.exe
new file mode 100755
index 0000000000000000000000000000000000000000..bf94cc44628d3ad0421c09760106c8894476a731
Binary files /dev/null and b/thirdparty/yara/bin/yarac64.exe differ
diff --git a/thirdparty/yara/yarabridge/yarabridge/yarabridge.vcxproj b/thirdparty/yara/yarabridge/yarabridge/yarabridge.vcxproj
index ce5dd10c803bcd8fb98ca2ef2aec0a501e00ac0d..c049e81dc96da5a71e9eb18b1b2b7bc585ab084b 100755
--- a/thirdparty/yara/yarabridge/yarabridge/yarabridge.vcxproj
+++ b/thirdparty/yara/yarabridge/yarabridge/yarabridge.vcxproj
@@ -113,7 +113,7 @@
       <AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
-      <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\bin\$(ProjectName).dll"</Command>
+      <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\YaraJNIWrapper\src\org\sleuthkit\autopsy\yara\$(ProjectName).dll"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -153,7 +153,7 @@
       <AdditionalDependencies>ws2_32.lib;crypt32.lib;libyara64.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <PostBuildEvent>
-      <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\bin\$(ProjectName).dll"</Command>
+      <Command>copy "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).dll" "$(SolutionDir)..\YaraJNIWrapper\src\org\sleuthkit\autopsy\yara\$(ProjectName).dll"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemGroup>