Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
VirtualMachineFinder.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2012-2015 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.vmextractor;
20 
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileReader;
24 import java.nio.file.Path;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.logging.Level;
31 import javax.swing.filechooser.FileFilter;
34 
38 public final class VirtualMachineFinder {
39 
40  private static final Logger logger = Logger.getLogger(VirtualMachineFinder.class.getName());
41 
42  private static final int MAX_VMDK_DESCRIPTOR_FILE_SIZE_BYTES = 10000;
43  private static final int MIN_VMDK_EXTENT_DESCRIPTOR_FIELDS_NUM = 4; // See readExtentFilesFromVmdkDescriptorFile() for details
44  private static final int FILE_NAME_FIELD_INDX_IN_EXTENT_DESCRIPTOR = 3; // See readExtentFilesFromVmdkDescriptorFile() for details
45 
47  private static final List<FileFilter> vmFiltersList = new ArrayList<>();
48 
49  static {
50  vmFiltersList.add(virtualMachineFilter);
51  }
52 
53  private static final List<String> VMDK_EXTS = Arrays.asList(new String[]{".vmdk"}); //NON-NLS
54  private static final GeneralFilter vmdkFilter = new GeneralFilter(VMDK_EXTS, "");
55  private static final List<FileFilter> vmdkFiltersList = new ArrayList<>();
56 
57  static {
58  vmdkFiltersList.add(vmdkFilter);
59  }
60 
61  private static boolean isVirtualMachine(String fileName) {
62  // is file a virtual machine
63  if (!isAcceptedByFiler(new File(fileName), vmFiltersList)) {
64  return false;
65  }
66  return true;
67  }
68 
76  public static List<String> identifyVirtualMachines(Path imageFolderPath) {
77 
78  // get a list of all files in the folder
79  List<String> files = getAllFilesInFolder(imageFolderPath.toString());
80  if (files.isEmpty()) {
81  return Collections.emptyList();
82  }
83 
84  // remove all non-vm files
85  for (Iterator<String> iterator = files.iterator(); iterator.hasNext();) {
86  String file = iterator.next();
87  if (!isVirtualMachine(file)) {
88  iterator.remove();
89  }
90  }
91 
92  // identify VMDK descriptor files - VMDK files with size less than 10KB
93  List<String> extentFiles = new ArrayList<>();
94  for (String fileName : files) {
95  File file = imageFolderPath.resolve(fileName).toFile();
96  if (isAcceptedByFiler(new File(fileName), vmdkFiltersList) && file.exists() && file.length() < MAX_VMDK_DESCRIPTOR_FILE_SIZE_BYTES) {
97  // this is likely a VMDK descriptor file - read vmdk extent files listed in it
98  extentFiles.addAll(readExtentFilesFromVmdkDescriptorFile(file));
99  }
100  }
101  // remove VMDK extent files from list of vm files to proces
102  files.removeAll(extentFiles);
103 
104  // what remains on the list is either a vmdk descriptor file or a VMDK file that doesn't have a descriptor file or different type of VM (e.g. VHD)
105  return files;
106  }
107 
116  private static List<String> readExtentFilesFromVmdkDescriptorFile(File file) {
117 
118  List<String> extentFiles = new ArrayList<>();
119 
120  // remove from the list all VMDK files that are listed in the descriptor file
121  try (BufferedReader br = new BufferedReader(new FileReader(file))) {
122  String line;
123  while ((line = br.readLine()) != null) {
124  // The extent descriptions provide the following key information:
125  // Access – may be RW, RDONLY, or NOACCESS
126  // Size in sectors – a sector is 512 bytes
127  // Type of extent – may be FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, or VMFSRAW.
128  // Filename
129  // Offset – the offset value is specified only for flat extents and corresponds to the offset in the file or device
130  // where the guest operating system’s data is located.
131  // Example: RW 4192256 SPARSE "win7-ult-vm-0-s001.vmdk"
132 
133  String[] splited = line.split(" ");
134  if (splited.length < MIN_VMDK_EXTENT_DESCRIPTOR_FIELDS_NUM) {
135  // line doesn't have enough fields, can't be an extent descriptor
136  continue;
137  }
138  if (splited[0].equals("RW") || splited[0].equals("RDONLY") || splited[0].equals("NOACCESS")) { //NON-NLS
139  // found an extent descriptor
140  // remove quotation marks around the file name
141  String extentFileName = splited[FILE_NAME_FIELD_INDX_IN_EXTENT_DESCRIPTOR].replace("\"", "");
142 
143  // add extent file to list of extent files
144  extentFiles.add(extentFileName);
145  }
146  }
147  } catch (Exception ex) {
148  logger.log(Level.WARNING, String.format("Error while parsing vmdk descriptor file %s", file.toString()), ex); //NON-NLS
149  }
150  return extentFiles;
151  }
152 
160  private static boolean isPartOfSplitVMDKImage(String fileName) {
161 
162  // only need to worry about ".vmdk" images
163  if (!isAcceptedByFiler(new File(fileName), vmdkFiltersList)) {
164  return false;
165  }
166 
167  // this needs to identify and handle different VMDK scenarios:
168  // i single image in a single file
169  // ii. Single image split over multiple files - just need to pass the first to TSK and it will combine the split image files.
170  // Note there may be more than than one split images in a single dir,
171  // e.g. icrd-te-google.vmdk, icrd-te-google-s001.vmdk, icrd-te-google-s002.vmdk... (split sparse vmdk format)
172  // e.g. win7-ult-vm.vmdk, win7-ult-vm-f001.vmdk, win7-ult-vm-f002.vmdk... (split flat vmdk format)
173  String fName = fileName.toLowerCase();
174  int lastPeriod = fName.lastIndexOf('.');
175  if (-1 == lastPeriod) {
176  return false;
177  }
178  String fNameNoExt = fName.substring(0, lastPeriod);
179  return fNameNoExt.matches(".*-[fs]\\d+$"); // anything followed by "-" then either "f" or "s" and followed by digits at the end of the string
180  }
181 
182  private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
183 
184  for (FileFilter filter : filters) {
185  if (filter.accept(file)) {
186  return true;
187  }
188  }
189  return false;
190  }
191 
200  private static List<String> getAllFilesInFolder(String path) {
201  // only returns files, skips folders
202  File file = new File(path);
203  String[] files = file.list((File current, String name) -> new File(current, name).isFile());
204  if (files == null) {
205  // null is returned when folder doesn't exist. need to check this condition, otherwise there is NullPointerException when converting to List
206  return Collections.emptyList();
207  }
208  return new ArrayList<>(Arrays.asList(files));
209  }
210 }
static List< String > identifyVirtualMachines(Path imageFolderPath)
static final List< String > VIRTUAL_MACHINE_EXTS
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
static boolean isAcceptedByFiler(File file, List< FileFilter > filters)

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