예제 #1
0
    def render_text(self, outfd, data):
        for task in data:
            proc_as = task.get_process_address_space()

            for map in task.get_proc_maps():
                if map.is_suspicious():
                    fname = map.get_path()                    
                    prots = map.get_perms()

                    content = proc_as.zread(map.start, 64)

                    outfd.write("Process: {0} Pid: {1} Address: {2:#x} File: {3}\n".format(
                        task.p_comm, task.p_pid, map.start, fname))

                    outfd.write("Protection: {0}\n".format(prots))

                    outfd.write("\n")

                    outfd.write("{0}\n".format("\n".join(
                        ["{0:#010x}  {1:<48}  {2}".format(map.start + o, h, ''.join(c))
                        for o, h, c in utils.Hexdump(content)
                        ])))

                    outfd.write("\n")
                    outfd.write("\n".join(
                        ["{0:#x} {1:<16} {2}".format(o, h, i)
                        for o, i, h in malfind.Disassemble(content, map.start)
                        ]))
                
                    outfd.write("\n\n")
예제 #2
0
def parse_yarascan_data(data, out, output="text"):
    import volatility.plugins.malware.malfind as malfind
    import volatility.utils as utils
    datas = getinfos(data, plugin_cols["yarascan"]["cols"])
    if output == "json":
        out.write("{}\n\n".format(datas))
        return
    elif output == "text":
        mode = "32bit"
        if platform.machine() == "AMD64":
            mode = "64bit"
        for rule, owner, addr, content in datas:
            out.write("Rule: {0}\n".format(rule))
            if owner == None:
                out.write("Owner: (Unknown Kernel Memory)\n")
            else:
                out.write("Owner: {0}\n".format(owner))
            out.write("Hexdump:\n")
            out.write("".join([
                "{0:#010x}  {1:<48}  {2}\n".format(addr, h, ''.join(c))
                for offset, h, c in utils.Hexdump(content.decode("hex"))
            ]))
            out.write("\n\nDisassembly:\n")
            out.write("\n".join([
                "{0:#x} {1:<16} {2}".format(o, h, i)
                for o, i, h in malfind.Disassemble(content.decode("hex"),
                                                   int(addr), mode)
            ]))
            out.write("\n\n")
    else:
        for rule, owner, addr, content in datas:
            out.write("{0},{1},{2}\n".format(rule, owner, addr, content))
        out.write("\n\n")
    out.write("\n\n")
예제 #3
0
def parse_malfind_data(data, out, output = "text"):
    import volatility.plugins.malware.malfind as malfind
    import volatility.utils as utils
    datas = getinfos(data, plugin_cols["malfind"]["cols"])
    if output == "json":
        out.write("{}\n\n".format(datas))
        return
    elif output == "text":
        mode = "32bit"
        if platform.machine() == "AMD64":
            mode = "64bit"
        for proc, pid, address, vadtag, protection, flags, data in datas:
            out.write("Process: {}, Pid: {}\n".format(proc, pid))
            out.write("VadTag: {}, Protection: {}, Flags: {}\n\n".format(vadtag, protection, flags))
            out.write("Raw data at address {0:#x}: {1}\n\n".format(address, data))
            out.write("Disassembly:\n")
            out.write("\n".join(
                    ["{0:#x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(data.decode("hex"), int(address), mode)
                    ]))
            out.write("\n\nHexdump:\n")
            out.write("{0}\n".format("\n".join(
                    ["{0:#010x}  {1:<48}  {2}".format(int(address) + o, h, ''.join(c))
                    for o, h, c in utils.Hexdump(data.decode("hex"))
                    ])))
            out.write("\n\n")
    else:
        for proc, pid, address, vadtag, protection, flags, data in datas:
            out.write("{},{},{},{},{},{},{}\n".format(proc, pid, address, vadtag, protection, flags, data))
        out.write("\n\n")
    out.write("\n\n")
예제 #4
0
    def render_text(self, outfd, data):
        for process, module, hook in data:

            outfd.write("*" * 72 + "\n")
            outfd.write("Hook mode: {0}\n".format(hook.Mode))
            outfd.write("Hook type: {0}\n".format(hook.Type))

            if process:
                outfd.write('Process: {0} ({1})\n'.format(
                    process.UniqueProcessId, process.ImageFileName))

            outfd.write("Victim module: {0} ({1:#x} - {2:#x})\n".format(
                str(module.BaseDllName or '') or ntpath.basename(str(module.FullDllName or '')),
                module.DllBase, module.DllBase + module.SizeOfImage))

            outfd.write("Function: {0}\n".format(hook.Detail))
            outfd.write("Hook address: {0:#x}\n".format(hook.hook_address))
            outfd.write("Hooking module: {0}\n\n".format(hook.HookModule))

            for n, info in enumerate(hook.disassembled_hops):
                (address, data) = info
                s = ["{0:#x} {1:<16} {2}".format(o, h, i)
                        for o, i, h in
                        malfind.Disassemble(data, int(address), bits = "32bit" if hook.decode_bits == distorm3.Decode32Bits else "64bit")
                    ]
                outfd.write("Disassembly({0}):\n{1}".format(n, "\n".join(s)))
                outfd.write("\n\n")
예제 #5
0
    def render_text(self, outfd, data):

        self.table_header(outfd, [
            ('CPU', '>6X'),
            ('Index', '>6X'),
            ('Selector', '[addr]'),
            ('Value', '[addrpad]'),
            ('Module', '20'),
            ('Section', '12'),
        ])

        for n, entry, addr, module in data:

            if module:
                module_name = str(module.BaseDllName or '')
                sect_name = self.get_section_name(module, addr)
            else:
                module_name = "UNKNOWN"
                sect_name = ''

            # The parent is IDT. The grand-parent is _KPCR.
            cpu_number = entry.obj_parent.obj_parent.ProcessorBlock.Number

            self.table_row(outfd, cpu_number, n, entry.Selector, addr,
                           module_name, sect_name)

            if self._config.verbose:
                data = entry.obj_vm.zread(addr, 32)
                outfd.write("\n".join([
                    "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in
                    malfind.Disassemble(data=data, start=addr, stoponret=True)
                ]))
                outfd.write("\n")
예제 #6
0
    def render_text(self, outfd, data):
        for process, module, hook in data:

            outfd.write("*" * 72 + "\n")
            outfd.write(f"Hook mode: {hook.Mode}\n")
            outfd.write(f"Hook type: {hook.Type}\n")

            if process:
                outfd.write(
                    f"Process: {process.UniqueProcessId} ({process.ImageFileName})\n"
                )

            dll_name = str(module.BaseDllName or '') or ntpath.basename(
                str(module.FullDllName or ''))
            outfd.write(
                f"Victim module: {dll_name} ({module.DllBase:#x} - {module.DllBase+module.SizeOfImage:#x})\n"
            )
            outfd.write(f"Function: {hook.Detail}\n")
            outfd.write(f"Hook address: {hook.hook_address:#x}\n")
            outfd.write(f"Hooking module: {hook.HookModule}\n\n")

            for n, info in enumerate(hook.disassembled_hops):
                (address, data) = info
                s = [
                    f"{o:#x} {h:<16} {i}" for o, i, h in malfind.Disassemble(
                        data,
                        int(address),
                        bits="32bit" if hook.decode_bits ==
                        distorm3.Decode32Bits else "64bit",
                    )
                ]
                outfd.write(f"Disassembly({n}):\n")
                outfd.write('\n'.join(s))
                outfd.write("\n\n")
