Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
TopProgramsSummary.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 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.datasourcesummary.datamodel;
20 
22 import java.io.File;
23 import java.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Date;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Set;
32 import java.util.function.Function;
33 import java.util.stream.Collectors;
34 import org.apache.commons.lang.StringUtils;
36 import org.sleuthkit.datamodel.BlackboardArtifact;
37 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
38 import org.sleuthkit.datamodel.BlackboardAttribute;
39 import org.sleuthkit.datamodel.DataSource;
40 import org.sleuthkit.datamodel.SleuthkitCase;
41 import org.sleuthkit.datamodel.TskCoreException;
42 
47 
48  private static final Set<Integer> ARTIFACT_UPDATE_TYPE_IDS = new HashSet<>(Arrays.asList(
49  ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID()
50  ));
51 
55  private enum JoinType {
59  OUTER
60  }
61 
65  private enum AttributeColumn {
68  value_int64
69  }
70 
74  private static final String QUERY_SUFFIX = "_query";
75 
80  private static final List<Function<List<String>, String>> SHORT_FOLDER_MATCHERS = Arrays.asList(
81  // handle Program Files and Program Files (x86) - if true, return the next folder
82  (pathList) -> {
83  if (pathList.size() < 2) {
84  return null;
85  }
86 
87  String rootParent = pathList.get(0).toUpperCase();
88  if ("PROGRAM FILES".equals(rootParent) || "PROGRAM FILES (X86)".equals(rootParent)) {
89  return pathList.get(1);
90  } else {
91  return null;
92  }
93  },
94  // if there is a folder named "APPLICATION DATA" or "APPDATA"
95  (pathList) -> {
96  for (String pathEl : pathList) {
97  String uppered = pathEl.toUpperCase();
98  if ("APPLICATION DATA".equals(uppered) || "APPDATA".equals(uppered)) {
99  return "AppData";
100  }
101  }
102  return null;
103  }
104  );
105 
122  private static String getAttributeJoin(JoinType joinType, AttributeColumn attributeColumn, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String keyName, String bbaName) {
123  String queryName = keyName + QUERY_SUFFIX;
124  String innerQueryName = "inner_attribute_" + queryName;
125 
126  return "\n" + joinType + " JOIN (\n"
127  + " SELECT \n"
128  + " " + innerQueryName + ".artifact_id,\n"
129  + " " + innerQueryName + "." + attributeColumn + " AS " + keyName + "\n"
130  + " FROM blackboard_attributes " + innerQueryName + "\n"
131  + " WHERE " + innerQueryName + ".attribute_type_id = " + attrType.getTypeID() + " -- " + attrType.name() + "\n"
132  + ") " + queryName + " ON " + queryName + ".artifact_id = " + bbaName + ".artifact_id\n";
133  }
134 
142  private static String getFullKey(String key) {
143  return key + QUERY_SUFFIX + "." + key;
144  }
145 
154  private static String getWhereString(List<String> clauses) {
155  if (clauses.isEmpty()) {
156  return "";
157  }
158 
159  List<String> parenthesized = clauses.stream()
160  .map(c -> "(" + c + ")")
161  .collect(Collectors.toList());
162 
163  return "\nWHERE " + String.join("\n AND ", parenthesized) + "\n";
164  }
165 
175  private static String getLikeClause(String column, String likeString, boolean isLike) {
176  return column + (isLike ? "" : " NOT") + " LIKE '" + likeString + "'";
177  }
178 
180 
183  }
184 
186  this.provider = provider;
187  }
188 
189  @Override
190  public Set<Integer> getArtifactTypeIdsForRefresh() {
192  }
193 
208  public List<TopProgramsResult> getTopPrograms(DataSource dataSource, int count)
209  throws SleuthkitCaseProviderException, TskCoreException, SQLException {
210  if (dataSource == null || count <= 0) {
211  return Collections.emptyList();
212  }
213 
214  // ntosboot should be ignored
215  final String ntosBootIdentifier = "NTOSBOOT";
216  // programs in windows directory to be ignored
217  final String windowsDir = "/WINDOWS%";
218 
219  final String nameParam = "name";
220  final String pathParam = "path";
221  final String runCountParam = "run_count";
222  final String lastRunParam = "last_run";
223 
224  String bbaQuery = "bba";
225 
226  final String query = "SELECT\n"
227  + " " + getFullKey(nameParam) + " AS " + nameParam + ",\n"
228  + " " + getFullKey(pathParam) + " AS " + pathParam + ",\n"
229  + " MAX(" + getFullKey(runCountParam) + ") AS " + runCountParam + ",\n"
230  + " MAX(" + getFullKey(lastRunParam) + ") AS " + lastRunParam + "\n"
231  + "FROM blackboard_artifacts " + bbaQuery + "\n"
232  + getAttributeJoin(JoinType.INNER, AttributeColumn.value_text, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, nameParam, bbaQuery)
233  + getAttributeJoin(JoinType.LEFT, AttributeColumn.value_text, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, pathParam, bbaQuery)
234  + getAttributeJoin(JoinType.LEFT, AttributeColumn.value_int32, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COUNT, runCountParam, bbaQuery)
235  + getAttributeJoin(JoinType.LEFT, AttributeColumn.value_int64, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, lastRunParam, bbaQuery)
236  + getWhereString(Arrays.asList(
237  bbaQuery + ".artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID(),
238  bbaQuery + ".data_source_obj_id = " + dataSource.getId(),
239  // exclude ntosBootIdentifier from results
240  getLikeClause(getFullKey(nameParam), ntosBootIdentifier, false),
241  // exclude windows directory items from results
242  getFullKey(pathParam) + " IS NULL OR " + getLikeClause(getFullKey(pathParam), windowsDir, false)
243  ))
244  + "GROUP BY " + getFullKey(nameParam) + ", " + getFullKey(pathParam) + "\n"
245  + "ORDER BY \n"
246  + " MAX(" + getFullKey(runCountParam) + ") DESC,\n"
247  + " MAX(" + getFullKey(lastRunParam) + ") DESC,\n"
248  + " " + getFullKey(nameParam) + " ASC";
249 
250  DataSourceInfoUtilities.ResultSetHandler<List<TopProgramsResult>> handler = (resultSet) -> {
251  List<TopProgramsResult> progResults = new ArrayList<>();
252 
253  boolean quitAtCount = false;
254 
255  while (resultSet.next() && (!quitAtCount || progResults.size() < count)) {
256  long lastRunEpoch = resultSet.getLong(lastRunParam);
257  Date lastRun = (resultSet.wasNull()) ? null : new Date(lastRunEpoch * 1000);
258 
259  Long runCount = resultSet.getLong(runCountParam);
260  if (resultSet.wasNull()) {
261  runCount = null;
262  }
263 
264  if (lastRun != null || runCount != null) {
265  quitAtCount = true;
266  }
267 
268  progResults.add(new TopProgramsResult(
269  resultSet.getString(nameParam),
270  resultSet.getString(pathParam),
271  runCount,
272  lastRun));
273  }
274 
275  return progResults;
276  };
277 
278  try (SleuthkitCase.CaseDbQuery dbQuery = provider.get().executeQuery(query);
279  ResultSet resultSet = dbQuery.getResultSet()) {
280 
281  return handler.process(resultSet);
282  }
283  }
284 
293  public String getShortFolderName(String strPath, String applicationName) {
294  if (strPath == null) {
295  return "";
296  }
297 
298  List<String> pathEls = new ArrayList<>(Arrays.asList(applicationName));
299 
300  File file = new File(strPath);
301  while (file != null && StringUtils.isNotBlank(file.getName())) {
302  pathEls.add(file.getName());
303  file = file.getParentFile();
304  }
305 
306  Collections.reverse(pathEls);
307 
308  for (Function<List<String>, String> matchEntry : SHORT_FOLDER_MATCHERS) {
309  String result = matchEntry.apply(pathEls);
310  if (StringUtils.isNotBlank(result)) {
311  return result;
312  }
313  }
314 
315  return "";
316  }
317 
321  public static class TopProgramsResult {
322 
323  private final String programName;
324  private final String programPath;
325  private final Long runTimes;
326  private final Date lastRun;
327 
335  TopProgramsResult(String programName, String programPath, Long runTimes, Date lastRun) {
336  this.programName = programName;
337  this.programPath = programPath;
338  this.runTimes = runTimes;
339  this.lastRun = lastRun;
340  }
341 
345  public String getProgramName() {
346  return programName;
347  }
348 
352  public String getProgramPath() {
353  return programPath;
354  }
355 
359  public Long getRunTimes() {
360  return runTimes;
361  }
362 
366  public Date getLastRun() {
367  return lastRun;
368  }
369  }
370 }
static String getAttributeJoin(JoinType joinType, AttributeColumn attributeColumn, BlackboardAttribute.ATTRIBUTE_TYPE attrType, String keyName, String bbaName)
List< TopProgramsResult > getTopPrograms(DataSource dataSource, int count)
static String getLikeClause(String column, String likeString, boolean isLike)
static final List< Function< List< String >, String > > SHORT_FOLDER_MATCHERS
String getShortFolderName(String strPath, String applicationName)

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.