1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21  """ 
 22  @author:       Michael Cohen <scudette@gmail.com> 
 23  @author:       AAron Walters and Brendan Dolan-Gavitt 
 24  @license:      GNU General Public License 2.0 or later 
 25  @contact:      awalters@volatilesystems.com,bdolangavitt@wesleyan.edu 
 26  @organization: Volatile Systems 
 27  """ 
 28  import re 
 29   
 30  from rekall import addrspace 
 31  from rekall.plugins import core 
 32  from rekall.plugins.windows.registry import registry 
 33  from rekall.plugins.overlays import basic 
 34  from rekall_lib import utils 
 35   
 36   
 37 -class PrintKey(registry.RegistryPlugin): 
  38      """Print a registry key, and its subkeys and values""" 
 39      __name = "printkey" 
 40   
 41      @classmethod 
 42 -    def args(cls, parser): 
  43          """Declare the command line args we need.""" 
 44          super(PrintKey, cls).args(parser) 
 45   
 46          parser.add_argument("-k", "--key", default="", 
 47                              help="Registry key to print.") 
 48   
 49          parser.add_argument("-r", "--recursive", default=False, 
 50                              type="Boolean", 
 51                              help='If set print the entire subtree.') 
  52   
 53   
 54 -    def __init__(self, key="", recursive=False, **kwargs): 
  55          """Print all keys and values contained by a registry key. 
 56   
 57          Args: 
 58            key: The key name to list. If not provided we list the root key in the 
 59              hive. 
 60   
 61            recursive: If set print the entire subtree. 
 62          """ 
 63          super(PrintKey, self).__init__(**kwargs) 
 64          self.key = key 
 65          self.recursive = recursive 
  66   
 68          yield key 
 69   
 70          if self.recursive: 
 71              for subkey in key.subkeys(): 
 72                  for subkey in self._list_keys(subkey): 
 73                      yield subkey 
  74   
 76          """Return the keys that match.""" 
 77          seen = set() 
 78          for hive_offset in self.hive_offsets: 
 79              reg = registry.RegistryHive( 
 80                  profile=self.profile, session=self.session, 
 81                  kernel_address_space=self.kernel_address_space, 
 82                  hive_offset=hive_offset) 
 83   
 84              key = reg.open_key(self.key) 
 85              for subkey in self._list_keys(key): 
 86                  if subkey in seen: 
 87                      break 
 88   
 89                  seen.add(subkey) 
 90   
 91                  yield reg, subkey 
  92   
 93 -    def voltext(self, key): 
  94          """Returns a string representing (S)table or (V)olatile keys.""" 
 95          return "(V)" if key.obj_offset & 0x80000000 else "(S)" 
  96   
 98          renderer.format("Legend: (S) = Stable   (V) = Volatile\n\n") 
 99          for reg, key in self.list_keys(): 
100              self.session.report_progress( 
101                  "Printing %s", lambda key=key: key.Path) 
102   
103              if key: 
104                  renderer.format("----------------------------\n") 
105                  renderer.format("Registry: {0}\n", reg.Name) 
106                  renderer.format("Key name: {0} {1} @ {2:addrpad}\n", key.Name, 
107                                  self.voltext(key), key.obj_vm.vtop(int(key))) 
108   
109                  renderer.format("Last updated: {0}\n", key.LastWriteTime) 
110                  renderer.format("\n") 
111                  renderer.format("Subkeys:\n") 
112   
113                  for subkey in key.subkeys(): 
114                      if not subkey.Name: 
115                          renderer.format( 
116                              "  Unknown subkey: {0}\n", subkey.Name.reason) 
117                      else: 
118                          renderer.format(u"  {1} {0}\n", 
119                                          subkey.Name, self.voltext(subkey)) 
120   
121                  renderer.format("\n") 
122                  renderer.format("Values:\n") 
123                  for value in key.values(): 
124                      renderer.format("{0:addrpad} ", value.obj_vm.vtop(value)) 
125                      if value.Type == 'REG_BINARY': 
126                          data = value.DecodedData 
127                          if isinstance(data, basestring): 
128                              renderer.format( 
129                                  u"{0:width=13} {1:width=15} : {2}\n", 
130                                  value.Type, value.Name, self.voltext(value)) 
131                              utils.WriteHexdump(renderer, value.DecodedData) 
132                      else: 
133                          renderer.format( 
134                              u"{0:width=13} {1:width=15} : {2} {3}\n", 
135                              value.Type, value.Name, self.voltext(value), 
136                              utils.SmartUnicode(value.DecodedData).strip()) 
  137   
