Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractRegistry.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2012-2020 Basis Technology Corp.
6  *
7  * Copyright 2012 42six Solutions.
8  * Contact: aebadirad <at> 42six <dot> com
9  * Project Contact/Architect: carrier <at> sleuthkit <dot> org
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.sleuthkit.autopsy.recentactivity;
24 
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.FileReader;
30 import java.io.FileWriter;
31 import java.io.IOException;
32 import java.io.StringReader;
33 import java.text.ParseException;
34 import java.text.SimpleDateFormat;
35 import java.util.logging.Level;
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import org.apache.commons.io.FilenameUtils;
40 import org.openide.modules.InstalledFileLocator;
41 import org.openide.util.NbBundle;
49 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
50 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.Node;
54 import org.w3c.dom.NodeList;
55 import org.xml.sax.InputSource;
56 import org.xml.sax.SAXException;
57 import java.nio.file.Path;
58 import java.util.AbstractMap;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.List;
62 import java.util.Collection;
63 import java.util.Date;
64 import java.util.HashMap;
65 import java.util.Map;
66 import java.util.Scanner;
67 import java.util.Set;
68 import java.util.HashSet;
69 import static java.util.Locale.US;
70 import static java.util.TimeZone.getTimeZone;
71 import org.openide.util.Lookup;
78 import org.sleuthkit.datamodel.AbstractFile;
79 import org.sleuthkit.datamodel.Account;
80 import org.sleuthkit.datamodel.BlackboardArtifact;
81 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
82 import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_OS_ACCOUNT;
83 import org.sleuthkit.datamodel.BlackboardAttribute;
84 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT;
85 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
86 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
87 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED;
88 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED;
89 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED;
90 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID;
91 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME;
92 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH;
93 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_ID;
94 import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME;
95 import org.sleuthkit.datamodel.Content;
96 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
97 import org.sleuthkit.datamodel.Report;
98 import org.sleuthkit.datamodel.TskCoreException;
99 import org.sleuthkit.datamodel.TskDataException;
100 
107 @NbBundle.Messages({
108  "RegRipperNotFound=Autopsy RegRipper executable not found.",
109  "RegRipperFullNotFound=Full version RegRipper executable not found.",
110  "Progress_Message_Analyze_Registry=Analyzing Registry Files",
111  "Shellbag_Artifact_Display_Name=Shell Bags",
112  "Shellbag_Key_Attribute_Display_Name=Key",
113  "Shellbag_Last_Write_Attribute_Display_Name=Last Write",
114  "Recently_Used_Artifacts_Office_Trustrecords=Stored in TrustRecords because Office security exception was granted",
115  "Recently_Used_Artifacts_ArcHistory=Recently opened by 7Zip",
116  "Recently_Used_Artifacts_Applets=Recently opened according to Applets registry key",
117  "Recently_Used_Artifacts_Mmc=Recently opened according to Windows Management Console MRU",
118  "Recently_Used_Artifacts_Winrar=Recently opened according to WinRAR MRU",
119  "Recently_Used_Artifacts_Officedocs=Recently opened according to Office MRU",
120  "Recently_Used_Artifacts_Adobe=Recently opened according to Adobe MRU",
121  "Recently_Used_Artifacts_Mediaplayer=Recently opened according to Media Player MRU",
122  "Registry_System_Bam=Recently Executed according to Background Activity Moderator (BAM)"
123 })
124 class ExtractRegistry extends Extract {
125 
126  private static final String USERNAME_KEY = "Username"; //NON-NLS
127  private static final String SID_KEY = "SID"; //NON-NLS
128  private static final String RID_KEY = "RID"; //NON-NLS
129  private static final String ACCOUNT_CREATED_KEY = "Account Created"; //NON-NLS
130  private static final String LAST_LOGIN_KEY = "Last Login Date"; //NON-NLS
131  private static final String LOGIN_COUNT_KEY = "Login Count"; //NON-NLS
132  private static final String FULL_NAME_KEY = "Full Name"; //NON-NLS
133  private static final String USER_COMMENT_KEY = "User Comment"; //NON-NLS
134  private static final String ACCOUNT_TYPE_KEY = "Account Type"; //NON-NLS
135  private static final String NAME_KEY = "Name"; //NON-NLS
136  private static final String PWD_RESET_KEY = "Pwd Rest Date"; //NON-NLS
137  private static final String PWD_FAILE_KEY = "Pwd Fail Date"; //NON-NLS
138  private static final String INTERNET_NAME_KEY = "InternetName"; //NON-NLS
139  private static final String PWD_DOES_NOT_EXPIRE_KEY = "Password does not expire"; //NON-NLS
140  private static final String ACCOUNT_DISABLED_KEY = "Account Disabled"; //NON-NLS
141  private static final String PWD_NOT_REQUIRED_KEY = "Password not required"; //NON-NLS
142  private static final String NORMAL_ACCOUNT_KEY = "Normal user account"; //NON-NLS
143  private static final String HOME_DIRECTORY_REQUIRED_KEY = "Home directory required";
144  private static final String TEMPORARY_DUPLICATE_ACCOUNT = "Temporary duplicate account";
145  private static final String MNS_LOGON_ACCOUNT_KEY = "MNS logon user account";
146  private static final String INTERDOMAIN_TRUST_ACCOUNT_KEY = "Interdomain trust account";
147  private static final String WORKSTATION_TRUST_ACCOUNT = "Workstation trust account";
148  private static final String SERVER_TRUST_ACCOUNT = "Server trust account";
149  private static final String ACCOUNT_AUTO_LOCKED = "Account auto locked";
150  private static final String PASSWORD_HINT = "Password Hint";
151 
152  private static final String[] PASSWORD_SETTINGS_FLAGS = {PWD_DOES_NOT_EXPIRE_KEY, PWD_NOT_REQUIRED_KEY};
153  private static final String[] ACCOUNT_SETTINGS_FLAGS = {ACCOUNT_AUTO_LOCKED, HOME_DIRECTORY_REQUIRED_KEY, ACCOUNT_DISABLED_KEY};
154  private static final String[] ACCOUNT_TYPE_FLAGS = {NORMAL_ACCOUNT_KEY, SERVER_TRUST_ACCOUNT, WORKSTATION_TRUST_ACCOUNT, INTERDOMAIN_TRUST_ACCOUNT_KEY, MNS_LOGON_ACCOUNT_KEY, TEMPORARY_DUPLICATE_ACCOUNT};
155 
156  final private static UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
157  final private static String RIP_EXE = "rip.exe";
158  final private static String RIP_PL = "rip.pl";
159  final private static String RIP_PL_INCLUDE_FLAG = "-I";
160  final private static int MS_IN_SEC = 1000;
161  final private static String NEVER_DATE = "Never";
162  final private static String SECTION_DIVIDER = "-------------------------";
163  final private static Logger logger = Logger.getLogger(ExtractRegistry.class.getName());
164  private final List<String> rrCmd = new ArrayList<>();
165  private final List<String> rrFullCmd = new ArrayList<>();
166  private final Path rrHome; // Path to the Autopsy version of RegRipper
167  private final Path rrFullHome; // Path to the full version of RegRipper
168  private Content dataSource;
169  private IngestJobContext context;
170  private Map<String, String> userNameMap;
171 
172  private static final String SHELLBAG_ARTIFACT_NAME = "RA_SHELL_BAG"; //NON-NLS
173  private static final String SHELLBAG_ATTRIBUTE_LAST_WRITE = "RA_SHELL_BAG_LAST_WRITE"; //NON-NLS
174  private static final String SHELLBAG_ATTRIBUTE_KEY = "RA_SHELL_BAG_KEY"; //NON-NLS
175 
176  BlackboardArtifact.Type shellBagArtifactType = null;
177  BlackboardAttribute.Type shellBagKeyAttributeType = null;
178  BlackboardAttribute.Type shellBagLastWriteAttributeType = null;
179 
180  ExtractRegistry() throws IngestModuleException {
181  moduleName = NbBundle.getMessage(ExtractIE.class, "ExtractRegistry.moduleName.text");
182 
183  final File rrRoot = InstalledFileLocator.getDefault().locate("rr", ExtractRegistry.class.getPackage().getName(), false); //NON-NLS
184  if (rrRoot == null) {
185  throw new IngestModuleException(Bundle.RegRipperNotFound());
186  }
187 
188  final File rrFullRoot = InstalledFileLocator.getDefault().locate("rr-full", ExtractRegistry.class.getPackage().getName(), false); //NON-NLS
189  if (rrFullRoot == null) {
190  throw new IngestModuleException(Bundle.RegRipperFullNotFound());
191  }
192 
193  String executableToRun = RIP_EXE;
194  if (!PlatformUtil.isWindowsOS()) {
195  executableToRun = RIP_PL;
196  }
197  rrHome = rrRoot.toPath();
198  String rrPath = rrHome.resolve(executableToRun).toString();
199  rrFullHome = rrFullRoot.toPath();
200 
201  if (!(new File(rrPath).exists())) {
202  throw new IngestModuleException(Bundle.RegRipperNotFound());
203  }
204  String rrFullPath = rrFullHome.resolve(executableToRun).toString();
205  if (!(new File(rrFullPath).exists())) {
206  throw new IngestModuleException(Bundle.RegRipperFullNotFound());
207  }
208  if (PlatformUtil.isWindowsOS()) {
209  rrCmd.add(rrPath);
210  rrFullCmd.add(rrFullPath);
211  } else {
212  String perl;
213  File usrBin = new File("/usr/bin/perl");
214  File usrLocalBin = new File("/usr/local/bin/perl");
215  if (usrBin.canExecute() && usrBin.exists() && !usrBin.isDirectory()) {
216  perl = "/usr/bin/perl";
217  } else if (usrLocalBin.canExecute() && usrLocalBin.exists() && !usrLocalBin.isDirectory()) {
218  perl = "/usr/local/bin/perl";
219  } else {
220  throw new IngestModuleException("perl not found in your system");
221  }
222  rrCmd.add(perl);
223  rrCmd.add(RIP_PL_INCLUDE_FLAG);
224  rrCmd.add(rrHome.toString());
225  rrCmd.add(rrPath);
226  rrFullCmd.add(perl);
227  rrFullCmd.add(RIP_PL_INCLUDE_FLAG);
228  rrFullCmd.add(rrFullHome.toString());
229  rrFullCmd.add(rrFullPath);
230  }
231  }
232 
236  private List<AbstractFile> findRegistryFiles() {
237  List<AbstractFile> allRegistryFiles = new ArrayList<>();
238  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
239 
240  // find the sam hives', process this first so we can map the user id's and sids for later use
241  try {
242  allRegistryFiles.addAll(fileManager.findFiles(dataSource, "sam", "/system32/config")); //NON-NLS
243  } catch (TskCoreException ex) {
244  String msg = NbBundle.getMessage(this.getClass(),
245  "ExtractRegistry.findRegFiles.errMsg.errReadingFile", "sam");
246  logger.log(Level.WARNING, msg, ex);
247  this.addErrorMessage(this.getName() + ": " + msg);
248  }
249 
250  // find the user-specific ntuser-dat files
251  try {
252  allRegistryFiles.addAll(fileManager.findFiles(dataSource, "ntuser.dat")); //NON-NLS
253  } catch (TskCoreException ex) {
254  logger.log(Level.WARNING, "Error fetching 'ntuser.dat' file."); //NON-NLS
255  }
256 
257  // find the user-specific ntuser-dat files
258  try {
259  allRegistryFiles.addAll(fileManager.findFiles(dataSource, "usrclass.dat")); //NON-NLS
260  } catch (TskCoreException ex) {
261  logger.log(Level.WARNING, String.format("Error finding 'usrclass.dat' files."), ex); //NON-NLS
262  }
263 
264  // find the system hives'
265  String[] regFileNames = new String[]{"system", "software", "security"}; //NON-NLS
266  for (String regFileName : regFileNames) {
267  try {
268  allRegistryFiles.addAll(fileManager.findFiles(dataSource, regFileName, "/system32/config")); //NON-NLS
269  } catch (TskCoreException ex) {
270  String msg = NbBundle.getMessage(this.getClass(),
271  "ExtractRegistry.findRegFiles.errMsg.errReadingFile", regFileName);
272  logger.log(Level.WARNING, msg, ex);
273  this.addErrorMessage(this.getName() + ": " + msg);
274  }
275  }
276  return allRegistryFiles;
277  }
278 
283  private void analyzeRegistryFiles() {
284  List<AbstractFile> allRegistryFiles = findRegistryFiles();
285 
286  // open the log file
287  FileWriter logFile = null;
288  try {
289  logFile = new FileWriter(RAImageIngestModule.getRAOutputPath(currentCase, "reg") + File.separator + "regripper-info.txt"); //NON-NLS
290  } catch (IOException ex) {
291  logger.log(Level.SEVERE, null, ex);
292  }
293 
294  for (AbstractFile regFile : allRegistryFiles) {
295  String regFileName = regFile.getName();
296  long regFileId = regFile.getId();
297  String regFileNameLocal = RAImageIngestModule.getRATempPath(currentCase, "reg") + File.separator + regFileName;
298  String outputPathBase = RAImageIngestModule.getRAOutputPath(currentCase, "reg") + File.separator + regFileName + "-regripper-" + Long.toString(regFileId); //NON-NLS
299  File regFileNameLocalFile = new File(regFileNameLocal);
300  try {
301  ContentUtils.writeToFile(regFile, regFileNameLocalFile, context::dataSourceIngestIsCancelled);
302  } catch (ReadContentInputStreamException ex) {
303  logger.log(Level.WARNING, String.format("Error reading registry file '%s' (id=%d).",
304  regFile.getName(), regFileId), ex); //NON-NLS
305  this.addErrorMessage(
306  NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
307  this.getName(), regFileName));
308  continue;
309  } catch (IOException ex) {
310  logger.log(Level.SEVERE, String.format("Error writing temp registry file '%s' for registry file '%s' (id=%d).",
311  regFileNameLocal, regFile.getName(), regFileId), ex); //NON-NLS
312  this.addErrorMessage(
313  NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
314  this.getName(), regFileName));
315  continue;
316  }
317 
318  if (context.dataSourceIngestIsCancelled()) {
319  break;
320  }
321 
322  try {
323  if (logFile != null) {
324  logFile.write(Long.toString(regFileId) + "\t" + regFile.getUniquePath() + "\n");
325  }
326  } catch (TskCoreException | IOException ex) {
327  logger.log(Level.SEVERE, null, ex);
328  }
329 
330  logger.log(Level.INFO, "{0}- Now getting registry information from {1}", new Object[]{moduleName, regFileNameLocal}); //NON-NLS
331  RegOutputFiles regOutputFiles = ripRegistryFile(regFileNameLocal, outputPathBase);
332  if (context.dataSourceIngestIsCancelled()) {
333  break;
334  }
335 
336  // parse the autopsy-specific output
337  if (regOutputFiles.autopsyPlugins.isEmpty() == false && parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
338  this.addErrorMessage(
339  NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
340  this.getName(), regFileName));
341  }
342 
343  // create a report for the full output
344  if (!regOutputFiles.fullPlugins.isEmpty()) {
345  //parse the full regripper output from SAM hive files
346  if (regFileNameLocal.toLowerCase().contains("sam") && parseSamPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
347  this.addErrorMessage(
348  NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
349  this.getName(), regFileName));
350  } else if (regFileNameLocal.toLowerCase().contains("ntuser") || regFileNameLocal.toLowerCase().contains("usrclass")) {
351  try {
352  List<ShellBag> shellbags = ShellBagParser.parseShellbagOutput(regOutputFiles.fullPlugins);
353  createShellBagArtifacts(regFile, shellbags);
354  createRecentlyUsedArtifacts(regOutputFiles.fullPlugins, regFile);
355  } catch (IOException | TskCoreException ex) {
356  logger.log(Level.WARNING, String.format("Unable to get shell bags from file %s", regOutputFiles.fullPlugins), ex);
357  }
358  } else if (regFileNameLocal.toLowerCase().contains("system") && parseSystemPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
359  this.addErrorMessage(
360  NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
361  this.getName(), regFileName));
362  }
363  try {
364  Report report = currentCase.addReport(regOutputFiles.fullPlugins,
365  NbBundle.getMessage(this.getClass(), "ExtractRegistry.parentModuleName.noSpace"),
366  "RegRipper " + regFile.getUniquePath(), regFile); //NON-NLS
367 
368  // Index the report content so that it will be available for keyword search.
369  KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class);
370  if (null == searchService) {
371  logger.log(Level.WARNING, "Keyword search service not found. Report will not be indexed");
372  } else {
373  searchService.index(report);
374  report.close();
375  }
376  } catch (TskCoreException e) {
377  this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
378  }
379  }
380  // delete the hive
381  regFileNameLocalFile.delete();
382  }
383 
384  try {
385  if (logFile != null) {
386  logFile.close();
387  }
388  } catch (IOException ex) {
389  logger.log(Level.SEVERE, null, ex);
390  }
391  }
392 
400  private RegOutputFiles ripRegistryFile(String regFilePath, String outFilePathBase) {
401  String autopsyType = ""; // Type argument for rr for autopsy-specific modules
402  String fullType; // Type argument for rr for full set of modules
403 
404  RegOutputFiles regOutputFiles = new RegOutputFiles();
405 
406  if (regFilePath.toLowerCase().contains("system")) { //NON-NLS
407  autopsyType = "autopsysystem"; //NON-NLS
408  fullType = "system"; //NON-NLS
409  } else if (regFilePath.toLowerCase().contains("software")) { //NON-NLS
410  autopsyType = "autopsysoftware"; //NON-NLS
411  fullType = "software"; //NON-NLS
412  } else if (regFilePath.toLowerCase().contains("ntuser")) { //NON-NLS
413  autopsyType = "autopsyntuser"; //NON-NLS
414  fullType = "ntuser"; //NON-NLS
415  } else if (regFilePath.toLowerCase().contains("sam")) { //NON-NLS
416  //fullType sam output files are parsed for user information
417  fullType = "sam"; //NON-NLS
418  } else if (regFilePath.toLowerCase().contains("security")) { //NON-NLS
419  fullType = "security"; //NON-NLS
420  } else if (regFilePath.toLowerCase().contains("usrclass")) { //NON-NLS
421  fullType = "usrclass"; //NON-NLS
422  } else {
423  return regOutputFiles;
424  }
425 
426  // run the autopsy-specific set of modules
427  if (!autopsyType.isEmpty()) {
428  regOutputFiles.autopsyPlugins = outFilePathBase + "-autopsy.txt"; //NON-NLS
429  String errFilePath = outFilePathBase + "-autopsy.err.txt"; //NON-NLS
430  logger.log(Level.INFO, "Writing RegRipper results to: {0}", regOutputFiles.autopsyPlugins); //NON-NLS
431  executeRegRipper(rrCmd, rrHome, regFilePath, autopsyType, regOutputFiles.autopsyPlugins, errFilePath);
432  }
433  if (context.dataSourceIngestIsCancelled()) {
434  return regOutputFiles;
435  }
436 
437  // run the full set of rr modules
438  if (!fullType.isEmpty()) {
439  regOutputFiles.fullPlugins = outFilePathBase + "-full.txt"; //NON-NLS
440  String errFilePath = outFilePathBase + "-full.err.txt"; //NON-NLS
441  logger.log(Level.INFO, "Writing Full RegRipper results to: {0}", regOutputFiles.fullPlugins); //NON-NLS
442  executeRegRipper(rrFullCmd, rrFullHome, regFilePath, fullType, regOutputFiles.fullPlugins, errFilePath);
443  try {
444  scanErrorLogs(errFilePath);
445  } catch (IOException ex) {
446  logger.log(Level.SEVERE, String.format("Unable to run RegRipper on %s", regFilePath), ex); //NON-NLS
447  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getName(), regFilePath));
448  }
449  }
450  return regOutputFiles;
451  }
452 
453  private void scanErrorLogs(String errFilePath) throws IOException {
454  File regfile = new File(errFilePath);
455  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
456  String line = reader.readLine();
457  while (line != null) {
458  line = line.trim();
459  if (line.toLowerCase().contains("error") || line.toLowerCase().contains("@inc")) {
460  logger.log(Level.WARNING, "Regripper file {0} contains errors from run", errFilePath); //NON-NLS
461 
462  }
463  line = reader.readLine();
464  }
465  }
466  }
467 
468  private void executeRegRipper(List<String> regRipperPath, Path regRipperHomeDir, String hiveFilePath, String hiveFileType, String outputFile, String errFile) {
469  try {
470  List<String> commandLine = new ArrayList<>();
471  for (String cmd : regRipperPath) {
472  commandLine.add(cmd);
473  }
474  commandLine.add("-r"); //NON-NLS
475  commandLine.add(hiveFilePath);
476  commandLine.add("-f"); //NON-NLS
477  commandLine.add(hiveFileType);
478 
479  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
480  processBuilder.directory(regRipperHomeDir.toFile()); // RegRipper 2.8 has to be run from its own directory
481  processBuilder.redirectOutput(new File(outputFile));
482  processBuilder.redirectError(new File(errFile));
483  ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
484  } catch (IOException ex) {
485  logger.log(Level.SEVERE, String.format("Error running RegRipper on %s", hiveFilePath), ex); //NON-NLS
486  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getName(), hiveFilePath));
487  }
488  }
489 
490  // @@@ VERIFY that we are doing the right thing when we parse multiple NTUSER.DAT
499  private boolean parseAutopsyPluginOutput(String regFilePath, AbstractFile regFile) {
500  FileInputStream fstream = null;
501  List<BlackboardArtifact> newArtifacts = new ArrayList<>();
502  try {
503  // Read the file in and create a Document and elements
504  File regfile = new File(regFilePath);
505  fstream = new FileInputStream(regfile);
506  String regString = new Scanner(fstream, "UTF-8").useDelimiter("\\Z").next(); //NON-NLS
507  String startdoc = "<?xml version=\"1.0\"?><document>"; //NON-NLS
508  String result = regString.replaceAll("----------------------------------------", "");
509  result = result.replaceAll("\\n", ""); //NON-NLS
510  result = result.replaceAll("\\r", ""); //NON-NLS
511  result = result.replaceAll("'", "&apos;"); //NON-NLS
512  result = result.replaceAll("&", "&amp;"); //NON-NLS
513  result = result.replace('\0', ' '); // NON-NLS
514  String enddoc = "</document>"; //NON-NLS
515  String stringdoc = startdoc + result + enddoc;
516  DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
517  Document doc = builder.parse(new InputSource(new StringReader(stringdoc)));
518 
519  // cycle through the elements in the doc
520  Element oroot = doc.getDocumentElement();
521  NodeList children = oroot.getChildNodes();
522  int len = children.getLength();
523  for (int i = 0; i < len; i++) {
524 
525  if (context.dataSourceIngestIsCancelled()) {
526  return false;
527  }
528 
529  Element tempnode = (Element) children.item(i);
530 
531  String dataType = tempnode.getNodeName();
532  NodeList timenodes = tempnode.getElementsByTagName("mtime"); //NON-NLS
533  Long mtime = null;
534  if (timenodes.getLength() > 0) {
535  Element timenode = (Element) timenodes.item(0);
536  String etime = timenode.getTextContent();
537  //sometimes etime will be an empty string and therefore can not be parsed into a date
538  if (etime != null && !etime.isEmpty()) {
539  try {
540  mtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime();
541  String Tempdate = mtime.toString();
542  mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
543  } catch (ParseException ex) {
544  logger.log(Level.WARNING, "Failed to parse epoch time when parsing the registry.", ex); //NON-NLS
545  }
546  }
547  }
548 
549  NodeList artroots = tempnode.getElementsByTagName("artifacts"); //NON-NLS
550  if (artroots.getLength() == 0) {
551  // If there isn't an artifact node, skip this entry
552  continue;
553  }
554 
555  Element artroot = (Element) artroots.item(0);
556  NodeList myartlist = artroot.getChildNodes();
557  String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
558 
559  // If all artifact nodes should really go under one Blackboard artifact, need to process it differently
560  switch (dataType) {
561  case "WinVersion": //NON-NLS
562  String version = "";
563  String systemRoot = "";
564  String productId = "";
565  String regOwner = "";
566  String regOrg = "";
567  Long installtime = null;
568  for (int j = 0; j < myartlist.getLength(); j++) {
569  Node artchild = myartlist.item(j);
570  // If it has attributes, then it is an Element (based off API)
571  if (artchild.hasAttributes()) {
572  Element artnode = (Element) artchild;
573 
574  String value = artnode.getTextContent();
575  if (value != null) {
576  value = value.trim();
577  }
578  String name = artnode.getAttribute("name"); //NON-NLS
579  if (name == null) {
580  continue;
581  }
582  switch (name) {
583  case "ProductName": // NON-NLS
584  version = value;
585  break;
586  case "CSDVersion": // NON-NLS
587  // This is dependant on the fact that ProductName shows up first in the module output
588  version = version + " " + value;
589  break;
590  case "SystemRoot": //NON-NLS
591  systemRoot = value;
592  break;
593  case "ProductId": //NON-NLS
594  productId = value;
595  break;
596  case "RegisteredOwner": //NON-NLS
597  regOwner = value;
598  break;
599  case "RegisteredOrganization": //NON-NLS
600  regOrg = value;
601  break;
602  case "InstallDate": //NON-NLS
603  if (value != null && !value.isEmpty()) {
604  try {
605  installtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(value).getTime();
606  String Tempdate = installtime.toString();
607  installtime = Long.valueOf(Tempdate) / MS_IN_SEC;
608  } catch (ParseException e) {
609  logger.log(Level.WARNING, "RegRipper::Conversion on DateTime -> ", e); //NON-NLS
610  }
611  }
612  break;
613  default:
614  break;
615  }
616  }
617  }
618  try {
619  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
620  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, version));
621  if (installtime != null) {
622  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, installtime));
623  }
624  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, parentModuleName, systemRoot));
625  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PRODUCT_ID, parentModuleName, productId));
626  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_OWNER, parentModuleName, regOwner));
627  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ORGANIZATION, parentModuleName, regOrg));
628 
629  // Check if there is already an OS_INFO artifact for this file, and add to that if possible.
630  ArrayList<BlackboardArtifact> results = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_INFO, regFile.getId());
631  if (results.isEmpty()) {
632  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
633  bbart.addAttributes(bbattributes);
634 
635  newArtifacts.add(bbart);
636  } else {
637  results.get(0).addAttributes(bbattributes);
638  }
639 
640  } catch (TskCoreException ex) {
641  logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard."); //NON-NLS
642  }
643  break;
644  case "Profiler": // NON-NLS
645  String os = "";
646  String procArch = "";
647  String tempDir = "";
648  for (int j = 0; j < myartlist.getLength(); j++) {
649  Node artchild = myartlist.item(j);
650  // If it has attributes, then it is an Element (based off API)
651  if (artchild.hasAttributes()) {
652  Element artnode = (Element) artchild;
653 
654  String value = artnode.getTextContent().trim();
655  String name = artnode.getAttribute("name"); //NON-NLS
656  switch (name) {
657  case "OS": // NON-NLS
658  os = value;
659  break;
660  case "PROCESSOR_ARCHITECTURE": // NON-NLS
661  procArch = value;
662  break;
663  case "PROCESSOR_IDENTIFIER": //NON-NLS
664  break;
665  case "TEMP": //NON-NLS
666  tempDir = value;
667  break;
668  default:
669  break;
670  }
671  }
672  }
673  try {
674  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
675  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VERSION, parentModuleName, os));
676  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE, parentModuleName, procArch));
677  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TEMP_DIR, parentModuleName, tempDir));
678 
679  // Check if there is already an OS_INFO artifact for this file and add to that if possible
680  ArrayList<BlackboardArtifact> results = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_INFO, regFile.getId());
681  if (results.isEmpty()) {
682  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
683  bbart.addAttributes(bbattributes);
684 
685  newArtifacts.add(bbart);
686  } else {
687  results.get(0).addAttributes(bbattributes);
688  }
689  } catch (TskCoreException ex) {
690  logger.log(Level.SEVERE, "Error adding os info artifact to blackboard."); //NON-NLS
691  }
692  break;
693  case "CompName": // NON-NLS
694  String compName = "";
695  String domain = "";
696  for (int j = 0; j < myartlist.getLength(); j++) {
697  Node artchild = myartlist.item(j);
698  // If it has attributes, then it is an Element (based off API)
699  if (artchild.hasAttributes()) {
700  Element artnode = (Element) artchild;
701 
702  String value = artnode.getTextContent().trim();
703  String name = artnode.getAttribute("name"); //NON-NLS
704 
705  if (name.equals("ComputerName")) { // NON-NLS
706  compName = value;
707  } else if (name.equals("Domain")) { // NON-NLS
708  domain = value;
709  }
710  }
711  }
712  try {
713  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
714  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, compName));
715  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, parentModuleName, domain));
716 
717  // Check if there is already an OS_INFO artifact for this file and add to that if possible
718  ArrayList<BlackboardArtifact> results = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_INFO, regFile.getId());
719  if (results.isEmpty()) {
720  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
721  bbart.addAttributes(bbattributes);
722 
723  newArtifacts.add(bbart);
724  } else {
725  results.get(0).addAttributes(bbattributes);
726  }
727  } catch (TskCoreException ex) {
728  logger.log(Level.SEVERE, "Error adding os info artifact to blackboard.", ex); //NON-NLS
729  }
730  break;
731  default:
732  for (int j = 0; j < myartlist.getLength(); j++) {
733  Node artchild = myartlist.item(j);
734  // If it has attributes, then it is an Element (based off API)
735  if (artchild.hasAttributes()) {
736  Element artnode = (Element) artchild;
737 
738  String value = artnode.getTextContent().trim();
739  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
740 
741  switch (dataType) {
742  case "recentdocs": //NON-NLS
743  // BlackboardArtifact bbart = tskCase.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
744  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", dataType, mtime));
745  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", dataType, mtimeItem));
746  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), "RecentActivity", dataType, value));
747  // bbart.addAttributes(bbattributes);
748  // @@@ BC: Why are we ignoring this...
749  break;
750  case "usb": //NON-NLS
751  try {
752  Long usbMtime = Long.parseLong(artnode.getAttribute("mtime")); //NON-NLS
753  usbMtime = Long.valueOf(usbMtime.toString());
754 
755  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
756  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, usbMtime));
757  String dev = artnode.getAttribute("dev"); //NON-NLS
758  String make = "";
759  String model = dev;
760  if (dev.toLowerCase().contains("vid")) { //NON-NLS
761  USBInfo info = USB_MAPPER.parseAndLookup(dev);
762  if (info.getVendor() != null) {
763  make = info.getVendor();
764  }
765  if (info.getProduct() != null) {
766  model = info.getProduct();
767  }
768  }
769  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, parentModuleName, make));
770  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, parentModuleName, model));
771  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, value));
772  bbart.addAttributes(bbattributes);
773 
774  newArtifacts.add(bbart);
775  } catch (TskCoreException ex) {
776  logger.log(Level.SEVERE, "Error adding device attached artifact to blackboard.", ex); //NON-NLS
777  }
778  break;
779  case "uninstall": //NON-NLS
780  Long itemMtime = null;
781  try {
782  String mTimeAttr = artnode.getAttribute("mtime");
783  if (mTimeAttr != null && !mTimeAttr.isEmpty()) {
784  itemMtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(mTimeAttr).getTime(); //NON-NLS
785  itemMtime /= MS_IN_SEC;
786  }
787  } catch (ParseException ex) {
788  logger.log(Level.SEVERE, "Failed to parse epoch time for installed program artifact.", ex); //NON-NLS
789  }
790 
791  try {
792  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, value));
793  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, itemMtime));
794  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
795  bbart.addAttributes(bbattributes);
796 
797  newArtifacts.add(bbart);
798  } catch (TskCoreException ex) {
799  logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard.", ex); //NON-NLS
800  }
801  break;
802  case "office": //NON-NLS
803  String officeName = artnode.getAttribute("name"); //NON-NLS
804 
805  try {
806  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
807  // @@@ BC: Consider removing this after some more testing. It looks like an Mtime associated with the root key and not the individual item
808  if (mtime != null) {
809  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, parentModuleName, mtime));
810  }
811  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, officeName));
812  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE, parentModuleName, value));
813  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, artnode.getNodeName()));
814  bbart.addAttributes(bbattributes);
815 
816  newArtifacts.add(bbart);
817  } catch (TskCoreException ex) {
818  logger.log(Level.SEVERE, "Error adding recent object artifact to blackboard.", ex); //NON-NLS
819  }
820  break;
821 
822  case "ProcessorArchitecture": //NON-NLS
823  // Architecture is now included under Profiler
824  //try {
825  // String processorArchitecture = value;
826  // if (processorArchitecture.equals("AMD64"))
827  // processorArchitecture = "x86-64";
828 
829  // BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
830  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE.getTypeID(), parentModuleName, processorArchitecture));
831  // bbart.addAttributes(bbattributes);
832  //} catch (TskCoreException ex) {
833  // logger.log(Level.SEVERE, "Error adding os info artifact to blackboard."); //NON-NLS
834  //}
835  break;
836 
837  case "ProfileList": //NON-NLS
838  try {
839  String homeDir = value;
840  String sid = artnode.getAttribute("sid"); //NON-NLS
841  String username = artnode.getAttribute("username"); //NON-NLS
842  BlackboardArtifact bbart = null;
843  try {
844  //check if any of the existing artifacts match this username
845  ArrayList<BlackboardArtifact> existingArtifacts = currentCase.getSleuthkitCase().getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
846  for (BlackboardArtifact artifact : existingArtifacts) {
847  if (artifact.getDataSource().getId() == regFile.getDataSourceObjectId()) {
848  BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID));
849  if (attribute != null && attribute.getValueString().equals(sid)) {
850  bbart = artifact;
851  break;
852  }
853  }
854  }
855  } catch (TskCoreException ex) {
856  logger.log(Level.SEVERE, "Error getting existing os account artifact", ex);
857  }
858  if (bbart == null) {
859  //create new artifact
860  bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
861  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
862  parentModuleName, username));
863  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
864  parentModuleName, sid));
865  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
866  parentModuleName, homeDir));
867  } else {
868  //add attributes to existing artifact
869  BlackboardAttribute bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_NAME));
870 
871  if (bbattr == null) {
872  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
873  parentModuleName, username));
874  }
875  bbattr = bbart.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_PATH));
876  if (bbattr == null) {
877  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
878  parentModuleName, homeDir));
879  }
880  }
881  bbart.addAttributes(bbattributes);
882  newArtifacts.add(bbart);
883  } catch (TskCoreException ex) {
884  logger.log(Level.SEVERE, "Error adding account artifact to blackboard.", ex); //NON-NLS
885  }
886  break;
887 
888  case "NtuserNetwork": // NON-NLS
889  try {
890  String localPath = artnode.getAttribute("localPath"); //NON-NLS
891  String remoteName = value;
892  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_REMOTE_DRIVE);
893  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCAL_PATH,
894  parentModuleName, localPath));
895  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH,
896  parentModuleName, remoteName));
897  bbart.addAttributes(bbattributes);
898  newArtifacts.add(bbart);
899  } catch (TskCoreException ex) {
900  logger.log(Level.SEVERE, "Error adding network artifact to blackboard.", ex); //NON-NLS
901  }
902  break;
903  case "SSID": // NON-NLS
904  String adapter = artnode.getAttribute("adapter"); //NON-NLS
905  try {
906  Long lastWriteTime = Long.parseLong(artnode.getAttribute("writeTime")); //NON-NLS
907  lastWriteTime = Long.valueOf(lastWriteTime.toString());
908  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SSID, parentModuleName, value));
909  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, lastWriteTime));
910  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, adapter));
911  BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_WIFI_NETWORK);
912  bbart.addAttributes(bbattributes);
913  newArtifacts.add(bbart);
914  } catch (TskCoreException ex) {
915  logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard.", ex); //NON-NLS
916  }
917  break;
918  case "shellfolders": // NON-NLS
919  // The User Shell Folders subkey stores the paths to Windows Explorer folders for the current user of the computer
920  // (https://technet.microsoft.com/en-us/library/Cc962613.aspx).
921  // No useful information. Skip.
922  break;
923 
924  default:
925  logger.log(Level.SEVERE, "Unrecognized node name: {0}", dataType); //NON-NLS
926  break;
927  }
928  }
929  }
930  break;
931  }
932  } // for
933  return true;
934  } catch (FileNotFoundException ex) {
935  logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS
936  } catch (SAXException ex) {
937  logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS
938  } catch (IOException ex) {
939  logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS
940  } catch (ParserConfigurationException ex) {
941  logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS
942  } finally {
943  try {
944  if (fstream != null) {
945  fstream.close();
946  }
947  } catch (IOException ex) {
948  }
949 
950  postArtifacts(newArtifacts);
951  }
952  return false;
953  }
954 
955  private boolean parseSystemPluginOutput(String regfilePath, AbstractFile regAbstractFile) {
956  File regfile = new File(regfilePath);
957  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
958  String line = reader.readLine();
959  while (line != null) {
960  line = line.trim();
961 
962  if (line.toLowerCase().matches("^bam v.*")) {
963  parseBamKey(regAbstractFile, reader, Bundle.Registry_System_Bam());
964  } else if (line.toLowerCase().matches("^bthport v..*")) {
965  parseBlueToothDevices(regAbstractFile, reader);
966  }
967  line = reader.readLine();
968  }
969  return true;
970  } catch (FileNotFoundException ex) {
971  logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
972  } catch (IOException ex) {
973  logger.log(Level.WARNING, "Error reading the system hive: {0}", ex); //NON-NLS
974  }
975 
976  return false;
977 
978  }
979 
992  private void parseBlueToothDevices(AbstractFile regFile, BufferedReader reader) throws FileNotFoundException, IOException {
993  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
994  String line = reader.readLine();
995  while ((line != null) && (!line.contains(SECTION_DIVIDER))) {
996  line = reader.readLine();
997 
998  if (line != null) {
999  line = line.trim();
1000  }
1001 
1002  if ((line != null) && (line.toLowerCase().contains("device unique id"))) {
1003  // Columns are seperated by colons :
1004  // Data : Values
1005  // Record is 4 lines in length (Device Unique Id, Name, Last Seen, LastConnected
1006  while (line != null && !line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.toLowerCase().contains("radio support not found")) {
1007  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1008  addBlueToothAttribute(line, attributes, TSK_DEVICE_ID);
1009  line = reader.readLine();
1010  // Name may not exist, check for it to make sure.
1011  if ((line != null) && (line.toLowerCase().contains("name"))) {
1012  addBlueToothAttribute(line, attributes, TSK_NAME);
1013  line = reader.readLine();
1014  }
1015  addBlueToothAttribute(line, attributes, TSK_DATETIME);
1016  line = reader.readLine();
1017  addBlueToothAttribute(line, attributes, TSK_DATETIME_ACCESSED);
1018  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING, regFile, attributes);
1019  if (bba != null) {
1020  bbartifacts.add(bba);
1021  }
1022  // Read blank line between records then next read line is start of next block
1023  reader.readLine();
1024  line = reader.readLine();
1025  }
1026 
1027  if (line != null) {
1028  line = line.trim();
1029  }
1030  }
1031  }
1032  if (!bbartifacts.isEmpty()) {
1033  postArtifacts(bbartifacts);
1034  }
1035  }
1036 
1037  private void addBlueToothAttribute(String line, Collection<BlackboardAttribute> attributes, ATTRIBUTE_TYPE attributeType) {
1038  if (line == null) {
1039  return;
1040  }
1041 
1042  String tokens[] = line.split(": ");
1043  if (tokens.length > 1 && !tokens[1].isEmpty()) {
1044  String tokenString = tokens[1];
1045  if (attributeType.getDisplayName().toLowerCase().contains("date")) {
1046  String dateString = tokenString.toLowerCase().replace(" z", "");
1047  // date format for plugin Tue Jun 23 10:27:54 2020 Z
1048  SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US);
1049  Long dateLong = Long.valueOf(0);
1050  try {
1051  Date newDate = dateFormat.parse(dateString);
1052  dateLong = newDate.getTime() / 1000;
1053  } catch (ParseException ex) {
1054  // catching error and displaying date that could not be parsed
1055  // we set the timestamp to 0 and continue on processing
1056  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for Bluetooth Last Seen attribute.", dateString), ex); //NON-NLS
1057  }
1058  attributes.add(new BlackboardAttribute(attributeType, getName(), dateLong));
1059  } else {
1060  attributes.add(new BlackboardAttribute(attributeType, getName(), tokenString));
1061  }
1062  }
1063  }
1064 
1074  private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile) {
1075  File regfile = new File(regFilePath);
1076  List<BlackboardArtifact> newArtifacts = new ArrayList<>();
1077  try (BufferedReader bufferedReader = new BufferedReader(new FileReader(regfile))) {
1078  // Read the file in and create a Document and elements
1079  String userInfoSection = "User Information";
1080  String previousLine = null;
1081  String line = bufferedReader.readLine();
1082  Set<Map<String, String>> userSet = new HashSet<>();
1083  Map<String, List<String>> groupMap = null;
1084  while (line != null) {
1085  if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
1086  readUsers(bufferedReader, userSet);
1087  }
1088 
1089  if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains("Group Membership Information")) {
1090  groupMap = readGroups(bufferedReader);
1091  }
1092 
1093  previousLine = line;
1094  line = bufferedReader.readLine();
1095  }
1096  Map<String, Map<String, String>> userInfoMap = new HashMap<>();
1097  //load all the user info which was read into a map
1098  for (Map<String, String> userInfo : userSet) {
1099  userInfoMap.put(userInfo.get(SID_KEY), userInfo);
1100  }
1101  //get all existing OS account artifacts
1102  List<BlackboardArtifact> existingOsAccounts = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
1103  for (BlackboardArtifact osAccount : existingOsAccounts) {
1104  //if the OS Account artifact was from the same data source check the user id
1105  if (osAccount.getDataSource().getId() == regAbstractFile.getDataSourceObjectId()) {
1106  BlackboardAttribute existingUserId = osAccount.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_USER_ID));
1107  if (existingUserId != null) {
1108  String userID = existingUserId.getValueString().trim();
1109  Map<String, String> userInfo = userInfoMap.remove(userID);
1110  //if the existing user id matches a user id which we parsed information for check if that information exists and if it doesn't add it
1111  if (userInfo != null) {
1112  osAccount.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userID), true, regAbstractFile));
1113  }
1114  }
1115  }
1116  }
1117 
1118  //add remaining userinfos as accounts;
1119  for (Map<String, String> userInfo : userInfoMap.values()) {
1120  BlackboardArtifact bbart = regAbstractFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT);
1121  bbart.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userInfo.get(SID_KEY)), false, regAbstractFile));
1122  // index the artifact for keyword search
1123  newArtifacts.add(bbart);
1124  }
1125  // Get a mapping of user sids to user names and save globally so it can be used for other areas
1126  // of the registry, ie: BAM key
1127  try {
1128  userNameMap = makeUserNameMap(dataSource);
1129  } catch (TskCoreException ex) {
1130  logger.log(Level.WARNING, "Unable to create OS Account user name map", ex);
1131  // This is not the end of the world we will just continue without
1132  // user names
1133  userNameMap = new HashMap<>();
1134  }
1135  return true;
1136  } catch (FileNotFoundException ex) {
1137  logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
1138  } catch (IOException ex) {
1139  logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS
1140  } catch (ParseException ex) {
1141  logger.log(Level.WARNING, "Error parsing the the date from the registry file", ex); //NON-NLS
1142  } catch (TskCoreException ex) {
1143  logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS
1144  } finally {
1145  postArtifacts(newArtifacts);
1146  }
1147  return false;
1148  }
1149 
1161  Collection<BlackboardAttribute> getAttributesForAccount(Map<String, String> userInfo, List<String> groupList, boolean existingUser, AbstractFile regAbstractFile) throws ParseException {
1162  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1163 
1164  SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'");
1165  regRipperTimeFormat.setTimeZone(getTimeZone("GMT"));
1166 
1167  if (!existingUser) {
1168  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
1169  getRAModuleName(), userInfo.get(SID_KEY)));
1170 
1171  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1172  this.moduleName, userInfo.get(USERNAME_KEY)));
1173  }
1174 
1175  String value = userInfo.get(ACCOUNT_CREATED_KEY);
1176  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
1177  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1178  getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
1179  }
1180 
1181  value = userInfo.get(LAST_LOGIN_KEY);
1182  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
1183  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1184  getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
1185  }
1186 
1187  value = userInfo.get(LOGIN_COUNT_KEY);
1188  if (value != null && !value.isEmpty()) {
1189  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1190  getRAModuleName(), Integer.parseInt(value)));
1191  }
1192 
1193  value = userInfo.get(ACCOUNT_TYPE_KEY);
1194  if (value != null && !value.isEmpty()) {
1195  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE,
1196  getRAModuleName(), value));
1197  }
1198 
1199  value = userInfo.get(USER_COMMENT_KEY);
1200  if (value != null && !value.isEmpty()) {
1201  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
1202  getRAModuleName(), value));
1203  }
1204 
1205  value = userInfo.get(NAME_KEY);
1206  if (value != null && !value.isEmpty()) {
1207  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1208  getRAModuleName(), value));
1209  }
1210 
1211  value = userInfo.get(INTERNET_NAME_KEY);
1212  if (value != null && !value.isEmpty()) {
1213  try {
1214  // Create an account for this email, if it doesn't already exist.
1215  Case.getCurrentCaseThrows()
1216  .getSleuthkitCase()
1217  .getCommunicationsManager()
1218  .createAccountFileInstance(Account.Type.EMAIL,
1219  value, getRAModuleName(), regAbstractFile);
1220  } catch (NoCurrentCaseException | TskCoreException ex) {
1221  logger.log(Level.SEVERE,
1222  String.format("Error adding email account with value "
1223  + "%s, to the case database for file %s [objId=%d]",
1224  value, regAbstractFile.getName(), regAbstractFile.getId()), ex);
1225  }
1226 
1227  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
1228  getRAModuleName(), value));
1229  }
1230 
1231  value = userInfo.get(FULL_NAME_KEY);
1232  if (value != null && !value.isEmpty()) {
1233  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DISPLAY_NAME,
1234  getRAModuleName(), value));
1235  }
1236 
1237  value = userInfo.get(PWD_RESET_KEY);
1238  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
1239  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET,
1240  getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
1241  }
1242 
1243  value = userInfo.get(PASSWORD_HINT);
1244  if (value != null && !value.isEmpty()) {
1245  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT,
1246  getRAModuleName(), value));
1247  }
1248 
1249  value = userInfo.get(PWD_FAILE_KEY);
1250  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
1251  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL,
1252  getRAModuleName(), regRipperTimeFormat.parse(value).getTime() / MS_IN_SEC));
1253  }
1254 
1255  String settingString = "";
1256  for (String setting : PASSWORD_SETTINGS_FLAGS) {
1257  if (userInfo.containsKey(setting)) {
1258  settingString += setting + ", ";
1259  }
1260  }
1261 
1262  if (!settingString.isEmpty()) {
1263  settingString = settingString.substring(0, settingString.length() - 2);
1264  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS,
1265  getRAModuleName(), settingString));
1266  }
1267 
1268  settingString = "";
1269  for (String setting : ACCOUNT_SETTINGS_FLAGS) {
1270  if (userInfo.containsKey(setting)) {
1271  settingString += setting + ", ";
1272  }
1273  }
1274 
1275  if (!settingString.isEmpty()) {
1276  settingString = settingString.substring(0, settingString.length() - 2);
1277  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS,
1278  getRAModuleName(), settingString));
1279  }
1280 
1281  settingString = "";
1282  for (String setting : ACCOUNT_TYPE_FLAGS) {
1283  if (userInfo.containsKey(setting)) {
1284  settingString += setting + ", ";
1285  }
1286  }
1287 
1288  if (!settingString.isEmpty()) {
1289  settingString = settingString.substring(0, settingString.length() - 2);
1290  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
1291  getRAModuleName(), settingString));
1292  }
1293 
1294  if (groupList != null && groupList.isEmpty()) {
1295  String groups = "";
1296  for (String group : groupList) {
1297  groups += group + ", ";
1298  }
1299 
1300  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GROUPS,
1301  getRAModuleName(), groups.substring(0, groups.length() - 2)));
1302  }
1303 
1304  return bbattributes;
1305  }
1306 
1318  private void readUsers(BufferedReader bufferedReader, Set<Map<String, String>> users) throws IOException {
1319  String line = bufferedReader.readLine();
1320  //read until end of file or next section divider
1321  String userName = "";
1322  String user_rid = "";
1323  while (line != null && !line.contains(SECTION_DIVIDER)) {
1324  //when a user name field exists read the name and id number
1325  if (line.contains(USERNAME_KEY)) {
1326  String regx = USERNAME_KEY + "\\s*?:";
1327  String userNameAndIdString = line.replaceAll(regx, "");
1328  userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
1329  user_rid = userNameAndIdString.substring(userNameAndIdString.lastIndexOf('['), userNameAndIdString.lastIndexOf(']'));
1330  } else if (line.contains(SID_KEY) && !userName.isEmpty()) {
1331  Map.Entry<String, String> entry = getSAMKeyValue(line);
1332 
1333  HashMap<String, String> userInfo = new HashMap<>();
1334  userInfo.put(USERNAME_KEY, userName);
1335  userInfo.put(RID_KEY, user_rid);
1336  userInfo.put(entry.getKey(), entry.getValue());
1337 
1338  //continue reading this users information until end of file or a blank line between users
1339  line = bufferedReader.readLine();
1340  while (line != null && !line.isEmpty()) {
1341  entry = getSAMKeyValue(line);
1342  if (entry != null) {
1343  userInfo.put(entry.getKey(), entry.getValue());
1344  }
1345  line = bufferedReader.readLine();
1346  }
1347  users.add(userInfo);
1348 
1349  userName = "";
1350  }
1351  line = bufferedReader.readLine();
1352  }
1353  }
1354 
1364  private void createRecentlyUsedArtifacts(String regFileName, AbstractFile regFile) throws FileNotFoundException, IOException {
1365  File regfile = new File(regFileName);
1366  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
1367  String line = reader.readLine();
1368  while (line != null) {
1369  line = line.trim();
1370 
1371  if (line.matches("^adoberdr v.*")) {
1372  parseAdobeMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Adobe());
1373  } else if (line.matches("^mpmru v.*")) {
1374  parseMediaPlayerMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mediaplayer());
1375  } else if (line.matches("^trustrecords v.*")) {
1376  parseOfficeTrustRecords(regFile, reader, Bundle.Recently_Used_Artifacts_Office_Trustrecords());
1377  } else if (line.matches("^ArcHistory:")) {
1378  parse7ZipMRU(regFile, reader, Bundle.Recently_Used_Artifacts_ArcHistory());
1379  } else if (line.matches("^applets v.*")) {
1380  parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Applets());
1381  } else if (line.matches("^mmc v.*")) {
1382  parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mmc());
1383  } else if (line.matches("^winrar v.*")) {
1384  parseWinRARMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Winrar());
1385  } else if (line.matches("^officedocs2010 v.*")) {
1386  parseOfficeDocs2010MRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Officedocs());
1387  }
1388  line = reader.readLine();
1389  }
1390  }
1391  }
1392 
1404  private void parseBamKey(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1405  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1406  String line = reader.readLine();
1407  // Read thru first bam output to get to second bam output which is the same but delimited
1408  while (!line.contains(SECTION_DIVIDER)) {
1409  line = reader.readLine();
1410  line = line.trim();
1411  }
1412  line = reader.readLine();
1413  line = line.trim();
1414  while (!line.contains(SECTION_DIVIDER)) {
1415  // Split the line into it parts based on delimiter of "|"
1416  // 1570493613|BAM|||\Device\HarddiskVolume3\Program Files\TechSmith\Snagit 2018\Snagit32.exe (S-1-5-21-3042408413-2583535980-1301764466-1001)
1417  String tokens[] = line.split("\\|");
1418  Long progRunDateTime = Long.valueOf(tokens[0]);
1419  // Split on " (S-" as this signifies a User SID, if S- not used then may have issues becuase of (x86) in path is valid.
1420  // We can add the S- back to the string that we split on since S- is a valid beginning of a User SID
1421  String fileNameSid[] = tokens[4].split("\\s+\\(S-");
1422  String userSid = "S-" + fileNameSid[1].substring(0, fileNameSid[1].length() - 1);
1423  String userName = userNameMap.get(userSid);
1424  if (userName == null) {
1425  userName = userSid;
1426  }
1427  String fileName = fileNameSid[0];
1428  if (fileName.startsWith("\\Device\\HarddiskVolume")) {
1429  // Start at point past the 2nd slash
1430  int fileNameStart = fileName.indexOf('\\', 16);
1431  fileName = fileName.substring(fileNameStart, fileName.length());
1432 
1433  }
1434  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1435  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, getName(), fileName));
1436  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, getName(), userName));
1437  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getName(), progRunDateTime));
1438  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, getName(), comment));
1439  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_PROG_RUN, regFile, attributes);
1440  if (bba != null) {
1441  bbartifacts.add(bba);
1442  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1443  if (bba != null) {
1444  bbartifacts.add(bba);
1445  }
1446  }
1447  line = reader.readLine();
1448  }
1449  if (!bbartifacts.isEmpty()) {
1450  postArtifacts(bbartifacts);
1451  }
1452  }
1453 
1465  private void parseAdobeMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1466  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1467  String line = reader.readLine();
1468  SimpleDateFormat adobePluginDateFormat = new SimpleDateFormat("yyyyMMddHHmmssZ", US);
1469  Long adobeUsedTime = Long.valueOf(0);
1470  while (!line.contains(SECTION_DIVIDER)) {
1471  line = reader.readLine();
1472  line = line.trim();
1473  if (line.matches("^Key name,file name,sDate,uFileSize,uPageCount")) {
1474  line = reader.readLine();
1475  // Columns are
1476  // Key name, file name, sDate, uFileSize, uPageCount
1477  while (!line.contains(SECTION_DIVIDER)) {
1478  // Split csv line, handles double quotes around individual file names
1479  // since file names can contain commas
1480  String tokens[] = line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
1481  String fileName = tokens[1].substring(0, tokens[1].length() - 1);
1482  fileName = fileName.replace("\"", "");
1483  if (fileName.charAt(0) == '/') {
1484  fileName = fileName.substring(1, fileName.length() - 1);
1485  fileName = fileName.replaceFirst("/", ":/");
1486  }
1487  // Check to see if more then 2 tokens, Date may not be populated, will default to 0
1488  if (tokens.length > 2) {
1489  // Time in the format of 20200131104456-05'00'
1490  try {
1491  String fileUsedTime = tokens[2].replaceAll("'", "");
1492  Date usedDate = adobePluginDateFormat.parse(fileUsedTime);
1493  adobeUsedTime = usedDate.getTime() / 1000;
1494  } catch (ParseException ex) {
1495  // catching error and displaying date that could not be parsed
1496  // we set the timestamp to 0 and continue on processing
1497  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for adobe file artifact.", tokens[2]), ex); //NON-NLS
1498  }
1499  }
1500  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1501  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1502  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getName(), adobeUsedTime));
1503  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1504  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1505  if (bba != null) {
1506  bbartifacts.add(bba);
1507  fileName = fileName.replace("\0", "");
1508  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1509  if (bba != null) {
1510  bbartifacts.add(bba);
1511  }
1512  }
1513  line = reader.readLine();
1514  }
1515  line = line.trim();
1516  }
1517  }
1518  if (!bbartifacts.isEmpty()) {
1519  postArtifacts(bbartifacts);
1520  }
1521  }
1522 
1535  private void parseMediaPlayerMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1536  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1537  String line = reader.readLine();
1538  while (!line.contains(SECTION_DIVIDER)) {
1539  line = reader.readLine();
1540  line = line.trim();
1541  if (line.contains("LastWrite")) {
1542  line = reader.readLine();
1543  // Columns are
1544  // FileX -> <Media file>
1545  while (!line.contains(SECTION_DIVIDER) && !line.contains("RecentFileList has no values.")) {
1546  // Split line on "> " which is the record delimiter between position and file
1547  String tokens[] = line.split("> ");
1548  String fileName = tokens[1];
1549  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1550  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1551  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1552  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1553  if (bba != null) {
1554  bbartifacts.add(bba);
1555  bba = createAssociatedArtifact(fileName, bba);
1556  if (bba != null) {
1557  bbartifacts.add(bba);
1558  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1559  if (bba != null) {
1560  bbartifacts.add(bba);
1561  }
1562  }
1563  }
1564  line = reader.readLine();
1565  }
1566  line = line.trim();
1567  }
1568  }
1569  if (!bbartifacts.isEmpty()) {
1570  postArtifacts(bbartifacts);
1571  }
1572  }
1573 
1586  private void parseGenericMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1587  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1588  String line = reader.readLine();
1589  while (!line.contains(SECTION_DIVIDER)) {
1590  line = reader.readLine();
1591  line = line.trim();
1592  if (line.contains("LastWrite")) {
1593  line = reader.readLine();
1594  // Columns are
1595  // FileX -> <file>
1596  while (!line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("Applets")
1597  && !line.contains(("Recent File List"))) {
1598  // Split line on "> " which is the record delimiter between position and file
1599  String tokens[] = line.split("> ");
1600  String fileName = tokens[1];
1601  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1602  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1603  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1604  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1605  if (bba != null) {
1606  bbartifacts.add(bba);
1607  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1608  if (bba != null) {
1609  bbartifacts.add(bba);
1610  }
1611  }
1612  line = reader.readLine();
1613  }
1614  line = line.trim();
1615  }
1616  }
1617  if (!bbartifacts.isEmpty()) {
1618  postArtifacts(bbartifacts);
1619  }
1620  }
1621 
1634  private void parseWinRARMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1635  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1636  String line = reader.readLine();
1637  while (!line.contains(SECTION_DIVIDER)) {
1638  line = reader.readLine();
1639  line = line.trim();
1640  if (line.contains("LastWrite")) {
1641  line = reader.readLine();
1642  // Columns are
1643  // FileX -> <Media file>
1644  if (!line.isEmpty()) {
1645  while (!line.contains(SECTION_DIVIDER)) {
1646  // Split line on "> " which is the record delimiter between position and file
1647  String tokens[] = line.split("> ");
1648  String fileName = tokens[1];
1649  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1650  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1651  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1652  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1653  if (bba != null) {
1654  bbartifacts.add(bba);
1655  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1656  if (bba != null) {
1657  bbartifacts.add(bba);
1658  }
1659  }
1660  line = reader.readLine();
1661  }
1662  }
1663  line = line.trim();
1664  }
1665  }
1666  if (!bbartifacts.isEmpty()) {
1667  postArtifacts(bbartifacts);
1668  }
1669  }
1670 
1683  private void parse7ZipMRU(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1684  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1685  String line = reader.readLine();
1686  line = line.trim();
1687  if (!line.contains("PathHistory:")) {
1688  while (!line.contains("PathHistory:") && !line.isEmpty()) {
1689  // Columns are
1690  // <fileName>
1691  String fileName = line;
1692  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1693  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1694  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1695  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1696  if (bba != null) {
1697  bbartifacts.add(bba);
1698  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1699  if (bba != null) {
1700  bbartifacts.add(bba);
1701  }
1702  }
1703  line = reader.readLine();
1704  line = line.trim();
1705  }
1706  }
1707  if (!bbartifacts.isEmpty()) {
1708  postArtifacts(bbartifacts);
1709  }
1710  }
1711 
1724  private void parseOfficeDocs2010MRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1725  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1726  String line = reader.readLine();
1727  line = line.trim();
1728  // Reading to the SECTION DIVIDER to get next section of records to process. Dates appear to have
1729  // multiple spaces in them that makes it harder to parse so next section will be easier to parse
1730  while (!line.contains(SECTION_DIVIDER)) {
1731  line = reader.readLine();
1732  }
1733  line = reader.readLine();
1734  while (!line.contains(SECTION_DIVIDER)) {
1735  // record has the following format
1736  // 1294283922|REG|||OfficeDocs2010 - F:\Windows_time_Rules_xp.doc
1737  String tokens[] = line.split("\\|");
1738  Long docDate = Long.valueOf(tokens[0]);
1739  String fileNameTokens[] = tokens[4].split(" - ");
1740  String fileName = fileNameTokens[1];
1741  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1742  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1743  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getName(), docDate));
1744  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1745  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1746  if (bba != null) {
1747  bbartifacts.add(bba);
1748  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1749  if (bba != null) {
1750  bbartifacts.add(bba);
1751  }
1752  }
1753  line = reader.readLine();
1754  line = line.trim();
1755  }
1756  if (!bbartifacts.isEmpty()) {
1757  postArtifacts(bbartifacts);
1758  }
1759  }
1760 
1773  private void parseOfficeTrustRecords(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1774  String userProfile = regFile.getParentPath();
1775  userProfile = userProfile.substring(0, userProfile.length() - 1);
1776  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1777  SimpleDateFormat pluginDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", US);
1778  Long usedTime = Long.valueOf(0);
1779  String line = reader.readLine();
1780  while (!line.contains(SECTION_DIVIDER)) {
1781  line = reader.readLine();
1782  line = line.trim();
1783  usedTime = Long.valueOf(0);
1784  if (!line.contains("**") && !line.contains("----------") && !line.contains("LastWrite")
1785  && !line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("TrustRecords")) {
1786  // Columns are
1787  // Date : <File Name>/<Website>
1788  // Split line on " : " which is the record delimiter between position and file
1789  String fileName = null;
1790  String tokens[] = line.split(" : ");
1791  fileName = tokens[1];
1792  fileName = fileName.replace("%USERPROFILE%", userProfile);
1793  // Time in the format of Wed May 31 14:33:03 2017 Z
1794  try {
1795  String fileUsedTime = tokens[0].replaceAll(" Z", "");
1796  Date usedDate = pluginDateFormat.parse(fileUsedTime);
1797  usedTime = usedDate.getTime() / 1000;
1798  } catch (ParseException ex) {
1799  // catching error and displaying date that could not be parsed
1800  // we set the timestamp to 0 and continue on processing
1801  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for TrustRecords artifact.", tokens[0]), ex); //NON-NLS
1802  }
1803  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1804  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
1805  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getName(), usedTime));
1806  attributes.add(new BlackboardAttribute(TSK_COMMENT, getName(), comment));
1807  BlackboardArtifact bba = createArtifactWithAttributes(ARTIFACT_TYPE.TSK_RECENT_OBJECT, regFile, attributes);
1808  if (bba != null) {
1809  bbartifacts.add(bba);
1810  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1811  if (bba != null) {
1812  bbartifacts.add(bba);
1813  }
1814  }
1815  line = line.trim();
1816  }
1817  }
1818  if (!bbartifacts.isEmpty()) {
1819  postArtifacts(bbartifacts);
1820  }
1821  }
1822 
1833  private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) {
1834  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
1835  String fileName = FilenameUtils.getName(filePathName);
1836  String filePath = FilenameUtils.getPath(filePathName);
1837  List<AbstractFile> sourceFiles;
1838  try {
1839  sourceFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS
1840  if (!sourceFiles.isEmpty()) {
1841  for (AbstractFile sourceFile : sourceFiles) {
1842  if (sourceFile.getParentPath().endsWith(filePath)) {
1843  Collection<BlackboardAttribute> bbattributes2 = new ArrayList<>();
1844  bbattributes2.addAll(Arrays.asList(
1845  new BlackboardAttribute(TSK_ASSOCIATED_ARTIFACT, this.getName(),
1846  bba.getArtifactID())));
1847 
1848  BlackboardArtifact associatedObjectBba = createArtifactWithAttributes(TSK_ASSOCIATED_OBJECT, sourceFile, bbattributes2);
1849  if (associatedObjectBba != null) {
1850  return associatedObjectBba;
1851  }
1852  }
1853  }
1854  }
1855  } catch (TskCoreException ex) {
1856  // only catching the error and displaying the message as the file may not exist on the
1857  // system anymore
1858  logger.log(Level.WARNING, String.format("Error finding actual file %s. file may not exist", filePathName)); //NON-NLS
1859  }
1860 
1861  return null;
1862  }
1863 
1873  private Map<String, String> makeUserNameMap(Content dataSource) throws TskCoreException {
1874  Map<String, String> userNameMap = new HashMap<>();
1875 
1876  List<BlackboardArtifact> accounts = blackboard.getArtifacts(TSK_OS_ACCOUNT.getTypeID(), dataSource.getId());
1877 
1878  for (BlackboardArtifact account : accounts) {
1879  BlackboardAttribute nameAttribute = getAttributeForArtifact(account, TSK_USER_NAME);
1880  BlackboardAttribute idAttribute = getAttributeForArtifact(account, TSK_USER_ID);
1881 
1882  String userName = nameAttribute != null ? nameAttribute.getDisplayString() : "";
1883  String userID = idAttribute != null ? idAttribute.getDisplayString() : "";
1884 
1885  if (!userID.isEmpty()) {
1886  userNameMap.put(userID, userName);
1887  }
1888  }
1889 
1890  return userNameMap;
1891  }
1892 
1903  private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
1904  return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID())));
1905  }
1906 
1915  void createShellBagArtifacts(AbstractFile regFile, List<ShellBag> shellbags) throws TskCoreException {
1916  List<BlackboardArtifact> artifacts = new ArrayList<>();
1917  try {
1918  for (ShellBag bag : shellbags) {
1919  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1920  BlackboardArtifact artifact = regFile.newArtifact(getShellBagArtifact().getTypeID());
1921  attributes.add(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource()));
1922  attributes.add(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey()));
1923 
1924  long time;
1925  time = bag.getLastWrite();
1926  if (time != 0) {
1927  attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getName(), time));
1928  }
1929 
1930  time = bag.getModified();
1931  if (time != 0) {
1932  attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time));
1933  }
1934 
1935  time = bag.getCreated();
1936  if (time != 0) {
1937  attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time));
1938  }
1939 
1940  time = bag.getAccessed();
1941  if (time != 0) {
1942  attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time));
1943  }
1944 
1945  artifact.addAttributes(attributes);
1946 
1947  artifacts.add(artifact);
1948  }
1949  } finally {
1950  postArtifacts(artifacts);
1951  }
1952  }
1953 
1962  private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException {
1963  if (shellBagArtifactType == null) {
1964  shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME);
1965 
1966  if (shellBagArtifactType == null) {
1967  try {
1968  tskCase.addBlackboardArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name()); //NON-NLS
1969  } catch (TskDataException ex) {
1970  // Artifact already exists
1971  logger.log(Level.INFO, String.format("%s may have already been defined for this case", SHELLBAG_ARTIFACT_NAME));
1972  }
1973 
1974  shellBagArtifactType = tskCase.getArtifactType(SHELLBAG_ARTIFACT_NAME);
1975  }
1976  }
1977 
1978  return shellBagArtifactType;
1979  }
1980 
1989  private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException {
1990  if (shellBagLastWriteAttributeType == null) {
1991  try {
1992  shellBagLastWriteAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE,
1993  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME,
1994  Bundle.Shellbag_Last_Write_Attribute_Display_Name());
1995  } catch (TskDataException ex) {
1996  // Attribute already exists get it from the case
1997  shellBagLastWriteAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE);
1998  }
1999  }
2000  return shellBagLastWriteAttributeType;
2001  }
2002 
2011  private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException {
2012  if (shellBagKeyAttributeType == null) {
2013  try {
2014  shellBagKeyAttributeType = tskCase.addArtifactAttributeType(SHELLBAG_ATTRIBUTE_KEY,
2015  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2016  Bundle.Shellbag_Key_Attribute_Display_Name());
2017  } catch (TskDataException ex) {
2018  // The attribute already exists get it from the case
2019  shellBagKeyAttributeType = tskCase.getAttributeType(SHELLBAG_ATTRIBUTE_KEY);
2020  }
2021  }
2022  return shellBagKeyAttributeType;
2023  }
2024 
2034  Map<String, List<String>> readGroups(BufferedReader bufferedReader) throws IOException {
2035  Map<String, List<String>> groupMap = new HashMap<>();
2036 
2037  String line = bufferedReader.readLine();
2038 
2039  int userCount = 0;
2040  String groupName = null;
2041 
2042  while (line != null && !line.contains(SECTION_DIVIDER)) {
2043 
2044  if (line.contains("Group Name")) {
2045  String value = line.replaceAll("Group Name\\s*?:", "").trim();
2046  groupName = (value.replaceAll("\\[\\d*?\\]", "")).trim();
2047  int startIndex = value.indexOf(" [") + 1;
2048  int endIndex = value.indexOf(']');
2049 
2050  if (startIndex != -1 && endIndex != -1) {
2051  String countStr = value.substring(startIndex + 1, endIndex);
2052  userCount = Integer.parseInt(countStr);
2053  }
2054  } else if (line.matches("Users\\s*?:")) {
2055  for (int i = 0; i < userCount; i++) {
2056  line = bufferedReader.readLine();
2057  if (line != null) {
2058  String sid = line.trim();
2059  List<String> groupList = groupMap.get(sid);
2060  if (groupList == null) {
2061  groupList = new ArrayList<>();
2062  groupMap.put(sid, groupList);
2063  }
2064  groupList.add(groupName);
2065  }
2066  }
2067  groupName = null;
2068  }
2069  line = bufferedReader.readLine();
2070  }
2071  return groupMap;
2072  }
2073 
2082  private Map.Entry<String, String> getSAMKeyValue(String line) {
2083  int index = line.indexOf(':');
2084  Map.Entry<String, String> returnValue = null;
2085  String key = null;
2086  String value = null;
2087 
2088  if (index != -1) {
2089  key = line.substring(0, index).trim();
2090  if (index + 1 < line.length()) {
2091  value = line.substring(index + 1).trim();
2092  } else {
2093  value = "";
2094  }
2095 
2096  } else if (line.contains("-->")) {
2097  key = line.replace("-->", "").trim();
2098  value = "true";
2099  }
2100 
2101  if (key != null) {
2102  returnValue = new AbstractMap.SimpleEntry<>(key, value);
2103  }
2104 
2105  return returnValue;
2106  }
2107 
2108  @Override
2109  public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
2110  this.dataSource = dataSource;
2111  this.context = context;
2112 
2113  progressBar.progress(Bundle.Progress_Message_Analyze_Registry());
2114  analyzeRegistryFiles();
2115 
2116  }
2117 
2121  private class RegOutputFiles {
2122 
2123  public String autopsyPlugins = "";
2124  public String fullPlugins = "";
2125  }
2126 }
synchronized List< AbstractFile > findFiles(String fileName)

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.