Autopsy  4.20.0
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  */
19 package org.sleuthkit.autopsy.modules.yara;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Path;
24 import java.nio.file.Paths;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.logging.Level;
30 import org.apache.commons.lang3.RandomStringUtils;
31 import org.openide.util.NbBundle.Messages;
41 import org.sleuthkit.autopsy.yara.YaraWrapperException;
42 import org.sleuthkit.datamodel.AbstractFile;
43 import org.sleuthkit.datamodel.Blackboard;
44 import org.sleuthkit.datamodel.Blackboard.BlackboardException;
45 import org.sleuthkit.datamodel.BlackboardArtifact;
46 import org.sleuthkit.datamodel.TskCoreException;
47 import org.sleuthkit.datamodel.TskData;
48 
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 
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
84  public void startUp(IngestJobContext context) throws IngestModuleException {
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 }
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
static final IngestModuleReferenceCounter refCounter
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.