예제 #7
0
    def render_text(self, outfd, data):

        addr_space = utils.load_as(self._config)

        # Compile the regular expression for filtering by driver name
        if self._config.regex != None:
            mod_re = re.compile(self._config.regex, re.I)
        else:
            mod_re = None

        mods = dict((addr_space.address_mask(mod.DllBase), mod)
                    for mod in modules.lsmod(addr_space))
        mod_addrs = sorted(mods.keys())

        bits = addr_space.profile.metadata.get('memory_model', '32bit')

        self.table_header(None, [('i', ">4"), ('Funcs', "36"),
                                 ('addr', '[addrpad]'), ('name', '')])

        for object_obj, driver_obj, _ in data:
            driver_name = str(object_obj.NameInfo.Name or '')
            # Continue if a regex was supplied and it doesn't match
            if mod_re != None:
                if not (mod_re.search(driver_name)
                        or mod_re.search(driver_name)):
                    continue

            # Write the standard header for each driver object
            outfd.write("{0}\n".format("-" * 50))
            outfd.write("DriverName: {0}\n".format(driver_name))
            outfd.write("DriverStart: {0:#x}\n".format(driver_obj.DriverStart))
            outfd.write("DriverSize: {0:#x}\n".format(driver_obj.DriverSize))
            outfd.write("DriverStartIo: {0:#x}\n".format(
                driver_obj.DriverStartIo))

            # Write the address and owner of each IRP function
            for i, function in enumerate(driver_obj.MajorFunction):
                function = driver_obj.MajorFunction[i]
                module = tasks.find_module(mods, mod_addrs,
                                           addr_space.address_mask(function))
                if module:
                    module_name = str(module.BaseDllName or '')
                else:
                    module_name = "Unknown"
                # This is where we check for inline hooks once the
                # ApiHooks plugin is ported to 2.1.
                self.table_row(outfd, i, MAJOR_FUNCTIONS[i], function,
                               module_name)

                if self._config.verbose:
                    data = addr_space.zread(function, 64)
                    outfd.write("\n".join([
                        "{0:#x} {1:<16} {2}".format(o, h, i)
                        for o, i, h in malfind.Disassemble(data=data,
                                                           start=function,
                                                           bits=bits,
                                                           stoponret=True)
                    ]))
                    outfd.write("\n")
예제 #8
0
def disAssembleInstr(instrStream, instrLocation, opcodeCount):
    toRet = []
    for _, i, _ in malfind.Disassemble(instrStream, instrLocation, True):
        toRet.append(i)
        opcodeCount = opcodeCount - 1
        if opcodeCount == 0:
            break
    return "; ".join(toRet)
예제 #9
0
    def get_json(self, data):
        results = {"Hooks":[]}
        for process, module, hook in data:

            if not self._config.NO_WHITELIST:

                if process:
                    process_name = str(process.ImageFileName)
                    process_id = int(process.UniqueProcessId)
                else:
                    process_name = ''
                    process_id = -1

                if self.whitelist(hook.hook_mode | hook.hook_type,
                                    process_name, hook.VictimModule,
                                    hook.HookModule, hook.Function):
                    #debug.debug("Skipping whitelisted function: {0} {1} {2} {3}".format(
                    #    process_name, hook.VictimModule, hook.HookModule,
                    #    hook.Function))
                    continue

            row = {'ImageFileName':process_name or '',
                   'Mode':str(hook.Mode),
                   'Type':str(hook.Type),
                   'UniqueProcessId':process_id,
                   'BaseDllName':str(module.BaseDllName or ''),
                   'SizeOfImage':int(module.SizeOfImage),
                   'FullDllName':ntpath.basename(str(module.FullDllName or '')),
                   'DllBase':long(module.DllBase),
                   'DllSize': "{}".format(module.SizeOfImage),
                   'DllEndAddress': module.DllBase + module.SizeOfImage,
                   'Detail': str(hook.Detail),
                   'HookAddress':long(hook.hook_address),
                   'HookModule':str(hook.HookModule),
                   'Disassembly':[]
                  }

            for n, info in enumerate(hook.disassembled_hops):
                (address, data) = info
                s = [{'Address':int(o), "Bytes":str(h), "Instruction":str(i)}
                        for o, i, h in
                        malfind.Disassemble(data, int(address), bits = "32bit" if hook.decode_bits == distorm3.Decode32Bits else "64bit")
                    ]
                disassembled = {'Disassembly':s,
                                'Address':"{}".format(address),
                                'Hop':n}
                row['Disassembly'].append(disassembled)
            results['Hooks'].append(row)

        return results
예제 #10
0
def printUnicornContext(pas, nextIns, unicornEng):
    print "Unicorn context: "
    instrStream = pas.read(nextIns, 20)
    for _, i, _ in malfind.Disassemble(instrStream, nextIns):
        print "\t %s" % i
    print "ESP = %s" % hex(unicornEng.reg_read(UC_X86_REG_ESP))
    print "EAX = %s" % hex(unicornEng.reg_read(UC_X86_REG_EAX))
    print "EBX = %s" % hex(unicornEng.reg_read(UC_X86_REG_EBX))
    print "ECX = %s" % hex(unicornEng.reg_read(UC_X86_REG_ECX))
    print "EDX = %s" % hex(unicornEng.reg_read(UC_X86_REG_EDX))
    print "ESI = %s" % hex(unicornEng.reg_read(UC_X86_REG_ESI))
    print "EDI = %s" % hex(unicornEng.reg_read(UC_X86_REG_EDI))
    print "EFLAGS = %s" % hex(unicornEng.reg_read(UC_X86_REG_EFLAGS))
    print ""
예제 #11
0
    def generate_output(self, outfd, vad, task, file_object_name,
                        peb_image_path_name):
        # this function will output data for a given VAD passed to it

        content = None

        outfd.write("Process: {0} Pid: {1} Ppid: {2}\n".format(
            task.ImageFileName, task.UniqueProcessId,
            task.InheritedFromUniqueProcessId))

        outfd.write("Address: {0:#x} Protection: {1}\n".format(
            vad.Start,
            vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v(), "")))

        if peb_image_path_name != None:
            outfd.write("Initially mapped file object: {0}\n".format(
                peb_image_path_name))
        else:
            outfd.write("Initially mapped file object: {0}\n".format("None"))

        if file_object_name != None:
            outfd.write(
                "Currently mapped file object: {0}\n".format(file_object_name))
        else:
            outfd.write("Currently mapped file object: {0}\n".format("None"))

        address_space = task.get_process_address_space()
        content = address_space.zread(vad.Start, 64)

        if content:
            outfd.write("{0}\n".format("\n".join([
                "{0:#010x}  {1:<48}  {2}".format(vad.Start + o, h, ''.join(c))
                for o, h, c in utils.Hexdump(content)
            ])))

            outfd.write("\n")
            outfd.write("\n".join([
                "{0:#010x} {1:<16} {2}".format(o, h, i)
                for o, i, h in malfind.Disassemble(content, vad.Start)
            ]))

        outfd.write("\n\n")

        # dump vad incase -D was specified
        if self._config.DUMP_DIR:
            filename = os.path.join(
                self._config.DUMP_DIR,
                "process.{0:#x}.{1:#x}.dmp".format(task.obj_offset, vad.Start))
            self.dump_vad(filename, vad, address_space)
