Пример #1
0
    def calculate(self):
        common.set_plugin_members(self)

        if self._config.SYSCALL_INDEXES:
            index_names = self._parse_handler_names()
        else:
            index_names = None

        sym_addrs = self.profile.get_all_addresses()

        table_addr = self.addr_space.profile.get_symbol("_sysent")

        nsysent = obj.Object(
            "int",
            offset=self.addr_space.profile.get_symbol("_nsysent"),
            vm=self.addr_space)
        sysents = obj.Object(theType="Array",
                             offset=table_addr,
                             vm=self.addr_space,
                             count=nsysent,
                             targetType="sysent")

        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked = ent_addr not in sym_addrs

            if index_names:
                sym_name = index_names[i]
            else:
                sym_name = self.profile.get_symbol_by_address(
                    "kernel", ent_addr)
                if not sym_name:
                    sym_name = "N/A"

            yield (table_addr, "SyscallTable", i, ent_addr, hooked, sym_name)
Пример #2
0
    def calculate(self):
        common.set_plugin_members(self)
        
        if self._config.SYSCALL_INDEXES:
            index_names = self._parse_handler_names()
        else:
            index_names = None

        sym_addrs = self.profile.get_all_addresses()

        table_addr = self.addr_space.profile.get_symbol("_sysent")

        nsysent = obj.Object("int", offset = self.addr_space.profile.get_symbol("_nsysent"), vm = self.addr_space)
        sysents = obj.Object(theType = "Array", offset = table_addr, vm = self.addr_space, count = nsysent, targetType = "sysent")

        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked  = ent_addr not in sym_addrs

            if index_names:
                sym_name = index_names[i]
            else:
                sym_name = self.profile.get_symbol_by_address("kernel", ent_addr)
                if not sym_name:
                    sym_name = "N/A"

            yield (table_addr, "SyscallTable", i, ent_addr, hooked, sym_name)
Пример #3
0
    def calculate(self):
        args = ()
        common.set_plugin_members(self)

        sym_addrs = self.profile.get_all_addresses()

        nsysent = obj.Object("int", offset = self.addr_space.profile.get_symbol("_nsysent"), vm = self.addr_space)
        sysents = obj.Object(theType = "Array", offset = self.addr_space.profile.get_symbol("_sysent"), vm = self.addr_space, count = nsysent, targetType = "sysent")

        for (i, sysent) in enumerate(sysents):
            hooked = False
            ent_addr = sysent.sy_call.v()
            syscall_name = self.profile.get_symbol_by_address("kernel", ent_addr)
            if 'dtrace' in syscall_name:
                # syscall probes: http://siliconblade.blogspot.com/2013/04/hunting-d-trace-rootkits-with.html
                hooked = "syscall_probe"
            else:
                # fbt probes: http://reverse.put.as/2013/05/07/syscan13-revisiting-mac-os-x-rootkits-presentation/
                data = sysent.obj_vm.zread(ent_addr + 1, 2)
                if binascii.hexlify(data) == 'f089':
                    hooked = 'fbt_probe'
                 
            if hooked != False:
                yield ('Syscall_Table', i, ent_addr, syscall_name, hooked)

        # mach_trap probes: http://felinemenace.org/~nemo/dtrace-infiltrate.pdf
        t = trap.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, index, call_addr, sym_name, other_hooked) in t.calculate():
            if other_hooked == True:
                sym_name = "HOOKED"

            if 'dtrace' in sym_name:
                hooked = "mach_trap_probe"
                yield ('Trap_Table', index, call_addr, sym_name, hooked)
