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 The Rekall Memory Forensics object system.
26
27 """
28 __author__ = ("Michael Cohen <scudette@gmail.com> based on original code "
29 "by AAron Walters and Brendan Dolan-Gavitt with contributions "
30 "by Mike Auty")
31
32 import atexit
33 import inspect
34 import json
35 import logging
36 import pdb
37 import operator
38 import os
39 import struct
40 import StringIO
41 import copy
42
43 import traceback
44
45 from rekall import addrspace
46 from rekall.ui import renderer
47 from rekall_lib import registry
48 from rekall_lib import utils
70
77
88
104
112
115
116 @staticmethod
119
120
121
122
123 ACCESS_LOG = ProfileLog()
124
125
126 -class Curry(object):
127 - def __init__(self, curry_target, *args, **kwargs):
128 self._target = curry_target
129 self._kwargs = kwargs
130 self._args = args
131 self._default_arguments = kwargs.pop("default_arguments", [])
132 self.__doc__ = self._target.__doc__
133 self.__wrapped__ = self._target
134
136
137 new_kwargs = self._kwargs.copy()
138 new_kwargs.update(kwargs)
139 return self._target(*(self._args + args), **new_kwargs)
140
142 """Return a list of default args for the target."""
143 if self._default_arguments is not None:
144 return self._default_arguments
145
146 args, _, _, defaults = inspect.getargspec(self._target)
147 if defaults:
148 return args[-len(defaults):]
149
150 return []
151
153 return getattr(self._target, attr)
154
285
286
287 -class Error(Exception):
288 """All object related exceptions come from this one."""
289
292 """Errors in setting the profile."""
293
296 __metaclass__ = registry.UniqueObjectIdMetaclass
297
298 obj_parent = NoneObject("No parent")
299 obj_name = NoneObject("No name")
300 obj_producers = None
301
302
303
304
305
306
307 - def __init__(self, type_name=None, offset=0, vm=None, profile=None,
308 parent=None, name='', context=None, session=None, **kwargs):
309 """Constructor for Base object.
310
311 Args:
312 type_name: The name of the type of this object. This different
313 from the class name, since the same class may implement many types
314 (e.g. Struct implements every instance in the vtype definition).
315
316 offset: The offset within the address space to this object exists.
317
318 vm: The address space this object uses to read itself from.
319
320 profile: The profile this object may use to dereference other
321 types.
322
323 parent: The object which created this object.
324
325 name: The name of this object.
326
327 context: An opaque dict which is passed to all objects created from
328 this object. This dict may contain context specific information
329 which each derived instance can use.
330
331 kwargs: Arbitrary args this object may accept - these can be passed in
332 the vtype language definition.
333 """
334 if kwargs:
335 session.logging.error("Unknown keyword args %s for %s",
336 kwargs, self.__class__.__name__)
337
338 if session is None:
339 raise RuntimeError("Session must be provided")
340
341 if profile is None:
342 profile = session.profile
343
344 self.obj_type = type_name or self.__class__.__name__
345
346
347
348 self.obj_offset = Pointer.integer_to_address(int(offset or 0))
349 self.obj_vm = vm
350 self.obj_parent = parent
351 self.obj_name = name
352 self.obj_profile = profile
353 self.obj_context = context or {}
354
355 if not session:
356 raise ValueError("Session must be provided.")
357
358 self.obj_session = session
359 self.obj_producers = set()
360
361 @utils.safe_property
364
365 @utils.safe_property
367 return self.obj_offset + self.obj_size
368
370 """Returns the raw data of this object."""
371 return self.obj_vm.read(self.obj_offset, self.obj_size)
372
373 @utils.safe_property
380
383
385 """Function for writing the object back to disk"""
386 pass
387
389 """This method is called when we test the truth value of an Object.
390
391 In rekall we consider an object to have True truth value only when it is
392 a valid object. Its possible for example to have a Pointer object which
393 is not valid - this will have a truth value of False.
394
395 You should be testing for validity like this:
396 if X:
397 # object is valid
398
399 Do not test for validity like this:
400
401 if int(X) == 0:
402
403 or
404
405 if X is None:
406 .....
407
408 the later form is not going to work when X is a NoneObject.
409 """
410 return self.is_valid()
411
413 return self.v() == other or (
414
415 (self.__class__ == other.__class__) and
416
417
418
419
420
421 (self.obj_vm.base == other.obj_vm.base) and
422 (self.obj_vm.vtop(self.obj_offset) ==
423 other.obj_vm.vtop(other.obj_offset)))
424
426
427
428
429
430 return hash(self.v())
431
432 @utils.safe_property
434 """Returns (usually 1) representation(s) of self usable as dict keys.
435
436 Using full base objects for indexing can be slow, especially with
437 Structs. This method returns a representation of the object that is
438 a suitable key - either the value of a primitive type, or the memory
439 address of the more complex ones.
440 """
441 return (self.v(),)
442
443 @classmethod
445 """Return all members that are intended to represent some data."""
446 for name in dir(cls):
447 candidate = getattr(cls, name)
448 if isinstance(candidate, property):
449 yield name, candidate
450
451 - def m(self, memname):
453
456
457 - def deref(self, vm=None):
458 """An alias for dereference - less to type."""
459 return self.dereference(vm=vm)
460
464
466 """Produces a pointer to this object.
467
468 This is the same as the C & operator and is the opposite of deref().
469 """
470 return self.obj_profile.Pointer(value=self.obj_offset, vm=self.obj_vm,
471 target=self.obj_type)
472
473 - def cast(self, type_name=None, vm=None, **kwargs):
474
475
476 offset = kwargs.pop("offset", self.obj_offset)
477 profile_obj = kwargs.pop("profile", self.obj_profile)
478
479 return profile_obj.Object(
480 type_name=type_name or self.obj_type, offset=offset,
481 vm=vm or self.obj_vm, parent=self.obj_parent,
482 context=self.obj_context, **kwargs)
483
484 - def v(self, vm=None):
485 """ Do the actual reading and decoding of this member
486
487 When vm is specified, we are asked to evaluate this object is another
488 address space than the one it was created on. Derived classes should
489 allow for this.
490 """
491 _ = vm
492 return NoneObject("No value for {0}", self.obj_name)
493
495 return utils.SmartStr(unicode(self))
496
505
507
508 if self.obj_offset == 0 and self.obj_name == "Prototype":
509 return "%s Prototype" % self.__class__.__name__
510
511 return "[{0} {1}] @ 0x{2:08X}".format(
512 self.__class__.__name__, self.obj_name,
513 self.obj_offset)
514
516 """Hide any members with _."""
517 result = self.__dict__.keys() + dir(self.__class__)
518
519 return result
520
529
532 def make_method(name):
533 def method(self, *args, **kw):
534 proxied = self.proxied()
535 try:
536
537
538 args = list(args)
539 args[0] = args[0].proxied()
540 except (AttributeError, IndexError):
541 pass
542
543 try:
544 method = getattr(operator, name)
545 args = [proxied] + args
546 except AttributeError:
547 method = getattr(proxied, name)
548
549 return method(*args, **kw)
550
551 return method
552
553 for name in mixin._specials:
554 setattr(mixin, name, make_method(name))
555
558 """ This MixIn implements the numeric protocol """
559 _specials = [
560
561 '__add__', '__sub__', '__mul__',
562 '__floordiv__', '__mod__', '__divmod__',
563 '__pow__', '__lshift__', '__rshift__',
564 '__and__', '__xor__', '__or__', '__div__',
565 '__truediv__', '__radd__', '__rsub__',
566 '__rmul__', '__rdiv__', '__rtruediv__',
567 '__rfloordiv__', '__rmod__', '__rdivmod__',
568 '__rpow__', '__rlshift__',
569 '__rrshift__', '__rand__', '__rxor__', '__ror__',
570 '__neg__', '__pos__',
571 '__abs__', '__invert__', '__int__', '__long__',
572 '__float__', '__oct__', '__hex__',
573
574
575 '__lt__', '__le__', '__eq__', '__ge__', '__gt__', '__index__',
576 ]
577
579 return not self == other
580
583 """This MixIn implements proxying for strings."""
584 _specials = [
585
586 '__lt__', '__le__', '__eq__', '__ge__', '__gt__', '__index__',
587 ]
588
590 return not self == other
591
592
593 CreateMixIn(NumericProxyMixIn)
594 CreateMixIn(StringProxyMixIn)
595
596
597 -class NativeType(NumericProxyMixIn, BaseObject):
598 - def __init__(self, value=None, format_string=None, session=None,
599 profile=None, **kwargs):
611
613 """Writes the data back into the address space"""
614 output = struct.pack(self.format_string, int(data))
615 return self.obj_vm.write(self.obj_offset, output)
616
619
621 return long(other) + self.v()
622
624 return long(other) - self.v()
625
626 @utils.safe_property
628 return struct.calcsize(self.format_string)
629
630 - def v(self, vm=None):
631 if self.value is not None:
632 return self.value
633
634 data = self.obj_vm.read(self.obj_offset, self.obj_size)
635 if not data:
636 return NoneObject("Unable to read {0} bytes from {1}",
637 self.obj_size, self.obj_offset)
638
639
640 (self.value,) = struct.unpack(self.format_string, data)
641
642 return self.value
643
646
648 try:
649 return " [{0}:{1}]: 0x{2:08X}".format(self.obj_type, self.obj_name,
650 self.v())
651 except ValueError:
652 return " [{0}:{1}]: {2}".format(self.obj_type, self.obj_name,
653 repr(self.v()))
654
655
656 -class Bool(NativeType):
658
661 """ A class splitting an integer into a bunch of bit. """
662
663 - def __init__(self, start_bit=0, end_bit=32, target=None,
664 native_type=None, **kwargs):
665 super(BitField, self).__init__(**kwargs)
666
667
668 if native_type:
669 target = native_type
670
671 self._proxy = self.obj_profile.Object(
672 target or "address", offset=self.obj_offset, vm=self.obj_vm,
673 context=self.obj_context)
674
675 self.target = target
676 self.start_bit = start_bit
677 self.end_bit = end_bit
678 self.mask = ((1 << end_bit) - 1) ^ ((1 << start_bit) - 1)
679
680 @utils.safe_property
683
684 - def v(self, vm=None):
685 i = self._proxy.v()
686 return (i & ((1 << self.end_bit) - 1)) >> self.start_bit
687
692
694 return " [{0}({1}-{2}):{3}]: 0x{4:08X}".format(
695 self.obj_type, self.start_bit, self.end_bit, self.obj_name,
696 self.v())
697
699 return bool(self._proxy.v() & self.mask)
700
703 """A pointer reads an 'address' object from the address space."""
704
705 - def __init__(self, target=None, target_args=None, value=None, **kwargs):
706 """Constructor.
707
708 Args:
709 target: The name of the target object (A string). We use the profile
710 to instantiate it.
711 target_args: The target will receive these as kwargs.
712 """
713 super(Pointer, self).__init__(value=value, **kwargs)
714
715 if value is not None:
716 self.obj_offset = NoneObject("No address specified")
717
718
719
720 self._proxy = self.obj_profile.Object(
721 "address", offset=self.obj_offset, value=value,
722 vm=self.obj_vm, context=self.obj_context)
723
724
725 self.target = target
726 self.target_args = target_args or {}
727 self.target_size = 0
728 self.kwargs = kwargs
729
730 @utils.safe_property
733
734 - def v(self, vm=None):
738
740 return self.deref().m(attr)
741
744
752
754 """Returns if what we are pointing to is valid """
755
756 return self.v() != 0
757
759 """Indexing a pointer indexes its target.
760
761 Note this is different than C which treats pointers as arrays:
762
763 struct foobar *p1;
764 struct foobar *p2[];
765
766 In C:
767 p[1] -> struct foobar
768 p[2] -> struct foobar *
769
770 In Rekall:
771 p[1] -> Not allowed since structs do not have [].
772 p[2] -> struct foobar.
773 """
774 res = self.dereference()
775 return res[item]
776
778 offset = self.v()
779
780
781 vm = vm or self.obj_vm
782
783 if offset:
784 kwargs = copy.deepcopy(self.target_args)
785 kwargs.update(dict(offset=offset, session=self.obj_session,
786 vm=vm, profile=self.obj_profile,
787 parent=self.obj_parent, name=self.obj_name))
788
789 if isinstance(self.target, basestring):
790 result = self.obj_profile.Object(
791 type_name=self.target,
792 context=self.obj_context, **kwargs)
793
794 elif callable(self.target):
795 result = self.target(**kwargs)
796 else:
797
798 result = Void(**kwargs)
799
800 if result.is_valid():
801 return result
802
803 return NoneObject("Pointer {0} @ {1} invalid",
804 self.obj_name, self.v())
805
808
810 return "Pointer {0}".format(self.v())
811
813 """This method is used in comparison operations.
814
815 This ideas here is to make it possible to easily write a condition such
816 as:
817
818 while ptr:
819 ...
820 ptr += 1
821
822 Pointers are considered non-zero if they are invalid (i.e. what they
823 point to is not mapped in. This is very subtle and might be the wrong
824 choice. Note that if the kernel actually maps the zero page in (which
825 can happen in some situations), then a null pointer is actually valid.
826 """
827 return bool(self.is_valid())
828
848
850 if isinstance(other, Pointer):
851 if not isinstance(other, self.__class__):
852 raise TypeError("Can not subtract non related pointers.")
853
854
855 self.target_size = (self.target_size or
856 self.obj_profile.Object(self.target).obj_size)
857
858 return (int(self) - int(other)) / self.target_size
859
860 return self.__add__(-other)
861
866
868 target = self.v()
869 target_name = self.obj_session.address_resolver.format_address(
870 target)
871 if target_name:
872 target_name = " (%s)" % target_name[0]
873 else:
874 target_name = ""
875
876 return "<%s %s to [%#010x%s] (%s)>" % (
877 self.target, self.__class__.__name__, target,
878 target_name, self.obj_name or '')
879
881 return u"Pointer to %s" % self.deref()
882
883 @utils.safe_property
886
888
889 result = self.dereference()
890
891 return getattr(result, attr)
892
894 """Delegate the iterator to the target."""
895 return iter(self.dereference())
896
897 - def dereference_as(self, target=None, target_args=None, vm=None,
898 profile=None, parent=None):
899 """Dereference ourselves into another type, or address space.
900
901 This method allows callers to explicitly override the setting in the
902 profile for this pointer.
903
904 Args:
905 target: The target to override.
906 target_args: The args to instantiate this target with.
907 vm: The address space to dereference the pointer in.
908 profile: If a new profile should be used to instantiate the target.
909 """
910 vm = vm or self.obj_vm
911
912 if profile is None:
913 profile = self.obj_profile
914
915 return profile.Object(
916 type_name=target or self.target, offset=self.v(), vm=vm,
917 parent=parent or self.obj_parent, context=self.obj_context,
918 **(target_args or {}))
919
920 @staticmethod
922 """Addresses only use 48 bits."""
923 return 0xffffffffffff & int(value)
924
927 """A 32 bit pointer (Even in 64 bit arch).
928
929 These kinds of pointers are used most commonly in the Registry code which
930 always treats the hives as 32 bit address spaces.
931 """
935
936
937 -class Void(Pointer):
939 kwargs['type_name'] = 'unsigned long'
940 super(Void, self).__init__(**kwargs)
941
942 - def v(self, vm=None):
943 return self.obj_offset
944
947
948 @utils.safe_property
950 self.obj_session.logging.warning(
951 "Void objects have no size! Are you doing pointer arithmetic on a "
952 "pointer to void?")
953 return 1
954
956 return "0x{0:08X}".format(self.v())
957
959 return "Void[{0} {1}] (0x{2:08x})".format(
960 self.__class__.__name__, self.obj_name or '', self.v())
961
964
965
966 -class Array(BaseObject):
967 """ An array of objects of the same size """
968
969 target_size = 0
970
971 - def __init__(self, count=0, target=None, target_args=None,
972 target_size=None, max_count=100000, size=0,
973 **kwargs):
974 """Instantiate an array of like items.
975
976 Args:
977 count: How many items belong to the array (not strictly enforced -
978 i.e. it is possible to read past the end). By default the array is
979 unbound.
980
981 max_count: The maximum size of the array. This is a safety mechanism
982 if count is calculated. max_count should be set to an upper bound on
983 the size of the array.
984
985 target: The name of the element to be instantiated on each point. The
986 size of the object returned by this should be the same for all
987 members of the array (i.e. all elements should be the same size).
988
989 size: The total size of the Array. If this is nonzero we calculate the
990 count so that just the right number of items fit in this specified
991 size.
992 """
993 super(Array, self).__init__(**kwargs)
994
995
996 if callable(count):
997 count = count(self.obj_parent)
998
999 if callable(target_size):
1000 target_size = target_size(self.obj_parent)
1001
1002 self.count = count
1003 self.max_count = max_count
1004
1005 if not target:
1006 raise AttributeError("Array must use a target parameter")
1007
1008 self.target = target
1009 self.target_args = target_args or {}
1010
1011 self.target_size = target_size
1012 if self.target_size is None:
1013 self.target_size = self.obj_profile.Object(
1014 self.target, offset=self.obj_offset, vm=self.obj_vm,
1015 profile=self.obj_profile, parent=self,
1016 **self.target_args).obj_size
1017
1018 if size > 0:
1019 self.count = size / self.target_size
1020
1021 @utils.safe_property
1023 """The size of the entire array."""
1024 return self.target_size * self.count
1025
1027
1028 if not self.obj_vm.is_valid_address(self.obj_offset):
1029 return
1030
1031 for position in utils.xrange(0, self.count):
1032
1033
1034
1035
1036
1037 if position > self.max_count:
1038 if self.obj_session.GetParameter("debug"):
1039 pdb.set_trace()
1040
1041 self.obj_session.logging.warn(
1042 "%s Array iteration truncated by max_count!", self.obj_name)
1043 break
1044
1045
1046
1047
1048
1049
1050
1051 yield self[position]
1052
1054 return "<{3} {0} x {1} @ 0x{2:08X}>".format(
1055 self.count, self.target, self.obj_offset, self.__class__.__name__)
1056
1058 result = [repr(self)]
1059 for i, x in enumerate(self):
1060 result.append(u"0x%04X %r" % (i, x))
1061
1062 if len(result) > 10:
1063 result.append(u"... More entries hidden")
1064 break
1065
1066 return u"\n".join(result)
1067
1069 if not other or self.count != len(other):
1070 return False
1071
1072 for i in xrange(self.count):
1073 if not self[i] == other[i]:
1074 return False
1075
1076 return True
1077
1079
1080 if isinstance(pos, slice):
1081 start, stop, step = pos.indices(self.count)
1082 return [self[i] for i in xrange(start, stop, step)]
1083
1084 pos = int(pos)
1085 offset = self.target_size * pos + self.obj_offset
1086 context = dict(index=pos)
1087 context.update(self.obj_context)
1088
1089 return self.obj_profile.Object(
1090 self.target, offset=offset, vm=self.obj_vm,
1091 parent=self, profile=self.obj_profile,
1092 name="{0}[{1}] ".format(self.obj_name, pos),
1093 context=context, **self.target_args)
1094
1096 if isinstance(item, int):
1097 self[item].write(value)
1098 else:
1099 super(Array, self).__setitem__(item, value)
1100
1103
1106 """This is an optimized Array implementation for arrays of Pointers.
1107
1108 The idea is to decode all pointers at once.
1109 """
1110
1122
1124 for i in xrange(len(self._data)):
1125 yield self[i]
1126
1128 return self.obj_profile.Pointer(value=self._data[pos], vm=self.obj_vm)
1129
1132 """An array of structs which do not all have the same size."""
1133
1134 - def __init__(self, maximum_size=None, maximum_offset=None, **kwargs):
1135 """Constructor.
1136
1137 This array may be initialized using one of the following parameters:
1138
1139 maximum_size: The maximum size of the array in bytes.
1140 maximum_offset: If we reach this offset iteration is terminated.
1141 count: The total count of items in this list.
1142
1143 max_count: The maximum size of the array. This is a safety mechanism if
1144 count is calculated. max_count should be set to an upper bound on the
1145 size of the array.
1146 """
1147 super(ListArray, self).__init__(**kwargs)
1148 if callable(maximum_size):
1149 maximum_size = int(maximum_size(self.obj_parent))
1150
1151 if callable(maximum_offset):
1152 maximum_offset = int(maximum_offset(self.obj_parent))
1153
1154
1155 if self.count == 0 and maximum_size is None and maximum_offset is None:
1156 raise TypeError(
1157 "One of count, maximum_offset, maximum_size must be specified.")
1158
1159 if maximum_size is not None:
1160 maximum_offset = self.obj_offset + maximum_size
1161
1162 self.maximum_offset = maximum_offset
1163
1165 """It is generally too expensive to rely on the count of this array."""
1166 raise NotImplementedError
1167
1168 @utils.safe_property
1170 """It is generally too expensive to rely on the size of this array."""
1171 raise NotImplementedError
1172
1174 offset = self.obj_offset
1175 count = 0
1176 while 1:
1177
1178 if self.maximum_offset and offset > self.maximum_offset:
1179 break
1180
1181 if self.count and count >= self.count:
1182 break
1183
1184 if count >= self.max_count:
1185 self.obj_session.logging.warn(
1186 "%s ListArray iteration truncated by max_count!",
1187 self.obj_name)
1188 break
1189
1190 item = self.obj_profile.Object(
1191 self.target, offset=offset, vm=self.obj_vm, parent=self,
1192 profile=self.obj_profile, context=self.obj_context,
1193 name="{0}[{1}] ".format(self.obj_name, count),
1194 **self.target_args)
1195
1196 item_size = item.obj_size
1197 if item_size <= 0:
1198 break
1199
1200 offset += item_size
1201 count += 1
1202
1203 yield item
1204
1206 for index, item in enumerate(self):
1207 if index == int(pos):
1208 return item
1209
1210 return NoneObject("Pos seems to be outside the array maximum_size.")
1211
1214 """A mixin providing comparison operators for its base offset."""
1215
1225
1228
1231
1234
1237
1240
1243
1244
1245 -class Struct(BaseAddressComparisonMixIn, BaseObject):
1246 """ A Struct is an object which represents a c struct
1247
1248 Structs have members at various fixed relative offsets from our own base
1249 offset.
1250 """
1251
1252 - def __init__(self, members=None, struct_size=0, callable_members=None,
1253 **kwargs):
1254 """ This must be instantiated with a dict of members. The keys
1255 are the offsets, the values are Curried Object classes that
1256 will be instantiated when accessed.
1257
1258 Args:
1259 members: A dict of callables to use for retrieving each member. (Key
1260 is member name, value is a callable). Normally these are populated
1261 by the profile system
1262
1263 struct_size: The size of this struct if known (Can be None).
1264 """
1265 super(Struct, self).__init__(**kwargs)
1266 ACCESS_LOG.LogFieldAccess(self.obj_profile.name, self.obj_type, None)
1267
1268 self.members = members or {}
1269 self.callable_members = callable_members or {}
1270 self.struct_size = struct_size
1271 self._cache = {}
1272
1275
1276 @utils.safe_property
1278 return ("%s(%#x, vm=%s@%s)" % (
1279 self.obj_type,
1280 self.obj_offset,
1281 self.obj_vm.vtop(self.obj_offset),
1282 self.obj_vm.base,
1283 ),)
1284
1286 return self.obj_offset
1287
1289 """Return our offset as an integer.
1290
1291 This allows us to interchange Struct and offsets.
1292 """
1293 return self.obj_offset
1294
1296 """The number of bytes before the object which are part of the object.
1297
1298 Some objects are preceeded with data before obj_offset which is still
1299 considered part of the object. Note that in that case the size of the
1300 object includes the preamble_size - hence
1301
1302 object_end = obj_offset + obj_size - obj.preamble_size()
1303 """
1304 return 0
1305
1306 @utils.safe_property
1308 if callable(self.struct_size):
1309
1310
1311 return self.struct_size(self) or 0
1312
1313 return self.struct_size
1314
1316 if self.obj_offset == 0 and self.obj_name == "Prototype":
1317 return "%s Prototype" % self.__class__.__name__
1318
1319 return "[{0} {1}] @ 0x{2:08X}".format(
1320 self.obj_type, self.obj_name or '', self.obj_offset)
1321
1323 result = self.__repr__() + "\n"
1324 width_name = 0
1325
1326 fields = []
1327
1328 for k in set(self.members).union(self.callable_members):
1329 width_name = max(width_name, len(k))
1330 obj = getattr(self, k)
1331 if obj == None:
1332 obj = self.m(k)
1333
1334 fields.append(
1335 (getattr(obj, "obj_offset", self.obj_offset) -
1336 self.obj_offset, k, utils.SmartUnicode(repr(obj))))
1337
1338 fields.sort()
1339
1340 return result + u"\n".join(
1341 [u" 0x%02X %s%s %s" % (offset, k, " " * (width_name - len(k)), v)
1342 for offset, k, v in fields]) + "\n"
1343
1344 - def v(self, vm=None):
1345 """ When a struct is evaluated we just return our offset.
1346 """
1347 return self.obj_offset
1348
1349 - def m(self, attr, allow_callable_attributes=False):
1350 """Fetch the member named by attr.
1351
1352 NOTE: When the member does not exist in this struct, we return a
1353 NoneObject instance. This allows one to write code such as:
1354
1355 struct.m("Field1") or struct.m("Field2") struct.m("Field2")
1356
1357 To access a field which has been renamed in different OS versions.
1358
1359 By default this method does not allow callable methods specified in
1360 overlays. This is to enable overriding of normal struct members by
1361 callable properties (otherwise infinite recursion might occur). If you
1362 really want to call overlays, specify allow_callable_attributes as True.
1363 """
1364
1365
1366 result = self._cache.get(attr)
1367 if result is not None:
1368 return result
1369
1370
1371 if "." in attr:
1372 result = self
1373 for sub_attr in attr.split("."):
1374 if allow_callable_attributes:
1375 result = getattr(result, sub_attr, None)
1376 if result is None:
1377 result = NoneObject("Attribute %s not found in %s",
1378 sub_attr, self.obj_type)
1379 else:
1380 result = result.m(sub_attr)
1381 self._cache[attr] = result
1382 return result
1383
1384 element = self.members.get(attr)
1385 if element is not None:
1386
1387
1388 if callable(element):
1389 return element(self)
1390
1391 offset, cls = element
1392 else:
1393 return NoneObject(u"Struct {0} has no member {1}",
1394 self.obj_name, attr)
1395
1396 if callable(offset):
1397
1398
1399 offset = int(offset(self))
1400 else:
1401
1402 offset = int(offset) + int(self.obj_offset)
1403
1404 try:
1405 result = cls(offset=offset, vm=self.obj_vm, parent=self, name=attr,
1406 profile=self.obj_profile, context=self.obj_context)
1407 except Error as e:
1408 result = NoneObject(str(e))
1409
1410 self._cache[attr] = result
1411 return result
1412
1413 - def multi_m(self, *args, **opts):
1414 """Retrieve a set of fields in order.
1415
1416 If a field is not found, then try the next field in the list until one
1417 field works. This approach allows us to propose a set of possible fields
1418 for an attribute to support renaming of struct fields in different
1419 versions.
1420 """
1421 allow_callable_attributes = opts.pop("allow_callable_attributes", True)
1422 for field in args:
1423 result = self.m(
1424 field, allow_callable_attributes=allow_callable_attributes)
1425 if result != None:
1426 return result
1427
1428 return NoneObject("No fields were found.")
1429
1431 result = self.m(attr)
1432 if result == None:
1433 raise AttributeError(attr)
1434
1435 return result
1436
1438 """Write a value to a member."""
1439 member = self.m(attr)
1440
1441 member.write(value)
1442 if not hasattr(member, 'write') or not member.write(value):
1443 raise ValueError("Error writing value to member " + attr)
1444
1445 - def walk_list(self, list_member, include_current=True, deref_as=None):
1446 """Walk a single linked list in this struct.
1447
1448 The current object can be optionally yielded as the first element.
1449
1450 Args:
1451 list_member: The member name which points to the next item in the
1452 list.
1453 """
1454 if include_current:
1455 yield self
1456
1457 seen = set()
1458 seen.add(self.obj_offset)
1459
1460 item = self
1461 while True:
1462 if deref_as:
1463 item = getattr(item, list_member).dereference_as(deref_as)
1464 else:
1465 item = getattr(item, list_member).deref()
1466
1467
1468
1469
1470 if not item or item == 0 or item.obj_offset in seen:
1471 break
1472
1473 seen.add(item.obj_offset)
1474 yield item
1475
1480 """A loader for a section in the profile JSON file.
1481
1482 The profile json serialization contains a number of sections, each has a
1483 well known name (e.g. $CONSTANTS, $FUNCTIONS, $STRUCT). When a profile class
1484 is initialized, it uses a variety of loaders to handle each section in the
1485 profile. This allows more complex sections to be introduced and extended.
1486 """
1487 __metaclass__ = registry.MetaclassRegistry
1488 __abstract = True
1489 order = 100
1490
1495
1540
1543 name = "$CONSTANTS"
1544
1548
1551 name = "$CONSTANT_TYPES"
1552
1554 profile.constant_types.update(constant_types)
1555 return profile
1556
1560
1563 name = "$ENUMS"
1564
1568
1571 name = "$REVENUMS"
1572
1576
1579 name = "$STRUCTS"
1580
1584
1587 """This section specifies a list of profiles to be merged into this one."""
1588 name = "$MERGE"
1589
1598
1600 name = 'dummy'
1601 volatile = False
1602
1605
1608
1609 - def read(self, _, length):
1611
1614 """A collection of types relating to a single compilation unit.
1615
1616 Profiles are usually not instantiated directly. Rather, the profiles are
1617 loaded from the profile repository using the session.LoadProfile() method.
1618 """
1619
1620
1621 overlays = None
1622
1623
1624
1625
1626 vtypes = None
1627
1628
1629 types = None
1630
1631
1632 __metaclass__ = registry.MetaclassRegistry
1633
1634
1635 constants = None
1636
1637
1638
1639 applied_modifications = None
1640
1641
1642 EMPTY_DESCRIPTOR = [0, {}]
1643
1644
1645
1646
1647 METADATA = {}
1648
1649
1650
1651 _metadata = None
1652
1653 @classmethod
1655 """Creates a profile directly from a JSON object.
1656
1657 Args:
1658 data: A data structure of an encoded profile. Described:
1659 http://www.rekall-forensic.com/docs/development.html#_profile_serializations
1660 session: A Session object.
1661 name: The name of the profile.
1662 profile: An optional initial profile to apply the new sections to. If
1663 None we create a new profile instance according to the $METADATA
1664 section.
1665
1666 Returns:
1667 a Profile() instance.
1668
1669 Raises:
1670 IOError if we can not load the profile.
1671
1672 """
1673 if "$METADATA" not in data:
1674 data["$METADATA"] = {}
1675
1676
1677 handlers = []
1678 for section in data:
1679 try:
1680 handlers.append(
1681 ProfileSectionLoader.classes_by_name[section][0])
1682 except KeyError:
1683
1684
1685 session.logging.warn(
1686 "Unable to parse profile section %s", section)
1687
1688
1689 handlers.sort(key=lambda x: x.order)
1690
1691
1692 for handler in handlers:
1693 profile = handler().LoadIntoProfile(
1694 session, profile, data[handler.name])
1695
1696 if profile and name:
1697 profile.name = name
1698 profile.data = data
1699
1700 return profile
1701
1702
1703
1704
1705 COMMON_CLASSES = {'BitField': BitField,
1706 'Pointer': Pointer,
1707 'Pointer32': Pointer32,
1708 'Void': Void,
1709 'void': Void,
1710 'Array': Array,
1711 'PointerArray': PointerArray,
1712 'ListArray': ListArray,
1713 'NativeType': NativeType,
1714 'Struct': Struct}
1715
1716 @classmethod
1718 """Install required types, classes and constants.
1719
1720 This method should be extended by derived classes. It is a class method
1721 to allow other profiles to call this method and install the various
1722 components into their own profiles.
1723 """
1724
1725 profile.add_classes(cls.COMMON_CLASSES)
1726
1727 profile._initialized = True
1728
1729 - def __init__(self, name=None, session=None, metadata=None, **kwargs):
1730 if kwargs:
1731 session.logging.error("Unknown keyword args %s", kwargs)
1732
1733 if name is None:
1734 name = self.__class__.__name__
1735
1736 self._metadata = self.METADATA.copy()
1737 for basecls in reversed(self.__class__.__mro__):
1738 self._metadata.update(getattr(basecls, "METADATA", {}))
1739
1740 self._metadata.update(metadata or {})
1741
1742 self.name = unicode(name)
1743 self.session = session
1744 if session is None:
1745 raise RuntimeError("Session must be specified.")
1746
1747 self.overlays = []
1748 self.vtypes = {}
1749 self.constants = {}
1750
1751
1752
1753 self.constant_types = {}
1754 self.constant_addresses = utils.SortedCollection(key=lambda x: x[0])
1755 self.enums = {}
1756 self.reverse_enums = {}
1757 self.applied_modifications = set()
1758 self.object_classes = {}
1759
1760
1761 self.data = None
1762
1763
1764 self.known_types = set()
1765
1766
1767 self.flush_cache()
1768
1769
1770 self._initialized = False
1771
1773 if not self._initialized:
1774 self.Initialize(self)
1775
1778
1780 """Makes a copy of this profile."""
1781 self.EnsureInitialized()
1782
1783
1784 result = self.__class__(name=self.name, session=self.session)
1785 result.vtypes = self.vtypes.copy()
1786 result.overlays = self.overlays[:]
1787 result.enums = self.enums.copy()
1788 result.reverse_enums = self.reverse_enums.copy()
1789 result.constants = self.constants.copy()
1790 result.constant_types = self.constant_types.copy()
1791 result.constant_addresses = self.constant_addresses.copy()
1792
1793
1794 result.object_classes = self.object_classes.copy()
1795 result._initialized = self._initialized
1796 result.known_types = self.known_types.copy()
1797 result._metadata = self._metadata.copy()
1798
1799
1800 return result
1801
1802 - def merge(self, other):
1822
1835
1840
1843
1848
1853
1858
1860 """Add the classes in the dict to our object classes mapping."""
1861 self.flush_cache()
1862
1863 if classes_dict:
1864 self.object_classes.update(classes_dict)
1865
1866 self.object_classes.update(kwargs)
1867 self.known_types.update(kwargs)
1868
1872
1873 - def add_constants(self, constants=None, constants_are_addresses=False, **_):
1874 """Add the kwargs as constants for this profile."""
1875 self.flush_cache()
1876
1877 for k, v in constants.iteritems():
1878 k = intern(str(k))
1879 self.constants[k] = v
1880 if constants_are_addresses:
1881 try:
1882
1883 address = Pointer.integer_to_address(v)
1884 existing_value = self.constant_addresses.get(address)
1885 if existing_value is None:
1886 self.constant_addresses[address] = k
1887 elif isinstance(existing_value, list):
1888 if k not in existing_value:
1889 existing_value.append(k)
1890 elif existing_value != k:
1891 self.constant_addresses[address] = [
1892 existing_value, k]
1893 except ValueError:
1894 pass
1895
1897 """Add the kwargs as a reverse enum for this profile."""
1898 for k, v in kwargs.iteritems():
1899 self.reverse_enums[intern(str(k))] = intern(str(v))
1900
1902 """Add the kwargs as an enum for this profile."""
1903
1904 for k, v in kwargs.iteritems():
1905 self.enums[intern(str(k))] = enum_definition = {}
1906 for enum, name in v.items():
1907 enum_definition[intern(str(enum))] = name
1908
1910 self.flush_cache()
1911
1912 abstract_types = utils.InternObject(abstract_types)
1913 self.known_types.update(abstract_types)
1914
1915
1916
1917
1918
1919
1920 for k, v in abstract_types.items():
1921 if isinstance(v, list):
1922 self.vtypes[k] = v
1923
1924 else:
1925 original = self.vtypes.get(k, self.EMPTY_DESCRIPTOR)
1926 original[1].update(v[1])
1927 if v[0]:
1928 original[0] = v[0]
1929
1930 self.vtypes[k] = original
1931
1933 """Compile the specific type and ensure it exists in the type cache.
1934
1935 The type_name here is a reference to the vtypes which are loaded into
1936 the profile.
1937 """
1938
1939 self.EnsureInitialized()
1940 if type_name in self.types:
1941 return
1942
1943 original_type_descriptor = type_descriptor = copy.deepcopy(
1944 self.vtypes.get(type_name, self.EMPTY_DESCRIPTOR))
1945
1946 for overlay in self.overlays:
1947 type_overlay = copy.deepcopy(overlay.get(type_name))
1948 type_descriptor = self._apply_type_overlay(
1949 type_descriptor, type_overlay)
1950
1951
1952
1953
1954 if isinstance(type_descriptor, str):
1955 self.compile_type(type_descriptor)
1956 self.types[type_name] = self.types[type_descriptor]
1957 type_descriptor = self.vtypes[type_descriptor]
1958
1959 if type_descriptor == self.EMPTY_DESCRIPTOR:
1960
1961
1962 self.types[type_name] = None
1963
1964 else:
1965
1966 members = {}
1967 callable_members = {}
1968
1969 size, field_description = type_descriptor
1970
1971 for k, v in field_description.items():
1972 k = str(k)
1973
1974
1975
1976
1977 if callable(v):
1978 callable_members[intern(k)] = v
1979
1980
1981
1982 original_v = original_type_descriptor[1].get(k)
1983 if original_v:
1984 members[intern(k)] = (
1985 original_v[0], self.list_to_type(k, original_v[1]))
1986
1987 elif v[0] == None:
1988 self.session.logging.warning(
1989 "%s has no offset in object %s. Check that vtypes "
1990 "has a concrete definition for it.",
1991 k, type_name)
1992 else:
1993 members[intern(str(k))] = (
1994 v[0], self.list_to_type(k, v[1]))
1995
1996
1997 cls = self.object_classes.get(type_name, Struct)
1998
1999 self.types[intern(str(type_name))] = self._make_struct_callable(
2000 cls, type_name, members, size, callable_members)
2001
2004 """Compile the structs class into a callable.
2005
2006 For write support we would like to add a __setattr__ on the struct
2007 classes. However, in python, once there is a __setattr__ method
2008 defined on an object, _EVERY_ setattr() operation on the object will
2009 go through this method - this is a performance killer. Since in this
2010 case we only want to trap accesses to the member fields, we can create
2011 a class with @property methods to get and set the attributes. We then
2012 overlay this class over the original struct class.
2013
2014 The resulting callable will instantiate the derived class (with the
2015 additional properties) over the provided offset.
2016
2017 Note that due to the JIT compiler, this method is called only once when
2018 each Struct object is first accessed, so it is not really
2019 expensive. OTOH the callables we produce here are called many many times
2020 (Each time the object is instantiated, or a field is accessed) and need
2021 to be as fast as possible.
2022 """
2023
2024
2025
2026
2027 properties = dict(callable_members=callable_members.keys())
2028 for name in set(members).union(callable_members):
2029
2030
2031 if hasattr(cls, name):
2032 continue
2033
2034 cb = callable_members.get(name)
2035 value = members.get(name)
2036
2037 getter = None
2038 setter = None
2039
2040
2041
2042
2043 if cb:
2044
2045
2046 def CbGetter(self, cb=cb):
2047 try:
2048 return cb(self)
2049 except Exception as e:
2050 return NoneObject("Failed to run callback %s" % e)
2051
2052 getter = CbGetter
2053
2054 elif value:
2055
2056 getter = lambda self, name=name: self.m(name)
2057 setter = lambda self, v=value, n=name: self.SetMember(n, v)
2058
2059 properties[name] = utils.safe_property(getter, setter, None, name)
2060
2061
2062
2063
2064
2065
2066
2067
2068 derived_cls = type(str(type_name), (cls,), properties)
2069
2070 return Curry(derived_cls,
2071 type_name=type_name, members=members,
2072 callable_members=callable_members, struct_size=size)
2073
2075 """Converts the list expression into a target, target_args notation.
2076
2077 Legacy vtypes use lists to specify the objects. This function is used to
2078 convert from the legacy format to the more accurate modern
2079 format. Hopefully the legacy format can be deprecated at some point.
2080
2081 Args:
2082 typeList: A list of types. e.g. ['pointer64', ['_HMAP_TABLE']]
2083
2084 Returns:
2085 A target, target_args tuple. Target is the class name which should be
2086 instantiated, while target_args is a dict of args to be passed to
2087 this class.
2088 e.g. 'Pointer', {target="_HMAP_TABLE"}
2089 """
2090
2091
2092 if len(typeList) == 1:
2093 target = typeList[0]
2094 target_args = {}
2095
2096
2097
2098 elif typeList[0] == 'pointer' or typeList[0] == 'pointer64':
2099 target = "Pointer"
2100 target_args = self.legacy_field_descriptor(typeList[1])
2101
2102
2103 elif typeList[0] == 'array':
2104 target = "Array"
2105 target_args = self.legacy_field_descriptor(typeList[2])
2106 target_args['count'] = typeList[1]
2107
2108 elif len(typeList) > 2:
2109 self.session.logging.error("Invalid typeList %s" % (typeList,))
2110
2111 else:
2112 target = typeList[0]
2113 target_args = typeList[1]
2114
2115 return dict(target=target, target_args=target_args)
2116
2118 """Parses a specification list and returns a VType object.
2119
2120 This function is a bit complex because we support lots of
2121 different list types for backwards compatibility.
2122
2123 This is the core function which effectively parses the VType language.
2124 """
2125
2126 target_spec = self.legacy_field_descriptor(typeList)
2127
2128
2129 target = target_spec['target']
2130 target_args = target_spec['target_args']
2131
2132
2133
2134 if isinstance(target_args, dict):
2135 return Curry(self.Object, type_name=target, name=name,
2136 **target_args)
2137
2138
2139
2140
2141 elif isinstance(target_args, list):
2142 self.session.logging.warning(
2143 "Deprecated vtype expression %s for member %s, assuming int",
2144 typeList, name)
2145
2146 else:
2147
2148 self.session.logging.warning(
2149 "Unable to find a type for %s, assuming int", typeList)
2150
2151 return Curry(self.Object, type_name='int', name=name)
2152
2154 """Return a prototype of objects of type 'type_name'.
2155
2156 A prototype is a dummy object that looks like a type, but uses data
2157 from the profile to provide a list of members and type information.
2158 """
2159 self.compile_type(type_name)
2160 return self.Object(type_name=type_name, name="Prototype",
2161 vm=DummyAS(self.session))
2162
2172
2177
2184
2186 """Add an overlay to the current overlay stack."""
2187 self.flush_cache()
2188 self.overlays.append(copy.deepcopy(overlay))
2189 self.known_types.update(overlay)
2190
2192 """Update the overlay with the missing information from type.
2193
2194 If overlay has None in any slot it gets applied from vtype.
2195
2196 Args:
2197 type_member: A descriptor for a single type struct. This is always of
2198 the following form:
2199
2200 [StructSize, {
2201 field_name_1: [.... Field descriptor ...],
2202 field_name_2: [.... Field descriptor ...],
2203 }]
2204
2205 overlay: An overlay descriptor for the same type described by
2206 type_member or a callable which will be used to instantiate the
2207 required type.
2208 """
2209
2210 if overlay is None:
2211 return type_member
2212
2213 if type_member is None:
2214 return overlay
2215
2216
2217
2218 if callable(overlay):
2219 return overlay
2220
2221
2222 if isinstance(overlay, basestring):
2223 return overlay
2224
2225
2226 if len(overlay) != 2 or not isinstance(overlay[1], dict):
2227 raise RuntimeError("Overlay error: Invalid overlay %s" % overlay)
2228
2229 if len(type_member) != 2 or not isinstance(type_member[1], dict):
2230 raise RuntimeError("VType error: Invalid type descriptor %s" %
2231 type_member)
2232
2233
2234 if overlay[0] is None:
2235 overlay[0] = type_member[0]
2236
2237
2238 field_overlay = overlay[1]
2239
2240
2241
2242 for k, v in type_member[1].items():
2243 if k not in field_overlay:
2244 field_overlay[k] = v
2245 else:
2246 field_overlay[k] = self._apply_field_overlay(
2247 v, field_overlay[k])
2248
2249 return overlay
2250
2252 """Update the field overlay with the missing information from type.
2253
2254 If the overlay has None in any slot it gets applied from vtype.
2255
2256 Args:
2257 field_member: A field descriptor. This can be of the modern form:
2258
2259 [Offset, [TargetName, dict(arg1=value1, arg2=value2)]]
2260
2261 The second part is termed the field descriptor. If the overlay
2262 specifies a field descriptor it will completely replace the
2263 vtype's descriptor.
2264
2265 Alternatively we also support the legacy form:
2266 [TargetName, [values]]
2267
2268
2269 Note that if the Target name differs we deem the entire field to
2270 be overlayed and replace the entire definition with the overlayed
2271 one.
2272
2273 field_overlay: Can be a field descriptor as above, or a callable - in
2274 which case this field member will be called when the field is
2275 accessed.
2276 """
2277
2278 if field_overlay is None:
2279 return field_member
2280
2281 if callable(field_overlay):
2282 return field_overlay
2283
2284 if callable(field_member):
2285 return field_member
2286
2287
2288 if len(field_overlay) != 2 or not isinstance(field_overlay[1], list):
2289 raise RuntimeError(
2290 "Overlay error: Invalid overlay %s" % field_overlay)
2291
2292 if len(field_member) != 2 or not isinstance(field_member[1], list):
2293 raise RuntimeError("VType error: Invalid field type descriptor %s" %
2294 field_member)
2295
2296 offset, field_description = field_member
2297 if field_overlay[0] is None:
2298 field_overlay[0] = offset
2299
2300 if field_overlay[1] is None:
2301 field_overlay[1] = field_description
2302
2303 return field_overlay
2304
2306 """Retrieve a constant from the profile.
2307
2308 Args:
2309 constant: The name of the constant to retrieve.
2310
2311 is_address: If true the constant is converted to an address.
2312 """
2313 ACCESS_LOG.LogConstant(self.name, constant)
2314 self.EnsureInitialized()
2315
2316 result = self.constants.get(constant)
2317 if callable(result):
2318 result = result()
2319
2320 if result is None:
2321 result = NoneObject(
2322 "Constant %s does not exist in profile." % constant)
2323
2324 elif is_address:
2325 result = Pointer.integer_to_address(result)
2326
2327 return result
2328
2329 - def get_constant_object(self, constant, target=None, target_args=None,
2330 vm=None, **kwargs):
2331 """A help function for retrieving pointers from the symbol table."""
2332 self.EnsureInitialized()
2333
2334 if vm is None:
2335 vm = self.session.GetParameter("default_address_space")
2336
2337 if target is None:
2338 if constant not in self.constant_types:
2339 raise TypeError("Unknown constant type for %s" % constant)
2340
2341
2342 try:
2343 target, target_args = self.constant_types[constant]
2344 except ValueError:
2345 target = self.constant_types[constant][0]
2346
2347 kwargs.update(target_args or {})
2348 offset = self.get_constant(constant, is_address=True)
2349 if not offset:
2350 return offset
2351
2352 result = self.Object(target, profile=self, offset=offset, vm=vm,
2353 **kwargs)
2354 return result
2355
2366
2387
2388 - def get_enum(self, enum_name, field=None):
2389 result = self.enums.get(enum_name)
2390 if result and field != None:
2391 result = result.get(field)
2392 return result
2393
2395 result = self.reverse_enums.get(enum_name)
2396 if result and field != None:
2397 result = result.get(field)
2398 return result
2399
2401 """Support tab completion."""
2402 return sorted(self.__dict__.keys() + list(self.known_types) +
2403 dir(self.__class__))
2404
2406 """Make it easier to instantiate individual members.
2407
2408 This method makes it possible to use the form:
2409
2410 self.profile._EPROCESS(vm=self.kernel_address_space, offset=X)
2411
2412 Which is easier to type and works well with attribute completion
2413 (provided by __dir__).
2414 """
2415 self.compile_type(attr)
2416
2417 if self.types[attr] is None and attr not in self.object_classes:
2418 raise AttributeError("No such vtype: %s" % attr)
2419
2420 return Curry(self.Object, attr)
2421
2422 - def Object(self, type_name=None, offset=None, vm=None, name=None,
2423 parent=None, context=None, **kwargs):
2424 """ A function which instantiates the object named in type_name (as
2425 a string) from the type in profile passing optional args of
2426 kwargs.
2427
2428 Args:
2429 type_name: The name of the Struct to instantiate (e.g. _EPROCESS).
2430
2431 vm: The address space to instantiate the object onto. If not provided
2432 we use a dummy null padded address space.
2433
2434 offset: The location in the address space where the object is
2435 instantiated.
2436
2437 name: An optional name for the object.
2438
2439 context: An opaque dict which is passed to all objects created from
2440 this object.
2441
2442 parent: The object can maintain a reference to its parent object.
2443 """
2444 name = name or type_name
2445
2446
2447 if name.__class__ not in (unicode, str):
2448 raise ValueError("Type name must be a string")
2449
2450 if offset is None:
2451 offset = 0
2452 if vm is None:
2453 vm = addrspace.BaseAddressSpace.classes["DummyAddressSpace"](
2454 size=self.get_obj_size(name) or 0, session=self.session)
2455
2456 else:
2457 offset = int(offset)
2458 if vm is None:
2459 vm = self.session.GetParameter("default_address_space")
2460
2461 kwargs['profile'] = self
2462 kwargs.setdefault("session", self.session)
2463
2464
2465 self.compile_type(type_name)
2466
2467
2468
2469 cls = self.types[type_name]
2470 if cls is not None:
2471 result = cls(offset=offset, vm=vm, name=name,
2472 parent=parent, context=context,
2473 **kwargs)
2474
2475 return result
2476
2477 elif type_name in self.object_classes:
2478 result = self.object_classes[type_name](
2479 type_name=type_name,
2480 offset=offset,
2481 vm=vm,
2482 name=name,
2483 parent=parent,
2484 context=context,
2485 **kwargs)
2486
2487 if isinstance(result, Struct):
2488
2489 self.session.logging.error(
2490 "Instantiating a Struct class %s without an overlay. "
2491 "Please ensure an overlay is defined.", type_name)
2492
2493 return result
2494
2495 else:
2496
2497 return NoneObject("Cant find object %s in profile %s?",
2498 type_name, self)
2499
2501 return u"<%s profile %s (%s)>" % (
2502 self.metadata("arch"), self.name, self.__class__.__name__)
2503
2505 return unicode(self)
2506
2508 return virtual_address & self.constants.get(
2509 "MaxPointer", 0xffffffffffff)
2510
2514 """Let the test manipulate the data json object directly."""
2515 self.data = data
2516
2522
2525 """A profile modification adds new types to an existing profile.
2526
2527 A ProfileModification must be invoked explicitely. We have these as plugins
2528 so its easier to find a modification by name. A typical invokation looks
2529 like:
2530
2531 class myPlugin(plugin.Command):
2532 def __init__(self, **kwargs):
2533 super(myPlugin, self).__init__(**kwargs)
2534
2535 # Update the profile with the "VolRegistrySupport" implementation.
2536 self.profile = obj.ProfileModification.classes[
2537 'VolRegistrySupport'](self.profile)
2538
2539 Note that this plugin must explicitely apply the correct modification. This
2540 allows the plugin to choose from a number of different implementations. For
2541 example, in the above say we have one implementation (i.e. overlays, object
2542 classes etc) called VolRegistrySupport and another called
2543 ScudetteRegistrySupport, we can choose between them.
2544
2545 Now suppose that ScudetteRegistrySupport introduces an advanced class with
2546 extra methods:
2547
2548 class _CM_KEY_INDEX(obj.Struct):
2549 .....
2550 def SpecialMethod(...):
2551 ....
2552
2553 The plugin relies on using this specific implementation (i.e. if we loaded
2554 the other profile modification, this myPlugin will fail because it will
2555 attempt to call an undefined method! Essentially by explicitely loading the
2556 modification, the plugin declares that it relies on the
2557 ScudetteRegistrySupport implementation, but does not preclude having another
2558 implementation.
2559 """
2561
2562 result = profile.copy()
2563
2564
2565 cls.modify(result)
2566
2567 return result
2568
2569 @classmethod
2571 """This class should modify the profile appropritately.
2572
2573 The profile will be a copy of the original profile and will be returned
2574 to the class caller.
2575
2576 Args:
2577 A profile to be modified.
2578 """
2579
2582 """A BaseObject representing an address."""
2583