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

Copyright © 2012-2016 Basis Technology. Generated on: Mon Apr 24 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.