Пример #4
0
    def calculate(self):
        common.set_plugin_members(self)

        sym_addrs = self.profile.get_all_addresses()

        table_addr = self.addr_space.profile.get_symbol("_sysent")

        nsysent = obj.Object(
            "int",
            offset=self.addr_space.profile.get_symbol("_nsysent"),
            vm=self.addr_space)
        sysents = obj.Object(theType="Array",
                             offset=table_addr,
                             vm=self.addr_space,
                             count=nsysent,
                             targetType="sysent")

        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked = ent_addr not in sym_addrs

            if hooked == False:
                sym_name = self.profile.get_symbol_by_address(
                    "kernel", ent_addr)
            else:
                sym_name = "HOOKED"

            yield (table_addr, "SyscallTable", i, ent_addr, hooked, sym_name)
    def calculate(self):
        common.set_plugin_members(self)

        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset = kp, vm = self.addr_space)
        kernel_start = kmodk.address
        kernel_end = kernel_start + kmodk.m('size')
  
        # check if kext functions are modified, including kernel symbols
        if self._config.CHECKKEXTS  or self._config.CHECKKERNEL:
            # get symbols from kext __TEXT in memory rather than file
            kext_addr_list = []

            # get kernel address
            kmod = obj.Object("kmod_info", offset = self.addr_space.profile.get_symbol("_g_kernel_kmod_info"), vm = self.addr_space)
            kext_addr_list.append(('__kernel__', kmod.address, kmod.m('size')))
            
            # get all kexts
            if self._config.CHECKKERNEL == False:
                # get other kext addresses 
                p = self.addr_space.profile.get_symbol("_kmod")
                kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space)
                kmod = kmodaddr.dereference_as("kmod_info")
                while kmod.is_valid():
                    kext_addr_list.append((kmod.name, kmod.address, kmod.m('size')))
                    kmod = kmod.next

            # loop thru kexts
            for kext_name, kext_address, kext_size in kext_addr_list:
                k_start = kext_address
                k_end  = kext_address + kext_size

                #loop thru kext functions
                for func_name, func_addr in self.getKextSymbols(kext_addr = kext_address, onlyFunctions = True, fmodel = model):

                    # false positive, remove if needed
                    if func_name in ["pthreads_dummy_symbol"]:
                        continue

                    # check if function's been modified
                    modified, dst_addr, op_addr = self.isCallReferenceModified(model, distorm_mode, func_addr, k_start, k_end)
                    if modified:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name
                        yield (func_addr, func_name, op_addr, dst_addr, hook_kext)
    def calculate(self):
        common.set_plugin_members(self)

        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset = kp, vm = self.addr_space)
        k_start = kmodk.address
        k_end = k_start + kmodk.m('size')
  
        # check if trustedbsd mac_policy_list is shadowed
        is_shadowed = False
        shadow_addr = None

        # some functions with MAC_CHECK/mac_policy_list references: mac_proc_check_get_task_name, mac_proc_check_get_task, mac_proc_check_fork, mac_cred_check_label_update, mac_cred_check_visible, mac_proc_check_debug, mac_proc_check_run_cs_invalid, mac_proc_check_sched, mac_proc_check_signal, mac_proc_check_wait, mac_proc_check_setlcid, mac_proc_check_getlcid, mac_lctx_check_label_update, mac_proc_check_suspend_resume, mac_port_check_service, mac_port_label_compute, mac_file_check_create, mac_file_check_dup, mac_file_check_fcntl, mac_file_check_ioctl, mac_file_check_inherit, mac_file_check_receive, mac_file_check_get_offset, mac_file_check_change_offset, mac_file_check_get, mac_file_check_set, mac_file_check_lock, mac_file_check_mmap
        original_mpl_addr = self.addr_space.profile.get_symbol("_mac_policy_list")
        original_mpl = obj.Object("mac_policy_list", offset = original_mpl_addr, vm = self.addr_space)

        # to get the disassembly of MAC_CHECK, disassemble mac_proc_check_get_task since targeted by REX [http://reverse.put.as/2014/03/18/teaching-rex-another-trustedbsd-trick-to-hide-from-volatility/]
        func_addr = self.addr_space.profile.get_symbol('_mac_proc_check_get_task')
        content = self.addr_space.read(func_addr, 1024)
        op_prev = None
        for op in distorm3.Decompose(func_addr, content, distorm_mode):
            if not op.valid or (op.mnemonic == 'NOP' and op_prev.mnemonic == "RET"):
                break

            if model == "64bit":
                if op.mnemonic == 'LEA' and op.operands[0].type == 'Register' and op.operands[0].name in ['RDI','RAX','R13','RSP','RBX','R12','R13','R14','R15']:
                    curr_mpl_addr = op.address + op.operands[1].disp + op.size
                    curr_mpl = obj.Object("mac_policy_list", offset = curr_mpl_addr, vm = self.addr_space)
                    # check if mac_policy_list address and mac_policy_list.entries address have changed
                    if curr_mpl_addr != original_mpl_addr or original_mpl.entries.v() != curr_mpl.entries.v():
                        is_shadowed = True
                        shadow_addr = curr_mpl_addr
                        yield(original_mpl_addr, shadow_addr, op.address)
                        print "mac_policy_address is shadowed! Original Address: {0:#10x}, Shadow Address: {1:#10x}, Modification at: {2:#10x}".format(original_mpl_addr, shadow_addr, op.address)
                        break
            elif model == "32bit":
                if op.mnemonic == 'MOV' and op.operands[0].type == 'Register' and op.operands[0].name in ['EAX'] and op.operands[1].type == 'AbsoluteMemoryAddress':
                    curr_mpl_entries_addr = op.operands[1].disp
                    # check if mac_policy_list.entries address has changed
                    if curr_mpl_entries_addr != original_mpl.entries.v():
                        is_shadowed = True
                        shadow_addr = curr_mpl_entries_addr
			yield (original_mpl.entries.v(), shadow_addr, op.address)
                        print "mac_policy_address is shadowed! Original Entries Address: {0:#10x}, Shadow Entries Address: {1:#10x}, Modification at: {2:#10x}".format(original_mpl.entries.v(), shadow_addr, op.address)
                        break              
            op_prev = op
