Exemplo n.º 1
0
def block_begin(params):
    global cm
    from api import CallbackManager
    import api
    from ipython_shell import start_shell

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    tb = params["tb"]

    pgd = api.get_running_process(cpu_index)
    start_shell()
    if api.get_os_bits() == 32:
        pyrebox_print("Adding optimized callback at 0x100218f\n")
        cm.add_callback(CallbackManager.BLOCK_BEGIN_CB,
                        optimized_block_begin,
                        name="block_begin_optimized",
                        addr=0x100218f, pgd=pgd)
    elif api.get_os_bits() == 64:
        pyrebox_print("Adding optimized callback at 0xfffff96000139f20\n")
        cm.add_callback(CallbackManager.BLOCK_BEGIN_CB,
                        optimized_block_begin,
                        name="block_begin_optimized",
                        addr=0xfffff96000139f20, pgd=pgd)
    api.stop_monitoring_process(pgd)
    pyrebox_print("Stopped monitoring process\n")
    cm.rm_callback("block_begin")
    pyrebox_print("Unregistered callback\n")
Exemplo n.º 2
0
def ntopenprocess(params, pid, proc, update_vads):
    #  OUT PHANDLE             ProcessHandle,
    #  IN ACCESS_MASK          AccessMask,
    #  IN POBJECT_ATTRIBUTES   ObjectAttributes,
    #  IN PCLIENT_ID           ClientId );
    from mw_monitor_classes import mwmon
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)

    # Read the first parameter (process handle)
    params = read_parameters(cpu, 1)

    # Set callback on return address
    callback_name = mwmon.cm.generate_callback_name("ntopenprocess_ret")

    callback_function = functools.partial(ntopenprocessret,
                                          pid=pid,
                                          callback_name=callback_name,
                                          proc_hdl_p=params[1],
                                          proc=proc,
                                          update_vads=update_vads)

    mwmon.cm.add_callback(api.CallbackManager.INSN_BEGIN_CB,
                          callback_function,
                          name=callback_name,
                          addr=params[0],
                          pgd=pgd)
Exemplo n.º 3
0
    def __handle_host_request_exec_args_linux(self, cpu_index, cpu):
        """
            Handle the host_request_exec_args interface call.

            Argument in EAX: the buffer to write to
            Argument in EBX: the max size of the buffer to write to

            Returns number of bytes written in EAX, or -1 if the call failed.
        """

        if isinstance(cpu, X86CPU):
            buf = cpu.EAX
            size = cpu.EBX
        elif isinstance(cpu, X64CPU):
            buf = cpu.RAX
            size = cpu.RBX

        TARGET_LONG_SIZE = api.get_os_bits() / 8

        args = self.__file_to_execute["args"]

        argv_size = TARGET_LONG_SIZE * (len(args) + 1) + sum(len(x) + 1 for x in args)

        if argv_size > self.__agent_buffer_size:
            raise ValueError("The size of the args should not exceed %d bytes" %
                             self.__agent_buffer_size)

        # self.__printer("GuestAgentPlugin: host_request_exec_args(0x%08x, %d)
        # called" % (buf, size))
        pgd = api.get_running_process(cpu_index)
        try:
            # Security check: the buffer should be located on the allowed
            # boundaries
            if self.__check_buffer_validity(buf, size):
                self.__write_strings_array(
                    pgd, buf, args)
                if isinstance(cpu, X86CPU):
                    api.w_r(
                        cpu_index, "EAX", argv_size)
                elif isinstance(cpu, X64CPU):
                    api.w_r(
                        cpu_index, "RAX", argv_size)
            else:
                self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" +
                               "within the allowed boundaries %x (%x)" % (buf, size))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", -1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", -1)

        except Exception as ex:
            self.__printer(
                "HostFilesPlugin: Exception %s while trying to write file args to guest" % (str(ex)))
            if isinstance(cpu, X86CPU):
                api.w_r(cpu_index, "EAX", -1)
            elif isinstance(cpu, X64CPU):
                api.w_r(cpu_index, "RAX", -1)
Exemplo n.º 4
0
def ntmapviewofsection_ret(params,
                           pid,
                           callback_name,
                           mapped_sec,
                           mapping_proc,
                           base_p, size_p,
                           offset_p,
                           proc,
                           update_vads):
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import SectionMap
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)

    # First, remove callback
    mwmon.cm.rm_callback(callback_name)

    if base_p != 0:
        base = dereference_target_long(base_p, pgd)
    else:
        base = 0

    if size_p != 0:
        size = dereference_target_long(size_p, pgd)
    else:
        size = 0

    # Offset is always 8 bytes
    if offset_p != 0:
        try:
            offset = struct.unpack("Q", api.r_va(pgd, offset_p, 8))[0]
        except:
            offset = 0
            mwmon.printer("Could not dereference offset in NtMapViewOfSection return, in interproc.py")
    else:
        offset = 0

    mapping_proc.section_maps.append(
        SectionMap(mapped_sec, base, size, offset))

    if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
        f = mwmon.interproc_text_log_handle
        if TARGET_LONG_SIZE == 4:
            f.write("[PID: %x] NtMapViewOfSection: Base: %08x Size: %08x Offset: %08x / Section: %s\n" %
                    (pid, base, size, offset, mapped_sec.backing_file))
        elif TARGET_LONG_SIZE == 8:
            f.write("[PID: %x] NtMapViewOfSection: Base: %16x Size: %16x Offset: %08x / Section: %s\n" %
                    (pid, base, size, offset, mapped_sec.backing_file))

    if update_vads:
        proc.update_vads()
def tlb_exec(params):
    global cm
    global counter
    import api

    cpu = params["cpu"]
    addr = params["vaddr"]

    pgd = api.get_running_process(cpu.CPU_INDEX)
    pyrebox_print("TLB exec, PGD %x Addr %x\n" % (pgd, addr))
Exemplo n.º 6
0
def my_function(params):
    global cm
    import api
    from ipython_shell import start_shell

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Insn end at (%x) %x\n" % (pgd, cpu.PC))
    start_shell()
Exemplo n.º 7
0
def op_insn_begin(params):
    global cm
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Process %x hit the callback at %x\n" % (pgd, cpu.PC))
    cm.rm_callback("insn_begin_optimized")
    pyrebox_print("Unregistered callback\n")
Exemplo n.º 8
0
 def __read_string(self, cpu_index, addr):
     """
         Read a string from the virtual address space of the guest's user mode.
     """
     pgd = api.get_running_process(cpu_index)
     string = []
     for i in range(256):
         byte = api.r_va(pgd, addr + i, 1)
         if byte == "\x00":
             break
         string.append(byte)
     return "".join(string)
Exemplo n.º 9
0
    def __opcode_range_callback(self, params):
        """
            Called by the callback manager when the desired opcode is hit.
        """
        cpu_index = params["cpu_index"]
        cpu = params["cpu"]
        cur_pc = params["cur_pc"]
        next_pc = params["next_pc"]
        try:
            if self.__status == GuestAgentPlugin.__AGENT_READY:
                function = api.r_va(api.get_running_process(cpu_index), cur_pc + 3, 2)
                try:
                    handler = {
                        "\x00\x00": self.__handle_host_version,
                        "\x00\x01": self.__handle_host_message,
                        "\x00\x02": self.__handle_host_get_command,
                        "\x10\x00": self.__handle_host_open,
                        "\x10\x01": self.__handle_host_read,
                        "\x10\x02": self.__handle_host_close,
                        "\x10\x03": self.__handle_host_get_file_name,
                        "\x20\x00": self.__handle_host_request_exec_path,
                        "\x20\x01": self.__handle_host_request_exec_args,
                        "\x20\x02": self.__handle_host_request_exec_env,
                        "\x20\x03": self.__handle_host_request_exec_args_linux,
                        "\x20\x04": self.__handle_host_request_exec_env_linux

                    }[function]
                    handler(cpu_index, cpu)
                except KeyError:
                    self.__printer(
                        "HostFilePlugin: Unknown host opcode %x at 0x%08x" % (function, cur_pc))

                # Advance the program counter.
                # Needs to be done explicitly, as Qemu doesn't know the instruction
                # length.
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EIP", cpu.EIP + 10)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RIP", cpu.RIP + 10)
            elif self.__status == GuestAgentPlugin.__AGENT_RUNNING:
                # Agent already running but not ready yet (the base
                # address was not correctly determined yet.

                # Advance the program counter.
                # Needs to be done explicitly, as Qemu doesn't know the instruction
                # length.
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EIP", cpu.EIP + 10)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RIP", cpu.RIP + 10)
        except Exception as e:
            self.__printer("Exception occurred on opcode callback: %s" % str(e))
Exemplo n.º 10
0
    def __handle_host_read(self, cpu_index, cpu):
        """
            Handle the host_read interface call.

            Argument in EAX: The file descriptor.
            Argument in EBX: Pointer to the buffer (VA) where bytes should be read into.
            Argument in ECX: Size of the buffer.
            Returns number of bytes read in EAX, or -1 if the call failed.
        """
        if isinstance(cpu, X86CPU):
            fd = cpu.EAX
            buf = cpu.EBX
            size = cpu.ECX
        elif isinstance(cpu, X64CPU):
            fd = cpu.RAX
            buf = cpu.RBX
            size = cpu.RCX

        # self.__printer("GuestAgentPlugin: host_read(%d, 0x%08x, %d) called" %
        # (fd, buf, size))
        if fd not in self.__file_descriptors:
            self.__printer(
                "HostFilesPlugin: host_read tried to access invalid file descriptor %d" % fd)
            return

        pgd = api.get_running_process(cpu_index)
        try:
            data = self.__file_descriptors[fd].read(size)
            # Security check: the buffer should be located on the allowed
            # boundaries
            if self.__check_buffer_validity(buf, size):
                api.w_va(pgd, buf, data, len(data))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", len(data))
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", len(data))
            else:
                self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" +
                               "within the allowed boundaries %x (%x)" % (buf, size))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", -1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", -1)

        except Exception as ex:
            self.__printer(
                "HostFilesPlugin: Exception %s while trying to read from file descriptor %d" % (str(ex), fd))
            if isinstance(cpu, X86CPU):
                api.w_r(cpu_index, "EAX", -1)
            elif isinstance(cpu, X64CPU):
                api.w_r(cpu_index, "RAX", -1)
Exemplo n.º 11
0
def my_function(params):
    global cm
    import api
    from ipython_shell import start_shell

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    tb = params["tb"]
    cur_pc = params["cur_pc"]
    next_pc = params["next_pc"]

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Block end at (%x) %x -> %x\n" % (pgd, cur_pc, next_pc))
    start_shell()
