1import operator 2 3from abc import ABCMeta, abstractmethod 4from core import ( 5 caching, 6 gettype, 7) 8 9from .kmem import KMem, MemoryRange 10 11 12class MemoryObject(object, metaclass=ABCMeta): 13 """ 14 Abstract class for any memory object resolved by Whatis 15 """ 16 17 MO_KIND = None 18 19 def __init__(self, kmem, address): 20 self.kmem = kmem 21 self.address = address 22 23 @property 24 @abstractmethod 25 def object_range(self): 26 """ 27 Returns the MemoryRange for this object if any 28 """ 29 pass 30 31 @abstractmethod 32 def describe(self, verbose=False): 33 """ 34 Method to describe oneself for whatis 35 """ 36 pass 37 38 39class UnknownMemoryObject(MemoryObject): 40 """ Fallback Memory Object for unclaimed addresses """ 41 42 MO_KIND = "<unknown>" 43 44 @property 45 def object_range(self): 46 return None 47 48 def describe(self, verbose=False): 49 print("Unknown Memory Object Info") 50 print(" this address is not recognized, please implement/extend") 51 print(" a WhatisProvider to recognize it in the future") 52 print() 53 54 55class WhatisProvider(object): 56 """ Base class for Whatis Providers """ 57 58 """ 59 List of direct subclasses, used for resolution 60 """ 61 subproviders = [] 62 63 """ 64 Evaluation cost of this provider 65 66 the higher the cost, the later it gets evaluated. 67 """ 68 69 COST = 10 70 71 def __init__(self, target): 72 self._children = list(cls(target) for cls in self.__class__.subproviders) 73 self.kmem = KMem.get_shared() 74 self.target = target 75 76 @staticmethod 77 @caching.cache_statically 78 def get_shared(target=None): 79 return WhatisProvider(target) 80 81 def find_provider(self, address): 82 return next(iter(c for c in self._children if c.claims(address)), self) 83 84 def claims(self, address): 85 """ 86 Returns whether this provider "claims" the address 87 88 @param address (int) 89 The addrress being considered 90 """ 91 92 pass 93 94 def lookup(self, address): 95 """ 96 Lookup a memory object by address 97 98 @param address (int) 99 The addrress being considered 100 101 @returns (MemoryObject) 102 """ 103 104 return UnknownMemoryObject(self.kmem, address) 105 106 def describe(self, mo): 107 """ 108 Describe a memory object 109 110 Providers can override this method to add more information. 111 """ 112 113 print(( 114 "Basic Info\n" 115 " kind : {0.__class__.MO_KIND}\n" 116 " address : {0.address:#x}" 117 ).format(mo)) 118 119 mem_r = mo.object_range 120 if mem_r is None: 121 print(" {:<21s}: Unknown".format("object range")) 122 else: 123 print(" {:<21s}: {r.start:#x} - {r.end:#x} ({r.size:,d} bytes)".format( 124 "object range", r = mem_r)) 125 address = mo.address 126 if address != mem_r.start: 127 print(" {:<21s}: {:,d} from start, {:,d} to end".format( 128 "offset", address - mem_r.start, mem_r.end - address)) 129 130 print() 131 132 133def whatis_provider(cls): 134 """ 135 Class decorator for Whatis providers 136 """ 137 138 if not issubclass(cls, WhatisProvider): 139 raise TypeError("{} is not a subclass of WhatisProvider".format(cls.__name__)) 140 141 cls.subproviders = [] 142 base = cls.__base__ 143 144 if base != object: 145 k = next(( 146 k for k in ['claims', 'lookup'] 147 if getattr(cls, k) == getattr(base, k) 148 ), None) 149 if k: 150 raise TypeError("{} must reimplement function '{}'".format(cls.__name__, k)) 151 152 base.subproviders.append(cls) 153 base.subproviders.sort(key=operator.attrgetter('COST')) 154 155 return cls 156 157 158__all__ = [ 159 whatis_provider.__name__, 160 161 MemoryObject.__name__, 162 WhatisProvider.__name__, 163] 164