1*19c3b8c2SApple OSS Distributionsfrom __future__ import absolute_import, division 2*19c3b8c2SApple OSS Distributions 3*19c3b8c2SApple OSS Distributionsfrom builtins import hex 4*19c3b8c2SApple OSS Distributions 5*19c3b8c2SApple OSS Distributionsfrom builtins import object 6*19c3b8c2SApple OSS Distributionsimport logging 7*19c3b8c2SApple OSS Distributionsfrom . import target 8*19c3b8c2SApple OSS Distributionsimport struct 9*19c3b8c2SApple OSS Distributions 10*19c3b8c2SApple OSS Distributionsfrom xnu import * 11*19c3b8c2SApple OSS Distributionsfrom core.operating_system import Armv8_RegisterSet, Armv7_RegisterSet, I386_RegisterSet, X86_64RegisterSet 12*19c3b8c2SApple OSS Distributionsfrom core import caching 13*19c3b8c2SApple OSS Distributions 14*19c3b8c2SApple OSS Distributions""" these defines should come from an authoritative header file """ 15*19c3b8c2SApple OSS DistributionsCPU_TYPE_I386 = 0x00000007 16*19c3b8c2SApple OSS DistributionsCPU_TYPE_X86_64 = 0x01000007 17*19c3b8c2SApple OSS DistributionsCPU_TYPE_ARM = 0x0000000c 18*19c3b8c2SApple OSS DistributionsCPU_TYPE_ARM64 = 0x0100000c 19*19c3b8c2SApple OSS DistributionsCPU_TYPE_ARM64_32 = 0x0200000c 20*19c3b8c2SApple OSS Distributions 21*19c3b8c2SApple OSS Distributionsdef GetRegisterSetForCPU(cputype, subtype): 22*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_ARM64: 23*19c3b8c2SApple OSS Distributions retval = Armv8_RegisterSet 24*19c3b8c2SApple OSS Distributions elif cputype == CPU_TYPE_ARM64_32: 25*19c3b8c2SApple OSS Distributions retval = Armv8_RegisterSet 26*19c3b8c2SApple OSS Distributions elif cputype == CPU_TYPE_ARM: 27*19c3b8c2SApple OSS Distributions retval = Armv7_RegisterSet 28*19c3b8c2SApple OSS Distributions elif cputype == CPU_TYPE_I386: 29*19c3b8c2SApple OSS Distributions retval = I386_RegisterSet 30*19c3b8c2SApple OSS Distributions elif cputype == CPU_TYPE_X86_64: 31*19c3b8c2SApple OSS Distributions retval = X86_64RegisterSet 32*19c3b8c2SApple OSS Distributions 33*19c3b8c2SApple OSS Distributions """ crash if unknown cputype """ 34*19c3b8c2SApple OSS Distributions 35*19c3b8c2SApple OSS Distributions return retval.register_info['registers'] 36*19c3b8c2SApple OSS Distributions 37*19c3b8c2SApple OSS Distributions 38*19c3b8c2SApple OSS Distributionsclass UserThreadObject(object): 39*19c3b8c2SApple OSS Distributions """representation of userspace thread""" 40*19c3b8c2SApple OSS Distributions def __init__(self, thr_obj, cputype, cpusubtype): 41*19c3b8c2SApple OSS Distributions super(UserThreadObject, self).__init__() 42*19c3b8c2SApple OSS Distributions self.thread = thr_obj 43*19c3b8c2SApple OSS Distributions self.registerset = GetRegisterSetForCPU(cputype, cpusubtype) 44*19c3b8c2SApple OSS Distributions self.thread_id = unsigned(self.thread.thread_id) 45*19c3b8c2SApple OSS Distributions self.is64Bit = bool(cputype & 0x01000000) 46*19c3b8c2SApple OSS Distributions 47*19c3b8c2SApple OSS Distributions if self.is64Bit: 48*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_X86_64: 49*19c3b8c2SApple OSS Distributions self.reg_type = "x86_64" 50*19c3b8c2SApple OSS Distributions self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_64 51*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_ARM64: 52*19c3b8c2SApple OSS Distributions self.reg_type = "arm64" 53*19c3b8c2SApple OSS Distributions self.saved_state = self.thread.machine.upcb.uss.ss_64 54*19c3b8c2SApple OSS Distributions else: 55*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_I386: 56*19c3b8c2SApple OSS Distributions self.reg_type = "i386" 57*19c3b8c2SApple OSS Distributions self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_32 58*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_ARM: 59*19c3b8c2SApple OSS Distributions self.reg_type = "arm" 60*19c3b8c2SApple OSS Distributions self.saved_state = self.thread.machine.contextData.ss.uss.ss_32 61*19c3b8c2SApple OSS Distributions if cputype == CPU_TYPE_ARM64_32: 62*19c3b8c2SApple OSS Distributions self.reg_type = "arm64" 63*19c3b8c2SApple OSS Distributions self.saved_state = self.thread.machine.upcb.uss.ss_64 64*19c3b8c2SApple OSS Distributions 65*19c3b8c2SApple OSS Distributions logging.debug("created thread id 0x%x of type %s, cputype 0x%x" 66*19c3b8c2SApple OSS Distributions % (self.thread_id, self.reg_type, cputype)) 67*19c3b8c2SApple OSS Distributions 68*19c3b8c2SApple OSS Distributions def getRegisterValueByName(self, name): 69*19c3b8c2SApple OSS Distributions if self.reg_type == 'arm64': 70*19c3b8c2SApple OSS Distributions if name in ('x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28'): 71*19c3b8c2SApple OSS Distributions return unsigned(getattr(self.saved_state, 'x')[int(name.strip('x'))]) 72*19c3b8c2SApple OSS Distributions 73*19c3b8c2SApple OSS Distributions return unsigned(getattr(self.saved_state, name)) 74*19c3b8c2SApple OSS Distributions 75*19c3b8c2SApple OSS Distributions if self.reg_type == "x86_64": 76*19c3b8c2SApple OSS Distributions if name in ('rip', 'rflags', 'cs', 'rsp', 'cpu'): 77*19c3b8c2SApple OSS Distributions return unsigned(getattr(self.saved_state.isf, name)) 78*19c3b8c2SApple OSS Distributions return unsigned(getattr(self.saved_state, name)) 79*19c3b8c2SApple OSS Distributions 80*19c3b8c2SApple OSS Distributions if self.reg_type == "arm": 81*19c3b8c2SApple OSS Distributions if name in ('r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12'): 82*19c3b8c2SApple OSS Distributions retval = unsigned(getattr(self.saved_state, 'r')[int(name.strip('r'))]) 83*19c3b8c2SApple OSS Distributions else: 84*19c3b8c2SApple OSS Distributions retval = unsigned(getattr(self.saved_state, name)) 85*19c3b8c2SApple OSS Distributions return retval 86*19c3b8c2SApple OSS Distributions 87*19c3b8c2SApple OSS Distributions #TODO for i386 88*19c3b8c2SApple OSS Distributions 89*19c3b8c2SApple OSS Distributions def getName(self): 90*19c3b8c2SApple OSS Distributions return str(self.thread_id) 91*19c3b8c2SApple OSS Distributions 92*19c3b8c2SApple OSS Distributions def getRegisterData(self, reg_num): 93*19c3b8c2SApple OSS Distributions """ returns None if there is error """ 94*19c3b8c2SApple OSS Distributions if reg_num < 0 or reg_num >= len(self.registerset): 95*19c3b8c2SApple OSS Distributions logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, self.thread_id)) 96*19c3b8c2SApple OSS Distributions return None 97*19c3b8c2SApple OSS Distributions return self.getRegisterValueByName(self.registerset[reg_num]['name']) 98*19c3b8c2SApple OSS Distributions 99*19c3b8c2SApple OSS Distributions 100*19c3b8c2SApple OSS Distributionsclass UserProcess(target.Process): 101*19c3b8c2SApple OSS Distributions """ Represent a user process and thread states """ 102*19c3b8c2SApple OSS Distributions def __init__(self, task): 103*19c3b8c2SApple OSS Distributions self.task = task 104*19c3b8c2SApple OSS Distributions self.proc = GetProcFromTask(task) 105*19c3b8c2SApple OSS Distributions if not self.proc: 106*19c3b8c2SApple OSS Distributions raise ValueError("Task has no associated BSD process.") 107*19c3b8c2SApple OSS Distributions dataregisters64bit = False 108*19c3b8c2SApple OSS Distributions ptrsize = 4 109*19c3b8c2SApple OSS Distributions 110*19c3b8c2SApple OSS Distributions if task.t_flags & 0x1: 111*19c3b8c2SApple OSS Distributions ptrsize = 8 112*19c3b8c2SApple OSS Distributions if task.t_flags & 0x2: 113*19c3b8c2SApple OSS Distributions dataregisters64bit = True 114*19c3b8c2SApple OSS Distributions 115*19c3b8c2SApple OSS Distributions self.cputype = unsigned(self.proc.p_cputype) 116*19c3b8c2SApple OSS Distributions self.cpusubtype = unsigned(self.proc.p_cpusubtype) 117*19c3b8c2SApple OSS Distributions 118*19c3b8c2SApple OSS Distributions super(UserProcess, self).__init__(self.cputype, self.cpusubtype, ptrsize) 119*19c3b8c2SApple OSS Distributions dbg_message = "process:%s is64bit:%d ptrsize:%d cputype:0x%x cpusubtype:0x%x" % (hex(self.proc), int(dataregisters64bit), ptrsize, self.cputype, self.cpusubtype) 120*19c3b8c2SApple OSS Distributions self.proc_platform = int(GetProcPlatform(self.proc)) 121*19c3b8c2SApple OSS Distributions if self.proc_platform == xnudefines.P_PLATFORM_MACOS: 122*19c3b8c2SApple OSS Distributions self.hinfo['ostype'] = 'macosx' 123*19c3b8c2SApple OSS Distributions elif self.proc_platform == xnudefines.P_PLATFORM_WATCHOS: 124*19c3b8c2SApple OSS Distributions self.hinfo['ostype'] = 'watchos' 125*19c3b8c2SApple OSS Distributions elif self.proc_platform == xnudefines.P_PLATFORM_TVOS: 126*19c3b8c2SApple OSS Distributions self.hinfo['ostype'] = 'tvos' 127*19c3b8c2SApple OSS Distributions else: 128*19c3b8c2SApple OSS Distributions self.hinfo['ostype'] = 'ios' 129*19c3b8c2SApple OSS Distributions dbg_message += " ostype:%s" % self.hinfo['ostype'] 130*19c3b8c2SApple OSS Distributions 131*19c3b8c2SApple OSS Distributions if str(kern.arch).lower().startswith('arm'): 132*19c3b8c2SApple OSS Distributions addressing_bits = 64 - int(kern.globals.gT1Sz) 133*19c3b8c2SApple OSS Distributions self.hinfo['addressing_bits'] = addressing_bits 134*19c3b8c2SApple OSS Distributions dbg_message += " addressing_bits:%d" % addressing_bits 135*19c3b8c2SApple OSS Distributions 136*19c3b8c2SApple OSS Distributions self.registerset = GetRegisterSetForCPU(self.cputype, self.cpusubtype) 137*19c3b8c2SApple OSS Distributions logging.info(dbg_message) 138*19c3b8c2SApple OSS Distributions self.threads = {} 139*19c3b8c2SApple OSS Distributions self.threads_ids_list = [] 140*19c3b8c2SApple OSS Distributions logging.debug("iterating over threads in process") 141*19c3b8c2SApple OSS Distributions for thval in IterateQueue(task.threads, 'thread *', 'task_threads'): 142*19c3b8c2SApple OSS Distributions self.threads[unsigned(thval.thread_id)] = UserThreadObject(thval, self.cputype, self.cpusubtype) 143*19c3b8c2SApple OSS Distributions self.threads_ids_list.append(unsigned(thval.thread_id)) 144*19c3b8c2SApple OSS Distributions 145*19c3b8c2SApple OSS Distributions def getRegisterDataForThread(self, th_id, reg_num): 146*19c3b8c2SApple OSS Distributions if th_id not in self.threads: 147*19c3b8c2SApple OSS Distributions logging.critical("0x%x thread id is not found in this task") 148*19c3b8c2SApple OSS Distributions return '' 149*19c3b8c2SApple OSS Distributions if reg_num < 0 or reg_num >= len(self.registerset): 150*19c3b8c2SApple OSS Distributions logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, th_id)) 151*19c3b8c2SApple OSS Distributions return '' 152*19c3b8c2SApple OSS Distributions value = self.threads[th_id].getRegisterData(reg_num) 153*19c3b8c2SApple OSS Distributions return self.encodeRegisterData(value, bytesize=(self.registerset[reg_num]['bitsize'] // 8)) 154*19c3b8c2SApple OSS Distributions 155*19c3b8c2SApple OSS Distributions def getRegisterCombinedDataForThread(self, th_id): 156*19c3b8c2SApple OSS Distributions if th_id not in self.threads: 157*19c3b8c2SApple OSS Distributions logging.critical("0x%x thread id is not found in this task" % th_id) 158*19c3b8c2SApple OSS Distributions return '' 159*19c3b8c2SApple OSS Distributions cur_thread = self.threads[th_id] 160*19c3b8c2SApple OSS Distributions retval = 'thread:%s;name:%s;' % (self.encodeThreadID(th_id), cur_thread.getName()) 161*19c3b8c2SApple OSS Distributions pos = 0 162*19c3b8c2SApple OSS Distributions for rinfo in self.registerset: 163*19c3b8c2SApple OSS Distributions name = rinfo['name'] 164*19c3b8c2SApple OSS Distributions format = "%02x:%s;" 165*19c3b8c2SApple OSS Distributions value = cur_thread.getRegisterValueByName(name) 166*19c3b8c2SApple OSS Distributions value_endian_correct_str = self.encodeRegisterData(value, bytesize=(rinfo['bitsize'] // 8)) 167*19c3b8c2SApple OSS Distributions retval += format % (pos, value_endian_correct_str) 168*19c3b8c2SApple OSS Distributions pos += 1 169*19c3b8c2SApple OSS Distributions return retval 170*19c3b8c2SApple OSS Distributions 171*19c3b8c2SApple OSS Distributions def getThreadStopInfo(self, th_id): 172*19c3b8c2SApple OSS Distributions if th_id not in self.threads: 173*19c3b8c2SApple OSS Distributions logging.critical("0x%x thread id is not found in this task") 174*19c3b8c2SApple OSS Distributions return '' 175*19c3b8c2SApple OSS Distributions return 'T02' + self.getRegisterCombinedDataForThread(th_id) + 'threads:' + self.getThreadsInfo()+';' 176*19c3b8c2SApple OSS Distributions 177*19c3b8c2SApple OSS Distributions def getRegisterInfo(self, regnum): 178*19c3b8c2SApple OSS Distributions #something similar to 179*19c3b8c2SApple OSS Distributions #"name:x1;bitsize:64;offset:8;encoding:uint;format:hex;gcc:1;dwarf:1;set:General Purpose Registers;" 180*19c3b8c2SApple OSS Distributions if regnum >= len(self.registerset): 181*19c3b8c2SApple OSS Distributions logging.debug("No register_info for number %d." % regnum) 182*19c3b8c2SApple OSS Distributions return 'E45' 183*19c3b8c2SApple OSS Distributions 184*19c3b8c2SApple OSS Distributions rinfo = self.registerset[regnum] 185*19c3b8c2SApple OSS Distributions retval = '' 186*19c3b8c2SApple OSS Distributions for i in list(rinfo.keys()): 187*19c3b8c2SApple OSS Distributions i_val = str(rinfo[i]) 188*19c3b8c2SApple OSS Distributions if i == 'set': 189*19c3b8c2SApple OSS Distributions i_val = 'General Purpose Registers' 190*19c3b8c2SApple OSS Distributions retval += '%s:%s;' % (str(i), i_val) 191*19c3b8c2SApple OSS Distributions 192*19c3b8c2SApple OSS Distributions return retval 193*19c3b8c2SApple OSS Distributions 194*19c3b8c2SApple OSS Distributions def getProcessInfo(self): 195*19c3b8c2SApple OSS Distributions retval = '' 196*19c3b8c2SApple OSS Distributions #pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3; 197*19c3b8c2SApple OSS Distributions #ostype:macosx;vendor:apple;endian:little;ptrsize:8; 198*19c3b8c2SApple OSS Distributions pinfo = {'effective-uid': 'ecf', 'effective-gid': 'b', 'endian': 'little', 'vendor': 'apple'} 199*19c3b8c2SApple OSS Distributions pinfo['pid'] = "%x" % (GetProcPIDForTask(self.task)) 200*19c3b8c2SApple OSS Distributions pinfo['parent-pid'] = "%x" % (unsigned(self.proc.p_ppid)) 201*19c3b8c2SApple OSS Distributions pinfo['ptrsize'] = str(self.ptrsize) 202*19c3b8c2SApple OSS Distributions pinfo['ostype'] = 'macosx' 203*19c3b8c2SApple OSS Distributions pinfo['cputype'] = "%x" % self.cputype 204*19c3b8c2SApple OSS Distributions pinfo['cpusubtype'] = "%x" % self.cpusubtype 205*19c3b8c2SApple OSS Distributions pinfo['real-uid'] = "%x" % (unsigned(self.proc.p_ruid)) 206*19c3b8c2SApple OSS Distributions pinfo['real-gid'] = "%x" % (unsigned(self.proc.p_rgid)) 207*19c3b8c2SApple OSS Distributions if str(kern.arch).find('arm') >= 0: 208*19c3b8c2SApple OSS Distributions pinfo['ostype'] = 'ios' 209*19c3b8c2SApple OSS Distributions for i in list(pinfo.keys()): 210*19c3b8c2SApple OSS Distributions i_val = str(pinfo[i]) 211*19c3b8c2SApple OSS Distributions retval += '%s:%s;' % (str(i), i_val) 212*19c3b8c2SApple OSS Distributions return retval 213*19c3b8c2SApple OSS Distributions 214*19c3b8c2SApple OSS Distributions def readMemory(self, address, size): 215*19c3b8c2SApple OSS Distributions cache_key = "{}-{}-{}".format(hex(self.task), hex(address), size) 216*19c3b8c2SApple OSS Distributions cache_data = caching.GetDynamicCacheData(cache_key) 217*19c3b8c2SApple OSS Distributions if cache_data: 218*19c3b8c2SApple OSS Distributions return self.encodeByteString(cache_data) 219*19c3b8c2SApple OSS Distributions data = GetUserDataAsString(self.task, address, size) 220*19c3b8c2SApple OSS Distributions if not data: 221*19c3b8c2SApple OSS Distributions logging.error("Failed to read memory task:{: <#018x} {: <#018x} {:d}".format(self.task, address, size)) 222*19c3b8c2SApple OSS Distributions else: 223*19c3b8c2SApple OSS Distributions caching.SaveDynamicCacheData(cache_key, data) 224*19c3b8c2SApple OSS Distributions return self.encodeByteString(data) 225*19c3b8c2SApple OSS Distributions 226*19c3b8c2SApple OSS Distributions def getSharedLibInfoAddress(self): 227*19c3b8c2SApple OSS Distributions return unsigned(self.task.all_image_info_addr) 228