예제 #12
0
    def disassemble(self, address_space, entry_point):
        """
        :param address_space: process's address space object
        :param entry_point: Start address
        :return: A string of the disassembled code
        Disassemble the 64 bytes of code by giving the process's
        address space and the start address
        """
        entry_point = int(entry_point)
        content = address_space.read(entry_point, 64)

        # Check if we could have read from memory, might be paged
        if content:
            disassemble_code = "\t"
            disassemble_code += ("{0}\n\n".format("\n\t".join([
                "{0:#010x}  {1:<48}  {2}".format(entry_point + o, h,
                                                 ''.join(c))
                for o, h, c in utils.Hexdump(content)
            ])))
            disassemble_code += "\t"

            # Rather disassemble with distrom3 than malfind
            if has_distorm:
                # Get OS profile
                mode = address_space.profile.metadata.get('memory_model')

                if mode == '64bit':
                    mode = distorm3.Decode64Bits

                else:
                    mode = distorm3.Decode32Bits

                disassemble_code += "\n\t".join(["{0:<#010x} {1:<16} {2}".format(o, h, i) \
                                              for o, _size, i, h in \
                                              distorm3.DecodeGenerator(entry_point, content, mode)])

            else:
                disassemble_code += "\n\t".join([
                    "{0:#010x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(content, entry_point)
                ])

            disassemble_code += "\n"

        else:
            disassemble_code = "\t** Couldn't read memory\n"

        return disassemble_code
예제 #13
0
    def render_text(self, outfd, data):
        linux_common.set_plugin_members(self)

        if self.addr_space.profile.metadata.get('memory_model',
                                                '32bit') == '32bit':
            bits = '32bit'
        else:
            bits = '64bit'

        for task in data:
            proc_as = task.get_process_address_space()

            for vma in task.get_proc_maps():

                if vma.is_suspicious():
                    fname = vma.vm_name(task)
                    if fname == "[vdso]":
                        continue

                    prots = vma.protection()
                    flags = vma.flags()

                    content = proc_as.zread(vma.vm_start, 64)

                    outfd.write(
                        "Process: {0} Pid: {1} Address: {2:#x} File: {3}\n".
                        format(task.comm, task.pid, vma.vm_start, fname))

                    outfd.write("Protection: {0}\n".format(prots))

                    outfd.write("Flags: {0}\n".format(str(flags)))
                    outfd.write("\n")

                    outfd.write("{0}\n".format("\n".join([
                        "{0:#016x}  {1:<48}  {2}".format(
                            vma.vm_start + o, h, ''.join(c))
                        for o, h, c in utils.Hexdump(content)
                    ])))

                    outfd.write("\n")
                    outfd.write("\n".join([
                        "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in
                        malfind.Disassemble(content, vma.vm_start, bits=bits)
                    ]))

                    outfd.write("\n\n")
예제 #14
0
    def render_text(self, outfd, data):
        for process, module, hook in data:

            if not self._config.NO_WHITELIST:

                if process:
                    process_name = str(process.ImageFileName)
                else:
                    process_name = ''

                if self.whitelist(hook.hook_mode | hook.hook_type,
                                  process_name, hook.VictimModule,
                                  hook.HookModule, hook.Function):
                    #debug.debug("Skipping whitelisted function: {0} {1} {2} {3}".format(
                    #    process_name, hook.VictimModule, hook.HookModule,
                    #    hook.Function))
                    continue

            outfd.write("*" * 72 + "\n")
            outfd.write("Hook mode: {0}\n".format(hook.Mode))
            outfd.write("Hook type: {0}\n".format(hook.Type))

            if process:
                outfd.write('Process: {0} ({1})\n'.format(
                    process.UniqueProcessId, process.ImageFileName))

            outfd.write("Victim module: {0} ({1:#x} - {2:#x})\n".format(
                str(module.BaseDllName or '')
                or ntpath.basename(str(module.FullDllName or '')),
                module.DllBase, module.DllBase + module.SizeOfImage))

            outfd.write("Function: {0}\n".format(hook.Detail))
            outfd.write("Hook address: {0:#x}\n".format(hook.hook_address))
            outfd.write("Hooking module: {0}\n\n".format(hook.HookModule))

            for n, info in enumerate(hook.disassembled_hops):
                (address, data) = info
                s = [
                    "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in
                    malfind.Disassemble(data,
                                        int(address),
                                        bits="32bit" if hook.decode_bits ==
                                        distorm3.Decode32Bits else "64bit")
                ]
                outfd.write("Disassembly({0}):\n{1}".format(n, "\n".join(s)))
                outfd.write("\n\n")
예제 #15
0
def parse_malfind_data(data, out, output = "text"):
    import volatility.plugins.malware.malfind as malfind
    datas = getinfos(data, plugin_cols["malfind"]["cols"])
    if output == "json":
        out.write("{}\n\n".format(datas))
        return
    elif output == "text":
        for proc, address, data in datas:
            out.write("Process: {}\n\n".format(proc))
            out.write("Raw data at address {0:#x}: {1}\n\n".format(address, data))
            out.write("Disassembly:\n")
            out.write("\n".join(
                    ["{0:#x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(data.decode("hex"), int(address))
                    ]))
            out.write("\n\n")
    else:
        for proc, address, data in datas:
            out.write("{0},{1},{2}\n".format(proc, address, data))
        out.write("\n\n")
    out.write("\n\n")
예제 #16
0
    def render_text(self, outfd, data):
        for task in data:
            proc_as = task.get_process_address_space()

            for vma in task.get_proc_maps():

                if vma.is_suspicious():
                    fname = vma.vm_name(task)
                    if fname == "[vdso]":
                        continue

                    prots = vma.protection()
                    flags = vma.flags()

                    content = proc_as.zread(vma.vm_start, 64)

                    outfd.write(
                        "Process: {0} Pid: {1} Address: {2:#x} File: {3}\n".
                        format(task.comm, task.pid, vma.vm_start, fname))

                    outfd.write("Protection: {0}\n".format(prots))

                    outfd.write("Flags: {0}\n".format(str(flags)))
                    outfd.write("\n")

                    outfd.write("{0}\n".format("\n".join([
                        "{0:#010x}  {1:<48}  {2}".format(
                            vma.vm_start + o, h, ''.join(c))
                        for o, h, c in utils.Hexdump(content)
                    ])))

                    outfd.write("\n")
                    outfd.write("\n".join([
                        "{0:#x} {1:<16} {2}".format(o, h, i)
                        for o, i, h in malfind.Disassemble(
                            content, vma.vm_start)
                    ]))

                    outfd.write("\n\n")
