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 subprocess.call([self.options.virtualbox.path,
80 "startvm",
81 label,
82 "--type",
83 self.options.virtualbox.mode],
84 stdout=subprocess.PIPE,
85 stderr=subprocess.PIPE)
86 except OSError as e:
87 raise CuckooMachineError("VBoxManage failed starting the machine "
88 "in %s mode: %s" %
89 (self.options.virtualbox.mode.upper(), e))
90 self._wait_status(label, self.RUNNING)
91
92 - def stop(self, label):
93 """Stops a virtual machine.
94 @param label: virtual machine name.
95 @raise CuckooMachineError: if unable to stop.
96 """
97 log.debug("Stopping vm %s" % label)
98
99 if self._status(label) in [self.POWEROFF, self.ABORTED]:
100 raise CuckooMachineError("Trying to stop an already stopped "
101 "vm %s" % label)
102
103 try:
104 proc = subprocess.Popen([self.options.virtualbox.path,
105 "controlvm", label, "poweroff"],
106 stdout=subprocess.PIPE,
107 stderr=subprocess.PIPE)
108
109
110 stop_me = 0
111 while proc.poll() is None:
112 if stop_me < int(self.options_globals.timeouts.vm_state):
113 time.sleep(1)
114 stop_me += 1
115 else:
116 log.debug("Stopping vm %s timeouted. Killing" % label)
117 proc.terminate()
118
119 if proc.returncode != 0 and \
120 stop_me < int(self.options_globals.timeouts.vm_state):
121 log.debug("VBoxManage exited with error "
122 "powering off the machine")
123 except OSError as e:
124 raise CuckooMachineError("VBoxManage failed powering off the "
125 "machine: %s" % e)
126 self._wait_status(label, [self.POWEROFF, self.ABORTED, self.SAVED])
127
129 """Lists virtual machines installed.
130 @return: virtual machine names list.
131 """
132 try:
133 proc = subprocess.Popen([self.options.virtualbox.path,
134 "list", "vms"],
135 stdout=subprocess.PIPE,
136 stderr=subprocess.PIPE)
137 output, _ = proc.communicate()
138 except OSError as e:
139 raise CuckooMachineError("VBoxManage error listing "
140 "installed machines: %s" % e)
141
142 machines = []
143 for line in output.split("\n"):
144 try:
145 label = line.split('"')[1]
146 if label == "<inaccessible>":
147 log.warning("Found an inaccessible virtual machine: "
148 "please check his state")
149 else:
150 machines.append(label)
151 except IndexError:
152 continue
153
154 return machines
155
157 """Gets current status of a vm.
158 @param label: virtual machine name.
159 @return: status string.
160 """
161 log.debug("Getting status for %s" % label)
162 status = None
163 try:
164 proc = subprocess.Popen([self.options.virtualbox.path,
165 "showvminfo",
166 label,
167 "--machinereadable"],
168 stdout=subprocess.PIPE,
169 stderr=subprocess.PIPE)
170 output, err = proc.communicate()
171
172 if proc.returncode != 0:
173
174
175
176 log.debug("VBoxManage returns error checking status for "
177 "machine %s: %s", label, err)
178 status = self.ERROR
179 except OSError as e:
180 log.warning("VBoxManage failed to check status for machine %s: %s",
181 label, e)
182 status = self.ERROR
183 if not status:
184 for line in output.split("\n"):
185 state = re.match(r"VMState=\"(\w+)\"", line, re.M|re.I)
186 if state:
187 status = state.group(1)
188 log.debug("Machine %s status %s" % (label, status))
189 status = status.lower()
190
191 if status:
192 self.set_status(label, status)
193 return status
194 else:
195 raise CuckooMachineError("Unable to get status for %s" % label)
196
198 """Takes a memory dump.
199 @param path: path to where to store the memory dump.
200 """
201 try:
202 subprocess.call([self.options.virtualbox.path, "debugvm",
203 label, "dumpguestcore", "--filename", path],
204 stdout=subprocess.PIPE,
205 stderr=subprocess.PIPE)
206 log.info("Successfully generated memory dump for virtual machine "
207 "with label %s to path %s", label, path)
208 except OSError as e:
209 raise CuckooMachineError("VBoxManage failed to take a memory "
210 "dump of the machine with label %s: %s" %
211 (label, e))
212