Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
EvalRegistryObj.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.report.modules.stix;
20 
21 import com.williballenthin.rejistry.RegistryHiveFile;
22 import com.williballenthin.rejistry.RegistryKey;
23 import com.williballenthin.rejistry.RegistryParseException;
24 import com.williballenthin.rejistry.RegistryValue;
26 import org.sleuthkit.datamodel.TskCoreException;
27 import org.sleuthkit.datamodel.Content;
29 import org.sleuthkit.datamodel.AbstractFile;
30 import java.util.List;
31 import java.util.ArrayList;
32 import java.io.IOException;
33 import java.io.UnsupportedEncodingException;
34 import java.io.File;
35 import java.util.regex.Pattern;
36 import java.util.regex.Matcher;
37 import org.mitre.cybox.objects.WindowsRegistryKey;
38 import org.mitre.cybox.common_2.ConditionTypeEnum;
40 
44 class EvalRegistryObj extends EvaluatableObject {
45 
46  private final WindowsRegistryKey obj;
47  private final List<RegistryFileInfo> regFiles = new ArrayList<>();
48 
49  EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
50  obj = a_obj;
51  id = a_id;
52  spacing = a_spacing;
53  regFiles.addAll(a_regFiles);
54  }
55 
56  private EvalRegistryObj() {
57  obj = null;
58  id = null;
59  spacing = "";
60  }
61 
62  @Override
63  public synchronized ObservableResult evaluate() {
64 
65  setWarnings("");
66 
67  // Key name is required
68  if (obj.getKey() == null) {
69  return new ObservableResult(id, "RegistryObject: No key found", //NON-NLS
70  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
71  }
72 
73  // For now, only support a full string match
74  if (!((obj.getKey().getCondition() == null)
75  || (obj.getKey().getCondition() == ConditionTypeEnum.EQUALS))) {
76  return new ObservableResult(id, "RegistryObject: Can not support condition " + obj.getKey().getCondition() //NON-NLS
77  + " on Key field", //NON-NLS
78  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
79  }
80 
81  setUnsupportedFieldWarnings();
82 
83  // Make a list of hives to test
84  List<RegistryFileInfo> hiveList = new ArrayList<>();
85  if (obj.getHive() == null) {
86  // If the hive field is missing, add everything
87  hiveList.addAll(regFiles);
88  } else if (obj.getHive().getValue().toString().startsWith("HKEY")) { //NON-NLS
89  // If the hive name is HKEY_LOCAL_MACHINE, add the ones from the config directory.
90  // Otherwise, add the others
91  for (RegistryFileInfo regFile : regFiles) {
92  if (regFile.getAbstractFile().getParentPath() != null) {
93  Pattern pattern = Pattern.compile("system32", Pattern.CASE_INSENSITIVE);
94  Matcher matcher = pattern.matcher(regFile.getAbstractFile().getParentPath());
95  if (matcher.find()) {
96  // Looking for system files and found one, so add it to the list
97  if (obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
98  hiveList.add(regFile);
99  }
100  } else {
101  // Looking for non-system files and found one, so add it to the list
102  if (!obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
103  hiveList.add(regFile);
104  }
105  }
106  }
107  }
108  } else {
109  // Otherwise, try to match the name
110  String stixHiveName = obj.getHive().getValue().toString();
111 
112  // The temp files will end \Temp\STIX\(hive)_(number)
113  Pattern pattern = Pattern.compile("Temp.STIX." + stixHiveName, Pattern.CASE_INSENSITIVE);
114 
115  for (RegistryFileInfo hive : regFiles) {
116  Matcher matcher = pattern.matcher(hive.getTempFileName());
117  if (matcher.find()) {
118  hiveList.add(hive);
119  }
120  }
121 
122  // If nothing matched, add all the files
123  if (hiveList.isEmpty()) {
124  hiveList.addAll(regFiles);
125  }
126  }
127 
128  // This is unlikely to happen unless we have no registry files to test against
129  if (hiveList.isEmpty()) {
130  return new ObservableResult(id, "RegistryObject: No matching registry hives found", //NON-NLS
131  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
132  }
133 
134  for (RegistryFileInfo hive : hiveList) {
135  try {
136  ObservableResult result = testRegistryFile(hive);
137  if (result.isTrue()) {
138  return result;
139  }
140  } catch (Exception ex) {
141  // The registry parser seems to throw lots of different types of exceptions,
142  // so make sure to catch them all by this point. Malformed registry files
143  // in particular cause problems.
144  addWarning("Error processing registry file " + hive); //NON-NLS
145  }
146  }
147 
148  if (obj.getHive() == null) {
149  return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue(), //NON-NLS
150  spacing, ObservableResult.ObservableState.FALSE, null);
151  }
152  return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue() //NON-NLS
153  + " in hive " + obj.getHive().getValue(), //NON-NLS
154  spacing, ObservableResult.ObservableState.FALSE, null);
155 
156  }
157 
165  private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
166  try {
167  RegistryKey root = openRegistry(a_regInfo.getTempFileName());
168  RegistryKey result = findKey(root, obj.getKey().getValue().toString());
169 
170  if (result == null) {
171 
172  // Take another shot looking for the key minus the first part of the path (sometimes the
173  // hive file name is here). This should only happen if the hive name started
174  // with "HKEY"
175  if ((obj.getHive() != null)
176  && obj.getHive().getValue().toString().startsWith("HKEY")) { //NON-NLS
177  String[] parts = obj.getKey().getValue().toString().split("\\\\");
178  String newKey = "";
179  for (int i = 1; i < parts.length; i++) {
180  if (newKey.length() > 0) {
181  newKey += "\\";
182  }
183  newKey += parts[i];
184  }
185  result = findKey(root, newKey);
186  }
187 
188  if (result == null) {
189  return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue(), //NON-NLS
190  spacing, ObservableResult.ObservableState.FALSE, null);
191  }
192  }
193 
194  if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
195  // No values to test
196  List<StixArtifactData> artData = new ArrayList<>();
197  artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
198  return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
199  spacing, ObservableResult.ObservableState.TRUE, artData);
200  }
201 
202  // Test all the values
203  for (org.mitre.cybox.objects.RegistryValueType stixRegValue : obj.getValues().getValues()) {
204  try {
205  for (RegistryValue valFromFile : result.getValueList()) {
206 
207  // Test if the name field matches (if present)
208  boolean nameSuccess = true; // True if the name matches or isn't present
209  if (stixRegValue.getName() != null) {
210  try {
211  nameSuccess = compareStringObject(stixRegValue.getName(), valFromFile.getName());
212  } catch (UnsupportedEncodingException ex) {
213  nameSuccess = false;
214  }
215  }
216 
217  boolean valueSuccess = true;
218  if (nameSuccess && (stixRegValue.getData() != null)) {
219  switch (valFromFile.getValueType()) {
220  case REG_SZ:
221  case REG_EXPAND_SZ:
222 
223  try {
224  valueSuccess = compareStringObject(stixRegValue.getData(),
225  valFromFile.getValue().getAsString());
226  } catch (UnsupportedEncodingException ex) {
227  valueSuccess = false;
228  }
229  break;
230  case REG_DWORD:
231  case REG_BIG_ENDIAN:
232  case REG_QWORD:
233 
234  // Only support "equals" for now.
235  if ((stixRegValue.getData().getCondition() == null)
236  || (stixRegValue.getData().getCondition() == ConditionTypeEnum.EQUALS)) {
237 
238  // Try to convert the STIX string to a long
239  try {
240  long stixValue = Long.decode(stixRegValue.getData().getValue().toString());
241 
242  try {
243  valueSuccess = (stixValue == valFromFile.getValue().getAsNumber());
244  } catch (UnsupportedEncodingException ex) {
245  valueSuccess = false;
246  }
247  } catch (NumberFormatException ex) {
248  // We probably weren't looking at a numeric field to begin with,
249  // so getting this exception isn't really an error.
250  valueSuccess = false;
251  }
252  } else {
253  valueSuccess = false;
254  }
255 
256  break;
257  default:
258  // Nothing to do here. These are the types we don't handle:
259  // REG_BIN, REG_FULL_RESOURCE_DESCRIPTOR, REG_LINK, REG_MULTI_SZ, REG_NONE,
260  // REG_RESOURCE_LIST, REG_RESOURCE_REQUIREMENTS_LIST
261  }
262  }
263 
264  if (nameSuccess && valueSuccess) {
265  // Found a match for all values
266  List<StixArtifactData> artData = new ArrayList<>();
267  artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
268  return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
269  + " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
270  + " = " + stixRegValue.getData().getValue().toString(),
271  spacing, ObservableResult.ObservableState.TRUE, artData);
272  }
273  }
274  } catch (Exception ex) {
275  // Broad catch here becase the registry parser can create all kinds of exceptions beyond what it reports.
276  return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
277  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
278  }
279  }
280  } catch (TskCoreException ex) {
281  return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
282  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
283  }
284 
285  return new ObservableResult(id, "RegistryObject: Not done", //NON-NLS
286  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
287  }
288 
289  public RegistryKey openRegistry(String hive) throws TskCoreException {
290 
291  try {
292  RegistryHiveFile regFile = new RegistryHiveFile(new File(hive));
293  RegistryKey root = regFile.getRoot();
294  return root;
295  } catch (IOException ex) {
296  throw new TskCoreException("Error opening registry file - " + ex.getLocalizedMessage()); //NON-NLS
297  } catch (RegistryParseException ex) {
298  throw new TskCoreException("Error opening root node of registry - " + ex.getLocalizedMessage()); //NON-NLS
299  }
300  }
301 
310  public RegistryKey findKey(RegistryKey root, String name) {
311 
312  RegistryKey currentKey = root;
313 
314  // Split the key name into parts
315  String[] parts = name.split("\\\\");
316  for (String part : parts) {
317 
318  if (part.length() > 0) {
319  try {
320  currentKey = currentKey.getSubkey(part);
321  } catch (Exception ex) {
322  // We get an exception if the value wasn't found (not a RegistryParseException).
323  // There doesn't seem to be a cleaner way to test for existance without cycling though
324  // everything ourselves. (Broad catch because things other than RegistryParseException
325  // can happen)
326  return null;
327  }
328  }
329  }
330 
331  // If we make it this far, we've found it
332  return currentKey;
333  }
334 
341  public static List<RegistryFileInfo> copyRegistryFiles() throws TskCoreException {
342 
343  // First get all the abstract files
344  List<AbstractFile> regFilesAbstract = findRegistryFiles();
345 
346  // List to hold all the extracted file names plus their abstract file
347  List<RegistryFileInfo> regFilesLocal = new ArrayList<>();
348 
349  // Make the temp directory
350  String tmpDir;
351  try {
352  tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
353  } catch (NoCurrentCaseException ex) {
354  throw new TskCoreException(ex.getLocalizedMessage());
355  }
356  File dir = new File(tmpDir);
357  if (dir.exists() == false) {
358  dir.mkdirs();
359  }
360 
361  long index = 1;
362  for (AbstractFile regFile : regFilesAbstract) {
363  String regFileName = regFile.getName();
364  String regFileNameLocal = tmpDir + File.separator + regFileName + "_" + index;
365  File regFileNameLocalFile = new File(regFileNameLocal);
366  try {
367  // Don't save any unallocated versions
368  if (regFile.getMetaFlagsAsString().contains("Allocated")) { //NON-NLS
369  ContentUtils.writeToFile(regFile, regFileNameLocalFile);
370  regFilesLocal.add(new EvalRegistryObj().new RegistryFileInfo(regFile, regFileNameLocal));
371  }
372  } catch (IOException ex) {
373  throw new TskCoreException(ex.getLocalizedMessage());
374  }
375  index++;
376  }
377 
378  return regFilesLocal;
379  }
380 
385  private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
386  List<AbstractFile> registryFiles = new ArrayList<>();
387  Case openCase;
388  try {
389  openCase = Case.getCurrentCaseThrows();
390  } catch (NoCurrentCaseException ex) {
391  throw new TskCoreException(ex.getLocalizedMessage());
392  }
393  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = openCase.getServices().getFileManager();
394 
395  for (Content ds : openCase.getDataSources()) {
396 
397  // find the user-specific ntuser-dat files
398  registryFiles.addAll(fileManager.findFiles(ds, "ntuser.dat")); //NON-NLS
399 
400  // find the system hives
401  String[] regFileNames = new String[]{"system", "software", "security", "sam"}; //NON-NLS
402  for (String regFileName : regFileNames) {
403  List<AbstractFile> allRegistryFiles = fileManager.findFiles(ds, regFileName, "/system32/config"); //NON-NLS
404  for (AbstractFile regFile : allRegistryFiles) {
405  // Don't want anything from regback
406  if (!regFile.getParentPath().contains("RegBack")) { //NON-NLS
407  registryFiles.add(regFile);
408  }
409  }
410  }
411  }
412 
413  return registryFiles;
414  }
415 
416  private void setUnsupportedFieldWarnings() {
417  List<String> fieldNames = new ArrayList<>();
418 
419  if (obj.getNumberValues() != null) {
420  fieldNames.add("Number_Values"); //NON-NLS
421  }
422  if (obj.getModifiedTime() != null) {
423  fieldNames.add("Modified_Time"); //NON-NLS
424  }
425  if (obj.getCreatorUsername() != null) {
426  fieldNames.add("Creator_Username"); //NON-NLS
427  }
428  if (obj.getHandleList() != null) {
429  fieldNames.add("Handle_List"); //NON-NLS
430  }
431  if (obj.getNumberSubkeys() != null) {
432  fieldNames.add("Number_Subkeys"); //NON-NLS
433  }
434  if (obj.getSubkeys() != null) {
435  fieldNames.add("Subkeys"); //NON-NLS
436  }
437  if (obj.getByteRuns() != null) {
438  fieldNames.add("Byte_Runs"); //NON-NLS
439  }
440 
441  String warningStr = "";
442  for (String name : fieldNames) {
443  if (!warningStr.isEmpty()) {
444  warningStr += ", ";
445  }
446  warningStr += name;
447  }
448 
449  addWarning("Unsupported field(s): " + warningStr); //NON-NLS
450  }
451 
456  public class RegistryFileInfo {
457 
458  private final AbstractFile abstractFile;
459  private final String tempFileName;
460 
461  public RegistryFileInfo(AbstractFile a_abstractFile, String a_tempFileName) {
462  abstractFile = a_abstractFile;
463  tempFileName = a_tempFileName;
464  }
465 
471  AbstractFile getAbstractFile() {
472  return abstractFile;
473  }
474 
480  String getTempFileName() {
481  return tempFileName;
482  }
483 
484  }
485 }
RegistryFileInfo(AbstractFile a_abstractFile, String a_tempFileName)
synchronized List< AbstractFile > findFiles(String fileName)

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