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