Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
YaraIngestModule.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2020-2021 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.modules.yara;
20
21import java.io.File;
22import java.io.IOException;
23import java.nio.file.Path;
24import java.nio.file.Paths;
25import java.util.ArrayList;
26import java.util.List;
27import java.util.Map;
28import java.util.concurrent.ConcurrentHashMap;
29import java.util.logging.Level;
30import org.apache.commons.lang3.RandomStringUtils;
31import org.openide.util.NbBundle.Messages;
32import org.sleuthkit.autopsy.casemodule.Case;
33import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
34import org.sleuthkit.autopsy.coreutils.Logger;
35import org.sleuthkit.autopsy.coreutils.PlatformUtil;
36import org.sleuthkit.autopsy.datamodel.ContentUtils;
37import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter;
38import org.sleuthkit.autopsy.ingest.IngestJobContext;
39import org.sleuthkit.autopsy.ingest.IngestModule;
40import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
41import org.sleuthkit.autopsy.yara.YaraWrapperException;
42import org.sleuthkit.datamodel.AbstractFile;
43import org.sleuthkit.datamodel.Blackboard;
44import org.sleuthkit.datamodel.Blackboard.BlackboardException;
45import org.sleuthkit.datamodel.BlackboardArtifact;
46import org.sleuthkit.datamodel.TskCoreException;
47import org.sleuthkit.datamodel.TskData;
48
53public class YaraIngestModule extends FileIngestModuleAdapter {
54
55 // 15MB
56 private static final int FILE_SIZE_THRESHOLD_MB = 100;
57 private static final int FILE_SIZE_THRESHOLD_BYTE = FILE_SIZE_THRESHOLD_MB * 1024 * 1024;
58 private static final int YARA_SCAN_TIMEOUT_SEC = 30 * 60 * 60; // 30 minutes.
59
61 private final static Logger logger = Logger.getLogger(YaraIngestModule.class.getName());
62 private static final String YARA_DIR = "yara";
63 private static final Map<Long, Path> pathsByJobId = new ConcurrentHashMap<>();
64 private static final String RULESET_DIR = "RuleSets";
65
67
68 private IngestJobContext context = null;
69 private Long jobId;
70
76 YaraIngestModule(YaraIngestJobSettings settings) {
77 this.settings = settings;
78 }
79
80 @Messages({
81 "YaraIngestModule_windows_error_msg=The YARA ingest module is only available on 64bit Windows.",})
82
83 @Override
85 this.context = context;
86 this.jobId = context.getJobId();
87
89 throw new IngestModule.IngestModuleException(Bundle.YaraIngestModule_windows_error_msg());
90 }
91
92 if (refCounter.incrementAndGet(jobId) == 1) {
93 // compile the selected rules & put into temp folder based on jobID
94 Path tempDir = getTempDirectory(jobId);
95 Path tempRuleSetDir = Paths.get(tempDir.toString(), RULESET_DIR);
96 if(!tempRuleSetDir.toFile().exists()) {
97 tempRuleSetDir.toFile().mkdir();
98 }
99
100 if(settings.hasSelectedRuleSets()) {
101 YaraIngestHelper.compileRules(settings.getSelectedRuleSetNames(), tempRuleSetDir);
102 } else {
103 logger.log(Level.INFO, "YARA ingest module: No rule set was selected for this ingest job.");
104 }
105 }
106 }
107
108 @Override
109 public void shutDown() {
110 if (context != null && refCounter.decrementAndGet(jobId) == 0) {
111 // do some clean up.
112 Path jobPath = pathsByJobId.get(jobId);
113 if (jobPath != null) {
114 jobPath.toFile().delete();
115 pathsByJobId.remove(jobId);
116 }
117 }
118 }
119
120 @Override
121 public ProcessResult process(AbstractFile file) {
122
123 if(!settings.hasSelectedRuleSets()) {
124 return ProcessResult.OK;
125 }
126
127 if (settings.onlyExecutableFiles()) {
128 String extension = file.getNameExtension();
129 if (!extension.equals("exe")) {
130 return ProcessResult.OK;
131 }
132 }
133
134 // Skip the file if its 0 in length or a directory.
135 if (file.getSize() == 0 ||
136 file.isDir() ||
137 file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
138 return ProcessResult.OK;
139 }
140
141 try {
142 List<BlackboardArtifact> artifacts = new ArrayList<>();
143 File ruleSetsDir = Paths.get(getTempDirectory(jobId).toString(), RULESET_DIR).toFile();
144
145 // If the file size is less than FILE_SIZE_THRESHOLD_BYTE read the file
146 // into a buffer, else make a local copy of the file.
147 if(file.getSize() < FILE_SIZE_THRESHOLD_BYTE) {
148 byte[] fileBuffer = new byte[(int)file.getSize()];
149
150 int dataRead = file.read(fileBuffer, 0, file.getSize());
151 if(dataRead != 0) {
152 artifacts.addAll( YaraIngestHelper.scanFileForMatches(file, ruleSetsDir, fileBuffer, dataRead, YARA_SCAN_TIMEOUT_SEC));
153 }
154 } else {
155 File tempCopy = createLocalCopy(file);
156 artifacts.addAll( YaraIngestHelper.scanFileForMatches(file, ruleSetsDir, tempCopy, YARA_SCAN_TIMEOUT_SEC));
157 tempCopy.delete();
158 }
159
160 if(!artifacts.isEmpty()) {
161 Blackboard blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
162 blackboard.postArtifacts(artifacts, YaraIngestModuleFactory.getModuleName(), context.getJobId());
163 }
164
165 } catch (BlackboardException | NoCurrentCaseException | IngestModuleException | TskCoreException | YaraWrapperException ex) {
166 logger.log(Level.SEVERE, String.format("YARA ingest module failed to process file id %d", file.getId()), ex);
167 return ProcessResult.ERROR;
168 } catch(IOException ex) {
169 logger.log(Level.SEVERE, String.format("YARA ingest module failed to make a local copy of given file id %d", file.getId()), ex);
170 return ProcessResult.ERROR;
171 }
172
173 return ProcessResult.OK;
174 }
175
186 private synchronized Path getTempDirectory(long jobId) throws IngestModuleException {
187 Path jobPath = pathsByJobId.get(jobId);
188 if (jobPath != null) {
189 return jobPath;
190 }
191
192 Path baseDir;
193 try {
194 baseDir = Paths.get(Case.getCurrentCaseThrows().getTempDirectory(), YARA_DIR);
195 } catch (NoCurrentCaseException ex) {
196 throw new IngestModuleException("Failed to create YARA ingest model temp directory, no open case.", ex);
197 }
198
199 // Make the base yara directory, as needed
200 if (!baseDir.toFile().exists()) {
201 baseDir.toFile().mkdirs();
202 }
203
204 String randomDirName = String.format("%s_%d", RandomStringUtils.randomAlphabetic(8), jobId);
205 jobPath = Paths.get(baseDir.toString(), randomDirName);
206 jobPath.toFile().mkdir();
207
208 pathsByJobId.put(jobId, jobPath);
209
210 return jobPath;
211 }
212
223 protected File createLocalCopy(AbstractFile file) throws IngestModuleException, IOException {
224 String tempFileName = RandomStringUtils.randomAlphabetic(15) + file.getId() + ".temp";
225
226 File tempFile = Paths.get(getTempDirectory(context.getJobId()).toString(), tempFileName).toFile();
227 ContentUtils.writeToFile(file, tempFile, context::dataSourceIngestIsCancelled);
228
229 return tempFile;
230 }
231
232}
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
static final IngestModuleReferenceCounter refCounter

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.