Пример #7
0
    def calculate(self):
        args = ()
        common.set_plugin_members(self)

        sym_addrs = self.profile.get_all_addresses()

        nsysent = obj.Object(
            "int",
            offset=self.addr_space.profile.get_symbol("_nsysent"),
            vm=self.addr_space)
        sysents = obj.Object(
            theType="Array",
            offset=self.addr_space.profile.get_symbol("_sysent"),
            vm=self.addr_space,
            count=nsysent,
            targetType="sysent")

        for (i, sysent) in enumerate(sysents):
            hooked = False
            ent_addr = sysent.sy_call.v()
            syscall_name = self.profile.get_symbol_by_address(
                "kernel", ent_addr)
            if 'dtrace' in syscall_name:
                # syscall probes: http://siliconblade.blogspot.com/2013/04/hunting-d-trace-rootkits-with.html
                hooked = "syscall_probe"
            else:
                # fbt probes: http://reverse.put.as/2013/05/07/syscan13-revisiting-mac-os-x-rootkits-presentation/
                data = sysent.obj_vm.zread(ent_addr + 1, 2)
                if binascii.hexlify(data) == 'f089':
                    hooked = 'fbt_probe'

            if hooked != False:
                yield ('Syscall_Table', i, ent_addr, syscall_name, hooked)

        # mach_trap probes: http://felinemenace.org/~nemo/dtrace-infiltrate.pdf
        t = trap.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, index, call_addr, sym_name,
             other_hooked) in t.calculate():
            if other_hooked == True:
                sym_name = "HOOKED"

            if 'dtrace' in sym_name:
                hooked = "mach_trap_probe"
                yield ('Trap_Table', index, call_addr, sym_name, hooked)
Пример #8
0
    def calculate(self):
        common.set_plugin_members(self)

        sym_addrs = self.profile.get_all_addresses()

        table_addr = self.addr_space.profile.get_symbol("_sysent")

        nsysent = obj.Object("int", offset = self.addr_space.profile.get_symbol("_nsysent"), vm = self.addr_space)
        sysents = obj.Object(theType = "Array", offset = table_addr, vm = self.addr_space, count = nsysent, targetType = "sysent")

        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked  = ent_addr not in sym_addrs

            if hooked == False:
                sym_name = self.profile.get_symbol_by_address("kernel", ent_addr)
            else:
                sym_name = "HOOKED"

            yield (table_addr, "SyscallTable", i, ent_addr, hooked, sym_name)
Пример #9
0
    def calculate(self):
        common.set_plugin_members(self)

        (kernel_symbol_addresses, kmod) = common.get_kernel_function_addrs(self)
        
        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        sym_addrs = self.profile.get_all_function_addresses()

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset = kp, vm = self.addr_space)
        k_start = kmodk.address
        k_end = k_start + kmodk.m('size')

        ####### STEP 1 - CHECK SYSTEM CALL INLINE HOOKS ############
 
        # get syscall table      
        nsysent = obj.Object("int", offset = self.addr_space.profile.get_symbol("_nsysent"), vm = self.addr_space)
        sysents = obj.Object(theType = "Array", offset = self.addr_space.profile.get_symbol("_sysent"), vm = self.addr_space, count = nsysent, targetType = "sysent")

        # check if syscall table entries have been modified
        dict_syscall_funcs = {}
        list_syscall_names = []
        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked  = ent_addr not in sym_addrs # using check_syscalls method
            inlined, dst_addr = self.isInlined(model, distorm_mode, ent_addr, kernel_symbol_addresses, [kmodk]) 
            prolog_inlined = self.isPrologInlined(model, distorm_mode, ent_addr)
            if hooked == True or inlined == True or prolog_inlined == True:
                if dst_addr != None:
                    kext = self.findKextWithAddress(dst_addr)
                else:
                    kext = self.findKextWithAddress(ent_addr)
                yield ("SyscallTable1", i, ent_addr, hooked, (inlined or prolog_inlined), False, '-', kext)
            else:
                ent_name = self.profile.get_symbol_by_address_type("kernel", ent_addr, "N_FUN")
                # check for duplicate syscall functions
                if ent_name != "_nosys" and ent_name in dict_syscall_funcs:
                    prev_ent = dict_syscall_funcs[ent_name]
                    kext = self.findKextWithAddress(ent_addr)
                    yield ("SyscallTable", list_syscall_names.index(ent_name), prev_ent.sy_call.v(), False, False, False, '-', kext)
                    yield ("DuplicateSyscall -> {0}".format(ent_name), i, ent_addr, True, False, False, '-', kext)
                else:
                    # check for dtrace syscall hooks
                    if ent_name.find("dtrace") > -1:
                        kext = self.findKextWithAddress(ent_addr)
                        yield ("SyscallTable", i, ent_addr, False, False, False, '-', kext)
                    else:
                        # add to list
                        list_syscall_names.append(ent_name)
                        dict_syscall_funcs[ent_name] = sysent
    

        ####### STEP 2 - KERNEL & KEXTS ############### 

        # get symbols from kext __TEXT in memory rather than file
        kext_addr_list = []

        # get kernel address
        kmod = obj.Object("kmod_info", offset = self.addr_space.profile.get_symbol("_g_kernel_kmod_info"), vm = self.addr_space)
        kext_addr_list.append((kmod.address.v(), kmod.address + kmod.m('size'), '__kernel__'))
        
        # get other kext addresses 
        p = self.addr_space.profile.get_symbol("_kmod")
        kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space)
        kmod = kmodaddr.dereference_as("kmod_info")
        while kmod.is_valid():
            kext_addr_list.append((kmod.address.v(), kmod.address + kmod.m('size'), kmod.name))
            kmod = kmod.next

        # loop thru kexts
        for kext_address, kext_end, kext_name in kext_addr_list:
            #loop thru kext functions
            for func_name, func_addr in self.getKextSymbols(kext_addr = kext_address, onlyFunctions = True, fmodel = model):
                inlined = False

                # false positive, remove if needed
                if func_name in ["pthreads_dummy_symbol"]:
                    continue

                # check if function's been modified
                modified, dst_addr = self.isCallReferenceModified(model, distorm_mode, func_addr, kernel_symbol_addresses, kext_addr_list)
                if modified:
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name
                   
                    yield ("SymbolsTable", '-', func_addr, False, modified, False, '-', hook_kext)

                inlined, dst_addr = self.isInlined(model, distorm_mode, func_addr, kernel_symbol_addresses, kext_addr_list)
                if inlined:
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name 
                    yield ("SymbolsTable", '-', func_addr, False, inlined, False, '-', hook_kext)

        ########## STEP 3 - TRAP TABLE ###############

        # check if trap table hooked using check_trap_table
        args = ()
        trap = check_trap_table.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, i, call_addr, sym_name, hooked) in trap.calculate():
            if hooked == True or 'dtrace' in sym_name:
                kext = self.findKextWithAddress(call_addr)
                yield ("TrapTable", i, call_addr, hooked, False, False, '-', kext)
            
            else:
                inlined, dst_addr = self.isInlined(model, distorm_mode, call_addr, kernel_symbol_addresses, [kmodk]) 
                if inlined: 
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name 
                    
                    yield ("TrapTable", '-', func_addr, False, inlined, False, '-', hook_kext)
                else:
                    modified, dst_addr = self.isCallReferenceModified(model, distorm_mode, call_addr, kernel_symbol_addresses, [kmodk])

                    if modified:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name
                       
                        yield ("TrapTable", '-', func_addr, False, modified, False, '-', hook_kext)
