Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.modules.vmextractor;
20
21import java.io.BufferedReader;
22import java.io.File;
23import java.io.FileReader;
24import java.nio.file.Path;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collections;
28import java.util.Iterator;
29import java.util.List;
30import java.util.logging.Level;
31import javax.swing.filechooser.FileFilter;
32import org.sleuthkit.autopsy.casemodule.GeneralFilter;
33import org.sleuthkit.autopsy.coreutils.Logger;
34
38public 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 {
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 {
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 final List< String > VIRTUAL_MACHINE_EXTS
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static List< String > identifyVirtualMachines(Path imageFolderPath)
static boolean isAcceptedByFiler(File file, List< FileFilter > filters)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.