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