Пример #10
0
    def calculate(self):
        common.set_plugin_members(self)
        args = ()

        memory_model = self.addr_space.profile.metadata.get('memory_model', 0)
        if memory_model == '32bit':
            distorm_mode = distorm3.Decode32Bits
            master_idt_type = "_master_idt64"
            idt_type = "real_gate64"
        else:
            idt_type = "real_gate64"
            distorm_mode = distorm3.Decode64Bits
            master_idt_type = "_master_idt64"

        sym_addrs = self.profile.get_all_addresses()

        # size of idt table is 256 so far
        IDTSZ = 256

        # get number of cpus
        real_ncpus = obj.Object("int", offset = self.addr_space.profile.get_symbol("_real_ncpus"), vm = self.addr_space)

        # get cpu_data_ptr/cpu_data array addresses
	cpu_data_ptrs = obj.Object(theType = 'Array', offset = self.addr_space.profile.get_symbol("_cpu_data_ptr"), vm = self.addr_space, targetType = "unsigned long long", count = real_ncpus)

        # master_idt not in cpu_desc_table so use the symbol instead: http://www.opensource.apple.com/source/xnu/xnu-1699.24.8/osfmk/i386/mp_desc.c
        master_idt_addr = self.addr_space.profile.get_symbol(master_idt_type)

        for i in range(0, real_ncpus -1):
            # for master cpu, use master_idt_addr
            if i == 0:
                idt_addr = master_idt_addr
            else:
                if memory_model == "32bit":
                    break

                cpu_data = obj.Object('cpu_data', offset = cpu_data_ptrs[i], vm = self.addr_space)
                # get idt addr which is at the beginning of the cpu_desc_table
                idt_addr = cpu_data.cpu_desc_tablep.v()

            idt_table = obj.Object(theType = 'Array', offset = idt_addr, vm = self.addr_space, targetType = idt_type, count = IDTSZ)

            for j in range(0, IDTSZ):
                hooked = False
                inlined = True

                ent = idt_table[j]

                if memory_model == '32bit':
                    idt32_nums = [0,1,255] + range(3,32) + range(127, 132)
                    if j not in idt32_nums:
                        continue
                    stub_addr = ent.offset_low16 + (ent.offset_high16 << 16) 
                else:
                    stub_addr = ent.offset_low16 + (ent.offset_high16 << 16) + (ent.offset_top32 << 32)

                selector = dict_seg64.get(int(ent.selector16), 'UNKNOWN')

                # 6th and 7th bits are for dpl
                # http://www.logix.cz/michal/doc/i386/chp06-03.htm
                dpl = (ent.access8 >> 5) & 0x3
            
                if stub_addr in sym_addrs:
                    idt_name = self.profile.get_symbol_by_address("kernel", stub_addr)
                    # symbols file has same address for both _hi64_text_base and _t64_zero_div, proper name is _t64_zero_div
                    if memory_model == "32bit" and idt_name == "_hi64_text_base":
                        idt_name = "_t64_zero_div"
                else:
                    idt_name = "UNKNOWN"

                module_name = self.findKextWithAddress(stub_addr)

                # check if idt stub is within the kernel OR function/idt name is somewhat known idt entry
                if str(module_name) == "__kernel__" and idt_name[:4] in ['_idt', '__in', '_t64', '_hi6', '_a64', '_mc6'] and idt_name != "UNKNOWN":
                    hooked = False
                else:
                    hooked = True

                # check if handler has been tampered with
                if self.hasValidHandler(stub_addr, memory_model, distorm_mode):
                    inlined = False

                # uncomment the next line and comment the following to use the module in the script as described at: http://siliconblade.blogspot.com/ 
                # yield(i, j, stub_addr, idt_name, dpl, selector, module_name, hooked, inlined, ent)
                yield(i, j, stub_addr, idt_name, dpl, selector, module_name, hooked, inlined)
