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