19package org.sleuthkit.autopsy.recentactivity;
22import java.io.FileNotFoundException;
23import java.io.IOException;
24import java.nio.file.Path;
25import java.nio.file.Paths;
26import java.sql.ResultSet;
27import java.sql.SQLException;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.HashMap;
33import java.util.logging.Level;
35import org.apache.commons.io.FilenameUtils;
36import org.openide.modules.InstalledFileLocator;
37import org.openide.util.NbBundle.Messages;
38import org.sleuthkit.autopsy.casemodule.Case;
39import org.sleuthkit.autopsy.casemodule.services.FileManager;
40import org.sleuthkit.autopsy.coreutils.ExecUtil;
41import org.sleuthkit.autopsy.coreutils.Logger;
42import org.sleuthkit.autopsy.coreutils.PlatformUtil;
43import org.sleuthkit.autopsy.coreutils.SQLiteDBConnect;
44import org.sleuthkit.autopsy.datamodel.ContentUtils;
45import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
46import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
47import org.sleuthkit.autopsy.ingest.IngestJobContext;
48import org.sleuthkit.datamodel.AbstractFile;
49import org.sleuthkit.datamodel.BlackboardArtifact;
50import org.sleuthkit.datamodel.BlackboardAttribute;
51import org.sleuthkit.datamodel.Content;
52import org.sleuthkit.datamodel.TskCoreException;
58final class ExtractSru
extends Extract {
60 private static final Logger logger = Logger.getLogger(ExtractSru.class.getName());
62 private static final String APPLICATION_USAGE_SOURCE_NAME =
"System Resource Usage - Application Usage";
63 private static final String NETWORK_USAGE_SOURCE_NAME =
"System Resource Usage - Network Usage";
64 private static final String SRU_TOOL_FOLDER =
"markmckinnon";
65 private static final String SRU_TOOL_NAME_X64_WINDOWS =
"mm_artifact_parser_x64_win.exe";
66 private static final String SRU_TOOL_NAME_X64_LINUX =
"mm_artifact_parser_x64_linux";
67 private static final String SRU_TOOL_NAME_X64_MACOS =
"mm_artifact_parser_x64_macos";
68 private static final String SRU_TOOL_NAME_AARCH64_LINUX =
"mm_artifact_parser_aarch64_linux";
69 private static final String SRU_TOOL_NAME_AARCH64_MACOS =
"mm_artifact_parser_aarch64_macos";
70 private static final String SRU_OUTPUT_FILE_NAME =
"Output.txt";
71 private static final String SRU_ERROR_FILE_NAME =
"Error.txt";
73 private static final Map<String, AbstractFile> applicationFilesFound =
new HashMap<>();
74 private final IngestJobContext context;
77 "ExtractSru_module_name=System Resource Usage Analyzer"
79 ExtractSru(IngestJobContext context) {
80 super(Bundle.ExtractSru_module_name(), context);
81 this.context = context;
85 "ExtractSru_error_finding_export_srudb_program=Error finding export_srudb program",
86 "ExtractSru_process_error_executing_export_srudb_program=Error running export_srudb program"
90 void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
92 String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator +
"sru";
93 File dir =
new File(modOutPath);
94 if (dir.exists() ==
false) {
98 String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(),
"sru", context.getJobId());
99 String softwareHiveFileName = getSoftwareHiveFile(dataSource, tempDirPath);
101 if (softwareHiveFileName ==
null) {
105 AbstractFile sruAbstractFile = getSruFile(dataSource, tempDirPath);
107 if (sruAbstractFile ==
null) {
111 final String sruDumper = getPathForSruDumper();
112 if (sruDumper ==
null) {
113 this.addErrorMessage(Bundle.ExtractSru_error_finding_export_srudb_program());
114 logger.log(Level.SEVERE,
"Error finding export_srudb program");
118 if (context.dataSourceIngestIsCancelled()) {
123 String modOutFile = modOutPath + File.separator + sruAbstractFile.getId() +
"_srudb.db3";
124 String sruFileName = tempDirPath + File.separator + sruAbstractFile.getId() +
"_" + sruAbstractFile.getName();
126 extractSruFiles(sruDumper, sruFileName, modOutFile, tempDirPath, softwareHiveFileName);
128 findSruExecutedFiles(modOutFile, dataSource);
130 createNetUsageArtifacts(modOutFile, sruAbstractFile);
131 createAppUsageArtifacts(modOutFile, sruAbstractFile);
132 }
catch (IOException ex) {
133 logger.log(Level.SEVERE,
"Error processing SRUDB.dat file", ex);
134 this.addErrorMessage(Bundle.ExtractSru_process_error_executing_export_srudb_program());
139 "ExtractSru_process_errormsg_find_software_hive=Unable to find SOFTWARE HIVE file",
140 "ExtractSru_process_errormsg_write_software_hive=Unable to write SOFTWARE HIVE file"
151 String getSoftwareHiveFile(Content dataSource, String tempDirPath) {
152 FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
154 List<AbstractFile> softwareHiveFiles;
157 softwareHiveFiles = fileManager.findFiles(dataSource,
"SOFTWARE");
158 }
catch (TskCoreException ex) {
159 this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_software_hive());
160 logger.log(Level.WARNING,
"Unable to find SOFTWARE HIVE file.", ex);
164 String softwareHiveFileName =
null;
166 for (AbstractFile softwareFile : softwareHiveFiles) {
168 if (softwareFile.getParentPath().endsWith(
"/config/")) {
169 softwareHiveFileName = tempDirPath + File.separator + softwareFile.getId() +
"_" + softwareFile.getName();
172 ContentUtils.writeToFile(softwareFile,
new File(softwareHiveFileName));
173 }
catch (IOException ex) {
174 this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_software_hive());
175 logger.log(Level.WARNING, String.format(
"Unable to write %s to temp directory. File name: %s", softwareFile.getName(), softwareFile), ex);
180 return softwareHiveFileName;
184 "ExtractSru_process_errormsg_find_srudb_dat=Unable to find srudb.dat file",
185 "ExtractSru_process_errormsg_write_srudb_dat=Unable to write srudb.dat file"
195 AbstractFile getSruFile(Content dataSource, String tempDirPath) {
196 FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
198 List<AbstractFile> sruFiles;
201 sruFiles = fileManager.findFiles(dataSource,
"SRUDB.DAT");
202 }
catch (TskCoreException ex) {
203 this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_srudb_dat());
204 logger.log(Level.WARNING,
"Unable to find SRUDB.DAT file.", ex);
208 AbstractFile sruAbstractFile =
null;
210 for (AbstractFile sruFile : sruFiles) {
212 String sruFileName = tempDirPath + File.separator + sruFile.getId() +
"_" + sruFile.getName();
213 sruAbstractFile = sruFile;
216 ContentUtils.writeToFile(sruFile,
new File(sruFileName));
217 }
catch (IOException ex) {
218 this.addErrorMessage(Bundle.ExtractSru_process_errormsg_write_srudb_dat());
219 logger.log(Level.WARNING, String.format(
"Unable to write %s to temp directory. File name: %s", sruFile.getName(), sruFile), ex);
224 return sruAbstractFile;
237 void extractSruFiles(String sruExePath, String sruFile, String tempOutFile, String tempOutPath, String softwareHiveFile)
throws IOException {
238 final Path outputFilePath = Paths.get(tempOutPath, SRU_OUTPUT_FILE_NAME);
239 final Path errFilePath = Paths.get(tempOutPath, SRU_ERROR_FILE_NAME);
241 List<String> commandLine =
new ArrayList<>();
242 commandLine.add(sruExePath);
243 commandLine.add(
"-a");
244 commandLine.add(
"sru");
245 commandLine.add(
"-sr");
246 commandLine.add(sruFile);
247 commandLine.add(
"-sh");
248 commandLine.add(softwareHiveFile);
249 commandLine.add(
"-db");
250 commandLine.add(tempOutFile);
252 ProcessBuilder processBuilder =
new ProcessBuilder(commandLine);
253 processBuilder.redirectOutput(outputFilePath.toFile());
254 processBuilder.redirectError(errFilePath.toFile());
256 ExecUtil.execute(processBuilder,
new DataSourceIngestModuleProcessTerminator(context,
true));
259 private String getPathForSruDumper() {
261 if (PlatformUtil.isWindowsOS()) {
262 path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_X64_WINDOWS);
263 }
else if (PlatformUtil.isLinuxOS()) {
264 if (
"aarch64".equals(PlatformUtil.getOSArch())) {
265 path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_AARCH64_LINUX);
267 path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_X64_LINUX);
269 }
else if (PlatformUtil.isMacOS()) {
270 if (
"aarch64".equals(PlatformUtil.getOSArch())) {
271 path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_AARCH64_MACOS);
273 path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_X64_MACOS);
276 File sruToolFile = InstalledFileLocator.getDefault().locate(path.toString(),
277 ExtractSru.class.getPackage().getName(),
false);
278 if (sruToolFile !=
null) {
279 return sruToolFile.getAbsolutePath();
285 private void findSruExecutedFiles(String sruDb, Content dataSource) {
287 org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
289 String sqlStatement =
"SELECT DISTINCT SUBSTR(LTRIM(IdBlob, '\\Device\\HarddiskVolume'), INSTR(LTRIM(IdBlob, '\\Device\\HarddiskVolume'), '\\')) "
290 +
" application_name, idBlob source_name FROM SruDbIdMapTable WHERE idType = 0 AND idBlob NOT LIKE '!!%'";
292 try (SQLiteDBConnect tempdbconnect =
new SQLiteDBConnect(
"org.sqlite.JDBC",
"jdbc:sqlite:" + sruDb);
293 ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
295 while (resultSet.next()) {
297 if (context.dataSourceIngestIsCancelled()) {
298 logger.log(Level.INFO,
"Cancelled SRU Artifact Creation.");
302 String applicationName = resultSet.getString(
"application_name");
303 String sourceName = resultSet.getString(
"source_name");
305 String normalizePathName = FilenameUtils.normalize(applicationName,
true);
306 String fileName = FilenameUtils.getName(normalizePathName);
307 String filePath = FilenameUtils.getPath(normalizePathName);
308 if (fileName.contains(
" [")) {
309 fileName = fileName.substring(0, fileName.indexOf(
" ["));
311 List<AbstractFile> sourceFiles;
313 sourceFiles = fileManager.
findFiles(dataSource, fileName, filePath);
314 for (AbstractFile sourceFile : sourceFiles) {
315 if (sourceFile.getParentPath().endsWith(filePath)) {
316 applicationFilesFound.put(sourceName.toLowerCase(), sourceFile);
320 }
catch (TskCoreException ex) {
321 logger.log(Level.WARNING, String.format(
"Error finding actual file %s. file may not exist", normalizePathName));
324 }
catch (SQLException ex) {
325 logger.log(Level.WARNING,
"Error while trying to read into a sqlite db.", ex);
330 private void createNetUsageArtifacts(String sruDb, AbstractFile sruAbstractFile) {
331 List<BlackboardArtifact> bba =
new ArrayList<>();
333 String sqlStatement =
"SELECT STRFTIME('%s', timestamp) ExecutionTime, b.application_name, b.Application_Name formatted_application_name, username User_Name, \n" +
334 " bytesSent, BytesRecvd \n" +
335 " FROM network_Usage a, SruDbIdMapTable s, exe_to_app b, userNames u\n" +
336 " WHERE s.idType = 0 and s.idIndex = appId and idblob = b.source_name and u.idindex = userid \n" +
337 " order by ExecutionTime;";
339 try (SQLiteDBConnect tempdbconnect =
new SQLiteDBConnect(
"org.sqlite.JDBC",
"jdbc:sqlite:" + sruDb);
340 ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
342 while (resultSet.next()) {
344 if (context.dataSourceIngestIsCancelled()) {
345 logger.log(Level.INFO,
"Cancelled SRU Net Usage Artifact Creation.");
349 String applicationName = resultSet.getString(
"Application_Name");
350 String formattedApplicationName = resultSet.getString(
"formatted_Application_name");
351 Long executionTime = Long.valueOf(resultSet.getInt(
"ExecutionTime"));
352 Long bytesSent = Long.valueOf(resultSet.getInt(
"bytesSent"));
353 Long bytesRecvd = Long.valueOf(resultSet.getInt(
"BytesRecvd"));
354 String userName = resultSet.getString(
"User_Name");
356 Collection<BlackboardAttribute> bbattributes = Arrays.asList(
357 new BlackboardAttribute(
358 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getDisplayName(),
359 formattedApplicationName),
360 new BlackboardAttribute(
361 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME, getDisplayName(),
363 new BlackboardAttribute(
364 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getDisplayName(),
366 new BlackboardAttribute(
367 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_BYTES_SENT, getDisplayName(), bytesSent),
368 new BlackboardAttribute(
369 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_BYTES_RECEIVED, getDisplayName(), bytesRecvd),
370 new BlackboardAttribute(
371 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getDisplayName(), NETWORK_USAGE_SOURCE_NAME));
374 BlackboardArtifact bbart = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_PROG_RUN, sruAbstractFile, bbattributes);
376 BlackboardArtifact associateBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), bbart);
377 if (associateBbArtifact !=
null) {
378 bba.add(associateBbArtifact);
380 }
catch (TskCoreException ex) {
381 logger.log(Level.SEVERE,
"Exception Adding Artifact.", ex);
385 }
catch (SQLException ex) {
386 logger.log(Level.SEVERE,
"Error while trying to read into a sqlite db.", ex);
389 if (!context.dataSourceIngestIsCancelled()) {
394 private void createAppUsageArtifacts(String sruDb, AbstractFile sruAbstractFile) {
395 List<BlackboardArtifact> bba =
new ArrayList<>();
397 String sqlStatement =
"SELECT STRFTIME('%s', timestamp) ExecutionTime, b.Application_Name \n" +
398 " formatted_application_name, username User_Name \n" +
399 " FROM Application_Resource_Usage a, SruDbIdMapTable s, exe_to_app b, userNames u \n" +
400 " WHERE s.idType = 0 and s.idIndex = appId and idblob = b.source_name and u.idindex = userid \n" +
401 " order by ExecutionTime;";
403 try (SQLiteDBConnect tempdbconnect =
new SQLiteDBConnect(
"org.sqlite.JDBC",
"jdbc:sqlite:" + sruDb);
404 ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) {
406 while (resultSet.next()) {
408 if (context.dataSourceIngestIsCancelled()) {
409 logger.log(Level.INFO,
"Cancelled SRU Net Usage Artifact Creation.");
413 String formattedApplicationName = resultSet.getString(
"formatted_application_name");
414 Long executionTime = Long.valueOf(resultSet.getInt(
"ExecutionTime"));
415 String userName = resultSet.getString(
"User_Name");
417 Collection<BlackboardAttribute> bbattributes = Arrays.asList(
418 new BlackboardAttribute(
419 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getDisplayName(),
420 formattedApplicationName),
421 new BlackboardAttribute(
422 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME, getDisplayName(),
424 new BlackboardAttribute(
425 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getDisplayName(),
427 new BlackboardAttribute(
428 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getDisplayName(), APPLICATION_USAGE_SOURCE_NAME));
431 BlackboardArtifact bbart = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_PROG_RUN, sruAbstractFile, bbattributes);
433 BlackboardArtifact associateBbArtifact = createAssociatedArtifact(formattedApplicationName.toLowerCase(), bbart);
434 if (associateBbArtifact !=
null) {
435 bba.add(associateBbArtifact);
437 }
catch (TskCoreException ex) {
438 logger.log(Level.SEVERE,
"Exception Adding Artifact.", ex);
442 }
catch (SQLException ex) {
443 logger.log(Level.SEVERE,
"Error while trying to read into a sqlite db.", ex);
446 if (!context.dataSourceIngestIsCancelled()) {
462 private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba)
throws TskCoreException {
463 if (applicationFilesFound.containsKey(filePathName)) {
464 AbstractFile sourceFile = applicationFilesFound.get(filePathName);
465 return createAssociatedArtifact(sourceFile, bba);
List< AbstractFile > findFiles(String fileName)