1
2
3
4
5 import os
6 import re
7 import time
8 import logging
9 import subprocess
10 import os.path
11
12 from lib.cuckoo.common.abstracts import Machinery
13 from lib.cuckoo.common.exceptions import CuckooCriticalError
14 from lib.cuckoo.common.exceptions import CuckooMachineError
15
16 log = logging.getLogger(__name__)
17
19 """Virtualization layer for VirtualBox."""
20
21
22 SAVED = "saved"
23 RUNNING = "running"
24 POWEROFF = "poweroff"
25 ABORTED = "aborted"
26 ERROR = "machete"
27
43
45 """Start a virtual machine.
46 @param label: virtual machine name.
47 @raise CuckooMachineError: if unable to start.
48 """
49 log.debug("Starting vm %s" % label)
50
51 if self._status(label) == self.RUNNING:
52 raise CuckooMachineError("Trying to start an already "
53 "started vm %s" % label)
54
55 vm_info = self.db.view_machine_by_label(label)
56 virtualbox_args = [self.options.virtualbox.path, "snapshot", label]
57 if vm_info.snapshot:
58 log.debug("Using snapshot {0} for virtual machine "
59 "{1}".format(vm_info.snapshot, label))
60 virtualbox_args.extend(["restore", vm_info.snapshot])
61 else:
62 log.debug("Using current snapshot for virtual machine "
63 "{0}".format(label))
64 virtualbox_args.extend(["restorecurrent"])
65
66 try:
67 if subprocess.call(virtualbox_args,
68 stdout=subprocess.PIPE,
69 stderr=subprocess.PIPE):
70 raise CuckooMachineError("VBoxManage exited with error "
71 "restoring the machine's snapshot")
72 except OSError as e:
73 raise CuckooMachineError("VBoxManage failed restoring the "
74 "machine: %s" % e)
75
76 self._wait_status(label, self.SAVED)
77
78 try:
79 proc = subprocess.Popen([self.options.virtualbox.path,
80 "startvm",
81 label,
82 "--type",
83 self.options.virtualbox.mode],
84 stdout=subprocess.PIPE,
85 stderr=subprocess.PIPE)
86 output, err = proc.communicate()
87 if err:
88 raise OSError(err)
89 except OSError as e:
90 raise CuckooMachineError("VBoxManage failed starting the machine "
91 "in %s mode: %s" %
92 (self.options.virtualbox.mode.upper(), e))
93 self._wait_status(label, self.RUNNING)
94
95 - def stop(self, label):
96 """Stops a virtual machine.
97 @param label: virtual machine name.
98 @raise CuckooMachineError: if unable to stop.
99 """
100 log.debug("Stopping vm %s" % label)
101
102 if self._status(label) in [self.POWEROFF, self.ABORTED]:
103 raise CuckooMachineError("Trying to stop an already stopped "
104 "vm %s" % label)
105
106 try:
107 proc = subprocess.Popen([self.options.virtualbox.path,
108 "controlvm", label, "poweroff"],
109 stdout=subprocess.PIPE,
110 stderr=subprocess.PIPE)
111
112
113 stop_me = 0
114 while proc.poll() is None:
115 if stop_me < int(self.options_globals.timeouts.vm_state):
116 time.sleep(1)
117 stop_me += 1
118 else:
119 log.debug("Stopping vm %s timeouted. Killing" % label)
120 proc.terminate()
121
122 if proc.returncode != 0 and \
123 stop_me < int(self.options_globals.timeouts.vm_state):
124 log.debug("VBoxManage exited with error "
125 "powering off the machine")
126 except OSError as e:
127 raise CuckooMachineError("VBoxManage failed powering off the "
128 "machine: %s" % e)
129 self._wait_status(label, [self.POWEROFF, self.ABORTED, self.SAVED])
130
132 """Lists virtual machines installed.
133 @return: virtual machine names list.
134 """
135 try:
136 proc = subprocess.Popen([self.options.virtualbox.path,
137 "list", "vms"],
138 stdout=subprocess.PIPE,
139 stderr=subprocess.PIPE)
140 output, _ = proc.communicate()
141 except OSError as e:
142 raise CuckooMachineError("VBoxManage error listing "
143 "installed machines: %s" % e)
144
145 machines = []
146 for line in output.split("\n"):
147 try:
148 label = line.split('"')[1]
149 if label == "<inaccessible>":
150 log.warning("Found an inaccessible virtual machine, "
151 "please check its state.")
152 else:
153 machines.append(label)
154 except IndexError:
155 continue
156
157 return machines
158
160 """Gets current status of a vm.
161 @param label: virtual machine name.
162 @return: status string.
163 """
164 log.debug("Getting status for %s" % label)
165 status = None
166 try:
167 proc = subprocess.Popen([self.options.virtualbox.path,
168 "showvminfo",
169 label,
170 "--machinereadable"],
171 stdout=subprocess.PIPE,
172 stderr=subprocess.PIPE)
173 output, err = proc.communicate()
174
175 if proc.returncode != 0:
176
177
178
179 log.debug("VBoxManage returns error checking status for "
180 "machine %s: %s", label, err)
181 status = self.ERROR
182 except OSError as e:
183 log.warning("VBoxManage failed to check status for machine %s: %s",
184 label, e)
185 status = self.ERROR
186 if not status:
187 for line in output.split("\n"):
188 state = re.match(r"VMState=\"(\w+)\"", line, re.M|re.I)
189 if state:
190 status = state.group(1)
191 log.debug("Machine %s status %s" % (label, status))
192 status = status.lower()
193
194 if status:
195 self.set_status(label, status)
196 return status
197 else:
198 raise CuckooMachineError("Unable to get status for %s" % label)
199
201 """Takes a memory dump.
202 @param path: path to where to store the memory dump.
203 """
204 try:
205 subprocess.call([self.options.virtualbox.path, "debugvm",
206 label, "dumpguestcore", "--filename", path],
207 stdout=subprocess.PIPE,
208 stderr=subprocess.PIPE)
209 log.info("Successfully generated memory dump for virtual machine "
210 "with label %s to path %s", label, path)
211 except OSError as e:
212 raise CuckooMachineError("VBoxManage failed to take a memory "
213 "dump of the machine with label %s: %s" %
214 (label, e))
215