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