Пример #11
0
    def calculate(self):
        common.set_plugin_members(self)

        (kernel_symbol_addresses,
         kmod) = common.get_kernel_function_addrs(self)

        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        sym_addrs = self.profile.get_all_function_addresses()

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset=kp, vm=self.addr_space)
        k_start = kmodk.address
        k_end = k_start + kmodk.m('size')

        ####### STEP 1 - CHECK SYSTEM CALL INLINE HOOKS ############

        # get syscall table
        nsysent = obj.Object(
            "int",
            offset=self.addr_space.profile.get_symbol("_nsysent"),
            vm=self.addr_space)
        sysents = obj.Object(
            theType="Array",
            offset=self.addr_space.profile.get_symbol("_sysent"),
            vm=self.addr_space,
            count=nsysent,
            targetType="sysent")

        # check if syscall table entries have been modified
        dict_syscall_funcs = {}
        list_syscall_names = []
        for (i, sysent) in enumerate(sysents):
            ent_addr = sysent.sy_call.v()
            hooked = ent_addr not in sym_addrs  # using check_syscalls method
            inlined, dst_addr = self.isInlined(model, distorm_mode, ent_addr,
                                               kernel_symbol_addresses,
                                               [kmodk])
            prolog_inlined = self.isPrologInlined(model, distorm_mode,
                                                  ent_addr)
            if hooked == True or inlined == True or prolog_inlined == True:
                if dst_addr != None:
                    kext = self.findKextWithAddress(dst_addr)
                else:
                    kext = self.findKextWithAddress(ent_addr)
                yield ("SyscallTable1", i, ent_addr, hooked,
                       (inlined or prolog_inlined), False, '-', kext)
            else:
                ent_name = self.profile.get_symbol_by_address_type(
                    "kernel", ent_addr, "N_FUN")
                # check for duplicate syscall functions
                if ent_name != "_nosys" and ent_name in dict_syscall_funcs:
                    prev_ent = dict_syscall_funcs[ent_name]
                    kext = self.findKextWithAddress(ent_addr)
                    yield ("SyscallTable", list_syscall_names.index(ent_name),
                           prev_ent.sy_call.v(), False, False, False, '-',
                           kext)
                    yield ("DuplicateSyscall -> {0}".format(ent_name), i,
                           ent_addr, True, False, False, '-', kext)
                else:
                    # check for dtrace syscall hooks
                    if ent_name.find("dtrace") > -1:
                        kext = self.findKextWithAddress(ent_addr)
                        yield ("SyscallTable", i, ent_addr, False, False,
                               False, '-', kext)
                    else:
                        # add to list
                        list_syscall_names.append(ent_name)
                        dict_syscall_funcs[ent_name] = sysent

        ####### STEP 2 - KERNEL & KEXTS ###############

        # get symbols from kext __TEXT in memory rather than file
        kext_addr_list = []

        # get kernel address
        kmod = obj.Object(
            "kmod_info",
            offset=self.addr_space.profile.get_symbol("_g_kernel_kmod_info"),
            vm=self.addr_space)
        kext_addr_list.append(
            (kmod.address.v(), kmod.address + kmod.m('size'), '__kernel__'))

        # get other kext addresses
        p = self.addr_space.profile.get_symbol("_kmod")
        kmodaddr = obj.Object("Pointer", offset=p, vm=self.addr_space)
        kmod = kmodaddr.dereference_as("kmod_info")
        while kmod.is_valid():
            kext_addr_list.append(
                (kmod.address.v(), kmod.address + kmod.m('size'), kmod.name))
            kmod = kmod.next

        # loop thru kexts
        for kext_address, kext_end, kext_name in kext_addr_list:
            #loop thru kext functions
            for func_name, func_addr in self.getKextSymbols(
                    kext_addr=kext_address, onlyFunctions=True, fmodel=model):
                inlined = False

                # false positive, remove if needed
                if func_name in ["pthreads_dummy_symbol"]:
                    continue

                # check if function's been modified
                modified, dst_addr = self.isCallReferenceModified(
                    model, distorm_mode, func_addr, kernel_symbol_addresses,
                    kext_addr_list)
                if modified:
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name

                    yield ("SymbolsTable", '-', func_addr, False, modified,
                           False, '-', hook_kext)

                inlined, dst_addr = self.isInlined(model, distorm_mode,
                                                   func_addr,
                                                   kernel_symbol_addresses,
                                                   kext_addr_list)
                if inlined:
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name
                    yield ("SymbolsTable", '-', func_addr, False, inlined,
                           False, '-', hook_kext)

        ########## STEP 3 - TRAP TABLE ###############

        # check if trap table hooked using check_trap_table
        args = ()
        trap = check_trap_table.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, i, call_addr, sym_name,
             hooked) in trap.calculate():
            if hooked == True or 'dtrace' in sym_name:
                kext = self.findKextWithAddress(call_addr)
                yield ("TrapTable", i, call_addr, hooked, False, False, '-',
                       kext)

            else:
                inlined, dst_addr = self.isInlined(model, distorm_mode,
                                                   call_addr,
                                                   kernel_symbol_addresses,
                                                   [kmodk])
                if inlined:
                    if dst_addr != None:
                        hook_kext = self.findKextWithAddress(dst_addr)
                    else:
                        hook_kext = kext_name

                    yield ("TrapTable", '-', func_addr, False, inlined, False,
                           '-', hook_kext)
                else:
                    modified, dst_addr = self.isCallReferenceModified(
                        model, distorm_mode, call_addr,
                        kernel_symbol_addresses, [kmodk])

                    if modified:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name

                        yield ("TrapTable", '-', func_addr, False, modified,
                               False, '-', hook_kext)
