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