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