Autopsy  3.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 
162  private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
163  try {
164  RegistryKey root = openRegistry(a_regInfo.tempFileName);
165  RegistryKey result = findKey(root, obj.getKey().getValue().toString());
166 
167  if (result == null) {
168 
169  // Take another shot looking for the key minus the first part of the path (sometimes the
170  // hive file name is here). This should only happen if the hive name started
171  // with "HKEY"
172  if((obj.getHive() != null)
173  && obj.getHive().getValue().toString().startsWith("HKEY")){ //NON-NLS
174  String[] parts = obj.getKey().getValue().toString().split("\\\\");
175  String newKey = "";
176  for (int i = 1; i < parts.length; i++) {
177  if (newKey.length() > 0) {
178  newKey += "\\";
179  }
180  newKey += parts[i];
181  }
182  result = findKey(root, newKey);
183  }
184 
185  if (result == null) {
186  return new ObservableResult(id, "RegistryObject: Could not find key " + obj.getKey().getValue(), //NON-NLS
187  spacing, ObservableResult.ObservableState.FALSE, null);
188  }
189  }
190 
191  if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
192  // No values to test
193  List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
194  artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
195  return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
196  spacing, ObservableResult.ObservableState.TRUE, artData);
197  }
198 
199  // Test all the values
200  for (org.mitre.cybox.objects.RegistryValueType stixRegValue : obj.getValues().getValues()) {
201  try {
202  for (RegistryValue valFromFile : result.getValueList()) {
203 
204  // Test if the name field matches (if present)
205  boolean nameSuccess = true; // True if the name matches or isn't present
206  if (stixRegValue.getName() != null) {
207  try {
208  nameSuccess = compareStringObject(stixRegValue.getName(), valFromFile.getName());
209  } catch (UnsupportedEncodingException ex) {
210  nameSuccess = false;
211  }
212  }
213 
214  boolean valueSuccess = true;
215  if (nameSuccess && (stixRegValue.getData() != null)) {
216  switch (valFromFile.getValueType()) {
217  case REG_SZ:
218  case REG_EXPAND_SZ:
219 
220  try {
221  valueSuccess = compareStringObject(stixRegValue.getData(),
222  valFromFile.getValue().getAsString());
223  } catch (UnsupportedEncodingException ex) {
224  valueSuccess = false;
225  }
226  break;
227  case REG_DWORD:
228  case REG_BIG_ENDIAN:
229  case REG_QWORD:
230 
231  // Only support "equals" for now.
232  if ((stixRegValue.getData().getCondition() == null)
233  || (stixRegValue.getData().getCondition() == ConditionTypeEnum.EQUALS)) {
234 
235  // Try to convert the STIX string to a long
236  try {
237  long stixValue = Long.decode(stixRegValue.getData().getValue().toString());
238 
239  try {
240  valueSuccess = (stixValue == valFromFile.getValue().getAsNumber());
241  } catch (UnsupportedEncodingException ex) {
242  valueSuccess = false;
243  }
244  } catch (NumberFormatException ex) {
245  // We probably weren't looking at a numeric field to begin with,
246  // so getting this exception isn't really an error.
247  valueSuccess = false;
248  }
249  } else {
250  valueSuccess = false;
251  }
252 
253  break;
254  default:
255  // Nothing to do here. These are the types we don't handle:
256  // REG_BIN, REG_FULL_RESOURCE_DESCRIPTOR, REG_LINK, REG_MULTI_SZ, REG_NONE,
257  // REG_RESOURCE_LIST, REG_RESOURCE_REQUIREMENTS_LIST
258  }
259  }
260 
261  if (nameSuccess && valueSuccess) {
262  // Found a match for all values
263  List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
264  artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
265  return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
266  + " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
267  + " = " + stixRegValue.getData().getValue().toString(),
268  spacing, ObservableResult.ObservableState.TRUE, artData);
269  }
270  }
271  } catch (Exception ex) {
272  // Broad catch here becase the registry parser can create all kinds of exceptions beyond what it reports.
273  return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
274  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
275  }
276  }
277  } catch (TskCoreException ex) {
278  return new ObservableResult(id, "RegistryObject: Exception during evaluation: " + ex.getLocalizedMessage(), //NON-NLS
279  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
280  }
281 
282  return new ObservableResult(id, "RegistryObject: Not done", //NON-NLS
283  spacing, ObservableResult.ObservableState.INDETERMINATE, null);
284  }
285 
286  public RegistryKey openRegistry(String hive) throws TskCoreException {
287 
288  try {
289  RegistryHiveFile regFile = new RegistryHiveFile(new File(hive));
290  RegistryKey root = regFile.getRoot();
291  return root;
292  } catch (IOException ex) {
293  throw new TskCoreException("Error opening registry file - " + ex.getLocalizedMessage()); //NON-NLS
294  } catch (RegistryParseException ex) {
295  throw new TskCoreException("Error opening root node of registry - " + ex.getLocalizedMessage()); //NON-NLS
296  }
297  }
298 
306  public RegistryKey findKey(RegistryKey root, String name) {
307 
308  RegistryKey currentKey = root;
309 
310  // Split the key name into parts
311  String[] parts = name.split("\\\\");
312  for (String part : parts) {
313 
314  if (part.length() > 0) {
315  try {
316  currentKey = currentKey.getSubkey(part);
317  } catch (Exception ex) {
318  // We get an exception if the value wasn't found (not a RegistryParseException).
319  // There doesn't seem to be a cleaner way to test for existance without cycling though
320  // everything ourselves. (Broad catch because things other than RegistryParseException
321  // can happen)
322  return null;
323  }
324  }
325  }
326 
327  // If we make it this far, we've found it
328  return currentKey;
329  }
330 
337  public static List<RegistryFileInfo> copyRegistryFiles() throws TskCoreException {
338 
339  // First get all the abstract files
340  List<AbstractFile> regFilesAbstract = findRegistryFiles();
341 
342  // List to hold all the extracted file names plus their abstract file
343  List<RegistryFileInfo> regFilesLocal = new ArrayList<RegistryFileInfo>();
344 
345  // Make the temp directory
346  String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator + "STIX"; //NON-NLS
347  File dir = new File(tmpDir);
348  if (dir.exists() == false) {
349  dir.mkdirs();
350  }
351 
352  long index = 1;
353  for (AbstractFile regFile : regFilesAbstract) {
354  String regFileName = regFile.getName();
355  String regFileNameLocal = tmpDir + File.separator + regFileName + "_" + index;
356  File regFileNameLocalFile = new File(regFileNameLocal);
357  try {
358  // Don't save any unallocated versions
359  if (regFile.getMetaFlagsAsString().contains("Allocated")) { //NON-NLS
360  ContentUtils.writeToFile(regFile, regFileNameLocalFile);
361  regFilesLocal.add(new EvalRegistryObj().new RegistryFileInfo(regFile, regFileNameLocal));
362  }
363  } catch (IOException ex) {
364  throw new TskCoreException(ex.getLocalizedMessage());
365  }
366  index++;
367  }
368 
369  return regFilesLocal;
370  }
371 
376  private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
377  List<AbstractFile> registryFiles = new ArrayList<AbstractFile>();
378  org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
379 
380  for (Content ds : Case.getCurrentCase().getDataSources()) {
381 
382  // find the user-specific ntuser-dat files
383  registryFiles.addAll(fileManager.findFiles(ds, "ntuser.dat")); //NON-NLS
384 
385  // find the system hives
386  String[] regFileNames = new String[]{"system", "software", "security", "sam"}; //NON-NLS
387  for (String regFileName : regFileNames) {
388  List<AbstractFile> allRegistryFiles = fileManager.findFiles(ds, regFileName, "/system32/config"); //NON-NLS
389  for (AbstractFile regFile : allRegistryFiles) {
390  // Don't want anything from regback
391  if (!regFile.getParentPath().contains("RegBack")) { //NON-NLS
392  registryFiles.add(regFile);
393  }
394  }
395  }
396  }
397 
398  return registryFiles;
399  }
400 
401  private void setUnsupportedFieldWarnings() {
402  List<String> fieldNames = new ArrayList<String>();
403 
404  if (obj.getNumberValues() != null) {
405  fieldNames.add("Number_Values"); //NON-NLS
406  }
407  if (obj.getModifiedTime() != null) {
408  fieldNames.add("Modified_Time"); //NON-NLS
409  }
410  if (obj.getCreatorUsername() != null) {
411  fieldNames.add("Creator_Username"); //NON-NLS
412  }
413  if (obj.getHandleList() != null) {
414  fieldNames.add("Handle_List"); //NON-NLS
415  }
416  if (obj.getNumberSubkeys() != null) {
417  fieldNames.add("Number_Subkeys"); //NON-NLS
418  }
419  if (obj.getSubkeys() != null) {
420  fieldNames.add("Subkeys"); //NON-NLS
421  }
422  if (obj.getByteRuns() != null) {
423  fieldNames.add("Byte_Runs"); //NON-NLS
424  }
425 
426  String warningStr = "";
427  for (String name : fieldNames) {
428  if (!warningStr.isEmpty()) {
429  warningStr += ", ";
430  }
431  warningStr += name;
432  }
433 
434  addWarning("Unsupported field(s): " + warningStr); //NON-NLS
435  }
436 
441  public class RegistryFileInfo {
442 
443  private final AbstractFile abstractFile;
444  private final String tempFileName;
445 
446  public RegistryFileInfo(AbstractFile a_abstractFile, String a_tempFileName) {
447  abstractFile = a_abstractFile;
448  tempFileName = a_tempFileName;
449  }
450 
451  }
452 }
synchronized List< AbstractFile > findFiles(Content dataSource, String fileName)
RegistryFileInfo(AbstractFile a_abstractFile, String a_tempFileName)

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