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