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