Пример #12
0
    def calculate(self):
        common.set_plugin_members(self)

        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        sym_addrs = self.profile.get_all_addresses()

        # get all kexts and symbols
        if self._config.DISPLAYSYMBOLS != False:
            kext_addr_list = []
            # get kernel address
            kmod = obj.Object("kmod_info", offset = self.addr_space.profile.get_symbol("_g_kernel_kmod_info"), vm = self.addr_space)
            kext_addr_list.append(('__kernel__', kmod.address, kmod.m('size')))

            p = self.addr_space.profile.get_symbol("_kmod")
            kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space)
            kmod = kmodaddr.dereference_as("kmod_info")
            while kmod.is_valid():
                kext_addr_list.append((kmod.name, kmod.address, kmod.m('size')))
                kmod = kmod.next

            # loop thru kexts
            for kext_name, kext_address, kext_size in kext_addr_list:
                if  self._config.DISPLAYSYMBOLS in "{0}".format(kext_name):
                    k_start = kext_address
                    k_end  = kext_address + kext_size

                    #loop thru kext functions
                    for func_name, func_addr in self.getKextSymbols(kext_addr = kext_address, onlyFunctions = True, fmodel = model):                
                        print "{0} {1} {2:#10x}".format(kext_name, func_name, func_addr)

            yield ('-', 0, False, False, False, False, '-', '-')
            return

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset = kp, vm = self.addr_space)
        k_start = kmodk.address
        k_end = k_start + kmodk.m('size')
  
        # get syscall table      
        nsysent = obj.Object("int", offset = self.addr_space.profile.get_symbol("_nsysent"), vm = self.addr_space)
        sysents = obj.Object(theType = "Array", offset = self.addr_space.profile.get_symbol("_sysent"), vm = self.addr_space, count = nsysent, targetType = "sysent")

        # check if syscall table is shadowed, if so use shadow address
        (syscall_shadowed, shadow_addr) = self.isSyscallShadowed(model, distorm_mode, sysents.obj_offset)

        if syscall_shadowed:
            # use shadow table address to check hooking
            sysents = obj.Object(theType = "Array", offset = shadow_addr, vm = self.addr_space, count = nsysent, targetType = "sysent")
	
            # check if shadow syscall functions have been modified
            for (i, sysent) in enumerate(sysents):
                ent_addr = sysent.sy_call.v()
                inlined, dst_addr = self.isInlined(model, distorm_mode, ent_addr, k_start, k_end) 
                hooked  = ent_addr not in sym_addrs # using check_syscalls method
                prolog_inlined = self.isPrologInlined(model, distorm_mode, ent_addr) 
                if hooked == True or inlined == True or prolog_inlined == True:
                    if dst_addr != None:
                        kext = self.findKextWithAddress(dst_addr)
                    else:
                        kext = self.findKextWithAddress(ent_addr)
                    yield ("ShadowSyscallTable", i, ent_addr, hooked, inlined, syscall_shadowed, '-', kext)
        else:
            # check if syscall table entries have been modified
            dict_syscall_funcs = {}
            list_syscall_names = []
            for (i, sysent) in enumerate(sysents):
                ent_addr = sysent.sy_call.v()
                hooked  = ent_addr not in sym_addrs # using check_syscalls method
                inlined, dst_addr = self.isInlined(model, distorm_mode, ent_addr, k_start, k_end) 
                prolog_inlined = self.isPrologInlined(model, distorm_mode, ent_addr)
                if hooked == True or inlined == True or prolog_inlined == True:
                    if dst_addr != None:
                        kext = self.findKextWithAddress(dst_addr)
                    else:
                        kext = self.findKextWithAddress(ent_addr)
                    yield ("SyscallTable", i, ent_addr, hooked, (inlined or prolog_inlined), False, '-', kext)
                else:
                    ent_name = self.profile.get_symbol_by_address("kernel", ent_addr)
                    # check for duplicate syscall functions
                    if ent_name != "_nosys" and ent_name in dict_syscall_funcs:
                        prev_ent = dict_syscall_funcs[ent_name]
                        kext = self.findKextWithAddress(ent_addr)
                        yield ("SyscallTable", list_syscall_names.index(ent_name), prev_ent.sy_call.v(), False, False, False, '-', kext)
                        yield ("DuplicateSyscall -> {0}".format(ent_name), i, ent_addr, True, False, False, '-', kext)
                    else:
                        # check for dtrace syscall hooks
                        if ent_name.find("dtrace") > -1:
                            kext = self.findKextWithAddress(ent_addr)
                            yield ("SyscallTable", i, ent_addr, False, False, False, '-', kext)
                        else:
                            # add to list
                            list_syscall_names.append(ent_name)
                            dict_syscall_funcs[ent_name] = sysent
        
        # check if kext functions are inlined, including kernel symbols
        if self._config.CHECKKEXTS  or self._config.CHECKKERNEL:
            # get symbols from kext __TEXT in memory rather than file
            kext_addr_list = []

            # get kernel address
            kmod = obj.Object("kmod_info", offset = self.addr_space.profile.get_symbol("_g_kernel_kmod_info"), vm = self.addr_space)
            kext_addr_list.append(('__kernel__', kmod.address, kmod.m('size')))
            
            # get all kexts
            if self._config.CHECKKERNEL == False:
                # get other kext addresses 
                p = self.addr_space.profile.get_symbol("_kmod")
                kmodaddr = obj.Object("Pointer", offset = p, vm = self.addr_space)
                kmod = kmodaddr.dereference_as("kmod_info")
                while kmod.is_valid():
                    kext_addr_list.append((kmod.name, kmod.address, kmod.m('size')))
                    kmod = kmod.next

            # loop thru kexts
            for kext_name, kext_address, kext_size in kext_addr_list:
                k_start = kext_address
                k_end  = kext_address + kext_size

                #loop thru kext functions
                for func_name, func_addr in self.getKextSymbols(kext_addr = kext_address, onlyFunctions = True, fmodel = model):
                    inlined = False

                    # false positive, remove if needed
                    if func_name in ["pthreads_dummy_symbol"]:
                        continue

                    # check if function's been modified
                    modified, dst_addr = self.isCallReferenceModified(model, distorm_mode, func_addr, k_start, k_end)
                    if modified:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name
                        yield ("SymbolsTable", '-', func_addr, False, modified, False, '-', hook_kext)

                    inlined, dst_addr = self.isInlined(model, distorm_mode, func_addr, k_start, k_end)
                    #prolog_inlined = self.isPrologInlined(model, distorm_mode, func_addr)
                    if inlined:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name 
                        yield ("SymbolsTable", '-', func_addr, False, (inlined or prolog_inlined), False, '-', hook_kext)

        # check if trap table hooked using check_trap_table
        args = ()
        trap = check_trap_table.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, i, call_addr, sym_name, hooked) in trap.calculate():
            if hooked == True or 'dtrace' in sym_name:
                kext = self.findKextWithAddress(call_addr)
                yield ("TrapTable", i, call_addr, hooked, False, False, '-', kext)
