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