Exemplo n.º 12
0
def optimized_block_begin(params):
    global cm
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    tb = params["tb"]

    assert(cpu.PC == 0x100218f or cpu.PC == 0xfffff96000139f20)

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Process %x hit the callback at %x\n" % (pgd, cpu.PC))
    cm.rm_callback("block_begin_optimized")
    pyrebox_print("Unregistered callback\n")
Exemplo n.º 13
0
def insn_begin(params):
    global cm
    global pyrebox_print

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    if cpu.PC == 0x100218f and cm.callback_exists("insn_begin"):
        pgd = api.get_running_process(cpu_index)
        pyrebox_print("Process %x hit the callback at 0x100218f" % pgd)
        api.stop_monitoring_process(pgd)
        pyrebox_print("Stopped monitoring process")
        cm.rm_callback("insn_begin")
    else:
        print("This message should never be printed")
Exemplo n.º 14
0
def insn_begin(params):
    global cm
    from api import CallbackManager
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Adding insn optimized callback at %x\n" % cpu.PC)
    cm.add_callback(CallbackManager.INSN_BEGIN_CB, op_insn_begin, name="insn_begin_optimized", addr=cpu.PC, pgd=pgd)
    api.stop_monitoring_process(pgd)
    pyrebox_print("Stopped monitoring process\n")
    cm.rm_callback("insn_begin")
    pyrebox_print("Unregistered callback\n")
Exemplo n.º 15
0
def ntallocatevirtualmemory_ret(params,
                                pid,
                                callback_name,
                                mapping_proc=None,
                                base_addr_p=None,
                                zerobits=None,
                                size_p=None,
                                aloc_type=None,
                                access=None,
                                proc=None,
                                update_vads=None):

    from mw_monitor_classes import mwmon
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)

    # First, remove callback
    mwmon.cm.rm_callback(callback_name)
    # Now, dereference all the output pointers
    # base and size_p depend on 32-bit vs. 64 bit. This should be turned into
    # 8 bytes for 64 bit guest.

    if base_addr_p != 0:
        base = dereference_target_long(base_addr_p, pgd)
    else:
        base = 0

    if size_p != 0:
        size = dereference_target_long(size_p, pgd)
    else:
        size = 0

    if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
        f = mwmon.interproc_text_log_handle
        if TARGET_LONG_SIZE == 4:
            f.write("[PID: %x] NtAllocateVirtualMemory: Base: %08x Size: %08x Protect: %08x\n" %
                    (pid, base, size, access))
        elif TARGET_LONG_SIZE == 8:
            f.write("[PID: %x] NtAllocateVirtualMemory: Base: %016x Size: %016x Protect: %016x\n" %
                    (pid, base, size, access))

    if update_vads:
        proc.update_vads()
Exemplo n.º 16
0
def my_function(params):
    global cm
    global counter
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    tb = params["tb"]

    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Process %x hit the callback at %x\n" % (pgd, cpu.PC))
    counter = counter + 1
    if counter >= 100:
        api.stop_monitoring_process(pgd)
        pyrebox_print("Stopped monitoring process\n")
        cm.rm_callback("block_begin")
        pyrebox_print("Unregistered callback\n")
Exemplo n.º 17
0
    def __handle_host_request_exec_path(self, cpu_index, cpu):
        """
            Handle the host_request_exec_path interface call.

            Argument in EAX: the buffer to write to
            Argument in EBX: the max size of the buffer to write to

            Returns number of bytes written in EAX, or -1 if the call failed.
        """

        if isinstance(cpu, X86CPU):
            buf = cpu.EAX
            size = cpu.EBX
        elif isinstance(cpu, X64CPU):
            buf = cpu.RAX
            size = cpu.RBX
        # self.__printer("GuestAgentPlugin: host_request_exec_path(0x%08x, %d)
        # called" % (buf, size))
        pgd = api.get_running_process(cpu_index)
        try:
            # Security check: the buffer should be located on the allowed
            # boundaries
            if self.__check_buffer_validity(buf, size):
                api.w_va(pgd, buf, self.__file_to_execute[
                         "path"] + "\x00", len(self.__file_to_execute["path"]) + 1)
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", len(
                        self.__file_to_execute["path"]) + 1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", len(
                        self.__file_to_execute["path"]) + 1)
            else:
                self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" +
                               "within the allowed boundaries %x (%x)" % (buf, size))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", -1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", -1)

        except Exception as ex:
            self.__printer(
                "HostFilesPlugin: Exception %s while trying to write file path to guest" % (str(ex)))
            if isinstance(cpu, X86CPU):
                api.w_r(cpu_index, "EAX", -1)
            elif isinstance(cpu, X64CPU):
                api.w_r(cpu_index, "RAX", -1)
Exemplo n.º 18
0
def dump(cpu_index=None,
         cpu=None,
         pid=None,
         proc=None,
         update_vads=None,
         from_addr=None,
         callback_name=None,
         terminate_process=False):
    '''
    Dump the process, modules, vads...
    '''
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from utils import get_addr_space
    import api

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    mwmon.printer("Dumping process...")

    proc_hdl = None
    if terminate_process:
        if TARGET_LONG_SIZE == 4:
            # ret, proc_hdl, exit_status
            try:
                _, proc_hdl, _ = struct.unpack(
                    "<III",
                    api.r_va(api.get_running_process(cpu_index), cpu.ESP,
                             4 * 3))
            except:
                proc_hdl = 0
                mwmon.printer(
                    "Could not dereference process handle in dumper.py")
        elif TARGET_LONG_SIZE == 8:
            # We don't need the return address
            # ret = struct.unpack("<Q",
            # api.r_va(api.get_running_process(cpu_index), cpu.ESP, 8))[0]
            proc_hdl = cpu.RCX
            # We don't need the exit status
            # exit_status = cpu.RDX

        # It seems there are usually 2 calls, when a process terminates itself.
        # First, ZwTerminateProcess is called with 0 as proc_hdl, and afterwards
        # -1.
        if proc_hdl == 0:
            return

    if callback_name is not None:
        # First, remove callback
        mwmon.cm.rm_callback(callback_name)

    # Check if we have been called from the right from_addr
    if from_addr is not None:
        if TARGET_LONG_SIZE == 4:
            try:
                buff = api.r_va(api.get_running_process(cpu_index), cpu.ESP, 4)
                ret_addr = struct.unpack("<I", buff)[0]
            except:
                ret_addr = 0
                mwmon.printer(
                    "Could not dereference return address on dumper.py")
        elif TARGET_LONG_SIZE == 8:
            try:
                buff = api.r_va(api.get_running_process(cpu_index), cpu.RSP, 8)
                ret_addr = struct.unpack("<Q", buff)[0]
            except:
                ret_addr = 0
                mwmon.printer(
                    "Could not dereference return address on dumper.py")
        if from_addr != ret_addr:
            return

    # We have been called from the right point, now, dump.
    path = mwmon.dumper_path
    # Dump a file with the VAD info, etc, and a filename for each dumped file,
    # so that we can import feed IDA with it
    try:
        # Dump main executable.
        addr_space = get_addr_space()

        # If 1 handle is specified, get the pid for that handle instead
        # of the calling PID.
        if proc_hdl is not None:
            if (TARGET_LONG_SIZE == 4 and proc_hdl == 0xFFFFFFFF) or \
               (TARGET_LONG_SIZE == 8 and proc_hdl == 0xFFFFFFFFFFFFFFFF):
                # If the handle is 0xFFFFFFFF, then the process is the caller.
                pass
            else:
                eprocs = [
                    t for t in tasks.pslist(addr_space)
                    if t.UniqueProcessId == pid
                ]
                proc_obj = None
                # Search handle table for the new created process
                for task in eprocs:
                    if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
                        for handle in task.ObjectTable.handles():
                            if handle.is_valid(
                            ) and handle.HandleValue == proc_hdl and handle.get_object_type(
                            ) == "Process":
                                proc_obj = handle.dereference_as("_EPROCESS")
                                break
                        break
                if proc_obj is not None:
                    # If we found the handle to which it referred, update the
                    # corresponding pid
                    pid = int(proc_obj.UniqueProcessId)
                else:
                    return

        # Case when no PID is specified, just dump everything
        if pid is None:
            pids = [p.pid for p in mwmon.data.procs]
        # When one pid is specified, dump that PID
        else:
            pids = [pid]

        eprocs = [
            t for t in tasks.pslist(addr_space) if t.UniqueProcessId in pids
        ]
        for task in eprocs:
            mwmon.printer("Dumping process %x" % (task.UniqueProcessId))
            # Code adapted from procdump (volatility)
            task_space = task.get_process_address_space()
            if task_space is None:
                mwmon.printer("Error: Cannot acquire process AS")
                return
            elif task.Peb is None:
                # we must use m() here, because any other attempt to
                # reference task.Peb will try to instantiate the _PEB
                mwmon.printer(
                    "Error: PEB at {0:#x} is unavailable (possibly due to paging)"
                    .format(task.m('Peb')))
                return
            elif task_space.vtop(task.Peb.ImageBaseAddress) is None:
                mwmon.printer(
                    "Error: ImageBaseAddress at {0:#x} is unavailable" +
                    "(possibly due to paging)".format(
                        task.Peb.ImageBaseAddress))
                return
            else:
                mwmon.printer("Dumping executable for %x" %
                              (task.UniqueProcessId))
                dump_file = os.path.join(
                    path, "executable.%x.exe" % (task.UniqueProcessId))
                of = open(dump_file, 'wb')
                pe_file = obj.Object("_IMAGE_DOS_HEADER",
                                     offset=task.Peb.ImageBaseAddress,
                                     vm=task_space)
                try:
                    for offset, code in pe_file.get_image(unsafe=True,
                                                          memory=False,
                                                          fix=True):
                        of.seek(offset)
                        of.write(code)
                except ValueError, ve:
                    mwmon.printer("Error: {0}".format(ve))
                    return
                except exceptions.SanityCheckException, ve:
                    mwmon.printer("Error: {0} Try -u/--unsafe".format(ve))
                    return
