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

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