예제 #17
0
    def generator(self, data):
        # Determine which filters the user wants to see
        if self._config.FILTER:
            filters = set(self._config.FILTER.split(','))
        else:
            filters = set()

        for thread, addr_space, mods, mod_addrs, \
                     instances, hooked_tables, system_range, owner_name in data:
            # If the user didn't set filters, display all results. If
            # the user set one or more filters, only show threads
            # with matching results.
            tags = set([t for t, v in instances.items() if v.check()])

            if filters and not filters & tags:
                continue

            values = []

            values.append(Address(thread.obj_offset))
            values.append(int(thread.Cid.UniqueProcess))
            values.append(int(thread.Cid.UniqueThread))

            values.append(','.join(tags))
            values.append(str(thread.CreateTime))
            if thread.ExitTime > 0:
                values.append(str(thread.ExitTime))
            else:
                values.append('')

            values.append(str(thread.owning_process().ImageFileName))

            values.append(str(thread.attached_process().ImageFileName))

            # Lookup the thread's state
            state = str(thread.Tcb.State)

            # Find the wait reason
            if state == 'Waiting':
                state_reason = str(thread.Tcb.WaitReason)
            else:
                state_reason = ''

            values.append(state)
            values.append(state_reason)

            values.append(int(thread.Tcb.BasePriority))
            values.append(int(thread.Tcb.Priority))
            values.append(Address(thread.Tcb.Teb))

            values.append(Address(thread.StartAddress))
            values.append(owner_name)

            # Check the flag which indicates whether Win32StartAddress is valid
            if thread.SameThreadApcFlags & 1:
                values.append(Address(thread.Win32StartAddress))
            else:
                values.append(Address(-1))

            values.append(Address(thread.Tcb.Win32Thread))
            values.append(str(thread.CrossThreadFlags))

            # Disasemble the start address if possible
            dis = ''
            process_space = thread.owning_process().get_process_address_space()

            if process_space.is_valid_address(thread.StartAddress):
                buf = process_space.zread(thread.StartAddress, 24)

                mode = "32bit" if self.bits32 else "64bit"

                dis += "\n".join(["{0:#x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(buf, thread.StartAddress.v(), mode)])

            if self.bits32:
                # Print the registers if possible
                trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME")

                if trapframe:
                    for r in trapframe.Eip, trapframe.Eax, trapframe.Ebx, \
                            trapframe.Ecx, trapframe.Edx, trapframe.Esi, \
                            trapframe.Edi, trapframe.HardwareEsp, \
                            trapframe.Ebp, trapframe.ErrCode, trapframe.SegCs, \
                            trapframe.HardwareSegSs, trapframe.SegDs, \
                            trapframe.SegEs, trapframe.SegGs, trapframe.SegFs, \
                            trapframe.EFlags, trapframe.Dr0, trapframe.Dr1, \
                            trapframe.Dr2, trapframe.Dr3, trapframe.Dr6, \
                            trapframe.Dr7 :
                        values.append(Hex(r))
                else:
                    values.extend( [Hex(-1)] * 23 )

                values.append(Address(thread.Tcb.ServiceTable))

                ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE",
                    offset = thread.Tcb.ServiceTable,
                    vm = addr_space
                    )

                if ssdt_obj != None:
                    for i, desc in enumerate(ssdt_obj.Descriptors):
                        if desc.is_valid():
                            service_table = Address(desc.KiServiceTable.v())
                        else:
                            service_table = Address(-1)
                        # Show exactly which functions are hooked
                        table = desc.KiServiceTable.v()
                        if table not in hooked_tables.keys():
                            yield (0, values + [i, service_table, -1, '',
                                                Address(-1), '', dis])
                            continue
                        yielded=False
                        for (j, func_name, func_addr, mod_name) in hooked_tables[table]:
                            yielded=True
                            yield(0, values + [i, service_table, j, func_name,
                                               Address(func_addr), mod_name, dis])
                        if not yielded:
                            yield (0, values + [i, service_table, -1, '',
                                                Address(-1), '', dis])
                else:
                    values.extend([ -1, Address(-1), -1, '', Address(-1), '', dis ])
                    yield (0, values)
            else:
                # registers
                values.extend( [Hex(-1)] * 23 )
                # ssdt
                values.extend([ Address(-1), -1, Address(-1), -1, '',
                                Address(-1), '', dis ])
                yield (0, values)
예제 #18
0
    def render_text(self, outfd, data):

        # Determine which filters the user wants to see
        if self._config.FILTER:
            filters = set(self._config.FILTER.split(','))
        else:
            filters = set()

        for thread, addr_space, mods, mod_addrs, instances, hooked_tables in data:
            # If the user didn't set filters, display all results. If
            # the user set one or more filters, only show threads
            # with matching results.
            tags = set([t for t, v in list(instances.items()) if v.check()])

            if filters and not filters & tags:
                continue

            s = "------\n"

            s += "ETHREAD: {0:#010x} Pid: {1} Tid: {2}\n".format(
                thread.obj_offset, thread.Cid.UniqueProcess,
                thread.Cid.UniqueThread)

            s += "Tags: {0}\n".format(','.join(tags))
            s += "Created: {0}\n".format(thread.CreateTime)
            s += "Exited: {0}\n".format(thread.ExitTime)

            s += "Owning Process: {0}\n".format(
                thread.owning_process().ImageFileName)

            s += "Attached Process: {0}\n".format(
                thread.attached_process().ImageFileName)

            # Lookup the thread's state
            state = str(thread.Tcb.State)

            # Append the wait reason
            if state == 'Waiting':
                state = state + ':' + str(thread.Tcb.WaitReason)

            s += "State: {0}\n".format(state)
            s += "BasePriority: {0:#x}\n".format(thread.Tcb.BasePriority)
            s += "Priority: {0:#x}\n".format(thread.Tcb.Priority)
            s += "TEB: {0:#010x}\n".format(thread.Tcb.Teb)

            # If its a system thread, get the owning module
            if "SystemThread" in tags:
                owner = tasks.find_module(mods, mod_addrs, thread.StartAddress)
            else:
                owner = None

            if owner:
                owner_name = str(owner.BaseDllName or '')
            else:
                owner_name = "UNKNOWN"

            s += "StartAddress: {0:#010x} {1}\n".format(
                thread.StartAddress, owner_name)

            # Check the flag which indicates whether Win32StartAddress is valid
            if thread.SameThreadApcFlags & 1:
                s += "Win32StartAddress: {0:#010x}\n".format(
                    thread.Win32StartAddress)

            if self.bits32:
                s += "ServiceTable: {0:#010x}\n".format(
                    thread.Tcb.ServiceTable)

                ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE",
                                      offset=thread.Tcb.ServiceTable,
                                      vm=addr_space)

                if ssdt_obj != None:
                    for i, desc in enumerate(ssdt_obj.Descriptors):
                        if desc.is_valid():
                            s += "  [{0}] {1:#010x}\n".format(
                                i, desc.KiServiceTable.v())
                        else:
                            s += "  [{0}] -\n".format(i)
                        # Show exactly which functions are hooked
                        table = desc.KiServiceTable.v()
                        if table not in list(hooked_tables.keys()):
                            continue
                        for (i, func_name, func_addr,
                             mod_name) in hooked_tables[table]:
                            s += "      [{0:#x}] {1} {2:#x} {3}\n".format(
                                i, func_name, func_addr, mod_name)

            s += "Win32Thread: {0:#010x}\n".format(thread.Tcb.Win32Thread)
            s += "CrossThreadFlags: {0}\n".format(thread.CrossThreadFlags)

            # Print the registers if possible
            trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME")

            if trapframe and self.bits32:
                s += "Eip: {0:#10x}\n".format(trapframe.Eip)
                s += "  eax={0:#010x} ebx={1:#010x} ecx={2:#010x}".format(
                    trapframe.Eax, trapframe.Ebx, trapframe.Ecx)
                s += " edx={0:#010x} esi={1:#010x} edi={2:#010x}\n".format(
                    trapframe.Edx, trapframe.Esi, trapframe.Edi)
                s += "  eip={0:#010x} esp={1:#010x} ebp={2:#010x} err={3:#010x}\n".format(
                    trapframe.Eip, trapframe.HardwareEsp, trapframe.Ebp,
                    trapframe.ErrCode)
                s += "  cs={0:#04x} ss={1:#04x} ds={2:#04x}".format(
                    trapframe.SegCs, trapframe.HardwareSegSs, trapframe.SegDs)
                s += " es={0:#04x} gs={1:#04x} efl={2:#010x}\n".format(
                    trapframe.SegEs, trapframe.SegGs, trapframe.EFlags)
                s += "  dr0={0:#010x} dr1={1:#010x} dr2={2:#010x}".format(
                    trapframe.Dr0, trapframe.Dr1, trapframe.Dr2)
                s += " dr3={0:#010x} dr6={1:#010x} dr7={2:#010x}\n".format(
                    trapframe.Dr3, trapframe.Dr6, trapframe.Dr7)

            # Disasemble the start address if possible
            if addr_space.is_valid_address(thread.StartAddress):
                buf = addr_space.zread(thread.StartAddress, 24)

                s += "\n".join([
                    "{0:#x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(buf,
                                                       thread.StartAddress.v())
                ])

            outfd.write("{0}\n".format(s))
