modules.machinery.vmware

Package modules :: Package machinery :: Module vmware |
[hide private]
[frames] | no frames]

# Source Code for Module modules.machinery.vmware

      1  # Copyright (C) 2010-2013 Claudio Guarnieri.
      2  # Copyright (C) 2014-2016 Cuckoo Foundation.
      3  # This file was originally produced by Mike Tu.
      4  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
      5  # See the file 'docs/LICENSE' for copying permission.
      6
      7  import glob
      8  import logging
      9  import subprocess
     10  import os.path
     11  import shutil
     12  import time
     13
     14  from lib.cuckoo.common.abstracts import Machinery
     15  from lib.cuckoo.common.exceptions import CuckooMachineError
     16
     17  log = logging.getLogger(__name__)
     18
     19 -class VMware(Machinery):
     20      """Virtualization layer for VMware Workstation using vmrun utility."""
     21      LABEL = "vmx_path"
     22
     23 -    def _initialize_check(self):
     24          """Check for configuration file and vmware setup.
     25          @raise CuckooMachineError: if configuration is missing or wrong.
     26          """
     27          if not self.options.vmware.path:
     28              raise CuckooMachineError("VMware vmrun path missing, "
     29                                       "please add it to vmware.conf")
     30
     31          if not os.path.exists(self.options.vmware.path):
     32              raise CuckooMachineError("VMware vmrun not found in "
     33                                       "specified path %s" %
     34                                       self.options.vmware.path)
     35          # Consistency checks.
     36          for machine in self.machines():
     37              vmx_path = machine.label
     38
     39              snapshot = self._snapshot_from_vmx(vmx_path)
     40              self._check_vmx(vmx_path)
     41              self._check_snapshot(vmx_path, snapshot)
     42
     43          # Base checks.
     44          super(VMware, self)._initialize_check()
     45
     46 -    def _check_vmx(self, vmx_path):
     47          """Checks whether a vmx file exists and is valid.
     48          @param vmx_path: path to vmx file
     49          @raise CuckooMachineError: if file not found or not ending with .vmx
     50          """
     51          if not vmx_path.endswith(".vmx"):
     52              raise CuckooMachineError("Wrong configuration: vm path not "
     53                                       "ending with .vmx: %s)" % vmx_path)
     54
     55          if not os.path.exists(vmx_path):
     56              raise CuckooMachineError("Vm file %s not found" % vmx_path)
     57
     58 -    def _check_snapshot(self, vmx_path, snapshot):
     59          """Checks snapshot existance.
     60          @param vmx_path: path to vmx file
     61          @param snapshot: snapshot name
     62          @raise CuckooMachineError: if snapshot not found
     63          """
     64          try:
     65              p = subprocess.Popen([self.options.vmware.path,
     66                                    "listSnapshots", vmx_path],
     67                                   stdout=subprocess.PIPE,
     68                                   stderr=subprocess.PIPE)
     69              output, _ = p.communicate()
     70              output = output.decode("utf-8")
     71          except OSError as e:
     72              raise CuckooMachineError("Unable to get snapshot list for %s. "
     73                                       "Reason: %s" % (vmx_path, e))
     74          else:
     75              if output:
     76                  return snapshot in output
     77              else:
     78                  raise CuckooMachineError("Unable to get snapshot list for %s. "
     79                                           "No output from "
     80                                           "`vmrun listSnapshots`" % vmx_path)
     81
     82 -    def start(self, vmx_path, task):
     83          """Start a virtual machine.
     84          @param vmx_path: path to vmx file.
     85          @param task: task object.
     86          @raise CuckooMachineError: if unable to start.
     87          """
     88          snapshot = self._snapshot_from_vmx(vmx_path)
     89
     90          # Preventive check
     91          if self._is_running(vmx_path):
     92              raise CuckooMachineError("Machine %s is already running" %
     93                                       vmx_path)
     94
     95          self._revert(vmx_path, snapshot)
     96
     97          time.sleep(3)
     98
     99          log.debug("Starting vm %s" % vmx_path)
    100          try:
    101              p = subprocess.Popen([self.options.vmware.path,
    102                                    "start", vmx_path,
    103                                    self.options.vmware.mode],
    104                                   stdout=subprocess.PIPE,
    105                                   stderr=subprocess.PIPE)
    106              if self.options.vmware.mode.lower() == "gui":
    107                  output, _ = p.communicate()
    108                  if output:
    109                      raise CuckooMachineError("Unable to start machine "
    110                                               "%s: %s" % (vmx_path, output))
    111          except OSError as e:
    112              mode = self.options.vmware.mode.upper()
    113              raise CuckooMachineError("Unable to start machine %s in %s "
    114                                       "mode: %s" % (vmx_path, mode, e))
    115
    116 -    def stop(self, vmx_path):
    117          """Stops a virtual machine.
    118          @param vmx_path: path to vmx file
    119          @raise CuckooMachineError: if unable to stop.
    120          """
    121          log.debug("Stopping vm %s" % vmx_path)
    122          if self._is_running(vmx_path):
    123              try:
    124                  if subprocess.call([self.options.vmware.path,
    125                                      "stop", vmx_path, "hard"],
    126                                     stdout=subprocess.PIPE,
    127                                     stderr=subprocess.PIPE):
    128                      raise CuckooMachineError("Error shutting down "
    129                                               "machine %s" % vmx_path)
    130              except OSError as e:
    131                  raise CuckooMachineError("Error shutting down machine "
    132                                           "%s: %s" % (vmx_path, e))
    133          else:
    134              log.warning("Trying to stop an already stopped machine: %s",
    135                          vmx_path)
    136
    137 -    def _revert(self, vmx_path, snapshot):
    138          """Revets machine to snapshot.
    139          @param vmx_path: path to vmx file
    140          @param snapshot: snapshot name
    141          @raise CuckooMachineError: if unable to revert
    142          """
    143          log.debug("Revert snapshot for vm %s" % vmx_path)
    144          try:
    145              if subprocess.call([self.options.vmware.path,
    146                                  "revertToSnapshot", vmx_path, snapshot],
    147                                 stdout=subprocess.PIPE,
    148                                 stderr=subprocess.PIPE):
    149                  raise CuckooMachineError("Unable to revert snapshot for "
    150                                           "machine %s: vmrun exited with "
    151                                           "error" % vmx_path)
    152          except OSError as e:
    153              raise CuckooMachineError("Unable to revert snapshot for "
    154                                       "machine %s: %s" % (vmx_path, e))
    155
    156 -    def _is_running(self, vmx_path):
    157          """Checks if virtual machine is running.
    158          @param vmx_path: path to vmx file
    159          @return: running status
    160          """
    161          try:
    162              p = subprocess.Popen([self.options.vmware.path, "list"],
    163                                   stdout=subprocess.PIPE,
    164                                   stderr=subprocess.PIPE)
    165              output, error = p.communicate()
    166          except OSError as e:
    167              raise CuckooMachineError("Unable to check running status for %s. "
    168                                       "Reason: %s" % (vmx_path, e))
    169          else:
    170              if output:
    171                  return vmx_path.lower() in output.lower()
    172              else:
    173                  raise CuckooMachineError("Unable to check running status "
    174                                           "for %s. No output from "
    175                                           "`vmrun list`" % vmx_path)
    176
    177 -    def _snapshot_from_vmx(self, vmx_path):
    178          """Get snapshot for a given vmx file.
    179          @param vmx_path: configuration option from config file
    180          """
    181          vm_info = self.db.view_machine_by_label(vmx_path)
    182          return vm_info.snapshot
    183
    184 -    def dump_memory(self, vmx_path, path):
    185          """Take a memory dump of the machine."""
    186          if not os.path.exists(vmx_path):
    187              raise CuckooMachineError("Can't find .vmx file {0}. Ensure to configure a fully qualified path in vmware.conf (key = vmx_path)".format(vmx_path))
    188
    189          try:
    190              subprocess.call([self.options.vmware.path, "snapshot",
    191                               vmx_path, "memdump"],
    192                              stdout=subprocess.PIPE,
    193                              stderr=subprocess.PIPE)
    194          except OSError as e:
    195              raise CuckooMachineError("vmrun failed to take a memory dump of the machine with label %s: %s" % (vmx_path, e))
    196
    197          vmwarepath, _ = os.path.split(vmx_path)
    198          latestvmem = max(glob.iglob(os.path.join(vmwarepath, "*.vmem")),
    199                           key=os.path.getctime)
    200
    201          # We need to move the snapshot to the current analysis directory as
    202          # vmware doesn't support an option for the destination path :-/
    203          shutil.move(latestvmem, path)
    204
    205          # Old snapshot can be deleted, as it isn't needed any longer.
    206          try:
    207              subprocess.call([self.options.vmware.path, "deleteSnapshot",
    208                               vmx_path, "memdump"],
    209                              stdout=subprocess.PIPE,
    210                              stderr=subprocess.PIPE)
    211          except OSError as e:
    212              raise CuckooMachineError("vmrun failed to delete the temporary snapshot in %s: %s" % (vmx_path, e))
    213
    214          log.info("Successfully generated memory dump for virtual machine with label %s ", vmx_path)
    215