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