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