예제 #19
0
 def render_text(self, outfd, data):
     for (hol_proc_peb_info, hol_proc_vad_info, hol_pid, hol_type, similar_procs, parent_proc_info) in data:
         (proc, pid, proc_name, ppid, create_time, proc_cmd_line, proc_image_baseaddr, mod_baseaddr, 
          mod_size, mod_basename, mod_fullname) = hol_proc_peb_info
         (vad_filename, vad_baseaddr, vad_size, vad_protection, vad_tag) = hol_proc_vad_info
         (parent_name, parent_id) = parent_proc_info
         
         outfd.write("Hollowed Process Information:\n")
         outfd.write("\tProcess: {0} PID: {1}\n".format(proc_name, hol_pid))
         outfd.write("\tParent Process: {0} PPID: {1}\n".format(parent_name, ppid))
         outfd.write("\tCreation Time: {0}\n".format(create_time))
         outfd.write("\tProcess Base Name(PEB): {0}\n".format(mod_basename))
         outfd.write("\tCommand Line(PEB): {0}\n".format(proc_cmd_line))
         outfd.write("\tHollow Type: {0}\n".format(hollow_types[hol_type]))
         outfd.write("\n")
         outfd.write( "VAD and PEB Comparison:\n")
         outfd.write( "\tBase Address(VAD): {0:#x}\n".format(vad_baseaddr))
         outfd.write( "\tProcess Path(VAD): {0}\n".format(vad_filename))
         outfd.write( "\tVad Protection: {0}\n".format(vad_protection))
         outfd.write( "\tVad Tag: {0}\n".format(vad_tag))
         outfd.write("\n")
         
         if hol_type == 0:
             addr_space = proc.get_process_address_space()
             dos_header = obj.Object("_IMAGE_DOS_HEADER", offset=proc_image_baseaddr, vm=addr_space)
             nt_header = dos_header.get_nt_header()
             optional_header = obj.Object("_IMAGE_OPTIONAL_HEADER", offset=nt_header.obj_offset+0x18, vm=addr_space)
             ep_addr = proc_image_baseaddr + optional_header.AddressOfEntryPoint
             content = addr_space.read(ep_addr, 64)
             outfd.write("\tBase Address(PEB): {0:#x}\n".format(proc_image_baseaddr))
             outfd.write("\tProcess Path(PEB): {0}\n" .format(mod_fullname))
             outfd.write("\tMemory Protection: {0}\n".format(vad_protection))
             outfd.write("\tMemory Tag: {0}\n".format(vad_tag))
             outfd.write("\n")
             outfd.write("Disassembly(Entry Point):\n")
             if content != None:
                 outfd.write("\n".join(["\t{0:#010x} {1:<16} {2}".format(o, h, i) 
                  for o, i, h in malfind.Disassemble(content, ep_addr)
                 ]))
             else:
                 outfd.write("\tNo Disassembly: Memory Unreadable at {0:#010x}\n".format(ep_addr))
                 
             outfd.write("\n\n")
         
         if (hol_type == 1) or (hol_type == 2):
             for vad, addr_space in proc.get_vads():
                 if vad.Start == proc_image_baseaddr:
                     content = addr_space.read(vad.Start, 64)
                     outfd.write("\tBase Address(PEB): {0:#x}\n".format(proc_image_baseaddr))
                     outfd.write("\tProcess Path(PEB): {0}\n" .format(mod_fullname))
                     outfd.write("\tMemory Protection: {0}\n".format(str(vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v()) or  "")))
                     outfd.write("\tMemory Tag: {0}\n".format(str(vad.Tag or "")))
                     outfd.write("\n")
                     if content != None:
                         outfd.write("".join(["{0:#010x}  {1:<48}  {2}\n".format(vad.Start + o, h, ''.join(c))
                                    for o, h, c in utils.Hexdump(content)]))
                     else:
                         outfd.write("\tNo Hexdump: Memory Unreadable at {0:#010x}\n".format(vad.Start))
                     outfd.write("\n")
                     
         outfd.write("Similar Processes:\n")
         for similar_proc in similar_procs:
             (process_name, process_id, parent_name, parent_id, creation_time) = similar_proc
             outfd.write("\t{0}({1}) Parent:{2}({3}) Start:{4}\n".format(process_name,
                                                                         process_id,
                                                                         parent_name,
                                                                         parent_id,
                                                                         creation_time))
         outfd.write("\n")
         
         outfd.write("Suspicious Memory Regions:\n")
         for vad, addr_space in proc.get_vads():
             content = addr_space.read(vad.Start, 64)
             if content == None:
                 continue
             vad_prot = str(vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v()))
             if obj.Object("_IMAGE_DOS_HEADER", offset = vad.Start, vm = addr_space).e_magic != 0x5A4D:
                 flag = "No PE/Possibly Code"
                 if (vad_prot == "PAGE_EXECUTE_READWRITE"):
                     sus_addr = vad.Start
                     outfd.write("\t{0:#x}({1})  Protection: {2}  Tag: {3}\n".format(vad.Start,
                                                                                     flag,
                                                                                     vad_prot,
                                                                                     str(vad.Tag or "")))
                     if self._config.DUMP_DIR:
                         filename = os.path.join(self._config.DUMP_DIR,"process.{0}.{1:#x}.dmp".format(hol_pid, sus_addr))
                         self.dump_vad(filename, vad, addr_space)
                 
                 elif (vad_prot == "PAGE_EXECUTE_WRITECOPY"):
                     sus_addr = vad.Start
                     outfd.write("\t{0:#x}({1})  Protection: {2}  Tag: {3}\n".format(sus_addr,
                                                                                     flag,
                                                                                     vad_prot,
                                                                                     str(vad.Tag or "")))
                     if self._config.DUMP_DIR:
                         filename = os.path.join(self._config.DUMP_DIR,"process.{0}.{1:#x}.dmp".format(hol_pid, 
                                                                                                       sus_addr))
                         self.dump_vad(filename, vad, addr_space)
                     
             else:
                 if vad_prot == "PAGE_EXECUTE_READWRITE":
                     flag = "PE Found"
                     sus_addr = vad.Start
                     outfd.write("\t{0:#x}({1})  Protection: {2}  Tag: {3}\n".format(sus_addr,
                                                                                     flag,
                                                                                     vad_prot,
                                                                                     str(vad.Tag or "")))
                     if self._config.DUMP_DIR:
                         filename = os.path.join(self._config.DUMP_DIR,"process.{0}.{1:#x}.dmp".format(hol_pid, 
                                                                                                       sus_addr))
                         self.dump_vad(filename, vad, addr_space)
                 
                 elif (vad_prot == "PAGE_EXECUTE_WRITECOPY") and (not bool(vad.FileObject)):
                     flag = "PE - No Mapped File"
                     sus_addr = vad.Start
                     outfd.write("\t{0:#x}({1})  Protection: {2}  Tag: {3}\n".format(sus_addr,
                                                                                     flag,
                                                                                     vad_prot,
                                                                                     str(vad.Tag or "")))
                     if self._config.DUMP_DIR:
                         filename = os.path.join(self._config.DUMP_DIR,"process.{0}.{1:#x}.dmp".format(hol_pid, 
                                                                                                       sus_addr))
                         self.dump_vad(filename, vad, addr_space)
                     
         outfd.write("---------------------------------------------------\n\n")