138   
139 -class RegDump(core.DirectoryDumperMixin, registry.RegistryPlugin): 
 140      """Dump all registry hives from memory into a dump directory.""" 
141   
142      __name = 'regdump' 
143   
144 -    def dump_hive(self, hive_offset=None, reg=None, fd=None): 
 145          """Write the hive into the fd. 
146   
147          Args: 
148            hive_offset: The virtual offset where the hive is located. 
149            reg: Optionally an instance of registry.Registry helper. If provided 
150              hive_offset is ignored. 
151            fd: The file like object we write to. 
152          """ 
153          if reg is None: 
154              reg = registry.RegistryHive( 
155                  profile=self.profile, 
156                  kernel_address_space=self.kernel_address_space, 
157                  hive_offset=hive_offset) 
158   
159          count = 0 
160          for data in reg.address_space.save(): 
161              fd.write(data) 
162              count += len(data) 
163              self.session.report_progress( 
164                  "Dumping {0}Mb".format(count/1024/1024)) 
 165   
167           
168          for hive_offset in self.hive_offsets: 
169              reg = registry.RegistryHive( 
170                  profile=self.profile, session=self.session, 
171                  kernel_address_space=self.kernel_address_space, 
172                  hive_offset=hive_offset) 
173   
174               
175              filename = reg.Name.rsplit("\\", 1).pop() 
176   
177               
178              filename = re.sub(r"[^a-zA-Z0-9_\-@ ]", "_", filename) 
179   
180               
181              renderer.section() 
182              renderer.format("Dumping {0} into \"{1}\"\n", reg.Name, filename) 
183   
184              with renderer.open(directory=self.dump_dir, 
185                                 filename=filename, 
186                                 mode="wb") as fd: 
187                  self.dump_hive(reg=reg, fd=fd) 
188                  renderer.format("Dumped {0} bytes\n", fd.tell()) 
  189   
190   
191   
192 -class HiveDump(registry.RegistryPlugin): 
 193      """Prints out a hive""" 
194   
195      __name = "hivedump" 
196   
198          yield key 
199   
200          if key in seen: 
201              return 
202   
203          seen.add(key) 
204   
205          for subkey in key.subkeys(): 
206              for subsubkey in self._key_iterator(subkey, seen): 
207                  yield subsubkey 
 208   
210          seen = set() 
211   
212          for hive_offset in self.hive_offsets: 
213              reg = registry.RegistryHive( 
214                  hive_offset=hive_offset, session=self.session, 
215                  kernel_address_space=self.kernel_address_space, 
216                  profile=self.profile) 
217   
218              renderer.section() 
219              renderer.format("Hive {0}\n\n", reg.Name) 
220   
221              renderer.table_header([("Last Written", "timestamp", "<24"), 
222                                     ("Key", "key", "")]) 
223   
224              for key in self._key_iterator(reg.root, seen): 
225                  renderer.table_row(key.LastWriteTime, key.Path) 
  226   
227   
228   
229  sam_vtypes = { 
230      "UNICODE_STRING": [12, { 
231          "offset": [0, ["unsigned int"]], 
232          "len": [4, ["unsigned int"]], 
233          "Value": lambda x: x.obj_profile.UnicodeString( 
234              offset=x.offset+0xCC, 
235              length=x.len, vm=x.obj_vm), 
236   
237          }], 
238   
239      "Hash": [12, { 
240          "offset": [0, ["unsigned int"]], 
241          "len": [4, ["unsigned int"]], 
242          "Value": lambda x: x.obj_vm.read( 
243              x.offset+0xCC, x.len).encode("hex"), 
244   
245          }], 
246   
247      "V": [None, { 
248          "Type": [4, ["Enumeration", dict( 
249              choices={ 
250                  0xBC: "Default Admin User", 
251                  0xd4: "Custom Limited Acct", 
252                  0xb0: "Default Guest Acct" 
253                  }, 
254              target="unsigned int" 
255              )]], 
256          "UserName": [12, ['UNICODE_STRING']], 
257          "FullName": [24, ['UNICODE_STRING']], 
258          "Comment": [36, ['UNICODE_STRING']], 
259          "LanHash": [156, ['Hash']], 
260          "NTHash": [168, ['Hash']], 
261          }], 
262   
263      "F": [None, { 
264          "LastLoginTime": [8, ['WinFileTime']], 
265          "PwdResetDate": [24, ["WinFileTime"]], 
266          "AccountExpiration": [32, ["WinFileTime"]], 
267          "PasswordFailedTime": [40, ["WinFileTime"]], 
268          "LoginCount": [66, ["unsigned short int"]], 
269          "FailedLoginCount": [64, ["unsigned short int"]], 
270          "Rid": [48, ["unsigned int"]], 
271          "Flags": [56, ["Flags", dict( 
272              maskmap=utils.Invert({ 
273                  0x0001: "Account Disabled", 
274                  0x0002: "Home directory required", 
275                  0x0004: "Password not required", 
276                  0x0008: "Temporary duplicate account", 
277                  0x0010: "Normal user account", 
278                  0x0020: "MNS logon user account", 
279                  0x0040: "Interdomain trust account", 
280                  0x0080: "Workstation trust account", 
281                  0x0100: "Server trust account", 
282                  0x0200: "Password does not expire", 
283                  0x0400: "Account auto locked" 
284                  }), 
285              target="unsigned short int" 
286              )]], 
287          }], 
288      } 
289   
290   
291   
292 -class SAMProfile(basic.Profile32Bits, basic.BasicClasses): 
 293      """A profile to parse the SAM.""" 
