1
2
3
4
5
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
20 """Virtualization layer for VMware Workstation using vmrun utility."""
21 LABEL = "vmx_path"
22
45
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
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
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
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
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
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
202
203 shutil.move(latestvmem, path)
204
205
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