Пример #13
0
    def calculate(self):
        common.set_plugin_members(self)

        model = self.addr_space.profile.metadata.get('memory_model', 0)
        if model == '32bit':
            distorm_mode = distorm3.Decode32Bits
        else:
            distorm_mode = distorm3.Decode64Bits

        sym_addrs = self.profile.get_all_addresses()

        # get all kexts and symbols
        if self._config.DISPLAYSYMBOLS != False:
            kext_addr_list = []
            # get kernel address
            kmod = obj.Object("kmod_info",
                              offset=self.addr_space.profile.get_symbol(
                                  "_g_kernel_kmod_info"),
                              vm=self.addr_space)
            kext_addr_list.append(('__kernel__', kmod.address, kmod.m('size')))

            p = self.addr_space.profile.get_symbol("_kmod")
            kmodaddr = obj.Object("Pointer", offset=p, vm=self.addr_space)
            kmod = kmodaddr.dereference_as("kmod_info")
            while kmod.is_valid():
                kext_addr_list.append(
                    (kmod.name, kmod.address, kmod.m('size')))
                kmod = kmod.next

            # loop thru kexts
            for kext_name, kext_address, kext_size in kext_addr_list:
                if self._config.DISPLAYSYMBOLS in "{0}".format(kext_name):
                    k_start = kext_address
                    k_end = kext_address + kext_size

                    #loop thru kext functions
                    for func_name, func_addr in self.getKextSymbols(
                            kext_addr=kext_address,
                            onlyFunctions=True,
                            fmodel=model):
                        print "{0} {1} {2:#10x}".format(
                            kext_name, func_name, func_addr)

            yield ('-', 0, False, False, False, False, '-', '-')
            return

        # get kernel start, end
        kp = self.addr_space.profile.get_symbol("_g_kernel_kmod_info")
        kmodk = obj.Object("kmod_info", offset=kp, vm=self.addr_space)
        k_start = kmodk.address
        k_end = k_start + kmodk.m('size')

        # get syscall table
        nsysent = obj.Object(
            "int",
            offset=self.addr_space.profile.get_symbol("_nsysent"),
            vm=self.addr_space)
        sysents = obj.Object(
            theType="Array",
            offset=self.addr_space.profile.get_symbol("_sysent"),
            vm=self.addr_space,
            count=nsysent,
            targetType="sysent")

        # check if syscall table is shadowed, if so use shadow address
        (syscall_shadowed,
         shadow_addr) = self.isSyscallShadowed(model, distorm_mode,
                                               sysents.obj_offset)

        if syscall_shadowed:
            # use shadow table address to check hooking
            sysents = obj.Object(theType="Array",
                                 offset=shadow_addr,
                                 vm=self.addr_space,
                                 count=nsysent,
                                 targetType="sysent")

            # check if shadow syscall functions have been modified
            for (i, sysent) in enumerate(sysents):
                ent_addr = sysent.sy_call.v()
                inlined, dst_addr = self.isInlined(model, distorm_mode,
                                                   ent_addr, k_start, k_end)
                hooked = ent_addr not in sym_addrs  # using check_syscalls method
                prolog_inlined = self.isPrologInlined(model, distorm_mode,
                                                      ent_addr)
                if hooked == True or inlined == True or prolog_inlined == True:
                    if dst_addr != None:
                        kext = self.findKextWithAddress(dst_addr)
                    else:
                        kext = self.findKextWithAddress(ent_addr)
                    yield ("ShadowSyscallTable", i, ent_addr, hooked, inlined,
                           syscall_shadowed, '-', kext)
        else:
            # check if syscall table entries have been modified
            dict_syscall_funcs = {}
            list_syscall_names = []
            for (i, sysent) in enumerate(sysents):
                ent_addr = sysent.sy_call.v()
                hooked = ent_addr not in sym_addrs  # using check_syscalls method
                inlined, dst_addr = self.isInlined(model, distorm_mode,
                                                   ent_addr, k_start, k_end)
                prolog_inlined = self.isPrologInlined(model, distorm_mode,
                                                      ent_addr)
                if hooked == True or inlined == True or prolog_inlined == True:
                    if dst_addr != None:
                        kext = self.findKextWithAddress(dst_addr)
                    else:
                        kext = self.findKextWithAddress(ent_addr)
                    yield ("SyscallTable", i, ent_addr, hooked,
                           (inlined or prolog_inlined), False, '-', kext)
                else:
                    ent_name = self.profile.get_symbol_by_address(
                        "kernel", ent_addr)
                    # check for duplicate syscall functions
                    if ent_name != "_nosys" and ent_name in dict_syscall_funcs:
                        prev_ent = dict_syscall_funcs[ent_name]
                        kext = self.findKextWithAddress(ent_addr)
                        yield ("SyscallTable",
                               list_syscall_names.index(ent_name),
                               prev_ent.sy_call.v(), False, False, False, '-',
                               kext)
                        yield ("DuplicateSyscall -> {0}".format(ent_name), i,
                               ent_addr, True, False, False, '-', kext)
                    else:
                        # check for dtrace syscall hooks
                        if ent_name.find("dtrace") > -1:
                            kext = self.findKextWithAddress(ent_addr)
                            yield ("SyscallTable", i, ent_addr, False, False,
                                   False, '-', kext)
                        else:
                            # add to list
                            list_syscall_names.append(ent_name)
                            dict_syscall_funcs[ent_name] = sysent

        # check if kext functions are inlined, including kernel symbols
        if self._config.CHECKKEXTS or self._config.CHECKKERNEL:
            # get symbols from kext __TEXT in memory rather than file
            kext_addr_list = []

            # get kernel address
            kmod = obj.Object("kmod_info",
                              offset=self.addr_space.profile.get_symbol(
                                  "_g_kernel_kmod_info"),
                              vm=self.addr_space)
            kext_addr_list.append(('__kernel__', kmod.address, kmod.m('size')))

            # get all kexts
            if self._config.CHECKKERNEL == False:
                # get other kext addresses
                p = self.addr_space.profile.get_symbol("_kmod")
                kmodaddr = obj.Object("Pointer", offset=p, vm=self.addr_space)
                kmod = kmodaddr.dereference_as("kmod_info")
                while kmod.is_valid():
                    kext_addr_list.append(
                        (kmod.name, kmod.address, kmod.m('size')))
                    kmod = kmod.next

            # loop thru kexts
            for kext_name, kext_address, kext_size in kext_addr_list:
                k_start = kext_address
                k_end = kext_address + kext_size

                #loop thru kext functions
                for func_name, func_addr in self.getKextSymbols(
                        kext_addr=kext_address, onlyFunctions=True,
                        fmodel=model):
                    inlined = False

                    # false positive, remove if needed
                    if func_name in ["pthreads_dummy_symbol"]:
                        continue

                    # check if function's been modified
                    modified, dst_addr = self.isCallReferenceModified(
                        model, distorm_mode, func_addr, k_start, k_end)
                    if modified:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name
                        yield ("SymbolsTable", '-', func_addr, False, modified,
                               False, '-', hook_kext)

                    inlined, dst_addr = self.isInlined(model, distorm_mode,
                                                       func_addr, k_start,
                                                       k_end)
                    #prolog_inlined = self.isPrologInlined(model, distorm_mode, func_addr)
                    if inlined:
                        if dst_addr != None:
                            hook_kext = self.findKextWithAddress(dst_addr)
                        else:
                            hook_kext = kext_name
                        yield ("SymbolsTable", '-', func_addr, False,
                               (inlined
                                or prolog_inlined), False, '-', hook_kext)

        # check if trap table hooked using check_trap_table
        args = ()
        trap = check_trap_table.mac_check_trap_table(self._config, args)
        for (table_addr, table_name, i, call_addr, sym_name,
             hooked) in trap.calculate():
            if hooked == True or 'dtrace' in sym_name:
                kext = self.findKextWithAddress(call_addr)
                yield ("TrapTable", i, call_addr, hooked, False, False, '-',
                       kext)