294   
295      @classmethod 
 300   
301   
302 -class Users(registry.RegistryPlugin): 
 303      """Enumerate all users of this system. 
304   
305      Ref: 
306      samparse.pl from RegRipper. 
307   
308      # copyright 2012 Quantum Analytics Research, LLC 
309      # Author: H. Carvey, keydet89@yahoo.com 
310      """ 
311      name = "users" 
312   
338   
340          for user_rid, v, f in self.GenerateUsers(): 
341              renderer.section() 
342              renderer.format("Key {0} \n\n", user_rid.Path) 
343              renderer.table_header( 
344                  columns=[("", "property", "20"), 
345                           ("", "value", "")], 
346                  suppress_headers=True) 
347   
348              for field in v.members: 
349                  try: 
350                      renderer.table_row(field, getattr(v, field).Value) 
351                  except AttributeError: 
352                      renderer.table_row(field, getattr(v, field)) 
353   
354              for field in f.members: 
355                  renderer.table_row(field, getattr(f, field)) 
  356   
357   
358 -class Services(registry.RegistryPlugin): 
 359      """Enumerate all services.""" 
360      name = "services" 
361   
362       
363       
364      SERVICE_TYPE = { 
365          0x00000004: 'SERVICE_ADAPTER', 
366          0x00000002: 'SERVICE_FILE_SYSTEM_DRIVER', 
367          0x00000001: 'SERVICE_KERNEL_DRIVER', 
368          0x00000008: 'SERVICE_RECOGNIZER_DRIVER', 
369          0x00000010: 'SERVICE_WIN32_OWN_PROCESS', 
370          0x00000020: 'SERVICE_WIN32_SHARE_PROCESS' 
371          } 
372   
373      START_TYPE = { 
374          0x00000002: 'SERVICE_AUTO_START', 
375          0x00000000: 'SERVICE_BOOT_START', 
376          0x00000003: 'SERVICE_DEMAND_START', 
377          0x00000004: 'SERVICE_DISABLED', 
378          0x00000001: 'SERVICE_SYSTEM_START' 
379          } 
380   
381      ERROR_CONTROL = { 
382          0x00000003: 'SERVICE_ERROR_CRITICAL', 
383          0x00000000: 'SERVICE_ERROR_IGNORE', 
384          0x00000001: 'SERVICE_ERROR_NORMAL', 
385          0x00000002: 'SERVICE_ERROR_SEVERE' 
386          } 
387   
398   
400          for service in self.GenerateServices(): 
401              renderer.section(service.Name.v()) 
402              renderer.table_header([("Key", "key", "20"), 
403                                     ("Value", "value", "[wrap:60]")], 
404                                    suppress_headers=True) 
405   
406              for value in service.values(): 
407                  k = value.Name.v() 
408                  v = value.DecodedData 
409                  if value.Type == "REG_BINARY": 
410                      continue 
411   
412                  if isinstance(v, list): 
413                      v = ",".join([x for x in v if x]) 
414   
415                  if k == "Type": 
416                      v = self.SERVICE_TYPE.get(v, v) 
417   
418                  if k == "Start": 
419                      v = self.START_TYPE.get(v, v) 
420   
421                  if k == "ErrorControl": 
422                      v = self.ERROR_CONTROL.get(v, v) 
423   
424                  renderer.table_row(k, v) 
  425