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