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