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