예제 #20
0
    def render_text(self, outfd, data):

        if not has_distorm3:
            debug.warning("For best results please install distorm3")

        if self._config.DUMP_DIR and not os.path.isdir(self._config.DUMP_DIR):
            debug.error(self._config.DUMP_DIR + " is not a directory")

        for task in data:
            for vad, address_space in task.get_vads(vad_filter = task._injection_filter):

                if self._is_vad_empty(vad, address_space):
                    continue

                if self._config.SSDEEP and has_pydeep:
                    skip = False
                    # read the first page of the VAD then hash it
                    inject_buf = address_space.zread(vad.Start, 0x1000)
                    inject_hash = pydeep.hash_buf(inject_buf)
                    # loop through all the whitelist hashes and compare
                    for (whitelist_name, whitelist_hash) in whitelist_ssdeep:
                        alike = pydeep.compare(inject_hash, whitelist_hash)
                        # the comparison is greater than the threshold so display an informational message
                        # then skip the rest of the output in normal malfind
                        if alike > self._config.THRESHOLD:
                            outfd.write("Process: {0} Pid: {1} Address: {2:#x}\n".format(
                                task.ImageFileName, task.UniqueProcessId, vad.Start))
                            outfd.write("Injection is {0}% similar to whitelist hook {1}\n".format(alike, whitelist_name))
                            #outfd.write("  hook: {0}\n".format(inject_hash))
                            #outfd.write("  whitelist: {0}\n".format(whitelist_hash))
                            skip = True
                            continue
                    if skip:
                        continue

                content = address_space.zread(vad.Start, 64)

                outfd.write("Process: {0} Pid: {1} Address: {2:#x}\n".format(
                    task.ImageFileName, task.UniqueProcessId, vad.Start))

                outfd.write("Vad Tag: {0} Protection: {1}\n".format(
                    vad.Tag, vadinfo.PROTECT_FLAGS.get(vad.u.VadFlags.Protection.v(), "")))

                outfd.write("Flags: {0}\n".format(str(vad.u.VadFlags)))
                outfd.write("\n")

                outfd.write("{0}\n".format("\n".join(
                    ["{0:#010x}  {1:<48}  {2}".format(vad.Start + o, h, ''.join(c))
                    for o, h, c in utils.Hexdump(content)
                    ])))

                outfd.write("\n")
                outfd.write("\n".join(
                    ["{0:#x} {1:<16} {2}".format(o, h, i)
                    for o, i, h in malfind.Disassemble(content, vad.Start)
                    ]))

                # Dump the data if --dump-dir was supplied
                if self._config.DUMP_DIR:

                    filename = os.path.join(self._config.DUMP_DIR,
                        "process.{0:#x}.{1:#x}.dmp".format(
                        task.obj_offset, vad.Start))

                    self.dump_vad(filename, vad, address_space)

                outfd.write("\n\n")
예제 #21
0
    def render_text(self, outfd, data):
        for process, module, hook, addr_space in data:

            if not self._config.NO_WHITELIST:

                if process:
                    process_name = str(process.ImageFileName)
                else:
                    process_name = ''

                if self.whitelist(hook.hook_mode | hook.hook_type,
                                  process_name, hook.VictimModule,
                                  hook.HookModule, hook.Function):
                    #debug.debug("Skipping whitelisted function: {0} {1} {2} {3}".format(
                    #    process_name, hook.VictimModule, hook.HookModule,
                    #    hook.Function))
                    continue

                if self._config.SSDEEP and has_pydeep:
                    skip = False
                    # read from the start of the page containing the hook, then hash it
                    page_address = hook.hook_address & 0xFFFFF000
                    hook_buf = addr_space.zread(page_address, 0x1000)
                    hook_hash = pydeep.hash_buf(hook_buf)
                    # loop through all the whitelist hashes and compare
                    for (whitelist_name, whitelist_hash) in whitelist_ssdeep:
                        alike = pydeep.compare(hook_hash, whitelist_hash)
                        # the comparison is greater than the threshold so display an informational message
                        # then skip the rest of the output in normal malfind
                        if alike > self._config.THRESHOLD:
                            if process:
                                outfd.write('Process: {0} ({1})\n'.format(
                                    process.UniqueProcessId,
                                    process.ImageFileName))
                            outfd.write(
                                "Hook at 0x{0:x} in page 0x{1:x} is {2}% similar to whitelist hook {3}\n"
                                .format(hook.hook_address, page_address, alike,
                                        whitelist_name))
                            #outfd.write("  hook: {0}\n".format(hook_hash))
                            #outfd.write("  whitelist: {0}\n".format(whitelist_hash))
                            outfd.write("\n")
                            skip = True
                            continue
                    if skip:
                        continue

            outfd.write("*" * 72 + "\n")
            outfd.write("Hook mode: {0}\n".format(hook.Mode))
            outfd.write("Hook type: {0}\n".format(hook.Type))

            if process:
                outfd.write('Process: {0} ({1})\n'.format(
                    process.UniqueProcessId, process.ImageFileName))

            outfd.write("Victim module: {0} ({1:#x} - {2:#x})\n".format(
                str(module.BaseDllName or '')
                or ntpath.basename(str(module.FullDllName or '')),
                module.DllBase, module.DllBase + module.SizeOfImage))

            outfd.write("Function: {0}\n".format(hook.Detail))
            outfd.write("Hook address: {0:#x}\n".format(hook.hook_address))
            outfd.write("Hooking module: {0}\n\n".format(hook.HookModule))

            for n, info in enumerate(hook.disassembled_hops):
                (address, data) = info
                s = [
                    "{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in
                    malfind.Disassemble(data,
                                        int(address),
                                        bits="32bit" if hook.decode_bits ==
                                        distorm3.Decode32Bits else "64bit")
                ]
                outfd.write("Disassembly({0}):\n{1}".format(n, "\n".join(s)))
                outfd.write("\n\n")
예제 #22
0
    def check_for_jmp(self, thread, proc, addr_space):
        """
        :param thread: _ETHREAD Object
        :param proc: _EPROCESS Object
        :param addr_space: Process's address space object
        :return: None, JMP/CALL is determined if thread.jmp_data exists
        Try to detect if there is a suspicious JMP or CALL in the
        first 12 bytes of the thread's entry point
        JMP/CALL that points to the same vad are considered to be
        legitimate. When we detect a JMP/CALL to another allocated
        memory in a new vad we might suspect someone tampered
        and injected malicious code.
        """

        vad = thread.vad_object
        content = addr_space.read(thread.entry_point, 12)

        # Can't read thread's entry point from memory, might be paged
        if not content:
            return False

        # disassemble with distorm3, more accurate
        if has_distorm:

            # Get OS profile
            mode = addr_space.profile.metadata.get('memory_model')

            if mode == '64bit':
                mode = distorm3.Decode64Bits

            else:
                mode = distorm3.Decode32Bits

            disassemble_data = "\n".join(["{0:<#8x} {1:<32} {2}".format(o, h, i) \
                                          for o, _size, i, h in \
                                          distorm3.DecodeGenerator(int(thread.entry_point),content, mode)])

        else:

            disassemble_data = "\n".join(
            ["{0:#010x} {1:<16} {2}".format(o, h, i)
            for o, i, h in malfind.Disassemble(content, int(thread.entry_point))])

        # First check - if there is a jmp to an address
        jmp_list_to_addr = re.findall("\s*(?:call|jmp)\s*(0x[0-9a-f]+)\s*\n\s*",
                                      disassemble_data, re.I)

        # Second check - if there is a move and then jmp or call to the register
        jmp_list_to_register = re.findall("(0x[0-9a-f]+)\n0x[0-9a-f]+\s*[0-9a-f]+\s*(?:call|jmp)\s*[a-z]+\n",
                                          disassemble_data, re.I)

        jmp_list = jmp_list_to_addr + jmp_list_to_register

        # Check if we found a jmp
        if jmp_list:

            # Pass on every jmp
            for address in jmp_list:

                if not address:
                    continue

                address = int(address, 16)

                # Check if the address is in the vad
                if vad.Start <= address <= vad.End:
                    continue

                # Suspicious jump outside the vad range
                else:

                    in_vad_range = self.check_where_in_vad(address)

                    # Found a matching vad for the JMP address
                    if in_vad_range:
                        vad, vad_addr_space = in_vad_range
                        thread.jmp_data.append(("vad", vad, address))

                    # Found a suspicious JMP, but didn't find a matching vad in process memory checking kernel
                    else:

                        in_kernel_space = self.check_where_in_kernel(address)

                        if in_kernel_space:
                            module_name, module_start = in_kernel_space
                            thread.jmp_data.append(("kernel",
                                                    (module_name, module_start),
                                                    address))

                        else:
                            thread.jmp_data.append(("Couldn't find location", '', address))