Exemplo n.º 19
0
def ntunmapviewofsection(params, pid, proc, update_vads):
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from utils import get_addr_space
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    # IN HANDLE               ProcessHandle,
    # IN PVOID                BaseAddress);
    # Search for the map, and deactivate it

    pgd = api.get_running_process(cpu_index)

    ret_addr, proc_handle, base = read_parameters(cpu, 2)

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize proc_obj, that will point to the object of the referenced
    # process, and section_obj, idem
    proc_obj = None
    # Search handle table for the caller process
    for task in eprocs:
        if task.UniqueProcessId == pid:
            if (TARGET_LONG_SIZE == 4 and proc_handle == 0xffffffff) or \
               (TARGET_LONG_SIZE == 8 and proc_handle == 0xffffffffffffffff):
                proc_obj = task
                break
            elif task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
                for handle in task.ObjectTable.handles():
                    if handle.is_valid():
                        if handle.HandleValue == proc_handle and handle.get_object_type() == "Process":
                            proc_obj = handle.dereference_as("_EPROCESS")
                            break
                break

    mapping_proc = None
    if proc_obj is not None:
        for proc in mwmon.data.procs:
            if proc.pid == proc_obj.UniqueProcessId:
                mapping_proc = proc
                break
    if mapping_proc is not None:
        for m in mapping_proc.section_maps:
            if m.base == base and m.is_active():
                m.deactivate()
                if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
                    f = mwmon.interproc_text_log_handle
                    if (TARGET_LONG_SIZE == 4):
                        f.write("[PID: %x] NtUnmapViewOfSection: Base: %08x Size: %08x / Section: %s\n" %
                                (pid, base, m.size, m.section.backing_file))
                    elif (TARGET_LONG_SIZE == 8):
                        f.write("[PID: %x] NtUnmapViewOfSection: Base: %16x Size: %16x / Section: %s\n" %
                                (pid, base, m.size, m.section.backing_file))

    if update_vads:
        proc.update_vads()
