Autopsy  4.20.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-2016 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 = 4; // See readExtentFilesFromVmdkDescriptorFile() for details
44  private static final int FILE_NAME_FIELD_INDX = 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  public static final boolean isVirtualMachine(String fileName) {
62  return isAcceptedByFiler(new File(fileName), vmFiltersList);
63  }
64 
72  public static List<String> identifyVirtualMachines(Path imageFolderPath) {
73 
74  // get a list of all files in the folder
75  List<String> files = getAllFilesInFolder(imageFolderPath.toString());
76  if (files.isEmpty()) {
77  return Collections.emptyList();
78  }
79 
80  // remove all non-vm files
81  for (Iterator<String> iterator = files.iterator(); iterator.hasNext();) {
82  String file = iterator.next();
83  if (!isVirtualMachine(file)) {
84  iterator.remove();
85  }
86  }
87 
88  // identify VMDK descriptor files - VMDK files with size less than 10KB
89  List<String> extentFiles = new ArrayList<>();
90  for (String fileName : files) {
91  File file = imageFolderPath.resolve(fileName).toFile();
92  if (isAcceptedByFiler(new File(fileName), vmdkFiltersList) && file.exists() && file.length() < MAX_VMDK_DESCRIPTOR_FILE_SIZE_BYTES) {
93  // this is likely a VMDK descriptor file - read vmdk extent files listed in it
94  extentFiles.addAll(readExtentFilesFromVmdkDescriptorFile(file));
95  }
96  }
97  // remove VMDK extent files from list of vm files to proces
98  files.removeAll(extentFiles);
99 
100  // 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)
101  return files;
102  }
103 
112  private static List<String> readExtentFilesFromVmdkDescriptorFile(File file) {
113 
114  List<String> extentFiles = new ArrayList<>();
115 
116  // remove from the list all VMDK files that are listed in the descriptor file
117  try (BufferedReader br = new BufferedReader(new FileReader(file))) {
118  String line = br.readLine();
119  while (null != line) {
120  // The extent descriptions provide the following key information:
121  // Access – may be RW, RDONLY, or NOACCESS
122  // Size in sectors – a sector is 512 bytes
123  // Type of extent – may be FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, or VMFSRAW.
124  // Filename
125  // Offset – the offset value is specified only for flat extents and corresponds to the offset in the file or device
126  // where the guest operating system’s data is located.
127  // Example: RW 4192256 SPARSE "win7-ult-vm-0-s001.vmdk"
128 
129  String[] splited = line.split(" ");
130  if (splited.length < MIN_VMDK_EXTENT_DESCRIPTOR_FIELDS) {
131  // line doesn't have enough fields, can't be an extent descriptor
132  continue;
133  }
134  if (splited[0].equals("RW") || splited[0].equals("RDONLY") || splited[0].equals("NOACCESS")) { //NON-NLS
135  // found an extent descriptor
136  // remove quotation marks around the file name
137  String extentFileName = splited[FILE_NAME_FIELD_INDX].replace("\"", "");
138 
139  // add extent file to list of extent files
140  extentFiles.add(extentFileName);
141  }
142  line = br.readLine();
143  }
144  } catch (Exception ex) {
145  logger.log(Level.WARNING, String.format("Error while parsing vmdk descriptor file %s", file.toString()), ex); //NON-NLS
146  }
147  return extentFiles;
148  }
149 
150  private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
151 
152  for (FileFilter filter : filters) {
153  if (filter.accept(file)) {
154  return true;
155  }
156  }
157  return false;
158  }
159 
168  private static List<String> getAllFilesInFolder(String path) {
169  // only returns files, skips folders
170  File file = new File(path);
171  String[] files = file.list((File current, String name) -> new File(current, name).isFile());
172  if (files == null) {
173  // null is returned when folder doesn't exist. need to check this condition, otherwise there is NullPointerException when converting to List
174  return Collections.emptyList();
175  }
176  return new ArrayList<>(Arrays.asList(files));
177  }
178 
183  }
184 
185 }
static List< String > identifyVirtualMachines(Path imageFolderPath)
static final List< String > VIRTUAL_MACHINE_EXTS
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static boolean isAcceptedByFiler(File file, List< FileFilter > filters)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.