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