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