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