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