Package rekall :: Package plugins :: Package addrspaces :: Module vmem
[frames] | no frames]

Source Code for Module rekall.plugins.addrspaces.vmem

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright (C) 2012 Nir Izraeli (nirizr at gmail dot com) 
  4  # Copyright 2012 Sebastien Bourdon-Richard 
  5  # Copyright 2013 Google Inc. All Rights Reserved. 
  6   
  7  # Authors: 
  8  # Sebastien Bourdon-Richard, Nir Izraeli 
  9  # Adapted for Rekall by Michael Cohen <scudette@google.com>. 
 10  # 
 11  # This program is free software; you can redistribute it and/or modify 
 12  # it under the terms of the GNU General Public License as published by 
 13  # the Free Software Foundation; either version 2 of the License, or (at 
 14  # your option) any later version. 
 15  # 
 16  # This program is distributed in the hope that it will be useful, but 
 17  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 18  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 19  # General Public License for more details. 
 20  # 
 21  # You should have received a copy of the GNU General Public License 
 22  # along with this program; if not, write to the Free Software 
 23  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 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 
31 32 # pylint: disable=protected-access 33 34 35 -class VMemAddressSpace(addrspace.RunBasedAddressSpace):
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 # If we fail to open the vmss file it is not a proper vmem file. 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 # Fill in the runs list from the header. 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
70 71 -class VMSSAddressSpace(addrspace.RunBasedAddressSpace):
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 # Fill in the runs list from the header. 112 virtual_offsets = self.header.GetTagsData("memory", "regionPPN") 113 lengths = self.header.GetTagsData("memory", "regionSize") 114 115 # This represents a single memory blob stored in the output file. The 116 # regions are marked relative to this single blob. 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 # We should have enough regions here. 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
130 131 -class _VMWARE_HEADER(obj.Struct):
132 """Add convenience methods to the header.""" 133
134 - def __init__(self, **kwargs):
135 super(_VMWARE_HEADER, self).__init__(**kwargs) 136 self.obj_context["version"] = self.Version
137
138 - def PrintAllTags(self):
139 for group in self.Groups: 140 for tag in group.Tags: 141 print "%s.%s: %r" % (group.Name, tag.Name, tag.Data)
142
143 - def GetTags(self, group_name, tag_name):
144 result = [] 145 for group in self.Groups: 146 if group.Name != group_name: 147 continue 148 149 for tag in group.Tags: 150 if tag.Name != tag_name: 151 continue 152 153 result.append(tag) 154 155 return result
156
157 - def GetTagsData(self, group_name, tag_name):
158 return [x.Data for x in self.GetTags(group_name, tag_name)]
159
160 161 -class _VMWARE_GROUP(obj.Struct):
162 163 @utils.safe_property
164 - def Tags(self):
165 tag = self.TagsPointer.deref() 166 while tag.NameLength > 0: 167 yield tag 168 169 tag = tag.Next()
170
171 172 -class _VMWARE_TAG(obj.Struct):
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
182 - def Data(self):
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 # The data immediately follows the TagIndices array. 191 data_offset = self.TagIndices.obj_end 192 data_size = self.DataSize 193 194 # The Data member is described by an extended struct. 195 if data_size in (62, 63): 196 # Depending on the version, the extended struct changes. 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 # Is the data member a simple type? 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 # If the size is odd, we just return the data as a string. 211 return self.obj_profile.String( 212 offset=self.TagIndices.obj_end, term=None, length=data_size, 213 vm=self.obj_vm)
214
215 - def Next(self):
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
220 221 -class VMWareProfile(basic.BasicClasses):
222 """A profile for parsing VMWare structures.""" 223 @classmethod
224 - def Initialize(cls, profile):
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 # A pointer to a back to back list of tags within this 250 # group. Note tags are variable length - to get the next tag use 251 # _VMWARE_TAG.Next(), or simply use the _VMWARE_GROUP.Tags() 252 # iterator as a convenience. 253 'TagsPointer': [64, ['Pointer', dict( 254 target="_VMWARE_TAG" 255 )]], 256 }], 257 258 # This struct is used to denote data objects with a length 62 bytes 259 # or greater. 260 '_VMWARE_EXTENDED_DATA64': [None, { 261 'DataDiskSize': [0, ['unsigned long long']], 262 'DataMemSize': [8, ['unsigned long long']], 263 264 # A padding string is specified as a short before the actual 265 # data. 266 'PaddingLen': [16, ['unsigned short']], 267 'Padding': [18, ['String', dict( 268 length=lambda x: x.PaddingLen, 269 term=None, 270 )]], 271 272 # The data follows the padding string. Its length is specified 273 # by DataDiskSize. 274 'Data': [lambda x: x.Padding.obj_end, ["String", dict( 275 term=None, 276 length=lambda x: x.DataDiskSize, 277 )]], 278 }], 279 280 # This is the old struct only used with Version 0. It is the same as 281 # _VMWARE_EXTENDED_DATA64 except uses 32 bit sizes. 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 # The name of this tag. Tags exist within the group (which also 308 # has a name). 309 'NameLength': [1, ['unsigned char']], 310 'Name': [2, ['UnicodeString', dict( 311 length=lambda x: x.NameLength, 312 encoding='utf8')]], 313 314 # The TagIndices immediately follow the Name field (Which has 315 # variable length). 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