예제 #23
0
    def get_json(self, data):
        results = {}

        addr_space = utils.load_as(self._config)

        # Compile the regular expression for filtering by driver name
        if self._config.regex != None:
            mod_re = re.compile(self._config.regex, re.I)
        else:
            mod_re = None

        mods = dict((mod.DllBase, mod) for mod in modules.lsmod(addr_space))
        mod_addrs = sorted(mods.keys())

        bits = addr_space.profile.metadata.get('memory_model', '32bit')

        for driver in data:
            header = driver.get_object_header()

            driver_name = str(header.NameInfo.Name or '')

            # Continue if a regex was supplied and it doesn't match
            if mod_re != None:
                if not (mod_re.search(driver_name)
                        or mod_re.search(driver_name)):
                    continue

            row = {
                'DriverName': driver_name,
                'DriverStart': int(driver.DriverStart),
                'DriverSize': int(driver.DriverSize),
                'DriverStartIo': int(driver.DriverStartIo),
                'IrpFunctions': [],
                'Devices': [],
            }

            # Write the address and owner of each IRP function
            for i, function in enumerate(driver.MajorFunction):
                function = driver.MajorFunction[i]
                module = tasks.find_module(mods, mod_addrs, function)
                irp = {
                    'index': int(i),
                    'FunctionName': str(MAJOR_FUNCTIONS[i]),
                    'FunctionAddress': int(function),
                    'Disassembly': []
                }
                if module:
                    irp['BaseDllName'] = str(module.BaseDllName or '')
                else:
                    irp['BaseDllName'] = ''

                if self._config.verbose:
                    data = addr_space.zread(function, 64)
                    irp["Disassembly"] = [{
                        'Address': int(o),
                        "Bytes": str(h),
                        "Instruction": str(i)
                    } for o, i, h in malfind.Disassemble(
                        data=data, start=function, bits=bits, stoponret=True)]
                row['IrpFunctions'].append(irp)

            for device in driver.devices():

                device_header = obj.Object(
                    "_OBJECT_HEADER",
                    offset=device.obj_offset -
                    device.obj_vm.profile.get_obj_offset(
                        "_OBJECT_HEADER", "Body"),
                    vm=device.obj_vm,
                    native_vm=device.obj_native_vm)

                device_name = str(device_header.NameInfo.Name or '')

                dev = {
                    'Offset':
                    int(device.obj_offset),
                    'DeviceName':
                    device_name,
                    'DeviceCodes':
                    DEVICE_CODES.get(device.DeviceType.v(), "UNKNOWN"),
                    'AttachedDevices': []
                }

                level = 0

                for att_device in device.attached_devices():

                    device_header = obj.Object(
                        "_OBJECT_HEADER",
                        offset=att_device.obj_offset -
                        att_device.obj_vm.profile.get_obj_offset(
                            "_OBJECT_HEADER", "Body"),
                        vm=att_device.obj_vm,
                        native_vm=att_device.obj_native_vm)

                    device_name = str(device_header.NameInfo.Name or '')
                    name = (device_name + " - " +
                            str(att_device.DriverObject.DriverName or ''))

                    attached_device = {
                        'Offset':
                        att_device.obj_offset,
                        'DeviceName':
                        name,
                        'DeviceCodes':
                        DEVICE_CODES.get(att_device.DeviceType.v(), "UNKNOWN"),
                        'Level':
                        level
                    }

                    level += 1
                    dev['AttachedDevices'].append(attached_device)
                row['Devices'].append(dev)

            _addr = str(row['DriverStart'])
            results[_addr] = row

        return results
예제 #24
0
    def get_json(self, data):
        results = {}

        # Determine which filters the user wants to see
        if self._config.FILTER:
            filters = set(self._config.FILTER.split(','))
        else:
            filters = set()

        for thread, addr_space, mods, mod_addrs, \
            instances, hooked_tables, system_range, owner_name in data:
            # If the user didn't set filters, display all results. If
            # the user set one or more filters, only show threads
            # with matching results.
            tags = set([t for t, v in instances.items() if v.check()])

            if filters and not filters & tags:
                continue

            row = {
                'offset': int(thread.obj_offset),
                'UniqueProcess': int(thread.Cid.UniqueProcess),
                'UniqueThread': int(thread.Cid.UniqueThread),
                'Tags': [str(i) for i in tags],
                'CreateTime': str(thread.CreateTime),
                'ExitTime': str(thread.ExitTime),
                'ImageFileName': str(thread.owning_process().ImageFileName),
                'Attached': str(thread.attached_process().ImageFileName),
                'BasePriority': int(thread.Tcb.BasePriority),
                'Priority': int(thread.Tcb.Priority),
                'Teb': int(thread.Tcb.Teb),
                'State': str(thread.Tcb.State),
                'WaitReason': str(thread.Tcb.WaitReason),
                'StartAddress': int(thread.StartAddress),
                "SystemThread": bool("SystemThread" in tags),
                "OwnerName": "",
                "Win32StartAddressValid": thread.SameThreadApcFlags & 1,
                "Win32StartAddress": int(thread.Win32StartAddress),
                'ServiceTable':
                int(thread.Tcb.ServiceTable) if self.bits32 else "",
                "Win32Thread": int(thread.Tcb.Win32Thread),
                "CrossThreadFlags": int(thread.CrossThreadFlags),
                "TrapFrame": {},
                'SSDT': {},
                "Disassembly": []
            }

            # Print the registers if possible
            trapframe = thread.Tcb.TrapFrame.dereference_as("_KTRAP_FRAME")

            if trapframe and self.bits32:
                row["TrapFrame"] = {
                    key:
                    int(eval('trapframe.%s' % key, {'trapframe': trapframe}))
                    for key in trapframe.members.keys()
                }

            # Disasemble the start address if possible
            if addr_space.is_valid_address(thread.StartAddress):
                buf = addr_space.zread(thread.StartAddress, 24)
                row["Disassembly"] = [{
                    'Address': int(o),
                    "Bytes": str(h),
                    "Instruction": str(i)
                } for o, i, h in malfind.Disassemble(buf,
                                                     thread.StartAddress.v())]

            # If its a system thread, get the owning module
            if row["SystemThread"]:
                owner = tasks.find_module(mods, mod_addrs, thread.StartAddress)
                if not owner is None:
                    row["OwnerName"] = str(owner.BaseDllName or owner_name)

            if self.bits32:
                ssdt_obj = obj.Object("_SERVICE_DESCRIPTOR_TABLE",
                                      offset=thread.Tcb.ServiceTable,
                                      vm=addr_space)

                if ssdt_obj is not None:
                    for i, desc in enumerate(ssdt_obj.Descriptors):
                        row['SSDT'][str(i)] = {
                            'index': i,
                            'KiServiceTable': '',
                            'HookedSSDT': []
                        }
                        if desc.is_valid():
                            row['SSDT'][str(i)][
                                'KiServiceTable'] = desc.KiServiceTable.v()

                        table = desc.KiServiceTable.v()
                        if table not in hooked_tables.keys():
                            continue

                        # no use for this data so far
                        #
                        # for (j, func_name, func_addr, mod_name) in hooked_tables[table]:
                        #     row['SSDT'][str(i)]['HookedSSDT'].append({'index': j,
                        #                                               'FunctionName': func_name,
                        #                                               'FunctionAddress': func_addr,
                        #                                               'ModuleName': str(mod_name)})

            results[str(row['offset'])] = row

        return results
