Package rekall :: Package plugins :: Package darwin :: Module misc
[frames] | no frames]

Source Code for Module rekall.plugins.darwin.misc

  1  # Rekall Memory Forensics 
  2  # 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or (at 
  8  # your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, but 
 11  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  # General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License 
 16  # along with this program; if not, write to the Free Software 
 17  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 18  """Miscelaneous information gathering plugins.""" 
 19   
 20  __author__ = "Michael Cohen <scudette@google.com>" 
 21  import hashlib 
 22  import re 
 23   
 24  from rekall import obj 
 25  from rekall.plugins import core 
 26  from rekall.plugins.darwin import common 
 27  from rekall.plugins.renderers import visual_aides 
 28   
 29   
30 -class DarwinDMSG(common.AbstractDarwinCommand):
31 """Print the kernel debug messages.""" 32 33 __name = "dmesg" 34
35 - def render(self, renderer):
36 renderer.table_header([ 37 ("Message", "message", "<80")]) 38 39 # This is a circular buffer with the write pointer at the msg_bufx 40 # member. 41 msgbuf = self.profile.get_constant_object( 42 "_msgbufp", 43 target="Pointer", 44 target_args=dict( 45 target="msgbuf" 46 ) 47 ) 48 49 # Make sure the buffer is not too large. 50 size = min(msgbuf.msg_size, 0x400000) 51 if 0 < msgbuf.msg_bufx < size: 52 data = self.kernel_address_space.read(msgbuf.msg_bufc, size) 53 data = data[msgbuf.msg_bufx: size] + data[0:msgbuf.msg_bufx] 54 data = re.sub("\x00", "", data) 55 56 for x in data.splitlines(): 57 renderer.table_row(x)
58 59
60 -class DarwinMachineInfo(common.AbstractDarwinCommand):
61 """Show information about this machine.""" 62 63 __name = "machine_info" 64
65 - def render(self, renderer):
66 renderer.table_header([("Attribute", "attribute", "20"), 67 ("Value", "value", "10")]) 68 69 info = self.profile.get_constant_object( 70 "_machine_info", "machine_info") 71 72 for member in info.members: 73 renderer.table_row(member, info.m(member))
74 75
76 -class DarwinMount(common.AbstractDarwinCommand):
77 """Show mount points.""" 78 79 __name = "mount" 80
81 - def render(self, renderer):
82 renderer.table_header([ 83 ("Device", "device", "30"), 84 ("Mount Point", "mount_point", "60"), 85 ("Type", "type", "")]) 86 87 mount_list = self.profile.get_constant_object( 88 "_mountlist", "mount") 89 90 for mount in mount_list.walk_list("mnt_list.tqe_next", False): 91 renderer.table_row(mount.mnt_vfsstat.f_mntonname, 92 mount.mnt_vfsstat.f_mntfromname, 93 mount.mnt_vfsstat.f_fstypename)
94 95
96 -class DarwinPhysicalMap(common.AbstractDarwinCommand):
97 """Prints the EFI boot physical memory map.""" 98 99 __name = "phys_map" 100
101 - def render(self, renderer):
102 renderer.table_header([ 103 ("Physical Start", "phys", "[addrpad]"), 104 ("Physical End", "phys", "[addrpad]"), 105 ("Virtual", "virt", "[addrpad]"), 106 ("Pages", "pages", ">10"), 107 ("Type", "type", "")]) 108 109 boot_params = self.profile.get_constant_object( 110 "_PE_state", "PE_state").bootArgs 111 112 # Code from: 113 # xnu-1699.26.8/osfmk/i386/AT386/model_dep.c:560 114 memory_map = self.profile.Array( 115 boot_params.MemoryMap, 116 vm=self.physical_address_space, 117 target="EfiMemoryRange", 118 target_size=int(boot_params.MemoryMapDescriptorSize), 119 count=(boot_params.MemoryMapSize / 120 boot_params.MemoryMapDescriptorSize)) 121 122 runs = [] 123 for memory_range in memory_map: 124 start = memory_range.PhysicalStart 125 end = (memory_range.PhysicalStart 126 + 0x1000 127 * memory_range.NumberOfPages) 128 runs.append(dict( 129 value=unicode(memory_range.Type), start=start, end=end)) 130 renderer.table_row( 131 start, 132 end, 133 memory_range.VirtualStart.cast("Pointer"), 134 memory_range.NumberOfPages, 135 memory_range.Type) 136 137 # Render a heatmap. 138 139 # Automatically lower resolution for large images. 140 resolution = 0x1000 * 0x10 # 16 pages - conservative start. 141 column_count = 12 142 end = runs[-1]["end"] 143 # Keep it under 200 rows. 144 while end / resolution / column_count > 200: 145 resolution *= 2 146 147 notes = ("Resolution: %(pages)d pages (%(mb).2f MB) per cell.\n" 148 "Note that colors of overlapping regions are blended " 149 "using a weighted average. Letters in cells indicate " 150 "which regions from the legend are present. They are " 151 "ordered proportionally, by their respective page " 152 "counts in each cell.") % dict(pages=resolution / 0x1000, 153 mb=resolution / 1024.0 ** 2) 154 155 legend = visual_aides.MapLegend( 156 notes=notes, 157 legend=[("Am", "kEfiACPIMemoryNVS", (0x00, 0xff, 0x00)), 158 ("Ar", "kEfiACPIReclaimMemory", (0xc7, 0xff, 0x50)), 159 ("Bc", "kEfiBootServicesCode", (0xff, 0xa5, 0x00)), 160 ("Bd", "kEfiBootServicesData", (0xff, 0x00, 0x00)), 161 ("M", "kEfiConventionalMemory", (0xff, 0xff, 0xff)), 162 ("Ec", "kEfiLoaderCode", (0x00, 0xff, 0xff)), 163 ("Ed", "kEfiLoaderData", (0x00, 0x00, 0xff)), 164 ("I", "kEfiMemoryMappedIO", (0xff, 0xff, 0x00)), 165 ("X", "kEfiReservedMemoryType", (0x00, 0x00, 0x00)), 166 ("Rc", "kEfiRuntimeServicesCode", (0xff, 0x00, 0xff)), 167 ("Rd", "kEfiRuntimeServicesData", (0xff, 0x00, 0x50))]) 168 169 heatmap = visual_aides.RunBasedMap( 170 caption="Offset (p)", 171 legend=legend, 172 runs=runs, 173 resolution=resolution, 174 column_count=column_count) 175 176 renderer.table_header([ 177 dict(name="Visual mapping", width=120, style="full"), 178 dict(name="Legend", orientation="vertical", style="full", 179 width=40)]) 180 181 renderer.table_row(heatmap, legend)
182 183
184 -class DarwinBootParameters(common.AbstractDarwinCommand):
185 """Prints the kernel command line.""" 186 187 name = "boot_cmdline" 188 189 table_header = [ 190 dict(name="cmdline", type="str"), 191 ] 192
193 - def collect(self):
194 boot_args = self.profile.get_constant_object( 195 "_PE_state", "PE_state").bootArgs 196 197 yield dict(cmdline=boot_args.CommandLine.cast("String"))
198 199
200 -class DarwinSetProcessContext(core.SetProcessContextMixin, 201 common.ProcessFilterMixin, 202 common.AbstractDarwinCommand):
203 """A cc plugin for windows."""
204 205
206 -class DarwinVtoP(core.VtoPMixin, common.ProcessFilterMixin, 207 common.AbstractDarwinCommand):
208 """Describe virtual to physical translation on darwin platforms."""
209 210
211 -class DarwinImageFingerprint(common.AbstractDarwinParameterHook):
212 """Fingerprint the current image. 213 214 This parameter tries to get something unique about the image quickly. The 215 idea is that two different images (even of the same system at different 216 points in time) will have very different fingerprints. The fingerprint is 217 used as a key to cache persistent information about the system. 218 219 Live systems can not have a stable fingerprint and so return a NoneObject() 220 here. 221 222 We return a list of tuples: 223 (physical_offset, expected_data) 224 225 The list uniquely identifies the image. If one were to read all physical 226 offsets and find the expected_data at these locations, then we have a very 227 high level of confidence that the image is unique and matches the 228 fingerprint. 229 """ 230 name = "image_fingerprint" 231
232 - def calculate(self):
233 if self.session.physical_address_space.volatile: 234 return obj.NoneObject("No fingerprint for volatile image.") 235 236 result = [] 237 profile = self.session.profile 238 phys_as = self.session.physical_address_space 239 240 address_space = self.session.GetParameter("default_address_space") 241 242 label = profile.get_constant_object("_osversion", "String") 243 result.append((address_space.vtop(label.obj_offset), label.v())) 244 245 label = profile.get_constant_object("_version", "String") 246 result.append((address_space.vtop(label.obj_offset), label.v())) 247 248 label = profile.get_constant_object("_sched_tick", "String", 249 length=8, term=None) 250 result.append((address_space.vtop(label.obj_offset), label.v())) 251 252 catfish_offset = self.session.GetParameter("catfish_offset") 253 result.append((catfish_offset, phys_as.read(catfish_offset, 8))) 254 255 # List of processes should also be pretty unique. 256 for task in self.session.plugins.pslist().filter_processes(): 257 name = task.name.cast("String", length=30) 258 task_name_offset = address_space.vtop(name.obj_offset) 259 260 result.append((task_name_offset, name.v())) 261 262 return dict( 263 hash=hashlib.sha1(unicode(result).encode("utf8")).hexdigest(), 264 tests=result)
265 266
267 -class DarwinHighestUserAddress(common.AbstractDarwinParameterHook):
268 """The highest address for user mode/kernel mode division.""" 269 270 name = "highest_usermode_address" 271
272 - def calculate(self):
273 return 0x800000000000
274