1
2
3
4
5
6 import glob
7 import logging
8 import subprocess
9 import os.path
10 import shutil
11 import time
12
13 from lib.cuckoo.common.abstracts import Machinery
14 from lib.cuckoo.common.exceptions import CuckooMachineError
15
16 log = logging.getLogger(__name__)
17
19 """Virtualization layer for VMware Workstation using vmrun utility."""
20 LABEL = "vmx_path"
21
44
46 """Checks whether a vmx file exists and is valid.
47 @param vmx_path: path to vmx file
48 @raise CuckooMachineError: if file not found or not ending with .vmx
49 """
50 if not vmx_path.endswith(".vmx"):
51 raise CuckooMachineError("Wrong configuration: vm path not "
52 "ending with .vmx: %s)" % vmx_path)
53
54 if not os.path.exists(vmx_path):
55 raise CuckooMachineError("Vm file %s not found" % vmx_path)
56
58 """Checks snapshot existance.
59 @param vmx_path: path to vmx file
60 @param snapshot: snapshot name
61 @raise CuckooMachineError: if snapshot not found
62 """
63 try:
64 p = subprocess.Popen([self.options.vmware.path,
65 "listSnapshots", vmx_path],
66 stdout=subprocess.PIPE,
67 stderr=subprocess.PIPE)
68 output, _ = p.communicate()
69 except OSError as e:
70 raise CuckooMachineError("Unable to get snapshot list for %s. "
71 "Reason: %s" % (vmx_path, e))
72 else:
73 if output:
74 return snapshot in output
75 else:
76 raise CuckooMachineError("Unable to get snapshot list for %s. "
77 "No output from "
78 "`vmrun listSnapshots`" % vmx_path)
79
80 - def start(self, vmx_path):
81 """Start a virtual machine.
82 @param vmx_path: path to vmx file.
83 @raise CuckooMachineError: if unable to start.
84 """
85 snapshot = self._snapshot_from_vmx(vmx_path)
86
87
88 if self._is_running(vmx_path):
89 raise CuckooMachineError("Machine %s is already running" %
90 vmx_path)
91
92 self._revert(vmx_path, snapshot)
93
94 time.sleep(3)
95
96 log.debug("Starting vm %s" % vmx_path)
97 try:
98 p = subprocess.Popen([self.options.vmware.path,
99 "start", vmx_path,
100 self.options.vmware.mode],
101 stdout=subprocess.PIPE,
102 stderr=subprocess.PIPE)
103 if self.options.vmware.mode.lower() == "gui":
104 output, _ = p.communicate()
105 if output:
106 raise CuckooMachineError("Unable to start machine "
107 "%s: %s" % (vmx_path, output))
108 except OSError as e:
109 mode = self.options.vmware.mode.upper()
110 raise CuckooMachineError("Unable to start machine %s in %s "
111 "mode: %s" % (vmx_path, mode, e))
112
113 - def stop(self, vmx_path):
114 """Stops a virtual machine.
115 @param vmx_path: path to vmx file
116 @raise CuckooMachineError: if unable to stop.
117 """
118 log.debug("Stopping vm %s" % vmx_path)
119 if self._is_running(vmx_path):
120 try:
121 if subprocess.call([self.options.vmware.path,
122 "stop", vmx_path, "hard"],
123 stdout=subprocess.PIPE,
124 stderr=subprocess.PIPE):
125 raise CuckooMachineError("Error shutting down "
126 "machine %s" % vmx_path)
127 except OSError as e:
128 raise CuckooMachineError("Error shutting down machine "
129 "%s: %s" % (vmx_path, e))
130 else:
131 log.warning("Trying to stop an already stopped machine: %s",
132 vmx_path)
133
134 - def _revert(self, vmx_path, snapshot):
135 """Revets machine to snapshot.
136 @param vmx_path: path to vmx file
137 @param snapshot: snapshot name
138 @raise CuckooMachineError: if unable to revert
139 """
140 log.debug("Revert snapshot for vm %s" % vmx_path)
141 try:
142 if subprocess.call([self.options.vmware.path,
143 "revertToSnapshot", vmx_path, snapshot],
144 stdout=subprocess.PIPE,
145 stderr=subprocess.PIPE):
146 raise CuckooMachineError("Unable to revert snapshot for "
147 "machine %s: vmrun exited with "
148 "error" % vmx_path)
149 except OSError as e:
150 raise CuckooMachineError("Unable to revert snapshot for "
151 "machine %s: %s" % (vmx_path, e))
152
154 """Checks if virtual machine is running.
155 @param vmx_path: path to vmx file
156 @return: running status
157 """
158 try:
159 p = subprocess.Popen([self.options.vmware.path, "list"],
160 stdout=subprocess.PIPE,
161 stderr=subprocess.PIPE)
162 output, error = p.communicate()
163 except OSError as e:
164 raise CuckooMachineError("Unable to check running status for %s. "
165 "Reason: %s" % (vmx_path, e))
166 else:
167 if output:
168 return vmx_path in output
169 else:
170 raise CuckooMachineError("Unable to check running status "
171 "for %s. No output from "
172 "`vmrun list`" % vmx_path)
173
175 """Get snapshot for a given vmx file.
176 @param vmx_path: configuration option from config file
177 """
178 vm_info = self.db.view_machine_by_label(vmx_path)
179 return vm_info.snapshot
180
182 """Take a memory dump of the machine."""
183 if not os.path.exists(vmx_path):
184 raise CuckooMachineError("Can't find .vmx file {0}. Ensure to configure a fully qualified path in vmware.conf (key = vmx_path)".format(vmx_path))
185
186 try:
187 subprocess.call([self.options.vmware.path, "snapshot",
188 vmx_path, "memdump"],
189 stdout=subprocess.PIPE,
190 stderr=subprocess.PIPE)
191 except OSError as e:
192 raise CuckooMachineError("vmrun failed to take a memory dump of the machine with label %s: %s" % (vmx_path, e))
193
194 vmwarepath, _ = os.path.split(vmx_path)
195 latestvmem = max(glob.iglob(os.path.join(vmwarepath, "*.vmem")),
196 key=os.path.getctime)
197
198
199
200 shutil.move(latestvmem, path)
201
202
203 try:
204 subprocess.call([self.options.vmware.path, "deleteSnapshot",
205 vmx_path, "memdump"],
206 stdout=subprocess.PIPE,
207 stderr=subprocess.PIPE)
208 except OSError as e:
209 raise CuckooMachineError("vmrun failed to delete the temporary snapshot in %s: %s" % (vmx_path, e))
210
211 log.info("Successfully generated memory dump for virtual machine with label %s ", vmx_path)
212