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