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