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, "{key}")"/> + </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, "{key}")"/> + </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, "{key}")"/> + </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, "{key}")"/> + </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>