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