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