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