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 from rekall import addrspace
27 from rekall import obj
28 from rekall.plugins.addrspaces import standard
29 from rekall.plugins.overlays import basic
30 from rekall_lib import utils
36 __image = True
37
38 - def __init__(self, base=None, **kwargs):
39 """Currently this AS only supports files with the .vmem extension."""
40 self.as_assert(base != None, "No base address space provided")
41 self.as_assert(
42 getattr(base, "fname", "").endswith("vmem"),
43 "Only VMEM files supported.")
44
45 super(VMemAddressSpace, self).__init__(base=base, **kwargs)
46
47 vmss_location = base.fname[:-4] + "vmss"
48 try:
49 vmss_as = standard.FileAddressSpace(
50 filename=vmss_location, session=self.session)
51 except IOError:
52
53 raise addrspace.ASAssertionError
54
55 vmss_profile = VMWareProfile(session=self.session)
56 self.header = vmss_profile._VMWARE_HEADER(vm=vmss_as)
57 self.as_assert(
58 self.header.Magic in [
59 0xbed2bed0, 0xbad1bad1, 0xbed2bed2, 0xbed3bed3],
60 "Invalid VMware signature: {0:#x}".format(self.header.Magic))
61
62
63 virtual_offsets = self.header.GetTags("memory", "regionPPN")
64 file_offsets = self.header.GetTags("memory", "regionPageNum")
65 lengths = self.header.GetTags("memory", "regionSize")
66
67 for v, p, l in zip(virtual_offsets, file_offsets, lengths):
68 self.add_run(v * 0x1000, p * 0x1000, l * 0x1000)
69
72 """Support ESX .vmsn file format.
73
74 The VMSN file format contains a set of metadata in the form of tags, grouped
75 by groups at the header. There is a lot of metadata but the most interesting
76 metadata for us is the metadata in the "memory" group.
77
78 The file includes a "memory.Memory" data blob which contains the entire
79 memory snapshot of the running machine. The memory blob is serialized into
80 the file as a single large blob but contains physical memory runs stored
81 back to back inside it.
82
83 The following tags are used:
84
85 - memory.regionsCount: Stores the total number of regions.
86
87 - memory.regionPPN: In an array of physical addresses for each physical
88 memory regions in the virtual machine (in pages).
89
90 - memory.regionSize: Is the size of each physical memory region (in pages).
91
92 - memory.regionPageNum: Is the offset into the memory.Memory blob for each
93 region (in pages). This may be omitted if there is only one region.
94 """
95 __image = True
96
97 - def __init__(self, base=None, **kwargs):
98 self.as_assert(base != None, "No base address space provided")
99 super(VMSSAddressSpace, self).__init__(base=base, **kwargs)
100
101 vmss_profile = VMWareProfile(session=self.session)
102
103 self.header = vmss_profile._VMWARE_HEADER(vm=self.base)
104 self.as_assert(
105 self.header.Magic in [
106 0xbed2bed0, 0xbad1bad1, 0xbed2bed2, 0xbed3bed3],
107 "Invalid VMware signature: {0:#x}".format(self.header.Magic))
108
109 region_count = self.header.GetTagsData("memory", "regionsCount")[0]
110
111
112 virtual_offsets = self.header.GetTagsData("memory", "regionPPN")
113 lengths = self.header.GetTagsData("memory", "regionSize")
114
115
116
117 memory = self.header.GetTagsData("memory", "Memory")[0]
118 mem_regions = self.header.GetTagsData("memory", "regionPageNum") or [0]
119
120 for v, l, m in zip(virtual_offsets, lengths, mem_regions):
121 self.add_run(
122 v * 0x1000, m * 0x1000 + memory.obj_offset, l * 0x1000)
123
124
125 if region_count != len(list(self.runs)):
126 self.session.logging.error(
127 "VMSN file has incorrect number of runs %s, "
128 "should be %s", region_count, len(list(self.runs)))
129
132 """Add convenience methods to the header."""
133
135 super(_VMWARE_HEADER, self).__init__(**kwargs)
136 self.obj_context["version"] = self.Version
137
142
156
159
162
163 @utils.safe_property
170
173
174 DATA_MAP = {
175 1: "unsigned char",
176 2: "unsigned short",
177 4: "unsigned int",
178 8: "unsigned long long",
179 }
180
181 @utils.safe_property
183 """The data immediately follows the TagIndices array.
184
185 The size and type of the data is specified by the DataSize member. If
186 the DataSize takes on the special values 62 or 63, then the data is
187 described by an extended data descriptor (We call it
188 _VMWARE_EXTENDED_DATA64).
189 """
190
191 data_offset = self.TagIndices.obj_end
192 data_size = self.DataSize
193
194
195 if data_size in (62, 63):
196
197 if self.obj_context.get("Version") == 0:
198 return self.obj_profile._VMWARE_EXTENDED_DATA32(
199 data_offset, vm=self.obj_vm).Data
200 else:
201 return self.obj_profile._VMWARE_EXTENDED_DATA64(
202 data_offset, vm=self.obj_vm).Data
203
204
205 data_type = self.DATA_MAP.get(data_size)
206 if data_type:
207 return self.obj_profile.Object(
208 data_type, offset=data_offset, vm=self.obj_vm)
209
210
211 return self.obj_profile.String(
212 offset=self.TagIndices.obj_end, term=None, length=data_size,
213 vm=self.obj_vm)
214
216 """The next tag is immediately after this tag."""
217 return self.obj_profile._VMWARE_TAG(
218 self.Data.obj_end, vm=self.obj_vm, context=self.obj_context)
219
222 """A profile for parsing VMWare structures."""
223 @classmethod
225 super(VMWareProfile, cls).Initialize(profile)
226 basic.ProfileLLP64.Initialize(profile)
227
228 profile.add_overlay({
229 '_VMWARE_HEADER': [12, {
230 'Magic': [0, ['unsigned int']],
231
232 'Version': [0, ["BitField", dict(
233 start_bit=0,
234 end_bit=4,
235 target="unsigned int")]],
236
237 'GroupCount': [8, ['unsigned int']],
238 'Groups': [12, ['Array', dict(
239 count=lambda x: x.GroupCount,
240 target='_VMWARE_GROUP',
241 )]],
242 }],
243
244 '_VMWARE_GROUP': [80, {
245 'Name': [0, ['UnicodeString', dict(
246 length=64,
247 encoding='utf8')]],
248
249
250
251
252
253 'TagsPointer': [64, ['Pointer', dict(
254 target="_VMWARE_TAG"
255 )]],
256 }],
257
258
259
260 '_VMWARE_EXTENDED_DATA64': [None, {
261 'DataDiskSize': [0, ['unsigned long long']],
262 'DataMemSize': [8, ['unsigned long long']],
263
264
265
266 'PaddingLen': [16, ['unsigned short']],
267 'Padding': [18, ['String', dict(
268 length=lambda x: x.PaddingLen,
269 term=None,
270 )]],
271
272
273
274 'Data': [lambda x: x.Padding.obj_end, ["String", dict(
275 term=None,
276 length=lambda x: x.DataDiskSize,
277 )]],
278 }],
279
280
281
282 '_VMWARE_EXTENDED_DATA32': [None, {
283 'DataDiskSize': [0, ['unsigned long']],
284 'DataMemSize': [4, ['unsigned long']],
285 'PaddingLen': [8, ['unsigned short']],
286 'Padding': [10, ['String', dict(
287 length=lambda x: x.PaddingLen,
288 term=None,
289 )]],
290 'Data': [lambda x: x.Padding.obj_end, ["String", dict(
291 term=None,
292 length=lambda x: x.DataDiskSize
293 )]],
294 }],
295
296 '_VMWARE_TAG': [None, {
297 'TagIndicesCount': [0, ['BitField', dict(
298 start_bit=6,
299 end_bit=9,
300 target="unsigned char")]],
301
302 'DataSize': [0, ['BitField', dict(
303 start_bit=0,
304 end_bit=6,
305 target="unsigned char")]],
306
307
308
309 'NameLength': [1, ['unsigned char']],
310 'Name': [2, ['UnicodeString', dict(
311 length=lambda x: x.NameLength,
312 encoding='utf8')]],
313
314
315
316 'TagIndices': [lambda x: x.Name.obj_end,
317 ['Array', dict(
318 count=lambda x: x.TagIndicesCount,
319 target='unsigned int')]],
320
321 }],
322 })
323
324 profile.add_classes(
325 _VMWARE_TAG=_VMWARE_TAG,
326 _VMWARE_GROUP=_VMWARE_GROUP,
327 _VMWARE_HEADER=_VMWARE_HEADER,
328 )
329