Exemplo n.º 20
0
def module_entry_point(params):
    '''
        Callback on the entry point of the main module being monitored
    '''
    global APITRACER_ANTI_STOLEN
    global APITRACER_ENABLE_JMP
    global APITRACER_ENABLE_RET

    global cm
    global pyrebox_print
    import os
    from api import CallbackManager
    import api
    from interproc import interproc_data

    # Get pameters
    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    # Get running process
    pgd = api.get_running_process(cpu_index)

    new_proc = interproc_data.get_process_by_pgd(pgd)

    pid = new_proc.get_pid()

    pyrebox_print("Initializing API tracer for process %x" % pgd)

    cb_func = functools.partial(opcodes, proc=new_proc)

    #E8 cw   CALL rel16  Call near, relative, displacement relative to next instruction
    #E8 cd   CALL rel32  Call near, relative, displacement relative to next instruction
    #FF /2   CALL r/m16  Call near, absolute indirect, address given in r/m16
    #FF /2   CALL r/m32  Call near, absolute indirect, address given in r/m32
    #9A cd   CALL ptr16:16   Call far, absolute, address given in operand
    #9A cp   CALL ptr16:32   Call far, absolute, address given in operand
    #FF /3   CALL m16:16 Call far, absolute indirect, address given in m16:16
    #FF /3   CALL m16:32 Call far, absolute indirect, address given in m16:32

    cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                    functools.partial(cb_func, cb_name="call_e8_%x" % pid),
                    name="call_e8_%x" % pid,
                    start_opcode=0xE8,
                    end_opcode=0xE8)
    cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                    functools.partial(cb_func, cb_name="call_ff_%x" % pid),
                    name="call_ff_%x" % pid,
                    start_opcode=0xFF,
                    end_opcode=0xFF)
    cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                    functools.partial(cb_func, cb_name="call_9a_%x" % pid),
                    name="call_9a_%x" % pid,
                    start_opcode=0x9A,
                    end_opcode=0x9A)

    cm.add_trigger("call_e8_%x" % pid,
                   "mw_monitor2/trigger_jmp_call_ret_tracer.so")
    cm.set_trigger_var("call_e8_%x" % pid, "pgd", pgd)
    cm.set_trigger_var("call_e8_%x" % pid, "enable_ff_jmp",
                       1 if APITRACER_ENABLE_JMP else 0)

    cm.add_trigger("call_ff_%x" % pid,
                   "mw_monitor2/trigger_jmp_call_ret_tracer.so")
    cm.set_trigger_var("call_ff_%x" % pid, "pgd", pgd)
    cm.set_trigger_var("call_ff_%x" % pid, "enable_ff_jmp",
                       1 if APITRACER_ENABLE_JMP else 0)

    cm.add_trigger("call_9a_%x" % pid,
                   "mw_monitor2/trigger_jmp_call_ret_tracer.so")
    cm.set_trigger_var("call_9a_%x" % pid, "pgd", pgd)
    cm.set_trigger_var("call_9a_%x" % pid, "enable_ff_jmp",
                       1 if APITRACER_ENABLE_JMP else 0)

    #C3 RET NP Valid Valid Near return to calling procedure.
    #CB RET NP Valid Valid Far return to calling procedure.
    #C2 iw RET imm16 I Valid Valid Near return to calling procedure and pop imm16 bytes from stack.
    #CA iw RET imm16 I Valid Valid Far return to calling procedure and pop imm16 bytes from stack.

    if APITRACER_ENABLE_RET:
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="ret_c3_%x" % pid),
                        name="ret_c3_%x" % pid,
                        start_opcode=0xC3,
                        end_opcode=0xC3)
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="ret_cb_%x" % pid),
                        name="ret_cb_%x" % pid,
                        start_opcode=0xCB,
                        end_opcode=0xCB)
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="ret_c2_%x" % pid),
                        name="ret_c2_%x" % pid,
                        start_opcode=0xC2,
                        end_opcode=0xC2)
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="ret_ca_%x" % pid),
                        name="ret_ca_%x" % pid,
                        start_opcode=0xCA,
                        end_opcode=0xCA)

        cm.add_trigger("ret_c3_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("ret_c3_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("ret_c3_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

        cm.add_trigger("ret_cb_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("ret_cb_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("ret_cb_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

        cm.add_trigger("ret_c2_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("ret_c2_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("ret_c2_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

        cm.add_trigger("ret_ca_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("ret_ca_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("ret_ca_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

    #EB cb JMP rel8       Jump short, RIP = RIP + 8-bit displacement sign extended to 64-bits
    #E9 cw JMP rel16      Jump near, relative, displacement relative to next instruction. Not supported in 64-bit mode.
    #E9 cd JMP rel32      Jump near, relative, RIP = RIP + 32-bit displacement sign extended to 64-bits
    #FF /4 JMP r/m16      Jump near, absolute indirect, address = zeroextended r/m16. Not supported in 64-bit mode.
    #FF /4 JMP r/m32      Jump near, absolute indirect, address given in r/m32. Not supported in 64-bit mode.
    #FF /4 JMP r/m64      Jump near, absolute indirect, RIP = 64-Bit offset from register or memory
    #EA cd JMP ptr16:16   Jump far, absolute, address given in operand
    #EA cp JMP ptr16:32   Jump far, absolute, address given in operand
    #FF /5 JMP m16:16     Jump far, absolute indirect, address given in m16:16
    #FF /5 JMP m16:32     Jump far, absolute indirect, address given in m16:32.
    #FF /5 JMP m16:64     Jump far, absolute indirect, address given in m16:64

    if APITRACER_ENABLE_JMP:
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="jmp_e9_%x" % pid),
                        name="jmp_e9_%x" % pid,
                        start_opcode=0xE9,
                        end_opcode=0xE9)
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="jmp_ea_%x" % pid),
                        name="jmp_ea_%x" % pid,
                        start_opcode=0xEA,
                        end_opcode=0xEA)
        cm.add_callback(CallbackManager.OPCODE_RANGE_CB,
                        functools.partial(cb_func, cb_name="jmp_eb_%x" % pid),
                        name="jmp_eb_%x" % pid,
                        start_opcode=0xEB,
                        end_opcode=0xEB)

        cm.add_trigger("jmp_e9_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("jmp_e9_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("jmp_e9_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

        cm.add_trigger("jmp_ea_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("jmp_ea_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("jmp_ea_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

        cm.add_trigger("jmp_eb_%x" % pid,
                       "mw_monitor2/trigger_jmp_call_ret_tracer.so")
        cm.set_trigger_var("jmp_eb_%x" % pid, "pgd", pgd)
        cm.set_trigger_var("jmp_eb_%x" % pid, "enable_ff_jmp",
                           1 if APITRACER_ENABLE_JMP else 0)

    # Start monitoring process
    api.start_monitoring_process(pgd)
Exemplo n.º 21
0
    def __handle_host_request_exec_env_linux(self, cpu_index, cpu):
        """
            Handle the host_request_exec_env interface call.

            Argument in EAX: the buffer to write to
            Argument in EBX: the max size of the buffer to write to

            Returns number of bytes written in EAX, or -1 if the call failed.
        """

        if isinstance(cpu, X86CPU):
            buf = cpu.EAX
            size = cpu.EBX
        elif isinstance(cpu, X64CPU):
            buf = cpu.RAX
            size = cpu.RBX

        TARGET_LONG_SIZE = api.get_os_bits() / 8

        env = self.__file_to_execute["env"]

        pgd = api.get_running_process(cpu_index)
        # self.__printer("GuestAgentPlugin: host_request_exec_env(0x%08x, %d)
        # called" % (buf, size))
        if len(env) > 0:

            env = ["{:s}={:s}".format(k, v) for k, v in env.items()]
            env_size = sum(len(x) + 1 for x in env) + TARGET_LONG_SIZE * (len(env) + 1)

            try:
                # Security check: the buffer should be located on the allowed
                # boundaries
                if self.__check_buffer_validity(buf, size):
                    self.__write_strings_array(
                        pgd, buf, env)

                    if isinstance(cpu, X86CPU):
                        api.w_r(
                            cpu_index, "EAX", env_size)
                    elif isinstance(cpu, X64CPU):
                        api.w_r(
                            cpu_index, "RAX", env_size)
                else:
                    self.__printer("HostFilesPlugin: Declared buffer or buffer size are not" +
                                   "within the allowed boundaries %x (%x)" % (buf, size))
                    if isinstance(cpu, X86CPU):
                        api.w_r(cpu_index, "EAX", -1)
                    elif isinstance(cpu, X64CPU):
                        api.w_r(cpu_index, "RAX", -1)

            except Exception as ex:
                self.__printer(
                    "HostFilesPlugin: Exception %s while trying to write env vars to guest" % (str(ex)))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", -1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", -1)
        else:
            if isinstance(cpu, X86CPU):
                api.w_r(cpu_index, "EAX", 0)
            elif isinstance(cpu, X64CPU):
                api.w_r(cpu_index, "RAX", 0)
Exemplo n.º 22
0
def ntcreateprocess(params,
                    pid,
                    proc,
                    update_vads):

    # This function interface is for NTCreateProcess.
    # NtCreateProcessEx has different interface, but
    # the parameters we need, are aligned.

    # From Vista onwards, kernel32.dll calls NtCreateUserProcess
    # instead of NtCreateProcess(Ex).

    # NtCreateProcess:

    # OUT PHANDLE     ProcessHandle,
    # IN ACCESS_MASK  DesiredAccess,
    # IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
    # IN HANDLE   ParentProcess,
    # IN BOOLEAN  InheritObjectTable,
    # IN HANDLE SectionHandle     OPTIONAL,
    # IN HANDLE DebugPort     OPTIONAL,
    # IN HANDLE ExceptionPort     OPTIONAL

    # NtCreateProcessEx

    # OUT PHANDLE ProcessHandle,
    # IN ACCESS_MASK DesiredAccess,
    # IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    # IN HANDLE ParentProcess,
    # IN ULONG Flags,
    # IN HANDLE SectionHandle OPTIONAL,
    # IN HANDLE DebugPort OPTIONAL,
    # IN HANDLE ExceptionPort OPTIONAL,
    # IN BOOLEAN InJob

    # NtCreateUserProcess

    # PHANDLE ProcessHandle,
    # PHANDLE ThreadHandle,
    # ACCESS_MASK ProcessDesiredAccess,
    # ACCESS_MASK ThreadDesiredAccess,
    # POBJECT_ATTRIBUTES ProcessObjectAttributes,
    # POBJECT_ATTRIBUTES ThreadObjectAttributes,
    # ULONG ulProcessFlags,
    # ULONG ulThreadFlags,
    # PRTL_USER_PROCESS_PARAMETERS RtlUserProcessParameters,
    # PPS_CREATE_INFO PsCreateInfo,
    # PPS_ATTRIBUTE_LIST PsAttributeList

    from mw_monitor_classes import mwmon
    import api

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)
    # Set callback on return address

    # Read the first parameter (process handle)
    params = read_parameters(cpu, 1)

    callback_name = mwmon.cm.generate_callback_name("ntcreateprocess_ret")

    # Arguments to callback: the callback name, so that it can unset it, the
    # process handle variable

    callback_function = functools.partial(ntcreateprocessret,
                                          pid=pid,
                                          callback_name=callback_name,
                                          proc_hdl_p=params[1],
                                          proc=proc,
                                          update_vads=update_vads)

    mwmon.cm.add_callback(api.CallbackManager.INSN_BEGIN_CB,
                          callback_function,
                          name=callback_name,
                          addr=params[0],
                          pgd=pgd)
Exemplo n.º 23
0
def dump(params,
         pid=None,
         proc=None,
         update_vads=None,
         from_addr=None,
         callback_name=None,
         terminate_process=False):
    '''
    Dump the process, modules, vads...
    '''
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from utils import get_addr_space
    import api

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    mwmon.printer("Dumping process...")

    proc_hdl = None
    if terminate_process:
        if TARGET_LONG_SIZE == 4:
            # ret, proc_hdl, exit_status
            try:
                _, proc_hdl, _ = struct.unpack(
                    "<III", api.r_va(api.get_running_process(cpu_index), cpu.ESP, 4 * 3))
            except:
                proc_hdl = 0
                mwmon.printer("Could not dereference process handle in dumper.py")
        elif TARGET_LONG_SIZE == 8:
            # We don't need the return address
            # ret = struct.unpack("<Q",
            # api.r_va(api.get_running_process(cpu_index), cpu.ESP, 8))[0]
            proc_hdl = cpu.RCX
            # We don't need the exit status
            # exit_status = cpu.RDX

        # It seems there are usually 2 calls, when a process terminates itself.
        # First, ZwTerminateProcess is called with 0 as proc_hdl, and afterwards
        # -1.
        if proc_hdl == 0:
            return

    if callback_name is not None:
        # First, remove callback
        mwmon.cm.rm_callback(callback_name)

    # Check if we have been called from the right from_addr
    if from_addr is not None:
        if TARGET_LONG_SIZE == 4:
            try:
                buff = api.r_va(api.get_running_process(cpu_index), cpu.ESP, 4)
                ret_addr = struct.unpack("<I", buff)[0]
            except:
                ret_addr = 0
                mwmon.printer("Could not dereference return address on dumper.py")
        elif TARGET_LONG_SIZE == 8:
            try:
                buff = api.r_va(api.get_running_process(cpu_index), cpu.RSP, 8)
                ret_addr = struct.unpack("<Q", buff)[0]
            except:
                ret_addr = 0
                mwmon.printer("Could not dereference return address on dumper.py")
        if from_addr != ret_addr:
            return

    # We have been called from the right point, now, dump.
    path = mwmon.dumper_path
    # Dump a file with the VAD info, etc, and a filename for each dumped file,
    # so that we can import feed IDA with it
    try:
        # Dump main executable.
        addr_space = get_addr_space()

        # If 1 handle is specified, get the pid for that handle instead
        # of the calling PID.
        if proc_hdl is not None:
            if (TARGET_LONG_SIZE == 4 and proc_hdl == 0xFFFFFFFF) or \
               (TARGET_LONG_SIZE == 8 and proc_hdl == 0xFFFFFFFFFFFFFFFF):
                # If the handle is 0xFFFFFFFF, then the process is the caller.
                pass
            else:
                eprocs = [t for t in tasks.pslist(
                    addr_space) if t.UniqueProcessId == pid]
                proc_obj = None
                # Search handle table for the new created process
                for task in eprocs:
                    if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
                        for handle in task.ObjectTable.handles():
                            if handle.is_valid() and handle.HandleValue == proc_hdl and handle.get_object_type() == "Process":
                                proc_obj = handle.dereference_as("_EPROCESS")
                                break
                        break
                if proc_obj is not None:
                    # If we found the handle to which it referred, update the
                    # corresponding pid
                    pid = int(proc_obj.UniqueProcessId)
                else:
                    return

        # Case when no PID is specified, just dump everything
        if pid is None:
            pids = [p.pid for p in mwmon.data.procs]
        # When one pid is specified, dump that PID
        else:
            pids = [pid]

        eprocs = [t for t in tasks.pslist(
            addr_space) if t.UniqueProcessId in pids]
        for task in eprocs:
            mwmon.printer("Dumping process %x" % (task.UniqueProcessId))
            # Code adapted from procdump (volatility)
            task_space = task.get_process_address_space()
            if task_space is None:
                mwmon.printer("Error: Cannot acquire process AS")
                return
            elif task.Peb is None:
                # we must use m() here, because any other attempt to
                # reference task.Peb will try to instantiate the _PEB
                mwmon.printer(
                    "Error: PEB at {0:#x} is unavailable (possibly due to paging)".format(task.m('Peb')))
                return
            elif task_space.vtop(task.Peb.ImageBaseAddress) is None:
                mwmon.printer(
                    "Error: ImageBaseAddress at {0:#x} is unavailable" +
                    "(possibly due to paging)".format(task.Peb.ImageBaseAddress))
                return
            else:
                mwmon.printer(
                    "Dumping executable for %x" % (task.UniqueProcessId))
                dump_file = os.path.join(
                    path, "executable.%x.exe" % (task.UniqueProcessId))
                of = open(dump_file, 'wb')
                pe_file = obj.Object(
                    "_IMAGE_DOS_HEADER", offset=task.Peb.ImageBaseAddress, vm=task_space)
                try:
                    for offset, code in pe_file.get_image(unsafe=True,
                                                          memory=False,
                                                          fix=True):
                        of.seek(offset)
                        of.write(code)
                except ValueError, ve:
                    mwmon.printer("Error: {0}".format(ve))
                    return
                except exceptions.SanityCheckException, ve:
                    mwmon.printer("Error: {0} Try -u/--unsafe".format(ve))
                    return
Exemplo n.º 24
0
def opcode_range(cpu_index,cpu,cur_pc,next_pc):
    global cm
    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Opcode range callback (%x) PGD %x cur_pc %x next_pc %x\n" % (cpu_index,pgd,cur_pc,next_pc))
    start_shell()
Exemplo n.º 25
0
def my_function(cpu_index, cpu, tb, cur_pc, next_pc):
    global cm
    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Block end at (%x) %x -> %x\n" % (pgd, cur_pc, next_pc))
    start_shell()
Exemplo n.º 26
0
def ntreadfile(params, pid, proc, update_vads, is_write=False):
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import FileRead
    from mw_monitor_classes import FileWrite
    from mw_monitor_classes import File
    from utils import get_addr_space
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    # IN HANDLE   FileHandle,
    # IN HANDLE Event     OPTIONAL,
    # IN PIO_APC_ROUTINE ApcRoutine   OPTIONAL,
    # IN PVOID ApcContext     OPTIONAL,
    # OUT PIO_STATUS_BLOCK    IoStatusBlock,
    # OUT PVOID   Buffer,
    # IN ULONG    Length,
    # IN PLARGE_INTEGER ByteOffset    OPTIONAL,
    # IN PULONG Key   OPTIONAL

    pgd = api.get_running_process(cpu_index)

    # Read the parameters
    ret_addr, file_handle, arg2, arg3, arg4, arg5, buff, length, offset_p, arg9 = read_parameters(
        cpu, 9)

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize file_obj, that will point to the object of the referenced file
    file_obj = None

    # Search handle table for the new created process
    for task in eprocs:
        if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
            for handle in task.ObjectTable.handles():
                if handle.is_valid() and handle.HandleValue == file_handle and handle.get_object_type() == "File":
                    file_obj = handle.dereference_as("_FILE_OBJECT")
                    break
            break

    if file_obj is not None:
        file_instance = None
        for fi in mwmon.data.files:
            if fi.file_name == str(file_obj.FileName):
                file_instance = fi
                break

        # If we have still not recorded the file, add it to files to record
        if file_instance is None:
            file_instance = File(str(file_obj.FileName))
            mwmon.data.files.append(file_instance)
        # Now, record the read/write
        # curr_file_offset is never used
        # curr_file_offset = int(file_obj.CurrentByteOffset.QuadPart)
        # FO_SYNCHRONOUS_IO     0x0000002
        is_offset_maintained = ((file_obj.Flags & 0x0000002) != 0)

        # If no offset was specified, and the offset is mantained, the real
        # offset is taken from the file object
        offset = None
        if offset_p == 0 and is_offset_maintained:
            offset = int(file_obj.CurrentByteOffset.QuadPart)
        elif offset_p != 0:
            # If an offset is provided, the current offset in the file_object
            # will be updated, regardless of the flag.
            try:
                offset = struct.unpack("Q", api.r_va(pgd, offset_p, 8))[0]
            except:
                offset = 0
                mwmon.printer("Could not dereference offset in NtReadFile call in interproc.py")
        else:
            # If no offset was specified and the file object does not have the flag set, we may be in front of some kind
            # of corruption error or deliberate manipulation
            print "[!] The file object flag FO_SYNCHRONOUS_IO is not set, and no offset was provided"
            return

        # At this moment we do not record the data
        op = None

        for proc in mwmon.data.procs:
            if proc.pid == pid:
                local_proc = proc
                break

        if not is_write:
            op = FileRead(file_instance, local_proc, offset, length, None)
            if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
                f = mwmon.interproc_text_log_handle
                if TARGET_LONG_SIZE == 4:
                    f.write("[PID: %x] NtReadFile: Offset: %08x Size: %08x / %s\n" %
                            (pid, offset, length, str(file_obj.FileName)))
                elif TARGET_LONG_SIZE == 8:
                    f.write("[PID: %x] NtReadFile: Offset: %16x Size: %16x / %s\n" %
                            (pid, offset, length, str(file_obj.FileName)))
        else:
            op = FileWrite(file_instance, local_proc, offset, length, None)
            if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
                f = mwmon.interproc_text_log_handle
                if TARGET_LONG_SIZE == 4:
                    f.write("[PID: %x] NtWriteFile: Offset: %08x Size: %08x / %s\n" %
                            (pid, offset, length, str(file_obj.FileName)))
                elif TARGET_LONG_SIZE == 8:
                    f.write("[PID: %x] NtWriteFile: Offset: %16x Size: %16x / %s\n" %
                            (pid, offset, length, str(file_obj.FileName)))

        file_instance.add_operation(op)
        local_proc.file_operations.append(op)

    if update_vads:
        proc.update_vads()
Exemplo n.º 27
0
def ntvirtualprotect(params, pid, proc, update_vads):
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from utils import get_addr_space
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)

    #  IN HANDLE               ProcessHandle,
    #  IN OUT PVOID            *BaseAddress,
    #  IN OUT PULONG           NumberOfBytesToProtect,
    #  IN ULONG                NewAccessProtection,
    #  OUT PULONG              OldAccessProtection );
    # Keep a log of page permissions for each VAD. Log changes for every virtualprotect call.
    # Output this informaiton on the log file, signal the sections with
    # changed permissions.

    ret_addr, proc_handle, base_addr_p, size_p, new_access, old_access = read_parameters(
        cpu, 5)

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get call parameters

    base_addr = dereference_target_long(base_addr_p, pgd)
    size = dereference_target_long(size_p, pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize proc_obj, that will point to the object of the referenced
    # process, and section_obj, idem
    proc_obj = None
    # Search handle table for the caller process
    for task in eprocs:
        if task.UniqueProcessId == pid:
            if (TARGET_LONG_SIZE == 4 and proc_handle == 0xffffffff) or \
               (TARGET_LONG_SIZE == 8 and proc_handle == 0xffffffffffffffff):
                proc_obj = task
                break
            elif task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
                for handle in task.ObjectTable.handles():
                    if handle.is_valid():
                        if handle.HandleValue == proc_handle and handle.get_object_type() == "Process":
                            proc_obj = handle.dereference_as("_EPROCESS")
                            break
                break

    mapping_proc = None
    if proc_obj is not None:
        for proc in mwmon.data.procs:
            if proc.pid == proc_obj.UniqueProcessId:
                mapping_proc = proc
                break

    if mapping_proc is not None:
        for v in mapping_proc.vads:
            # If the block overlaps the vad:
            if base_addr >= v.start and base_addr < (v.start + v.size):
                v.update_page_access(base_addr, size, new_access)

    if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
        f = mwmon.interproc_text_log_handle
        if TARGET_LONG_SIZE == 4:
            f.write("[PID: %x] NtVirtualProtect: Base: %08x Size: %08x NewProtect: %08x\n" %
                    (pid, base_addr, size, new_access))
        elif TARGET_LONG_SIZE == 8:
            f.write("[PID: %x] NtVirtualProtect: Base: %016x Size: %016x NewProtect: %016x\n" %
                    (pid, base_addr, size, new_access))
    if update_vads:
        proc.update_vads()
Exemplo n.º 28
0
def ntopenprocessret(params, pid, callback_name, proc_hdl_p, proc, update_vads):
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import mw_monitor_start_monitoring_process
    from mw_monitor_classes import Process
    from api import get_running_process
    from utils import get_addr_space
    import api

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = get_running_process(cpu_index)

    # First, remove callback
    mwmon.cm.rm_callback(callback_name)

    # Do not continue if EAX/RAX returns and invalid return code.
    if read_return_parameter(cpu) != 0:
        return

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize proc_obj, that will point to the eprocess of the new created
    # process
    proc_obj = None

    # Dereference the output argument containing the hdl of the newly created
    # process
    proc_hdl = dereference_target_long(proc_hdl_p, pgd)

    # Search handle table for the new created process
    for task in eprocs:
        if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
            for handle in task.ObjectTable.handles():
                if handle.is_valid() and handle.HandleValue == proc_hdl and handle.get_object_type() == "Process":
                    proc_obj = handle.dereference_as("_EPROCESS")
                    break
            break

    if proc_obj is not None:
        if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
            f = mwmon.interproc_text_log_handle
            f.write("[PID: %x] NtOpenProcess: %s - PID: %x - CR3: %x\n" %
                    (pid,
                     str(proc_obj.ImageFileName),
                     int(proc_obj.UniqueProcessId),
                     int(proc_obj.Pcb.DirectoryTableBase.v())))

        # Check if we are already monitoring the process
        for proc in mwmon.data.procs:
            if proc.pid == int(proc_obj.UniqueProcessId):
                return
        new_proc = Process(str(proc_obj.ImageFileName))
        new_proc.set_pid(int(proc_obj.UniqueProcessId))
        new_proc.set_pgd(int(proc_obj.Pcb.DirectoryTableBase.v()))
        mw_monitor_start_monitoring_process(new_proc)
    else:
        if TARGET_LONG_SIZE == 4: 
            mwmon.printer("Error while trying to retrieve EPROCESS for handle %x, PID %x, EAX: %x" % (proc_hdl, pid, cpu.EAX))
        elif TARGET_LONG_SIZE == 8:
            mwmon.printer("Error while trying to retrieve EPROCESS for handle %x, PID %x, EAX: %x" % (proc_hdl, pid, cpu.RAX))

    if update_vads:
        proc.update_vads()

    return
Exemplo n.º 29
0
def ntwritevirtualmemory(params, pid, proc, update_vads, reverse=False):
    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import Injection
    import api
    from utils import get_addr_space

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    # _In_ HANDLE     ProcessHandle,
    # _In_ PVOID  BaseAddress,
    # _In_ PVOID  Buffer,
    # _In_ SIZE_T     NumberOfBytesToWrite,
    # _Out_opt_ PSIZE_T   NumberOfBytesWritten

    pgd = api.get_running_process(cpu_index)

    # Read the parameters
    ret_addr, proc_hdl, remote_addr, local_addr, size, size_out = read_parameters(
        cpu, 5)

    local_proc = None
    # Get local proc
    for proc in mwmon.data.procs:
        if proc.pid == pid:
            local_proc = proc
            break
    # Try to get remote process from list of monitored processes
    remote_proc = None
    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize proc_obj, that will point to the eprocess of the new created
    # process
    proc_obj = None

    # Search handle table for the new created process
    for task in eprocs:
        if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
            for handle in task.ObjectTable.handles():
                if handle.is_valid() and handle.HandleValue == proc_hdl and handle.get_object_type() == "Process":
                    proc_obj = handle.dereference_as("_EPROCESS")
                    break
            break
    if proc_obj is not None:
        for proc in mwmon.data.procs:
            if proc.pid == proc_obj.UniqueProcessId:
                remote_proc = proc
                break
    else:
        # Sometimes we get calls to this function over non-proc handles (e.g. type "Desktop")
        return
    if remote_proc is None:
        mwmon.printer(
            "[!]  Could not obtain remote proc, or it is not being monitored")
        return
    elif local_proc is None:
        mwmon.printer(
            "[!]  Could not obtain local proc, or it is not being monitored")
        return
    else:
        if reverse:
            data = None
            if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
                f = mwmon.interproc_text_log_handle
                if TARGET_LONG_SIZE == 4:
                    f.write("[PID: %x] NtReadVirtualMemory: PID: %x - Addr: %08x <-- PID: %x Addr: %08x / Size: %08x\n" %
                            (pid, local_proc.pid, local_addr, remote_proc.pid, remote_addr, size))
                elif TARGET_LONG_SIZE == 8:
                    f.write("[PID: %x] NtReadVirtualMemory: PID: %x - Addr: %16x <-- PID: %x Addr: %16x / Size: %16x\n" %
                            (pid, local_proc.pid, local_addr, remote_proc.pid, remote_addr, size))
        else:
            data = None
            if mwmon.interproc_text_log and mwmon.interproc_text_log_handle is not None:
                f = mwmon.interproc_text_log_handle
                if TARGET_LONG_SIZE == 4:
                    f.write("[PID: %x] NtWriteVirtualMemory: PID: %x - Addr: %08x --> PID: %x Addr: %08x / Size: %08x\n" %
                            (pid, local_proc.pid, local_addr, remote_proc.pid, remote_addr, size))
                elif TARGET_LONG_SIZE == 8:
                    f.write("[PID: %x] NtWriteVirtualMemory: PID: %x - Addr: %16x --> PID: %x Addr: %16x / Size: %16x\n" %
                            (pid, local_proc.pid, local_addr, remote_proc.pid, remote_addr, size))

        inj = Injection(remote_proc, remote_addr,
                        local_proc, local_addr, size, data, reverse)
        local_proc.add_injection(inj)

    if update_vads:
        proc.update_vads()
Exemplo n.º 30
0
def ntallocatevirtualmemory(params,
                            pid,
                            proc,
                            update_vads):

    import volatility.win32.tasks as tasks
    from mw_monitor_classes import mwmon
    import api
    from api import CallbackManager
    from utils import get_addr_space
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    pgd = api.get_running_process(cpu_index)

    # IN HANDLE               ProcessHandle,
    # IN OUT PVOID            *BaseAddress,
    # IN ULONG                ZeroBits,
    # IN OUT PULONG           RegionSize,
    # IN ULONG                AllocationType,
    # IN ULONG                Protect );

    # Only used for logging the event
    if not mwmon.interproc_text_log:
        return

    # Get call parameters
    (ret_addr, proc_handle, base_addr_p, zerobits,
     size_p, aloc_type, access) = read_parameters(cpu, 6)

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]

    # Initialize proc_obj, that will point to the object of the referenced
    # process, and section_obj, idem
    proc_obj = None
    # Search handle table for the caller process
    for task in eprocs:
        if task.UniqueProcessId == pid:
            if (TARGET_LONG_SIZE == 4 and proc_handle == 0xffffffff) or \
               (TARGET_LONG_SIZE == 8 and proc_handle == 0xffffffffffffffff):
                proc_obj = task
                break
            elif task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
                for handle in task.ObjectTable.handles():
                    if handle.is_valid():
                        if handle.HandleValue == proc_handle and handle.get_object_type() == "Process":
                            proc_obj = handle.dereference_as("_EPROCESS")
                            break
                break

    mapping_proc = None
    if proc_obj is not None:
        for proc in mwmon.data.procs:
            if proc.pid == proc_obj.UniqueProcessId:
                mapping_proc = proc
                break

    if mapping_proc is not None:
        # Arguments to callback: the callback name, so that it can unset it,
        # the process handle variable, and the section handle

        callback_name = mwmon.cm.generate_callback_name(
            "ntallocatevirtualmemory_ret")

        callback_function = functools.partial(ntallocatevirtualmemory_ret,
                                              pid=pid,
                                              callback_name=callback_name,
                                              mapping_proc=mapping_proc,
                                              base_addr_p=base_addr_p,
                                              zerobits=zerobits,
                                              size_p=size_p,
                                              aloc_type=aloc_type,
                                              access=access,
                                              proc=proc,
                                              update_vads=update_vads)

        mwmon.cm.add_callback(CallbackManager.INSN_BEGIN_CB,
                              callback_function,
                              name=callback_name,
                              addr=ret_addr,
                              pgd=pgd)
Exemplo n.º 31
0
def tlb_exec(cpu, addr):
    global cm
    global counter
    import api
    pgd = api.get_running_process(cpu.CPU_INDEX)
    pyrebox_print("TLB exec, PGD %x Addr %x\n" % (pgd, addr))
Exemplo n.º 32
0
def opcodes(params, db, proc):
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import is_in_pending_resolution
    from api import CallbackManager
    import api
    from DeviareDbParser import ArgumentParser

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    pc = params["cur_pc"]
    next_pc = params["next_pc"]

    # First, check if the next_pc is located in a module with
    # pending symbol resolution, and update symbols
    # accordingly
    if is_in_pending_resolution(proc.get_pgd(), next_pc):
        proc.update_symbols()

    try:
        # Locate nearest lower symbol
        sym = proc.locate_nearest_symbol(next_pc)
        if sym is None:
            return
        mod = sym.get_mod()
        fun = sym.get_fun()
        real_api_addr = sym.get_addr()
        # Reduce FP's by checking that the origin EIP is not also within the
        # same module (code reuse inside the dll)
        if mod in proc.modules:
            for (base, size) in proc.modules[mod]:
                if pc >= base and pc <= (base + size):
                    return

        # First shortcut: check if it is an excluded api/module, or included:
        if mwmon.exclude_apis_addrs is not None and len(mwmon.exclude_apis_addrs) > 0:
            if real_api_addr in mwmon.exclude_apis_addrs:
                return

        if mwmon.exclude_modules_addrs is not None and len(mwmon.exclude_modules_addrs) > 0:
            for (base, size) in mwmon.exclude_modules_addrs:
                if real_api_addr >= base and real_api_addr < (base + size):
                    return

        # Origin modules
        if mwmon.exclude_origin_modules_addrs is not None and len(mwmon.exclude_origin_modules_addrs) > 0:
            # pc is the originating pc
            for (base, size) in mwmon.exclude_origin_modules_addrs:
                if pc >= base and pc < (base + size):
                    return

        if mwmon.include_apis_addrs is not None and len(mwmon.include_apis_addrs) > 0:
            if real_api_addr not in mwmon.include_apis_addrs:
                return

        if proc.in_mod_boundaries(real_api_addr):

            pgd = api.get_running_process(cpu_index)

            # Set callback on return address
            if TARGET_LONG_SIZE == 4:
                try:
                    ret_addr_val = api.r_va(pgd, cpu.ESP, 4)
                    ret_addr = struct.unpack("<I", ret_addr_val)[0]
                except:
                    ret_addr = 0
                    mwmon.printer("Could not read return address on API tracer")
            elif TARGET_LONG_SIZE == 8:
                try:
                    ret_addr_val = api.r_va(pgd, cpu.RSP, 8)
                    ret_addr = struct.unpack("<Q", ret_addr_val)[0]
                except:
                    ret_addr = 0 
                    mwmon.printer("Could not read return address on API tracer")

            if mwmon.api_tracer_light_mode:
                if real_api_addr == next_pc:
                    if TARGET_LONG_SIZE == 4:
                        proc.add_call(pc, real_api_addr, "[PID: %x] %08x --> %s:%s(%08x) --> %08x\n" % (
                            proc.pid, pc, mod, fun, real_api_addr, ret_addr))
                    elif TARGET_LONG_SIZE == 8:
                        proc.add_call(pc, real_api_addr, "[PID: %x] %016x --> %s:%s(%016x) --> %016x\n" % (
                            proc.pid, pc, mod, fun, real_api_addr, ret_addr))
                else:
                    if TARGET_LONG_SIZE == 4:
                        proc.add_call(pc, real_api_addr, "[PID: %x] %08x --> %s:%s(+%x)(%08x) --> %08x\n" % (
                            proc.pid, pc, mod, fun, (next_pc - real_api_addr), next_pc, ret_addr))
                    elif TARGET_LONG_SIZE == 8:
                        proc.add_call(pc, real_api_addr, "[PID: %x] %016x --> %s:%s(+%x)(%016x) --> %016x\n" % (
                            proc.pid, pc, mod, fun, (next_pc - real_api_addr), next_pc, ret_addr))
                return

            data = APICallData()
            data.pc = pc
            data.mod = mod
            data.fun = fun
            data.ret_addr = ret_addr

            if TARGET_LONG_SIZE == 4:
                argument_parser = ArgumentParser(db, cpu, cpu.ESP, mod, fun)
            elif TARGET_LONG_SIZE == 8:
                argument_parser = ArgumentParser(db, cpu, cpu.RSP, mod, fun)

            if not argument_parser.in_db():
                return

            data.in_args = [arg for arg in argument_parser.get_in_args()]

            # If return address could not be read, we skip the callback
            if ret_addr != 0:
                callback_name = "ret_bp_%d" % mwmon.bp_counter

                callback = functools.partial(opcodes_ret,
                                             pc,
                                             real_api_addr,
                                             data,
                                             callback_name,
                                             argument_parser,
                                             mod,
                                             fun,
                                             proc)

                mwmon.cm.add_callback(CallbackManager.INSN_BEGIN_CB,
                                      callback,
                                      name=callback_name,
                                      addr=data.ret_addr,
                                      pgd=pgd)

                mwmon.bp_counter += 1

    except Exception as e:
        mwmon.printer(str(e))
        traceback.print_exc()
    finally:
        return
Exemplo n.º 33
0
def opcodes(params, db, proc):
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import is_in_pending_resolution
    from api import CallbackManager
    import api
    from DeviareDbParser import ArgumentParser

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    pc = params["cur_pc"]
    next_pc = params["next_pc"]

    # First, check if the next_pc is located in a module with
    # pending symbol resolution, and update symbols
    # accordingly
    if is_in_pending_resolution(proc.get_pgd(), next_pc):
        proc.update_symbols()

    try:
        # Locate nearest lower symbol
        sym = proc.locate_nearest_symbol(next_pc)
        if sym is None:
            return
        mod = sym.get_mod()
        fun = sym.get_fun()
        real_api_addr = sym.get_addr()
        # Reduce FP's by checking that the origin EIP is not also within the
        # same module (code reuse inside the dll)
        if mod in proc.modules:
            for (base, size) in proc.modules[mod]:
                if pc >= base and pc <= (base + size):
                    return

        # First shortcut: check if it is an excluded api/module, or included:
        if mwmon.exclude_apis_addrs is not None and len(
                mwmon.exclude_apis_addrs) > 0:
            if real_api_addr in mwmon.exclude_apis_addrs:
                return

        if mwmon.exclude_modules_addrs is not None and len(
                mwmon.exclude_modules_addrs) > 0:
            for (base, size) in mwmon.exclude_modules_addrs:
                if real_api_addr >= base and real_api_addr < (base + size):
                    return

        # Origin modules
        if mwmon.exclude_origin_modules_addrs is not None and len(
                mwmon.exclude_origin_modules_addrs) > 0:
            # pc is the originating pc
            for (base, size) in mwmon.exclude_origin_modules_addrs:
                if pc >= base and pc < (base + size):
                    return

        if mwmon.include_apis_addrs is not None and len(
                mwmon.include_apis_addrs) > 0:
            if real_api_addr not in mwmon.include_apis_addrs:
                return

        if proc.in_mod_boundaries(real_api_addr):

            pgd = api.get_running_process(cpu_index)

            # Set callback on return address
            if TARGET_LONG_SIZE == 4:
                try:
                    ret_addr_val = api.r_va(pgd, cpu.ESP, 4)
                    ret_addr = struct.unpack("<I", ret_addr_val)[0]
                except:
                    ret_addr = 0
                    mwmon.printer(
                        "Could not read return address on API tracer")
            elif TARGET_LONG_SIZE == 8:
                try:
                    ret_addr_val = api.r_va(pgd, cpu.RSP, 8)
                    ret_addr = struct.unpack("<Q", ret_addr_val)[0]
                except:
                    ret_addr = 0
                    mwmon.printer(
                        "Could not read return address on API tracer")

            if mwmon.api_tracer_light_mode:
                if real_api_addr == next_pc:
                    if TARGET_LONG_SIZE == 4:
                        proc.add_call(
                            pc, real_api_addr,
                            "[PID: %x] %08x --> %s:%s(%08x) --> %08x\n" %
                            (proc.pid, pc, mod, fun, real_api_addr, ret_addr))
                    elif TARGET_LONG_SIZE == 8:
                        proc.add_call(
                            pc, real_api_addr,
                            "[PID: %x] %016x --> %s:%s(%016x) --> %016x\n" %
                            (proc.pid, pc, mod, fun, real_api_addr, ret_addr))
                else:
                    if TARGET_LONG_SIZE == 4:
                        proc.add_call(
                            pc, real_api_addr,
                            "[PID: %x] %08x --> %s:%s(+%x)(%08x) --> %08x\n" %
                            (proc.pid, pc, mod, fun,
                             (next_pc - real_api_addr), next_pc, ret_addr))
                    elif TARGET_LONG_SIZE == 8:
                        proc.add_call(
                            pc, real_api_addr,
                            "[PID: %x] %016x --> %s:%s(+%x)(%016x) --> %016x\n"
                            % (proc.pid, pc, mod, fun,
                               (next_pc - real_api_addr), next_pc, ret_addr))
                return

            data = APICallData()
            data.pc = pc
            data.mod = mod
            data.fun = fun
            data.ret_addr = ret_addr

            if TARGET_LONG_SIZE == 4:
                argument_parser = ArgumentParser(db, cpu, cpu.ESP, mod, fun)
            elif TARGET_LONG_SIZE == 8:
                argument_parser = ArgumentParser(db, cpu, cpu.RSP, mod, fun)

            if not argument_parser.in_db():
                return

            data.in_args = [arg for arg in argument_parser.get_in_args()]

            # If return address could not be read, we skip the callback
            if ret_addr != 0:
                callback_name = "ret_bp_%d" % mwmon.bp_counter

                callback = functools.partial(opcodes_ret, pc, real_api_addr,
                                             data, callback_name,
                                             argument_parser, mod, fun, proc)

                mwmon.cm.add_callback(CallbackManager.INSN_BEGIN_CB,
                                      callback,
                                      name=callback_name,
                                      addr=data.ret_addr,
                                      pgd=pgd)

                mwmon.bp_counter += 1

    except Exception as e:
        mwmon.printer(str(e))
        traceback.print_exc()
    finally:
        return
Exemplo n.º 34
0
def opcodes(params, cb_name, proc):
    from api import CallbackManager
    import api
    from deviare_db_parser import ArgumentParser
    import struct

    global bp_counter
    global APITRACER_DATABASE32
    global APITRACER_DATABASE64
    global APITRACER_RULES
    global APITRACER_ANTI_STOLEN

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]
    pc = params["cur_pc"]
    next_pc = params["next_pc"]
    pgd = api.get_running_process(cpu_index)

    try:
        if APITRACER_ANTI_STOLEN:
            # Locate nearest lower symbol
            sym = proc.locate_nearest_symbol(next_pc)
        else:
            sym = proc.locate_nearest_symbol(next_pc, tolerate_offset=0x0)

        if sym is None:
            return

        mod = sym.get_mod()
        mod_fullname = sym.get_mod_fullname()
        fun = sym.get_fun()
        real_api_addr = sym.get_addr()

        caller_module_name = proc.get_overlapping_module(pc)

        # Reduce FP's by checking that the origin EIP is not also within the
        # same module (code reuse inside the dll)

        if mod_fullname == caller_module_name:
            return

        matched = False
        # Check if the API is in the list (included or excluded)
        for rule in APITRACER_RULES["rules"]:
            if rule["mod"] == "" or fnmatch.fnmatch(mod_fullname.lower(),
                                                    rule["mod"].lower()):
                if rule["fun"] == "" or fnmatch.fnmatch(
                        fun.lower(), rule["fun"].lower()):
                    if "from_mod" in rule and rule["from_mod"] != "":
                        if caller_module_name is not None:
                            if fnmatch.fnmatch(caller_module_name,
                                               rule["from_mod"].lower()):
                                matched = True
                                if rule["action"] == "reject":
                                    return
                                else:
                                    break
                                break
                    else:
                        matched = True
                        if rule["action"] == "reject":
                            return
                        else:
                            break

        # Apply default policy if not matched:
        if not matched and APITRACER_RULES["policy"] == "reject":
            return

        # Set callback on return address
        if TARGET_LONG_SIZE == 4:
            try:
                ret_addr_val = api.r_va(pgd, cpu.ESP, 4)
                ret_addr = struct.unpack("<I", ret_addr_val)[0]
            except Exception as e:
                ret_addr = 0
                pyrebox_print(
                    "Could not read return address on API tracer: %s" % str(e))
        elif TARGET_LONG_SIZE == 8:
            try:
                ret_addr_val = api.r_va(pgd, cpu.RSP, 8)
                ret_addr = struct.unpack("<Q", ret_addr_val)[0]
            except Exception as e:
                ret_addr = 0
                pyrebox_print(
                    "Could not read return address on API tracer: %s" % str(e))

        is_64_bit_dll = True
        if TARGET_LONG_SIZE == 4 or (TARGET_LONG_SIZE == 8 and proc.is_wow64()
                                     and "windows\\syswow64"
                                     in mod_fullname.lower()):
            is_64_bit_dll = False

        if APITRACER_LIGHT_MODE:
            bits = 32 if not is_64_bit_dll else 64
            if real_api_addr == next_pc:
                if TARGET_LONG_SIZE == 4:
                    proc.add_call(
                        pc, real_api_addr,
                        "[PID: %x] (%d) %08x --> %s:%s(%08x) --> %08x\n" %
                        (proc.get_pid(), bits, pc, mod_fullname, fun,
                         real_api_addr, ret_addr))
                elif TARGET_LONG_SIZE == 8:
                    proc.add_call(
                        pc, real_api_addr,
                        "[PID: %x] (%d) %016x --> %s:%s(%016x) --> %016x\n" %
                        (proc.get_pid(), bits, pc, mod_fullname, fun,
                         real_api_addr, ret_addr))
            else:
                if TARGET_LONG_SIZE == 4:
                    proc.add_call(
                        pc, real_api_addr,
                        "[PID: %x] (%d) %08x --> %s:%s(+%x)(%08x) --> %08x\n" %
                        (proc.get_pid(), bits, pc, mod_fullname, fun,
                         (next_pc - real_api_addr), next_pc, ret_addr))
                elif TARGET_LONG_SIZE == 8:
                    proc.add_call(
                        pc, real_api_addr,
                        "[PID: %x] (%d) %016x --> %s:%s(+%x)(%016x) --> %016x\n"
                        % (proc.get_pid(), bits, pc, mod_fullname, fun,
                           (next_pc - real_api_addr), next_pc, ret_addr))
            return

        data = APICallData()
        data.set_pc(pc)
        data.set_mod(mod)
        data.set_fun(fun)
        data.set_ret_addr(ret_addr)

        if not is_64_bit_dll:
            argument_parser = ArgumentParser(cpu, cpu.ESP, mod, fun, 32)
        else:
            argument_parser = ArgumentParser(cpu, cpu.RSP, mod, fun, 64)

        if not argument_parser.in_db():
            #pyrebox_print("API function not present in db: %s - %s" % (mod, fun))
            return

        data.set_in_args([arg for arg in argument_parser.get_in_args()])

        # Add the call as soon as it is produced, and update
        # the output parameters on return
        proc.add_call(pc, real_api_addr, data)

        # If return address could not be read, we skip the callback
        if ret_addr != 0:
            callback_name = "ret_bp_%d" % bp_counter

            callback = functools.partial(opcodes_ret, pc, real_api_addr, data,
                                         callback_name, argument_parser, mod,
                                         fun, proc)

            cm.add_callback(CallbackManager.INSN_BEGIN_CB,
                            callback,
                            name=callback_name,
                            addr=data.get_ret_addr(),
                            pgd=pgd)

            bp_counter += 1

    except Exception as e:
        pyrebox_print(str(e))
        traceback.print_exc()
    finally:
        return
Exemplo n.º 35
0
def op_insn_begin(cpu_index, cpu):
    global cm
    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Process %x hit the callback at %x\n" % (pgd, cpu.PC))
    cm.rm_callback("insn_begin_optimized")
    pyrebox_print("Unregistered callback\n")
Exemplo n.º 36
0
def disassemble(addr,cpu_index):
	'''
	Disassemble instruction. Receives 2 parameters:
		:param addr: Address from instruction to disassemble
		:type addr: int
		:param cpu_index: CPU index 
		:type cpu_index: int
	'''

	global logger
	global num_ins

	pgd = api.get_running_process(cpu_index)

	if api.get_os_bits()==32:
		md = Cs(CS_ARCH_X86, CS_MODE_32)
		content = api.r_va(pgd,addr,0x4)
	else:
		md = Cs(CS_ARCH_X86, CS_MODE_64)
		content = api.r_va(pgd,addr,0x6)
	
	md.detail = True
	
	for insn in md.disasm(content, addr):
		
		if insn.mnemonic == "call":

			if len(insn.operands) > 0:
				
				mycpu=api.r_cpu(0)
				
				simbolo=None

				if api.get_os_bits()==32:
					simbolo=api.va_to_sym(pgd,mycpu.EIP)
				else:
					simbolo=api.va_to_sym(pgd,mycpu.RIP)

				if simbolo != None and api.get_os_bits()!=32:

					## Microsoft x64 calling convention
					## 

					logger.info("[API]0x%x:\t%s\t%s\t[RIP]:0x%x\t%s\t[PGD]: %x",insn.address, insn.mnemonic, insn.op_str,mycpu.RIP,simbolo,pgd)
					num_ins = num_ins + 1

					## RCX - Arg 1 

					try:

						rcx_content = api.r_va(pgd,mycpu.RCX,0x100)
						logger.info("[RCX]: 0x%x [Data]: %s", mycpu.RCX,smart_format(rcx_content, 0x100, True))

					except:
						logger.info("[RCX]: 0x%x", mycpu.RCX)

					## RDX - Arg 2 

					try:

						rdx_content = api.r_va(pgd,mycpu.RDX,0x100)
						logger.info("[RDX]: 0x%x [Data]: %s", mycpu.RDX,smart_format(rdx_content, 0x100, True))

					except:
						logger.info("[RDX]: 0x%x", mycpu.RDX)

					## R8 - Arg 3

					try:

						r8_content = api.r_va(pgd,mycpu.R8,0x100)
						logger.info("[R8]: 0x%x [Data]: %s", mycpu.R8,smart_format(r8_content, 0x100, True))

					except:
						logger.info("[R8]: 0x%x", mycpu.R8)

					## R9 - Arg 4

					try:

						r9_content = api.r_va(pgd,mycpu.R9,0x100)
						logger.info("[R9]: 0x%x [Data]: %s", mycpu.R9,smart_format(r9_content, 0x100, True))

					except:
						logger.info("[R9]: 0x%x", mycpu.R9)

					## RAX - return value

					try:
						rax_content = api.r_va(pgd,mycpu.RAX,0x100)
						logger.info("[RAX]: 0x%x [Data]: %s", mycpu.RAX,smart_format(rax_content, 0x100, True))

					except:

						logger.info("[RAX]: 0x%x", mycpu.RAX)


					logger.info("--")

				elif simbolo != None :

					## x86 call conventions 
					# cdecl -> arguments are pushed on the stack in the reverse order. EAX return
					# syscall -> arguments are pushed on the stack right to left.
					# optlink -> arguments are pushed on the stack right to left.
					# ...  
					
					logger.info("[API]0x%x:\t%s\t%s\t[EIP]:0x%x\t%s\t[PGD]: %x",insn.address, insn.mnemonic, insn.op_str,mycpu.EIP,simbolo,pgd)
					num_ins = num_ins + 1

					bytestoread = 0x200

					try:
						eax_content = api.r_va(pgd,mycpu.EAX,bytestoread)
						logger.info("[EAX]: 0x%x [Data]: %s", mycpu.EAX,smart_format(eax_content, bytestoread, True))
						
					except:
						logger.info("[EAX]: 0x%x", mycpu.EAX)

					try:
						ecx_content = api.r_va(pgd,mycpu.ECX,bytestoread)
						logger.info("[ECX]: 0x%x [Data]: %s", mycpu.ECX,smart_format(ecx_content, bytestoread, True))					
						
					except:
						logger.info("[ECX]: 0x%x", mycpu.ECX)

					try:
						edx_content = api.r_va(pgd,mycpu.EDX,bytestoread)
						logger.info("[EDX]: 0x%x [Data]: %s", mycpu.EDX,smart_format(edx_content, bytestoread, True))					
						
					except:
						logger.info("[EDX]: 0x%x", mycpu.EDX)

					try:
						ebp_arg2_content = api.r_va(pgd,mycpu.EBP+8,bytestoread)
						logger.info("[EBP+8]: 0x%x [Data]: %s", mycpu.EBP+8,smart_format(ebp_arg2_content, bytestoread, True))
					except:
						logger.info("[EBP+8]: 0x%x", mycpu.EBP+8)

					try:
						ebp_arg3_content = api.r_va(pgd,mycpu.EBP+12,bytestoread)
						logger.info("[EBP+12]: 0x%x [Data]: %s", mycpu.EBP+12,smart_format(ebp_arg3_content, bytestoread, True))
					except:
						logger.info("[EBP+12]: 0x%x", mycpu.EBP+12)

					try:
						ebp_arg4_content = api.r_va(pgd,mycpu.EBP+16,bytestoread)
						logger.info("[EBP+16]: 0x%x [Data]: %s", mycpu.EBP+16,smart_format(ebp_arg4_content, bytestoread, True))
					except:
						logger.info("[EBP+16]: 0x%x", mycpu.EBP+16)

					try:
						ebp_arg5_content = api.r_va(pgd,mycpu.EBP+20,bytestoread)
						logger.info("[EBP+20]: 0x%x [Data]: %s", mycpu.EBP+20,smart_format(ebp_arg5_content, bytestoread, True))
					except:
						logger.info("[EBP+20]: 0x%x", mycpu.EBP+20)

					try:
						ebp_arg6_content = api.r_va(pgd,mycpu.EBP+24,bytestoread)
						logger.info("[EBP+24]: 0x%x [Data]: %s", mycpu.EBP+24,smart_format(ebp_arg6_content, bytestoread, True))
					except:
						logger.info("[EBP+24]: 0x%x", mycpu.EBP+24)

					logger.info("--")
Exemplo n.º 37
0
    def __handle_host_request_exec_env(self, cpu_index, cpu):
        """
            Handle the host_request_exec_env interface call.

            Argument in EAX: the buffer to write to
            Argument in EBX: the max size of the buffer to write to

            Returns number of bytes written in EAX, or -1 if the call failed.
        """

        if isinstance(cpu, X86CPU):
            buf = cpu.EAX
            size = cpu.EBX
        elif isinstance(cpu, X64CPU):
            buf = cpu.RAX
            size = cpu.RBX

        env = self.__file_to_execute["env"]

        pgd = api.get_running_process(cpu_index)
        # self.__printer("GuestAgentPlugin: host_request_exec_env(0x%08x, %d)
        # called" % (buf, size))
        if len(env) > 0:

            env_size = 0
            if len(env) > 0:
                env = ["{:s}={:s}".format(k, v) for k, v in env.items()]
                env_size = sum(len(x) + 1 for x in env) + 1
                if env_size > self.__agent_buffer_size:
                    raise ValueError(
                        "The size of the env variables should not exceed %d bytes"
                        % self.__agent_buffer_size)

            try:
                # Security check: the buffer should be located on the allowed
                # boundaries
                if self.__check_buffer_validity(buf, size):
                    self.__write_env_strings_array(pgd, buf, env)

                    if isinstance(cpu, X86CPU):
                        api.w_r(cpu_index, "EAX", env_size)
                    elif isinstance(cpu, X64CPU):
                        api.w_r(cpu_index, "RAX", env_size)
                else:
                    self.__printer(
                        "HostFilesPlugin: Declared buffer or buffer size are not"
                        + "within the allowed boundaries %x (%x)" %
                        (buf, size))
                    if isinstance(cpu, X86CPU):
                        api.w_r(cpu_index, "EAX", -1)
                    elif isinstance(cpu, X64CPU):
                        api.w_r(cpu_index, "RAX", -1)

            except Exception as ex:
                self.__printer(
                    "HostFilesPlugin: Exception %s while trying to write env vars to guest"
                    % (str(ex)))
                if isinstance(cpu, X86CPU):
                    api.w_r(cpu_index, "EAX", -1)
                elif isinstance(cpu, X64CPU):
                    api.w_r(cpu_index, "RAX", -1)
        else:
            if isinstance(cpu, X86CPU):
                api.w_r(cpu_index, "EAX", 0)
            elif isinstance(cpu, X64CPU):
                api.w_r(cpu_index, "RAX", 0)
Exemplo n.º 38
0
def my_function(cpu_index,cpu):
    global cm
    pgd = api.get_running_process(cpu_index)
    pyrebox_print("Insn end at (%x) %x\n" % (pgd,cpu.PC))
    start_shell()
Exemplo n.º 39
0
def ntmapviewofsection(params, pid, proc, update_vads):
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.overlays.windows.windows as windows
    from mw_monitor_classes import mwmon
    from mw_monitor_classes import Section
    from utils import get_addr_space
    import api
    from api import CallbackManager
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    cpu_index = params["cpu_index"]
    cpu = params["cpu"]

    # IN HANDLE               SectionHandle,
    # IN HANDLE               ProcessHandle,
    # IN OUT PVOID            *BaseAddress OPTIONAL,
    # IN ULONG                ZeroBits OPTIONAL,
    # IN ULONG                CommitSize,
    # IN OUT PLARGE_INTEGER   SectionOffset OPTIONAL,
    # IN OUT PULONG           ViewSize,
    # IN                      InheritDisposition,
    # IN ULONG                AllocationType OPTIONAL,
    # IN ULONG                Protect

    pgd = api.get_running_process(cpu_index)

    # Read the parameters
    ret_addr, section_handle, proc_handle, base_p, arg_3, arg_4, offset_p, size_p = read_parameters(
        cpu, 7)

    # Load volatility address space
    addr_space = get_addr_space(pgd)

    class _SECTION_OBJECT(obj.CType, windows.ExecutiveObjectMixin):

        def is_valid(self):
            return obj.CType.is_valid(self)

    addr_space.profile.object_classes.update(
        {'_SECTION_OBJECT': _SECTION_OBJECT})
    # Get list of processes, and filter out by the process that triggered the
    # call (current process id)
    eprocs = [t for t in tasks.pslist(addr_space) if t.UniqueProcessId == pid]
    # Initialize proc_obj, that will point to the object of the referenced
    # process, and section_obj, idem
    proc_obj = None
    section_obj = None
    mapping_proc = None
    if (TARGET_LONG_SIZE == 4 and proc_handle == 0xffffffff) or (TARGET_LONG_SIZE == 8 and proc_handle == 0xffffffffffffffff):
        for proc in mwmon.data.procs:
            if proc.pid == pid:
                mapping_proc = proc
                break
    # Search handle table for the caller process
    for task in eprocs:
        if task.UniqueProcessId == pid and task.ObjectTable.HandleTableList:
            for handle in task.ObjectTable.handles():
                if handle.is_valid():
                    if not mapping_proc and not proc_obj and \
                       handle.HandleValue == proc_handle and \
                       handle.get_object_type() == "Process":
                        proc_obj = handle.dereference_as("_EPROCESS")
                    elif handle.HandleValue == section_handle and handle.get_object_type() == "Section":
                        # We dereference the object as _SECTION_OBJECT, although it is not a _SECTION_OBJECT but a
                        # _SECTION, that is not present in the volatility overlay:
                        # http://forum.sysinternals.com/section-object_topic24975.html
                        # For a better reference see the comments on the Section class
                        # in mw_monitor_classes.py
                        section_obj = handle.dereference_as("_SECTION_OBJECT")
                if (proc_obj or mapping_proc) and section_obj:
                    break
            break
    # proc_obj represents the process over which the section is mapped
    # section_object represents the section being mapped.
    if (proc_obj is not None or mapping_proc is not None) and section_obj is not None:
        mapped_sec = None
        if not mapping_proc:
            for proc in mwmon.data.procs:
                if proc.pid == proc_obj.UniqueProcessId:
                    mapping_proc = proc
                    break
        if mapping_proc is None:
            mwmon.printer("[!] The mapping process is not being monitored," +
                          " a handle was obtained with an API different from " +
                          "OpenProcess or CreateProcess")
            return
        for sec in mwmon.data.sections:
            if sec.get_offset() == section_obj.obj_offset:
                mapped_sec = sec
                break

        # If the section was not in our list, we create an entry
        if mapped_sec is None:
            mapped_sec = Section(pgd, section_obj)
            mwmon.data.sections.append(mapped_sec)

        # Record the actual map once we return back from the call and we can
        # dereference output parameters
        callback_name = mwmon.cm.generate_callback_name("mapviewofsection_ret")
        # Arguments to callback: the callback name, so that it can unset it,
        # the process handle variable, and the section handle

        callback_function = functools.partial(ntmapviewofsection_ret,
                                              pid=pid,
                                              callback_name=callback_name,
                                              mapping_proc=mapping_proc,
                                              mapped_sec=mapped_sec,
                                              base_p=base_p,
                                              size_p=size_p,
                                              offset_p=offset_p,
                                              proc=proc,
                                              update_vads=update_vads)

        mwmon.cm.add_callback(CallbackManager.INSN_BEGIN_CB,
                              callback_function,
                              name=callback_name,
                              addr=ret_addr,
                              pgd=pgd)