예제 #25
0
    def examine(self, addr_space, process, thread, routine, apc, timer):
        # We will now emulate through the instruction stream, starting at the APC handler, and see if anything fishy
        # goes on. Specifically, we will see if the APC calls VirtualProtect. If it does, we will see if it also
        # tries to jump to the newly-VirtualProtect'ed memory - a sure sign of Gargoyle-ness.
        VirtualProtect   = self.findExport(process, addr_space, "KERNEL32.DLL", "VirtualProtect")
        VirtualProtectEx = self.findExport(process, addr_space, "KERNEL32.DLL", "VirtualProtectEx")
        # We'll need to set the process address space so that our badmem callback can use it later on.
        self.pas = process.get_process_address_space()
        self.emulationFaulted = None

        result = timerResult(process, thread, routine)
        self.dbgMsg("Timer %s APC %s routine %s in process %s ('%s') thread %s" % (hex(int(timer.obj_offset)), hex(int(apc.obj_offset)), hex(routine), hex(int(process.obj_offset)), process.ImageFileName, hex(thread.StartAddress)))

        unicornEng = Uc(UC_ARCH_X86, UC_MODE_32)
        # Populate the context from which to start emulating.
        # We use an arbitrary ESP, with a magic value to signify that the APC handler has returned.
        initialStackBase = 0x00000000f0000000
        unicornEng.mem_map(initialStackBase, 2 * 1024 * 1024)
        unicornEng.mem_write(initialStackBase + 0x100 + 0, "\xbe\xba\xde\xc0")
        # We push the argument which the APC handler is given
        unicornEng.mem_write(initialStackBase + 0x100 + 4, apc.NormalContext.obj_vm.read(apc.NormalContext.obj_offset, 4))
        unicornEng.reg_write(UC_X86_REG_ESP, initialStackBase + 0x100)

        # Set up our handlers, which will map memory on-demand from the debuggee
        unicornEng.hook_add(UC_HOOK_MEM_READ_UNMAPPED, self.badmem)
        unicornEng.hook_add(UC_HOOK_MEM_WRITE_INVALID, self.badmem)
        unicornEng.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.badmem)

        # There's not really much point mapping the GDT, since Unicorn doesn't properly support paging.
        # See Unicorn's bug #947, "(x86) Emulated CPU is not translating virtual memory addresses".

        # Now, lets emulate some instructions! We won't get many, because Unicorn can't emulate a lot of things (like
        # segment-prefixed instructions, as used by wow64) but we'll get enough to detect most ROP chains.
        instrEmulated = 0
        nextIns = routine
        memoryRange = None
        while instrEmulated < 10000:

            if self._config.VERBOSE > 0:
                print "Before instruction %d at %s:" % (instrEmulated, hex(nextIns))
                print "CS:IP = %s:%s SS:SP = %s:%s" % (
                    hex(unicornEng.reg_read(UC_X86_REG_CS)), hex(unicornEng.reg_read(UC_X86_REG_EIP)),
                    hex(unicornEng.reg_read(UC_X86_REG_SS)), hex(unicornEng.reg_read(UC_X86_REG_ESP)))

                instrStream = self.pas.read(nextIns, 15)
                for _, i, _ in malfind.Disassemble(instrStream, nextIns):
                    print "\t%s\t%s" % (hex(nextIns), i)
                    break

            # Attempt to emulate a single instruction
            try:
                unicornEng.emu_start(nextIns, nextIns + 0x10, count = 1)
            except unicorn.UcError as e1:
                break
            if self.emulationFaulted != None:
                break

            # Great, we emulated an instruction. Move on to the next instruction.
            nextIns = unicornEng.reg_read(UC_X86_REG_EIP)
            instrEmulated = instrEmulated + 1

            # If we're now at our magic address, then our APC has completed executing entirely. That's all, folks.
            if nextIns == 0xc0debabe:
                break

            # Now we can check for some suspicious circumstance.
            esp = unicornEng.reg_read(UC_X86_REG_ESP)
            if esp == int(apc.NormalContext):
                result.didROP = "True"
                self.dbgMsg("APC has performed stack pivot; new stack is its context pointer")
                if VirtualProtect == None:
                    # If we didn't find VirtualProtect, we can't go any further. I guess a stack pivot is a pretty big
                    # red flag anyway.
                    break
            if VirtualProtectEx != None:
                if nextIns == VirtualProtectEx:
                    result.didAdjustPerms = "True"

                    # Read the arguments to VirtualProtect, and the return address, from the stack
                    returnAddress = struct.unpack("I", unicornEng.mem_read(esp - 0, 4))[0]
                    memoryRange = struct.unpack("I", unicornEng.mem_read(esp + 8, 4))[0]

                    result.adjustedAddresses.append(memoryRange)
                    self.dbgMsg("VirtualProtectEx: Timer routine is adjusting memory permissions of range %s" % hex(memoryRange))
                    # Set the return address to whatever VirtualProtect would've returned to
                    nextIns = returnAddress
                    unicornEng.reg_write(UC_X86_REG_EIP, returnAddress)
                    # Pop five args plus the return address off the (32bit) stack
                    unicornEng.reg_write(UC_X86_REG_ESP, esp + (6*4))
                if VirtualProtect != None:
                    if nextIns == VirtualProtect:
                        result.didAdjustPerms = "True"

                        # Read the arguments to VirtualProtect, and the return address, from the stack
                        returnAddress = struct.unpack("I", unicornEng.mem_read(esp - 0, 4))[0]
                        memoryRange = struct.unpack("I", unicornEng.mem_read(esp + 4, 4))[0]

                        result.adjustedAddresses.append(memoryRange)
                        self.dbgMsg("VirtualProtect: Timer routine is adjusting memory permissions of range %s" % hex(memoryRange))
                        # Set the return address to whatever VirtualProtect would've returned to
                        nextIns = returnAddress
                        unicornEng.reg_write(UC_X86_REG_EIP, returnAddress)
                        # Pop four args plus the return address off the (32bit) stack
                        unicornEng.reg_write(UC_X86_REG_ESP, esp + (5 * 4))
                if nextIns in result.adjustedAddresses:
                    result.didJumpToAdjusted = "True"
                    result.probablePayload = nextIns
                    self.dbgMsg( "Timer routine is jumping to newly-executable code at %s!" % hex(memoryRange))
                    break
        yield result