Trees | Indices | Help |
|
---|
|
1 # Rekall Memory Forensics 2 # 3 # Copyright 2012 Philippe Teuwen, Thorsten Sick, Michael Cohen 4 # Copyright 2013 Google Inc. All Rights Reserved. 5 # 6 # This program is free software; you can redistribute it and/or modify 7 # it under the terms of the GNU General Public License as published by 8 # the Free Software Foundation; either version 2 of the License, or (at 9 # your option) any later version. 10 # 11 # This program is distributed in the hope that it will be useful, but 12 # WITHOUT ANY WARRANTY; without even the implied warranty of 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 # General Public License for more details. 15 # 16 # You should have received a copy of the GNU General Public License 17 # along with this program; if not, write to the Free Software 18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 # 20 21 """An Address Space for processing ELF64 coredumps.""" 22 # References: 23 # VirtualBox core format: 24 # http://www.virtualbox.org/manual/ch12.html#guestcoreformat 25 # ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf 26 27 # Note that as of version 1.6.0 WinPmem also uses ELF64 as the default imaging 28 # format. Except that WinPmem stores image metadata in a YAML file stored in the 29 # image. This address space supports both formats. 30 import os 31 import yaml 32 33 from rekall import addrspace 34 from rekall import constants 35 from rekall.plugins.addrspaces import standard 36 from rekall.plugins.overlays.linux import elf 37 38 PT_PMEM_METADATA = 0x6d656d70 # Spells 'pmem' 39 40 4143 """This AS supports ELF64 coredump format, as used by VirtualBox.""" 44 order = 30 45 46 __name = "elf64" 47 __image = True 48165 16650 super(Elf64CoreDump, self).__init__(**kwargs) 51 52 # Check the file for sanity. 53 self.check_file() 54 55 self.offset = 0 56 self.fname = '' 57 self._metadata = {} 58 59 # Now parse the ELF file. 60 elf_profile = elf.ELFProfile(session=self.session) 61 self.elf64_hdr = elf_profile.elf64_hdr(vm=self.base, offset=0) 62 63 self.as_assert(self.elf64_hdr.e_type == "ET_CORE", 64 "Elf file is not a core file.") 65 self.name = "%s|%s" % (self.__class__.__name__, self.base.name) 66 67 # Iterate over all the program headers and map the runs. 68 for segment in self.elf64_hdr.e_phoff: 69 if segment.p_type == "PT_LOAD": 70 # Some load segments are empty. 71 if (segment.p_filesz == 0 or 72 segment.p_filesz != segment.p_memsz): 73 continue 74 75 # Add the run to the memory map. 76 virtual_address = int(segment.p_paddr) or int(segment.p_vaddr) 77 self.add_run(virtual_address, # Virtual Addr 78 int(segment.p_offset), # File Addr 79 int(segment.p_memsz)) # Run end. 80 81 elif segment.p_type == PT_PMEM_METADATA: 82 self.LoadMetadata(segment.p_offset) 83 84 # NOTE: Deprecated! This will be removed soon. If you want to store 85 # metadata use AFF4 format. 86 87 # Search for the pmem footer signature. 88 footer = self.base.read(self.base.end() - 10000, 10000) 89 if "...\n" in footer[-6:]: 90 header_offset = footer.rfind("# PMEM") 91 if header_offset > 0: 92 self.LoadMetadata(self.base.end() - 10000 + header_offset)9395 """Checks the base file handle for sanity.""" 96 97 self.as_assert(self.base, 98 "Must stack on another address space") 99 100 ## Must start with the magic for elf 101 self.as_assert((self.base.read(0, 4) == "\177ELF"), 102 "Header signature invalid")103105 """Load the WinPmem metadata from the elf file.""" 106 self.session.logging.error( 107 "DEPRECATED Elf metadata found! " 108 "This will not be supported in the next release.") 109 try: 110 data = self.base.read(offset, 1024*1024) 111 yaml_file = data.split('...\n')[0] 112 113 metadata = yaml.safe_load(yaml_file) 114 except (yaml.YAMLError, TypeError) as e: 115 self.session.logging.error( 116 "Invalid file metadata, skipping: %s" % e) 117 return 118 119 for session_param, metadata_key in (("dtb", "CR3"), 120 ("kernel_base", "KernBase")): 121 if metadata_key in metadata: 122 self.session.SetParameter( 123 session_param, metadata[metadata_key]) 124 125 previous_section = metadata.pop("PreviousHeader", None) 126 if previous_section is not None: 127 self.LoadMetadata(previous_section) 128 129 pagefile_offset = metadata.get("PagefileOffset", None) 130 pagefile_size = metadata.get("PagefileSize", None) 131 132 if pagefile_offset is not None and pagefile_size is not None: 133 self.LoadPageFile(pagefile_offset, pagefile_size) 134 135 self._metadata.update(metadata)136 137 pagefile_offset = 0 138 pagefile_end = 0 139141 """We map the page file into the physical address space. 142 143 This allows us to treat all physical addresses equally - regardless if 144 they come from the memory or the page file. 145 """ 146 # Map the pagefile after the end of the physical address space. 147 vaddr = self.end() + 0x10000 148 149 self.session.logging.info( 150 "Loading pagefile into physical offset %#08x", vaddr) 151 152 # Map the pagefile into the 153 self.add_run(vaddr, pagefile_offset, pagefile_size) 154 155 # Remember the region for the pagefile. 156 self.pagefile_offset = vaddr 157 self.pagefile_end = vaddr + pagefile_size158160 if self.pagefile_offset <= addr <= self.pagefile_end: 161 return "%#x@Pagefile" % ( 162 addr - self.pagefile_offset) 163 164 return "%#x" % addr168 """A Linux kernel's /proc/kcore file also maps the entire physical ram. 169 170 http://lxr.free-electrons.com/source/Documentation/x86/x86_64/mm.txt 171 172 ffff880000000000 - ffffc7ffffffffff (=64 TB) direct mapping of all 173 physical memory. 174 """ 175 # We must run before the regular Elf64CoreDump address space in the voting 176 # order. 177 order = Elf64CoreDump.order - 1 178 179 __name = "elf64" 180 __image = True 181231 232183 super(KCoreAddressSpace, self).__init__(**kwargs) 184 185 # This is a live address space. 186 self.volatile = True 187 self.mapped_files = {} 188 189 # Collect all ranges between 0xffff880000000000 - 0xffffc7ffffffffff 190 runs = [] 191 192 for start, _, run in self.runs: 193 if 0xffff880000000000 < run.start < 0xffffc7ffffffffff: 194 runs.append((start - 0xffff880000000000, 195 run.file_offset, run.length)) 196 197 self.as_assert(runs, "No kcore compatible virtual ranges.") 198 self.runs.clear() 199 200 # At this point, we think this is a valid, usable kcore file. 201 # RHEL, however, disabled read access to /proc/kcore past the ELF 202 # headers and the file size reflects this. /proc/kcore usually has a 203 # size of at least 64TB (46bits of physical address space in x64). 204 # We use the file size to detect cases where kcore will be unusable. 205 206 if getattr(self.base, "fhandle", None): 207 try: 208 statinfo = os.fstat(self.base.fhandle.fileno()) 209 if statinfo.st_size < 2**46: 210 # We raise a TypeError and not an ASAssertionError because 211 # we need it to be catchable when rekall is used as a 212 # library (i.e GRR). ASAssertionErrors are swallowed by 213 # the address space selection algorithm. 214 raise RuntimeError( 215 "This kcore file is too small (%d bytes) and likely " 216 "invalid for memory analysis. You may want to use pmem " 217 "instead." % statinfo.st_size) 218 except(IOError, AttributeError): 219 pass 220 221 for x in runs: 222 self.add_run(*x)223234 """Convert the address_space to an ELF Core dump file. 235 236 The Core dump will be written to outfd which is expected to have a .write() 237 method. 238 """ 239 runs = list(address_space.get_mappings()) 240 241 elf_profile = elf.ELFProfile(session=session) 242 elf64_pheader = elf_profile.elf64_phdr() 243 elf64_pheader.p_type = "PT_LOAD" 244 elf64_pheader.p_align = 0x1000 245 elf64_pheader.p_flags = "PF_R" 246 247 elf64_header = elf_profile.elf64_hdr() 248 elf64_header.e_ident = elf64_header.e_ident.signature 249 elf64_header.e_type = 'ET_CORE' 250 elf64_header.e_phoff = elf64_header.obj_end 251 elf64_header.e_ehsize = elf64_header.obj_size 252 elf64_header.e_phentsize = elf64_pheader.obj_size 253 elf64_header.e_phnum = len(runs) 254 elf64_header.e_shnum = 0 # We don't have any sections. 255 256 # Where we start writing data. 257 file_offset = (elf64_header.obj_size + 258 # One Phdr for each run. 259 len(runs) * elf64_pheader.obj_size) 260 261 outfd.write(elf64_header.GetData()) 262 for run in runs: 263 elf64_pheader.p_paddr = run.start 264 elf64_pheader.p_memsz = run.length 265 elf64_pheader.p_offset = file_offset 266 elf64_pheader.p_filesz = run.length 267 268 outfd.write(elf64_pheader.GetData()) 269 270 file_offset += run.length 271 272 # Now just copy all the runs 273 total_data = 0 274 for run in runs: 275 offset = run.start 276 length = run.length 277 while length > 0: 278 data = address_space.read(offset, min(10000000, length)) 279 session.report_progress("Writing %sMb", total_data/1024/1024) 280 outfd.write(data) 281 length -= len(data) 282 offset += len(data) 283 total_data += len(data)284
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Mon Oct 9 03:29:49 2017 | http://epydoc.sourceforge.net |