1 2""" Please make sure you read the README COMPLETELY BEFORE reading anything below. 3 It is very critical that you read coding guidelines in Section E in README file. 4""" 5 6from cvalue import * 7from lazytarget import * 8from configuration import * 9import caching 10import lldb 11 12def IterateTAILQ_HEAD(headval, element_name): 13 """ iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h 14 params: 15 headval - value : value object representing the head of the list 16 element_name- str : string name of the field which holds the list links. 17 returns: 18 A generator does not return. It is used for iterating. 19 value : an object that is of type as headval->tqh_first. Always a pointer object 20 example usage: 21 list_head = kern.GetGlobalVariable('mountlist') 22 for entryobj in IterateTAILQ_HEAD(list_head, 'mnt_list'): 23 print GetEntrySummary(entryobj) 24 """ 25 iter_val = headval.tqh_first 26 while unsigned(iter_val) != 0 : 27 yield iter_val 28 iter_val = iter_val.__getattr__(element_name).tqe_next 29 #end of yield loop 30 31def IterateLinkedList(element, field_name): 32 """ iterate over a linked list. 33 This is equivalent to elt = element; while(elt) { do_work(elt); elt = elt-><field_name>; } 34 params: 35 element - value : value object representing element in the list. 36 field_name - str : name of field that holds pointer to next element 37 returns: Nothing. This is used as iterable 38 example usage: 39 first_zone = kern.GetGlobalVariable('first_zone') 40 for zone in IterateLinkedList(first_zone, 'next_zone'): 41 print GetZoneSummary(zone) 42 """ 43 elt = element 44 while unsigned(elt) != 0: 45 yield elt 46 elt = elt.__getattr__(field_name) 47 #end of while loop 48 49def IterateListEntry(element, element_type, field_name): 50 """ iterate over a list as defined with LIST_HEAD in bsd/sys/queue.h 51 params: 52 element - value : Value object for lh_first 53 element_type - str : Type of the next element 54 field_name - str : Name of the field in next element's structure 55 returns: 56 A generator does not return. It is used for iterating 57 value : an object thats of type (element_type) head->le_next. Always a pointer object 58 example usage: 59 headp = kern.globals.initproc.p_children 60 for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'): 61 print GetProcInfo(pp) 62 """ 63 elt = element.lh_first 64 if type(element_type) == str: 65 element_type = gettype(element_type) 66 while unsigned(elt) != 0: 67 yield elt 68 next_el = elt.__getattr__(field_name).le_next 69 elt = cast(next_el, element_type) 70 71def IterateQueue(queue_head, element_ptr_type, element_field_name): 72 """ iterate over a queue in kernel of type queue_head_t. refer to osfmk/kern/queue.h 73 params: 74 queue_head - value : Value object for queue_head. 75 element_ptr_type - lldb.SBType : a pointer type of the element 'next' points to. Typically its structs like thread, task etc.. 76 - str : OR a string describing the type. ex. 'task *' 77 element_field_name - str : name of the field in target struct. 78 returns: 79 A generator does not return. It is used for iterating. 80 value : an object thats of type (element_type) queue_head->next. Always a pointer object 81 """ 82 if type(element_ptr_type) == str : 83 element_ptr_type = gettype(element_ptr_type) 84 85 queue_head = queue_head.GetSBValue() 86 queue_head_addr = 0x0 87 if queue_head.TypeIsPointerType(): 88 queue_head_addr = queue_head.GetValueAsUnsigned() 89 else: 90 queue_head_addr = queue_head.GetAddress().GetLoadAddress(LazyTarget.GetTarget()) 91 cur_elt = queue_head.GetChildMemberWithName('next') 92 while True: 93 94 if not cur_elt.IsValid() or cur_elt.GetValueAsUnsigned() == 0 or cur_elt.GetValueAsUnsigned() == queue_head_addr: 95 break 96 elt = cur_elt.Cast(element_ptr_type) 97 yield value(elt) 98 cur_elt = elt.GetChildMemberWithName(element_field_name).GetChildMemberWithName('next') 99 100 101 102class KernelTarget(object): 103 """ A common kernel object that provides access to kernel objects and information. 104 The class holds global lists for task, terminated_tasks, procs, zones, zombroc etc. 105 It also provides a way to symbolicate an address or create a value from an address. 106 """ 107 def __init__(self, debugger): 108 """ Initialize the kernel debugging environment. 109 Target properties like architecture and connectedness are lazy-evaluted. 110 """ 111 self._debugger = debugger # This holds an lldb.SBDebugger object for debugger state 112 self._threads_list = [] 113 self._tasks_list = [] 114 self._allproc = [] 115 self._terminated_tasks_list = [] 116 self._zones_list = [] 117 self._zombproc_list = [] 118 self._kernel_types_cache = {} #this will cache the Type objects as and when requested. 119 self._version = None 120 self._arch = None 121 self._ptrsize = None # pointer size of kernel, not userspace 122 self.symbolicator = None 123 class _GlobalVariableFind(object): 124 def __init__(self, kern): 125 self._xnu_kernobj_12obscure12 = kern 126 def __getattr__(self, name): 127 v = self._xnu_kernobj_12obscure12.GetGlobalVariable(name) 128 if not v.GetSBValue().IsValid(): 129 raise ValueError('no such global variable by name: %s '%str(name)) 130 return v 131 self.globals = _GlobalVariableFind(self) 132 LazyTarget.Initialize(debugger) 133 134 def _GetSymbolicator(self): 135 """ Internal function: To initialize the symbolication from lldb.utils 136 """ 137 if not self.symbolicator is None: 138 return self.symbolicator 139 140 from lldb.utils import symbolication 141 symbolicator = symbolication.Symbolicator() 142 symbolicator.target = LazyTarget.GetTarget() 143 self.symbolicator = symbolicator 144 return self.symbolicator 145 146 def Symbolicate(self, addr): 147 """ simple method to get name of function/variable from an address. this is equivalent of gdb 'output /a 0xaddress' 148 params: 149 addr - int : typically hex value like 0xffffff80002c0df0 150 returns: 151 str - '' if no symbol found else the symbol name. 152 Note: this function only finds the first symbol. If you expect multiple symbol conflict please use SymbolicateFromAddress() 153 """ 154 ret_str = '' 155 syms = self.SymbolicateFromAddress(addr) 156 if len(syms) > 0: 157 ret_str +=syms[0].GetName() 158 return ret_str 159 160 def SymbolicateFromAddress(self, addr): 161 """ symbolicates any given address based on modules loaded in the target. 162 params: 163 addr - int : typically hex value like 0xffffff80002c0df0 164 returns: 165 [] of SBSymbol: In case we don't find anything than empty array is returned. 166 Note: a type of symbol can be figured out by gettype() function of SBSymbol. 167 example usage: 168 syms = kern.Symbolicate(0xffffff80002c0df0) 169 for s in syms: 170 if s.GetType() == lldb.eSymbolTypeCode: 171 print "Function", s.GetName() 172 if s.GetType() == lldb.eSymbolTypeData: 173 print "Variable", s.GetName() 174 """ 175 if type(int(1)) != type(addr): 176 if str(addr).strip().find("0x") == 0 : 177 addr = int(addr, 16) 178 else: 179 addr = int(addr) 180 ret_array = [] 181 symbolicator = self._GetSymbolicator() 182 syms = symbolicator.symbolicate(addr) 183 if not syms: 184 return ret_array 185 for s in syms: 186 ret_array.append(s.get_symbol_context().symbol) 187 return ret_array 188 189 def IsDebuggerConnected(self): 190 proc_state = LazyTarget.GetProcess().state 191 if proc_state == lldb.eStateInvalid : return False 192 if proc_state in [lldb.eStateStopped, lldb.eStateSuspended] : return True 193 194 def GetGlobalVariable(self, name): 195 """ Get the value object representation for a kernel global variable 196 params: 197 name : str - name of the variable. ex. version 198 returns: value - python object representing global variable. 199 raises : Exception in case the variable is not found. 200 """ 201 return value(LazyTarget.GetTarget().FindGlobalVariables(name, 0).GetValueAtIndex(0)) 202 203 def GetLoadAddressForSymbol(self, name): 204 """ Get the load address of a symbol in the kernel. 205 params: 206 name : str - name of the symbol to lookup 207 returns: int - the load address as an integer. Use GetValueFromAddress to cast to a value. 208 raises : LookupError - if the symbol is not found. 209 """ 210 name = str(name) 211 target = LazyTarget.GetTarget() 212 syms_arr = target.FindSymbols(name) 213 if syms_arr.IsValid() and len(syms_arr) > 0: 214 symbol = syms_arr[0].GetSymbol() 215 if symbol.IsValid(): 216 return int(symbol.GetStartAddress().GetLoadAddress(target)) 217 218 raise LookupError("Symbol not found: " + name) 219 220 def GetValueFromAddress(self, addr, type_str = 'void *'): 221 """ convert a address to value 222 params: 223 addr - int : typically hex value like 0xffffff80008dc390 224 type_str - str: type to cast to. Default type will be void * 225 returns: 226 value : a value object which has address as addr and type is type_str 227 """ 228 obj = value(self.globals.version.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr))) 229 obj = cast(obj, type_str) 230 return obj 231 232 def GetValueAsType(self, v, t): 233 """ Retrieves a global variable 'v' of type 't' wrapped in a vue object. 234 If 'v' is an address, creates a vue object of the appropriate type. 235 If 'v' is a name, looks for the global variable and asserts its type. 236 Throws: 237 NameError - If 'v' cannot be found 238 TypeError - If 'v' is of the wrong type 239 """ 240 if islong(v): 241 return self.GetValueFromAddress(v, t) 242 else: 243 var = LazyTarget.GetTarget().FindGlobalVariables(v, 1)[0] 244 if not var: 245 raise NameError("Failed to find global variable '{0}'".format(v)) 246 if var.GetTypeName() != t: 247 raise TypeError("{0} must be of type '{1}', not '{2}'".format(v, t, var.GetTypeName())) 248 return value(var) 249 250 def _GetIterator(self, iter_head_name, next_element_name='next', iter_head_type=None): 251 """ returns an iterator for a collection in kernel memory. 252 params: 253 iter_head_name - str : name of queue_head or list head variable. 254 next_element_name - str : name of the element that leads to next element. 255 for ex. in struct zone list 'next_zone' is the linking element. 256 returns: 257 iterable : typically used in conjunction with "for varname in iterable:" 258 """ 259 head_element = self.GetGlobalVariable(iter_head_name) 260 return head_element.GetSBValue().linked_list_iter(next_element_name) 261 262 def TruncPage(self, addr): 263 return (addr & ~(unsigned(self.GetGlobalVariable("page_size")) - 1)) 264 265 def RoundPage(self, addr): 266 return trunc_page(addr + unsigned(self.GetGlobalVariable("page_size")) - 1) 267 268 def StraddlesPage(self, addr, size): 269 if size > unsigned(self.GetGlobalVariable("page_size")): 270 return True 271 return (((addr + size) & (unsigned(self.GetGlobalVariable("page_size"))-1)) < size) 272 273 def PhysToKernelVirt(self, addr): 274 if self.arch == 'x86_64': 275 return (addr + unsigned(self.GetGlobalVariable('physmap_base'))) 276 elif self.arch == 'arm': 277 return (addr - unsigned(self.GetGlobalVariable("gPhysBase")) + unsigned(self.GetGlobalVariable("gVirtBase"))) 278 else: 279 raise ValueError("PhysToVirt does not support {0}".format(arch)) 280 281 def __getattribute__(self, name): 282 if name == 'zones' : 283 self._zones_list = caching.GetDynamicCacheData("kern._zones_list", []) 284 if len(self._zones_list) > 0: return self._zones_list 285 first_zone = self.GetGlobalVariable('first_zone') 286 for z in IterateLinkedList(first_zone, 'next_zone'): 287 self._zones_list.append(z) 288 caching.SaveDynamicCacheData("kern._zones_list", self._zones_list) 289 return self._zones_list 290 291 if name == 'threads' : 292 self._threads_list = caching.GetDynamicCacheData("kern._threads_list", []) 293 if len(self._threads_list) > 0 : return self._threads_list 294 thread_queue_head = self.GetGlobalVariable('threads') 295 thread_type = LazyTarget.GetTarget().FindFirstType('thread') 296 thread_ptr_type = thread_type.GetPointerType() 297 for th in IterateQueue(thread_queue_head, thread_ptr_type, 'threads'): 298 self._threads_list.append(th) 299 caching.SaveDynamicCacheData("kern._threads_list", self._threads_list) 300 return self._threads_list 301 302 if name == 'tasks' : 303 self._tasks_list = caching.GetDynamicCacheData("kern._tasks_list", []) 304 if len(self._tasks_list) > 0 : return self._tasks_list 305 task_queue_head = self.GetGlobalVariable('tasks') 306 task_type = LazyTarget.GetTarget().FindFirstType('task') 307 task_ptr_type = task_type.GetPointerType() 308 for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'): 309 self._tasks_list.append(tsk) 310 caching.SaveDynamicCacheData("kern._tasks_list", self._tasks_list) 311 return self._tasks_list 312 313 if name == 'terminated_tasks' : 314 self._terminated_tasks_list = caching.GetDynamicCacheData("kern._terminated_tasks_list", []) 315 if len(self._terminated_tasks_list) > 0 : return self._terminated_tasks_list 316 task_queue_head = self.GetGlobalVariable('terminated_tasks') 317 task_type = LazyTarget.GetTarget().FindFirstType('task') 318 task_ptr_type = task_type.GetPointerType() 319 for tsk in IterateQueue(task_queue_head, task_ptr_type, 'tasks'): 320 self._terminated_tasks_list.append(tsk) 321 caching.SaveDynamicCacheData("kern._terminated_tasks_list", self._terminated_tasks_list) 322 return self._terminated_tasks_list 323 324 if name == 'procs' : 325 self._allproc = caching.GetDynamicCacheData("kern._allproc", []) 326 if len(self._allproc) > 0 : return self._allproc 327 all_proc_head = self.GetGlobalVariable('allproc') 328 proc_val = cast(all_proc_head.lh_first, 'proc *') 329 while proc_val != 0: 330 self._allproc.append(proc_val) 331 proc_val = cast(proc_val.p_list.le_next, 'proc *') 332 caching.SaveDynamicCacheData("kern._allproc", self._allproc) 333 return self._allproc 334 335 if name == 'zombprocs' : 336 self._zombproc_list = caching.GetDynamicCacheData("kern._zombproc_list", []) 337 if len(self._zombproc_list) > 0 : return self._zombproc_list 338 zproc_head = self.GetGlobalVariable('zombproc') 339 proc_val = cast(zproc_head.lh_first, 'proc *') 340 while proc_val != 0: 341 self._zombproc_list.append(proc_val) 342 proc_val = cast(proc_val.p_list.le_next, 'proc *') 343 caching.SaveDynamicCacheData("kern._zombproc_list", self._zombproc_list) 344 return self._zombproc_list 345 346 if name == 'version' : 347 self._version = caching.GetStaticCacheData("kern.version", None) 348 if self._version != None : return self._version 349 self._version = str(self.GetGlobalVariable('version')) 350 caching.SaveStaticCacheData("kern.version", self._version) 351 return self._version 352 353 if name == 'arch' : 354 self._arch = caching.GetStaticCacheData("kern.arch", None) 355 if self._arch != None : return self._arch 356 arch = LazyTarget.GetTarget().triple.split('-')[0] 357 if arch in ('armv7', 'armv7s'): 358 self._arch = 'arm' 359 else: 360 self._arch = arch 361 caching.SaveStaticCacheData("kern.arch", self._arch) 362 return self._arch 363 364 if name == 'ptrsize' : 365 self._ptrsize = caching.GetStaticCacheData("kern.ptrsize", None) 366 if self._ptrsize != None : return self._ptrsize 367 arch = LazyTarget.GetTarget().triple.split('-')[0] 368 if arch in ('x86_64'): 369 self._ptrsize = 8 370 else: 371 self._ptrsize = 4 372 caching.SaveStaticCacheData("kern.ptrsize", self._ptrsize) 373 return self._ptrsize 374 375 return object.__getattribute__(self, name) 376 377