188cc0b97SApple OSS Distributionsimport logging
2e7776783SApple OSS Distributionsfrom . import target
388cc0b97SApple OSS Distributionsimport struct
488cc0b97SApple OSS Distributions
588cc0b97SApple OSS Distributionsfrom xnu import *
688cc0b97SApple OSS Distributionsfrom core.operating_system import Armv8_RegisterSet, Armv7_RegisterSet, I386_RegisterSet, X86_64RegisterSet
7bb611c8fSApple OSS Distributionsfrom core import caching
888cc0b97SApple OSS Distributions
976e12aa3SApple OSS Distributions""" these defines should come from an authoritative header file """
1088cc0b97SApple OSS DistributionsCPU_TYPE_I386 = 0x00000007
1188cc0b97SApple OSS DistributionsCPU_TYPE_X86_64 = 0x01000007
1288cc0b97SApple OSS DistributionsCPU_TYPE_ARM = 0x0000000c
1388cc0b97SApple OSS DistributionsCPU_TYPE_ARM64 = 0x0100000c
14a5e72196SApple OSS DistributionsCPU_TYPE_ARM64_32 = 0x0200000c
1588cc0b97SApple OSS Distributions
1688cc0b97SApple OSS Distributionsdef GetRegisterSetForCPU(cputype, subtype):
1776e12aa3SApple OSS Distributions    if cputype == CPU_TYPE_ARM64:
1888cc0b97SApple OSS Distributions        retval = Armv8_RegisterSet
19a5e72196SApple OSS Distributions    elif cputype == CPU_TYPE_ARM64_32:
20a5e72196SApple OSS Distributions        retval = Armv8_RegisterSet
2176e12aa3SApple OSS Distributions    elif cputype == CPU_TYPE_ARM:
2288cc0b97SApple OSS Distributions        retval = Armv7_RegisterSet
2388cc0b97SApple OSS Distributions    elif cputype == CPU_TYPE_I386:
2488cc0b97SApple OSS Distributions        retval = I386_RegisterSet
2576e12aa3SApple OSS Distributions    elif cputype == CPU_TYPE_X86_64:
2676e12aa3SApple OSS Distributions        retval = X86_64RegisterSet
2776e12aa3SApple OSS Distributions
2876e12aa3SApple OSS Distributions    """ crash if unknown cputype """
2988cc0b97SApple OSS Distributions
3088cc0b97SApple OSS Distributions    return retval.register_info['registers']
3188cc0b97SApple OSS Distributions
3288cc0b97SApple OSS Distributions
3388cc0b97SApple OSS Distributionsclass UserThreadObject(object):
3488cc0b97SApple OSS Distributions    """representation of userspace thread"""
355c2921b0SApple OSS Distributions    def __init__(self, thr_obj, cputype, cpusubtype):
368d741a5dSApple OSS Distributions        super().__init__()
3788cc0b97SApple OSS Distributions        self.thread = thr_obj
3888cc0b97SApple OSS Distributions        self.registerset = GetRegisterSetForCPU(cputype, cpusubtype)
3988cc0b97SApple OSS Distributions        self.thread_id = unsigned(self.thread.thread_id)
4088cc0b97SApple OSS Distributions        self.is64Bit = bool(cputype & 0x01000000)
4188cc0b97SApple OSS Distributions
4288cc0b97SApple OSS Distributions        if self.is64Bit:
4388cc0b97SApple OSS Distributions            if cputype == CPU_TYPE_X86_64:
4488cc0b97SApple OSS Distributions                self.reg_type = "x86_64"
4588cc0b97SApple OSS Distributions                self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_64
4688cc0b97SApple OSS Distributions            if cputype == CPU_TYPE_ARM64:
4788cc0b97SApple OSS Distributions                self.reg_type = "arm64"
4888cc0b97SApple OSS Distributions                self.saved_state = self.thread.machine.upcb.uss.ss_64
4988cc0b97SApple OSS Distributions        else:
5088cc0b97SApple OSS Distributions            if cputype == CPU_TYPE_I386:
5188cc0b97SApple OSS Distributions                self.reg_type = "i386"
5288cc0b97SApple OSS Distributions                self.saved_state = Cast(self.thread.machine.iss, 'x86_saved_state_t *').uss.ss_32
5388cc0b97SApple OSS Distributions            if cputype == CPU_TYPE_ARM:
5488cc0b97SApple OSS Distributions                self.reg_type = "arm"
5588cc0b97SApple OSS Distributions                self.saved_state = self.thread.machine.contextData.ss.uss.ss_32
56a5e72196SApple OSS Distributions            if cputype == CPU_TYPE_ARM64_32:
57a5e72196SApple OSS Distributions                self.reg_type = "arm64"
58a5e72196SApple OSS Distributions                self.saved_state = self.thread.machine.upcb.uss.ss_64
59cc9a6355SApple OSS Distributions
605c2921b0SApple OSS Distributions        logging.debug("created thread id 0x%x of type %s, cputype 0x%x"
615c2921b0SApple OSS Distributions                      % (self.thread_id, self.reg_type, cputype))
6288cc0b97SApple OSS Distributions
6388cc0b97SApple OSS Distributions    def getRegisterValueByName(self, name):
6488cc0b97SApple OSS Distributions        if self.reg_type == 'arm64':
6588cc0b97SApple 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'):
6688cc0b97SApple OSS Distributions                return unsigned(getattr(self.saved_state, 'x')[int(name.strip('x'))])
6788cc0b97SApple OSS Distributions
6888cc0b97SApple OSS Distributions            return unsigned(getattr(self.saved_state, name))
6988cc0b97SApple OSS Distributions
7088cc0b97SApple OSS Distributions        if self.reg_type == "x86_64":
7188cc0b97SApple OSS Distributions            if name in ('rip', 'rflags', 'cs', 'rsp', 'cpu'):
7288cc0b97SApple OSS Distributions                return unsigned(getattr(self.saved_state.isf, name))
7388cc0b97SApple OSS Distributions            return unsigned(getattr(self.saved_state, name))
7488cc0b97SApple OSS Distributions
7588cc0b97SApple OSS Distributions        if self.reg_type == "arm":
7688cc0b97SApple OSS Distributions            if name in ('r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12'):
7788cc0b97SApple OSS Distributions                retval = unsigned(getattr(self.saved_state, 'r')[int(name.strip('r'))])
7888cc0b97SApple OSS Distributions            else:
7988cc0b97SApple OSS Distributions                retval = unsigned(getattr(self.saved_state, name))
8088cc0b97SApple OSS Distributions            return retval
8188cc0b97SApple OSS Distributions
8288cc0b97SApple OSS Distributions        #TODO for i386
8388cc0b97SApple OSS Distributions
8488cc0b97SApple OSS Distributions    def getName(self):
8588cc0b97SApple OSS Distributions        return str(self.thread_id)
8688cc0b97SApple OSS Distributions
8788cc0b97SApple OSS Distributions    def getRegisterData(self, reg_num):
8888cc0b97SApple OSS Distributions        """ returns None if there is error """
8988cc0b97SApple OSS Distributions        if reg_num < 0 or reg_num >= len(self.registerset):
9088cc0b97SApple OSS Distributions            logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, self.thread_id))
9188cc0b97SApple OSS Distributions            return None
9288cc0b97SApple OSS Distributions        return self.getRegisterValueByName(self.registerset[reg_num]['name'])
9388cc0b97SApple OSS Distributions
9488cc0b97SApple OSS Distributions
9588cc0b97SApple OSS Distributionsclass UserProcess(target.Process):
9688cc0b97SApple OSS Distributions    """ Represent a user process and thread states """
9788cc0b97SApple OSS Distributions    def __init__(self, task):
9888cc0b97SApple OSS Distributions        self.task = task
995c2921b0SApple OSS Distributions        self.proc = GetProcFromTask(task)
100aca3beaaSApple OSS Distributions        self.cache = {}
101*33de042dSApple OSS Distributions        if self.proc is None:
1025c2921b0SApple OSS Distributions            raise ValueError("Task has no associated BSD process.")
10388cc0b97SApple OSS Distributions        dataregisters64bit = False
10488cc0b97SApple OSS Distributions        ptrsize = 4
10588cc0b97SApple OSS Distributions
10688cc0b97SApple OSS Distributions        if task.t_flags & 0x1:
10788cc0b97SApple OSS Distributions            ptrsize = 8
10888cc0b97SApple OSS Distributions        if task.t_flags & 0x2:
109cc9a6355SApple OSS Distributions            dataregisters64bit = True
11088cc0b97SApple OSS Distributions
11188cc0b97SApple OSS Distributions        self.cputype = unsigned(self.proc.p_cputype)
11288cc0b97SApple OSS Distributions        self.cpusubtype = unsigned(self.proc.p_cpusubtype)
113cc9a6355SApple OSS Distributions
1148d741a5dSApple OSS Distributions        super().__init__(self.cputype, self.cpusubtype, ptrsize)
115bb611c8fSApple 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)
116e7776783SApple OSS Distributions        self.proc_platform = int(GetProcPlatform(self.proc))
117bb611c8fSApple OSS Distributions        if self.proc_platform == xnudefines.P_PLATFORM_MACOS:
118cc9a6355SApple OSS Distributions            self.hinfo['ostype'] = 'macosx'
119bb611c8fSApple OSS Distributions        elif self.proc_platform == xnudefines.P_PLATFORM_WATCHOS:
120bb611c8fSApple OSS Distributions            self.hinfo['ostype'] = 'watchos'
121bb611c8fSApple OSS Distributions        elif self.proc_platform == xnudefines.P_PLATFORM_TVOS:
122bb611c8fSApple OSS Distributions            self.hinfo['ostype'] = 'tvos'
123bb611c8fSApple OSS Distributions        else:
124cc9a6355SApple OSS Distributions            self.hinfo['ostype'] = 'ios'
125bb611c8fSApple OSS Distributions        dbg_message += " ostype:%s" % self.hinfo['ostype']
126bb611c8fSApple OSS Distributions
1275c2921b0SApple OSS Distributions        if str(kern.arch).lower().startswith('arm'):
128bb611c8fSApple OSS Distributions            addressing_bits = 64 - int(kern.globals.gT1Sz)
129bb611c8fSApple OSS Distributions            self.hinfo['addressing_bits'] = addressing_bits
130bb611c8fSApple OSS Distributions            dbg_message += " addressing_bits:%d" % addressing_bits
131cc9a6355SApple OSS Distributions
132cc9a6355SApple OSS Distributions        self.registerset = GetRegisterSetForCPU(self.cputype, self.cpusubtype)
133bb611c8fSApple OSS Distributions        logging.info(dbg_message)
13488cc0b97SApple OSS Distributions        self.threads = {}
13588cc0b97SApple OSS Distributions        self.threads_ids_list = []
13688cc0b97SApple OSS Distributions        logging.debug("iterating over threads in process")
13788cc0b97SApple OSS Distributions        for thval in IterateQueue(task.threads, 'thread *', 'task_threads'):
1385c2921b0SApple OSS Distributions            self.threads[unsigned(thval.thread_id)] = UserThreadObject(thval, self.cputype, self.cpusubtype)
13988cc0b97SApple OSS Distributions            self.threads_ids_list.append(unsigned(thval.thread_id))
14088cc0b97SApple OSS Distributions
14188cc0b97SApple OSS Distributions    def getRegisterDataForThread(self, th_id, reg_num):
14288cc0b97SApple OSS Distributions        if th_id not in self.threads:
14388cc0b97SApple OSS Distributions            logging.critical("0x%x thread id is not found in this task")
14488cc0b97SApple OSS Distributions            return ''
14588cc0b97SApple OSS Distributions        if reg_num < 0 or reg_num >= len(self.registerset):
14688cc0b97SApple OSS Distributions            logging.warning("regnum %d is not defined for thread_id 0x%x" % (reg_num, th_id))
14788cc0b97SApple OSS Distributions            return ''
14888cc0b97SApple OSS Distributions        value = self.threads[th_id].getRegisterData(reg_num)
149e7776783SApple OSS Distributions        return self.encodeRegisterData(value, bytesize=(self.registerset[reg_num]['bitsize'] // 8))
15088cc0b97SApple OSS Distributions
15188cc0b97SApple OSS Distributions    def getRegisterCombinedDataForThread(self, th_id):
15288cc0b97SApple OSS Distributions        if th_id not in self.threads:
15388cc0b97SApple OSS Distributions            logging.critical("0x%x thread id is not found in this task" % th_id)
15488cc0b97SApple OSS Distributions            return ''
15588cc0b97SApple OSS Distributions        cur_thread = self.threads[th_id]
15688cc0b97SApple OSS Distributions        retval = 'thread:%s;name:%s;' % (self.encodeThreadID(th_id), cur_thread.getName())
15788cc0b97SApple OSS Distributions        pos = 0
15888cc0b97SApple OSS Distributions        for rinfo in self.registerset:
15988cc0b97SApple OSS Distributions            name = rinfo['name']
16088cc0b97SApple OSS Distributions            format = "%02x:%s;"
16188cc0b97SApple OSS Distributions            value = cur_thread.getRegisterValueByName(name)
162e7776783SApple OSS Distributions            value_endian_correct_str = self.encodeRegisterData(value, bytesize=(rinfo['bitsize'] // 8))
16388cc0b97SApple OSS Distributions            retval += format % (pos, value_endian_correct_str)
16488cc0b97SApple OSS Distributions            pos += 1
16588cc0b97SApple OSS Distributions        return retval
16688cc0b97SApple OSS Distributions
16788cc0b97SApple OSS Distributions    def getThreadStopInfo(self, th_id):
16888cc0b97SApple OSS Distributions        if th_id not in self.threads:
16988cc0b97SApple OSS Distributions            logging.critical("0x%x thread id is not found in this task")
17088cc0b97SApple OSS Distributions            return ''
17188cc0b97SApple OSS Distributions        return 'T02' + self.getRegisterCombinedDataForThread(th_id) + 'threads:' + self.getThreadsInfo()+';'
17288cc0b97SApple OSS Distributions
17388cc0b97SApple OSS Distributions    def getRegisterInfo(self, regnum):
17488cc0b97SApple OSS Distributions        #something similar to
17588cc0b97SApple OSS Distributions        #"name:x1;bitsize:64;offset:8;encoding:uint;format:hex;gcc:1;dwarf:1;set:General Purpose Registers;"
176bb611c8fSApple OSS Distributions        if regnum >= len(self.registerset):
17788cc0b97SApple OSS Distributions            logging.debug("No register_info for number %d." % regnum)
17888cc0b97SApple OSS Distributions            return 'E45'
17988cc0b97SApple OSS Distributions
18088cc0b97SApple OSS Distributions        rinfo = self.registerset[regnum]
18188cc0b97SApple OSS Distributions        retval = ''
182e7776783SApple OSS Distributions        for i in list(rinfo.keys()):
18388cc0b97SApple OSS Distributions            i_val = str(rinfo[i])
18488cc0b97SApple OSS Distributions            if i == 'set':
18588cc0b97SApple OSS Distributions                i_val = 'General Purpose Registers'
18688cc0b97SApple OSS Distributions            retval += '%s:%s;' % (str(i), i_val)
18788cc0b97SApple OSS Distributions
18888cc0b97SApple OSS Distributions        return retval
18988cc0b97SApple OSS Distributions
19088cc0b97SApple OSS Distributions    def getProcessInfo(self):
19188cc0b97SApple OSS Distributions        retval = ''
19288cc0b97SApple OSS Distributions        #pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3;
19388cc0b97SApple OSS Distributions        #ostype:macosx;vendor:apple;endian:little;ptrsize:8;
19488cc0b97SApple OSS Distributions        pinfo = {'effective-uid': 'ecf', 'effective-gid': 'b', 'endian': 'little', 'vendor': 'apple'}
19588cc0b97SApple OSS Distributions        pinfo['pid'] = "%x" % (GetProcPIDForTask(self.task))
19688cc0b97SApple OSS Distributions        pinfo['parent-pid'] = "%x" % (unsigned(self.proc.p_ppid))
19788cc0b97SApple OSS Distributions        pinfo['ptrsize'] = str(self.ptrsize)
19888cc0b97SApple OSS Distributions        pinfo['ostype'] = 'macosx'
19988cc0b97SApple OSS Distributions        pinfo['cputype'] = "%x" % self.cputype
20088cc0b97SApple OSS Distributions        pinfo['cpusubtype'] = "%x" % self.cpusubtype
20188cc0b97SApple OSS Distributions        pinfo['real-uid'] = "%x" % (unsigned(self.proc.p_ruid))
20288cc0b97SApple OSS Distributions        pinfo['real-gid'] = "%x" % (unsigned(self.proc.p_rgid))
20388cc0b97SApple OSS Distributions        if str(kern.arch).find('arm') >= 0:
20488cc0b97SApple OSS Distributions            pinfo['ostype'] = 'ios'
205e7776783SApple OSS Distributions        for i in list(pinfo.keys()):
20688cc0b97SApple OSS Distributions            i_val = str(pinfo[i])
20788cc0b97SApple OSS Distributions            retval += '%s:%s;' % (str(i), i_val)
20888cc0b97SApple OSS Distributions        return retval
20988cc0b97SApple OSS Distributions
21088cc0b97SApple OSS Distributions    def readMemory(self, address, size):
211bb611c8fSApple OSS Distributions        cache_key = "{}-{}-{}".format(hex(self.task), hex(address), size)
212aca3beaaSApple OSS Distributions        cache_data = self.cache.get(cache_key, None)
213bb611c8fSApple OSS Distributions        if cache_data:
214bb611c8fSApple OSS Distributions            return self.encodeByteString(cache_data)
21588cc0b97SApple OSS Distributions        data = GetUserDataAsString(self.task, address, size)
21688cc0b97SApple OSS Distributions        if not data:
21788cc0b97SApple OSS Distributions            logging.error("Failed to read memory task:{: <#018x} {: <#018x} {:d}".format(self.task, address, size))
218bb611c8fSApple OSS Distributions        else:
219aca3beaaSApple OSS Distributions            self.cache[cache_key] = data
22088cc0b97SApple OSS Distributions        return self.encodeByteString(data)
22188cc0b97SApple OSS Distributions
22288cc0b97SApple OSS Distributions    def getSharedLibInfoAddress(self):
22388cc0b97SApple OSS Distributions        return unsigned(self.task.all_image_info_addr)
224