-
Notifications
You must be signed in to change notification settings - Fork 95
Expand file tree
/
Copy pathmemory.py
More file actions
215 lines (158 loc) · 7.46 KB
/
memory.py
File metadata and controls
215 lines (158 loc) · 7.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# Copyright 2015-2017 F-Secure
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You may
# obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
"""Module for acquiring and analysing memory snapshots of a running VM.
The VolatilityHook for analysing memory snapshots requires volatility.
http://www.volatilityfoundation.org
"""
import os
import libvirt
from threading import Event
from datetime import datetime
from see import Hook
from see.context import PAUSED
from .utils import launch_process, collect_process_output, create_folder
class MemoryHook(Hook):
"""
Memory snapshotting hook.
On the given event, it dumps the Context's memory state
on a file in the given folder.
configuration::
{
"results_folder": "/folder/where/to/store/memory/dump/file",
"memory_snapshots_on_event": ["event_triggering_memory_snapshot"],
"compress_snapshots": False,
"delete_snapshots": False
}
"memory_snapshot_on_event" can be either a string or a list of Events.
If "compress_snapshots" is set to True, the snapshot files will be
archived as zlib to save space. Default to False.
If "delete_snapshots" is set to True, the snapshot files will be deleted
at the end of the execution. Default to False.
"""
def __init__(self, parameters):
super().__init__(parameters)
self.memdumps = []
self.setup_handlers()
def setup_handlers(self):
snapshots = self.configuration.get('memory_snapshots_on_event', ())
events = isinstance(snapshots, str) and [snapshots] or snapshots
for event in events:
self.context.subscribe(event, self.snapshot_handler)
self.logger.debug("Memory snapshot registered at %s event", event)
def snapshot_handler(self, event):
self.logger.debug("Event %s: taking memory snapshot.", event)
snapshot_path = self.memory_snapshot(event)
self.context.trigger("memory_snapshot_taken", path=snapshot_path)
self.logger.info("Memory snapshot %s taken.", snapshot_path)
def memory_snapshot(self, event):
folder_path = self.configuration['results_folder']
file_name = "%s_%s.bin%s" % (
event,
datetime.now().replace(microsecond=0).time().strftime("%H%M%S"),
self.configuration.get('compress_snapshots', False)
and '.gz' or '')
snapshot_path = os.path.join(folder_path, file_name)
create_folder(folder_path)
self.dump_memory(snapshot_path)
return snapshot_path
def dump_memory(self, memory_dump_path):
self.assert_context_state()
memory_snapshot(self.context, memory_dump_path,
self.configuration.get('compress_snapshots', False))
self.memdumps.append(memory_dump_path)
def assert_context_state(self):
if self.context.domain.state()[0] is not PAUSED:
raise RuntimeError("Context must be paused during memory snapshot")
def cleanup(self):
if self.configuration.get('delete_snapshots', False):
for memdump in self.memdumps:
os.remove(memdump)
class VolatilityHook(Hook):
"""
Volatility post-processor hook.
On the given event, it runs the given Volatility plugins
on all the provided memory snapshots.
The memory snapshots files paths must be communicated through
a "memory_snapsho_ttaken" event within the path attribute.
configuration::
{
"results_folder": "/folder/where/to/store/memory/dump/file",
"start_processing_on_event": "event_starting_async_processing",
"wait_processing_on_event": "event_waiting_async_processing",
"profile": "Win7SP1x64",
"plugins": ["mutantscan"]
}
On start_processing_on_event, the volatility process will be started
with the given plugins. All provided memory snapshots will be analysed
sequentially.
wait_processing_on_event allows to wait for the asyncronous processes
to terminate.
A profile key must be provided with the memory profile of the Sandbox.
The list of plugins will be passed directly to Volatiliti's multiscan
command.
"""
def __init__(self, parameters):
super().__init__(parameters)
self.snapshots = []
self.setup_handlers()
self.processing_done = Event()
def setup_handlers(self):
self.context.subscribe('memory_snapshot_taken',
self.memory_snapshot_handler)
if {'start_processing_on_event',
'wait_processing_on_event'} <= set(self.configuration):
event = self.configuration['start_processing_on_event']
self.context.subscribe_async(event, self.start_processing_handler)
self.logger.debug("Volatility scheduled at %s event", event)
event = self.configuration['wait_processing_on_event']
self.context.subscribe(event, self.stop_processing_handler)
self.logger.debug("Volatility processing wait at %s event", event)
def memory_snapshot_handler(self, event):
if hasattr(event, 'path'):
self.logger.debug("Event %s: new memory dump %s.",
event, event.path)
self.snapshots.append(event.path)
else:
self.logging.warning("%s event received, no path specified.")
def start_processing_handler(self, event):
"""Asynchronous handler starting the Volatility processes."""
self.logger.debug("Event %s: starting Volatility process(es).", event)
for snapshot in self.snapshots:
self.process_snapshot(snapshot)
self.processing_done.set()
def process_snapshot(self, snapshot):
profile = self.configuration.get('profile', ())
for plugin in self.configuration.get('plugins', ()):
try:
process_memory_snapshot(snapshot, profile, plugin)
except RuntimeError:
self.logger.exception("Unable to run %s plugin.", plugin)
def stop_processing_handler(self, event):
self.logger.debug("Event %s: waiting for Volatility process(es).",
event)
self.processing_done.wait()
self.logger.info("Done processing memory with Volatility.")
def memory_snapshot(context, memory_dump_path, compress):
# fix issue with libvirt's API
open(memory_dump_path, 'a').close() # touch file to set permissions
dump_flag = libvirt.VIR_DUMP_MEMORY_ONLY
if compress:
dump_format = libvirt.VIR_DOMAIN_CORE_DUMP_FORMAT_KDUMP_ZLIB
else:
dump_format = libvirt.VIR_DOMAIN_CORE_DUMP_FORMAT_RAW
context.domain.coreDumpWithFormat(memory_dump_path, dump_format, dump_flag)
def process_memory_snapshot(snapshot_path, profile, plugin):
process = launch_process('volatility',
'--profile=%s' % profile,
'--filename=%s' % snapshot_path,
plugin)
file_name = '%s_%s.log' % (snapshot_path.split('.')[0], plugin)
collect_process_output(process, file_name)