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