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")
def block_begin(cpu_index, cpu, tb):
    global cm
    from api import CallbackManager
    import api
    from ipython_shell import start_shell
    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")
Exemple #3
0
    def __init__(self, proc_name):
        import api
        self.TARGET_LONG_SIZE = api.get_os_bits() / 8
        self.__proc_num = Process.proc_counter
        Process.proc_counter += 1
        self.__proc_name = proc_name
        self.__pgd = 0
        self.__pid = 0
        self.__modules = {}

        # Record of API calls (related to VADs, and others
        self.__vads = []
        # Chunks of memory injected to other processes
        self.__injections = []
        self.__file_operations = []
        self.__section_maps = []

        # Indicates that this instance is a result of unpicking a serialized
        # object
        self.__unpickled = False

        # Exited. Indicates that process has already exited.
        self.__exited = False

        # Whether or not the process is a Wow64 process
        self.__wow64 = False

        self.__symbols = []
        self.__other_calls = []
        self.__all_calls = []
Exemple #4
0
def ntmapviewofsection_ret(params, cm, callback_name, mapped_sec, mapping_proc,
                           base_p, size_p, offset_p, proc, update_vads,
                           long_size):
    from core import SectionMap
    import api
    global interproc_data
    global interproc_config

    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
    cm.rm_callback(callback_name)

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

    if size_p != 0:
        size = dereference_target_long(size_p, pgd, long_size)
    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
            pp_debug(
                "Could not dereference offset in NtMapViewOfSection return, in interproc_callbacks.py\n"
            )
    else:
        offset = 0

    mapping_proc.add_section_map(
        SectionMap(mapped_sec, pgd, base, size, offset))

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

    if update_vads:
        proc.update_vads()
Exemple #5
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)
Exemple #6
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)
Exemple #7
0
def read_parameters(cpu, num_params):
    '''
        Reads parameters from the registers/stack
    '''
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        # All the parameters are on the stack
        # We need to read num_params values + the return address
        try:
            buff = api.r_va(cpu.CR3, cpu.ESP, (num_params + 1) * 4)
        except:
            buff = "\x00" * len((num_params + 1) * 4)
            mwmon.printer(
                "Could not read properly the parameters in interproc.py")
        params = struct.unpack("<" + "I" * (1 + num_params), buff)
        return params
    elif TARGET_LONG_SIZE == 8:
        params_regs = []
        params_stack = ()

        # Add the return address as parameter 0
        try:
            buff = api.r_va(cpu.CR3, cpu.RSP, 8)
        except:
            buff = "\x00" * 8
            mwmon.printer(
                "Could not read properly the parameters in interproc.py")

        params_regs.append(struct.unpack("<Q", buff)[0])

        if num_params <= 1:
            params_regs.append(cpu.RCX)
        if num_params <= 2:
            params_regs.append(cpu.RDX)
        if num_params <= 3:
            params_regs.append(cpu.R8)
        if num_params <= 4:
            params_regs.append(cpu.R9)
        if num_params > 4:
            # We need to read num_params + the return address + 0x20
            # 0x20 is for the 4 slots (of 8 bytes) allocated to store
            # register parameters (allocated by caller, used by callee)
            try:
                buff = api.r_va(cpu.CR3, cpu.RSP, (num_params + 5) * 8)
            except:
                buff = "\x00" * ((num_params + 5) * 8)
                mwmon.printer(
                    "Could not read properly the parameters in interproc.py")

            params_stack = struct.unpack("<" + "Q" * (5 + num_params), buff)
            params_stack = params_stack[5:]
        return (tuple(params_regs) + params_stack)
    else:
        raise Exception(
            "[interproc::read_return_parameter(cpu)] : Non-supported TARGET_LONG_SIZE: %d"
            % TARGET_LONG_SIZE)
Exemple #8
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()
Exemple #9
0
def dereference_target_long(addr, pgd):
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    typ = "<I" if TARGET_LONG_SIZE == 4 else "<Q"
    try:
        buff = api.r_va(pgd, addr, TARGET_LONG_SIZE)
    except:
        buff = "\x00" * TARGET_LONG_SIZE
        mwmon.printer("Could not dereference TARGET_LONG in interproc.py")
    return struct.unpack(typ, buff)[0]
Exemple #10
0
def dereference_target_long(addr, pgd):
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    typ = "<I" if TARGET_LONG_SIZE == 4 else "<Q"
    try:
        buff = api.r_va(pgd, addr, TARGET_LONG_SIZE)
    except:
        buff = "\x00" * TARGET_LONG_SIZE
        mwmon.printer("Could not dereference TARGET_LONG in interproc.py")
    return struct.unpack(typ, buff)[0]
Exemple #11
0
def log_calls():
    import api
    from interproc import interproc_data

    TARGET_LONG_SIZE = api.get_os_bits() / 8

    f_out = open(APITRACER_TEXT_LOG_PATH, "w")

    try:
        for proc in interproc_data.get_processes():

            f_out.write("Process (PID: %x) %s\n" %
                        (proc.get_pid(), proc.get_proc_name()))

            for vad in proc.get_vads():
                if len(vad.get_calls()) > 0:
                    if TARGET_LONG_SIZE == 4:
                        f_out.write(
                            "\n\nVAD [%08x - %08x] - %s\n\n" %
                            (vad.get_start(), vad.get_size(),
                             (vad.get_mapped_file() if vad.get_mapped_file()
                              is not None else "Not file mapped")))
                    elif TARGET_LONG_SIZE == 8:
                        f_out.write(
                            "\n\nVAD [%016x - %016x] - %s\n\n" %
                            (vad.get_start(), vad.get_size(),
                             (vad.get_mapped_file() if vad.get_mapped_file()
                              is not None else "Not file mapped")))
                    for data in vad.get_calls():
                        f_out.write("%s" % data[2].__str__())

            if len(proc.get_other_calls()) > 0:
                f_out.write("\n\n OTHER CALLS...\n\n")
                for call in proc.get_other_calls():
                    f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        pyrebox_print(str(e))
        pyrebox_print(traceback.print_exc())

    # Output ordered calls
    f_out = open(APITRACER_TEXT_LOG_PATH + ".ordered", "w")
    try:
        for proc in interproc_data.get_processes():
            f_out.write("Process (PID: %x) %s\n" %
                        (proc.get_pid(), proc.get_proc_name()))
            for data in proc.get_all_calls():
                f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        pyrebox_print(str(e))
        pyrebox_print(traceback.print_exc())
Exemple #12
0
def read_parameters(cpu, num_params):
    '''
        Reads parameters from the registers/stack
    '''
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        # All the parameters are on the stack
        # We need to read num_params values + the return address
        try:
            buff = api.r_va(cpu.CR3, cpu.ESP, (num_params + 1) * 4)
        except:
            buff = "\x00" * len((num_params + 1) * 4)
            mwmon.printer("Could not read properly the parameters in interproc.py")
        params = struct.unpack("<" + "I" * (1 + num_params), buff)
        return params
    elif TARGET_LONG_SIZE == 8:
        params_regs = []
        params_stack = ()

        # Add the return address as parameter 0
        try:
            buff = api.r_va(cpu.CR3, cpu.RSP, 8)
        except:
            buff = "\x00" * 8
            mwmon.printer("Could not read properly the parameters in interproc.py")

        params_regs.append(struct.unpack("<Q", buff)[0])

        if num_params <= 1:
            params_regs.append(cpu.RCX)
        if num_params <= 2:
            params_regs.append(cpu.RDX)
        if num_params <= 3:
            params_regs.append(cpu.R8)
        if num_params <= 4:
            params_regs.append(cpu.R9)
        if num_params > 4:
            # We need to read num_params + the return address + 0x20
            # 0x20 is for the 4 slots (of 8 bytes) allocated to store
            # register parameters (allocated by caller, used by callee)
            try:
                buff = api.r_va(cpu.CR3, cpu.RSP, (num_params + 5) * 8)
            except:
                buff = "\x00" * ((num_params + 5) * 8)
                mwmon.printer("Could not read properly the parameters in interproc.py")
                
            params_stack = struct.unpack(
                "<" + "Q" * (5 + num_params), buff)
            params_stack = params_stack[5:]
        return (tuple(params_regs) + params_stack)
    else:
        raise Exception(
            "[interproc::read_return_parameter(cpu)] : Non-supported TARGET_LONG_SIZE: %d" % TARGET_LONG_SIZE)
Exemple #13
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()
Exemple #14
0
def ntallocatevirtualmemory_ret(params,
                                cm,
                                callback_name,
                                mapping_proc=None,
                                base_addr_p=None,
                                zerobits=None,
                                size_p=None,
                                aloc_type=None,
                                access=None,
                                proc=None,
                                update_vads=None,
                                long_size=None):

    import api
    global interproc_data
    global interproc_config

    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
    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, long_size)
    else:
        base = 0

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

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

    if update_vads:
        proc.update_vads()
Exemple #15
0
def read_return_parameter(cpu):
    '''
        Returns the return parameter (EAX/RAX)
    '''
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        return cpu.EAX
    elif TARGET_LONG_SIZE == 8:
        return cpu.RAX
    else:
        raise Exception(
            "[interproc::read_return_parameter(cpu)] : Non-supported TARGET_LONG_SIZE: %d" % TARGET_LONG_SIZE)
Exemple #16
0
 def __write_strings_array(self, pgd, vaddr, array):
     """
         Write a char* arg[] array.
     """
     TARGET_LONG_SIZE = api.get_os_bits() / 8
     array_ptr = vaddr
     strings_ptr = vaddr + TARGET_LONG_SIZE * (len(array) + 1)
     for i, s in enumerate(array):
         api.w_va(pgd, array_ptr, struct.pack(
             "<" + ("L" if TARGET_LONG_SIZE == 4 else "Q"), strings_ptr), TARGET_LONG_SIZE)
         api.w_va(pgd, strings_ptr, s + "\x00", len(s) + 1)
         array_ptr += TARGET_LONG_SIZE
         strings_ptr += len(s) + 1
     api.w_va(pgd, array_ptr, "\x00" * TARGET_LONG_SIZE, TARGET_LONG_SIZE)
Exemple #17
0
def read_return_parameter(cpu):
    '''
        Returns the return parameter (EAX/RAX)
    '''
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        return cpu.EAX
    elif TARGET_LONG_SIZE == 8:
        return cpu.RAX
    else:
        raise Exception(
            "[interproc::read_return_parameter(cpu)] : Non-supported TARGET_LONG_SIZE: %d"
            % TARGET_LONG_SIZE)
Exemple #18
0
 def __write_strings_array(self, pgd, vaddr, array):
     """
         Write a char* arg[] array.
     """
     TARGET_LONG_SIZE = api.get_os_bits() / 8
     array_ptr = vaddr
     strings_ptr = vaddr + TARGET_LONG_SIZE * (len(array) + 1)
     for i, s in enumerate(array):
         api.w_va(pgd, array_ptr, struct.pack(
             "<" + ("L" if TARGET_LONG_SIZE == 4 else "Q"), strings_ptr), TARGET_LONG_SIZE)
         api.w_va(pgd, strings_ptr, s + "\x00", len(s) + 1)
         array_ptr += TARGET_LONG_SIZE
         strings_ptr += len(s) + 1
     api.w_va(pgd, array_ptr, "\x00" * TARGET_LONG_SIZE, TARGET_LONG_SIZE)
Exemple #19
0
def block_executed(cpu_index, cpu, tb, proc=None):
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    # Get the overlapping VAD, if we don't have it, update VADs
    if TARGET_LONG_SIZE == 4:
        page = cpu.EIP & 0xFFFFF000
    elif TARGET_LONG_SIZE == 8:
        page = cpu.RIP & 0xFFFFFFFFFFFFF000

    vad = proc.get_overlapping_vad(page)

    if vad is None:
        proc.update_vads()
    return
Exemple #20
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()
Exemple #21
0
def log_calls():
    from mw_monitor_classes import mwmon
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    f_out = open(mwmon.api_tracer_text_log_name, "w")
    try:
        for proc in mwmon.data.procs:
            if mwmon.api_tracer_procs is None or proc.proc_name in mwmon.api_tracer_procs:
                f_out.write("Process (PID: %x) %s\n" %
                            (proc.pid, proc.proc_name))
                for vad in proc.vads:
                    if len(vad.get_calls()) > 0:
                        if TARGET_LONG_SIZE == 4:
                            f_out.write("\n\nVAD [%08x - %08x]\n\n" %
                                        (vad.start, vad.size))
                        elif TARGET_LONG_SIZE == 8:
                            f_out.write("\n\nVAD [%016x - %016x]\n\n" %
                                        (vad.start, vad.size))
                        for data in vad.get_calls():
                            f_out.write("%s" % data[2].__str__())
                if len(proc.other_calls) > 0:
                    f_out.write("\n\n OTHER CALLS...\n\n")
                    for call in proc.other_calls:
                        f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        mwmon.printer(str(e))
        mwmon.printer(traceback.print_exc())

    # Output ordered calls
    f_out = open(mwmon.api_tracer_text_log_name + ".ordered", "w")
    try:
        for proc in mwmon.data.procs:
            if mwmon.api_tracer_procs is None or proc.proc_name in mwmon.api_tracer_procs:
                f_out.write("Process (PID: %x) %s\n" %
                            (proc.pid, proc.proc_name))
                for data in proc.all_calls:
                    f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        mwmon.printer(str(e))
        mwmon.printer(traceback.print_exc())
def log_calls():
    from mw_monitor_classes import mwmon
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    f_out = open(mwmon.api_tracer_text_log_name, "w")
    try:
        for proc in mwmon.data.procs:
            if mwmon.api_tracer_procs is None or proc.proc_name in mwmon.api_tracer_procs:
                f_out.write("Process (PID: %x) %s\n" %
                            (proc.pid, proc.proc_name))
                for vad in proc.vads:
                    if len(vad.get_calls()) > 0:
                        if TARGET_LONG_SIZE == 4:
                            f_out.write(
                                "\n\nVAD [%08x - %08x]\n\n" % (vad.start, vad.size))
                        elif TARGET_LONG_SIZE == 8:
                            f_out.write(
                                "\n\nVAD [%016x - %016x]\n\n" % (vad.start, vad.size))
                        for data in vad.get_calls():
                            f_out.write("%s" % data[2].__str__())
                if len(proc.other_calls) > 0:
                    f_out.write("\n\n OTHER CALLS...\n\n")
                    for call in proc.other_calls:
                        f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        mwmon.printer(str(e))
        mwmon.printer(traceback.print_exc())

    # Output ordered calls
    f_out = open(mwmon.api_tracer_text_log_name + ".ordered", "w")
    try:
        for proc in mwmon.data.procs:
            if mwmon.api_tracer_procs is None or proc.proc_name in mwmon.api_tracer_procs:
                f_out.write("Process (PID: %x) %s\n" %
                            (proc.pid, proc.proc_name))
                for data in proc.all_calls:
                    f_out.write("%s" % data[2].__str__())
        if f_out is not None:
            f_out.close()
    except Exception as e:
        mwmon.printer(str(e))
        mwmon.printer(traceback.print_exc())
Exemple #23
0
def ntdll_breakpoint_func(proc, cpu_index, cpu):
    ''' 
        Breakpoint for the first instruction executed in the main module
    '''
    global ntdll_breakpoint
    from mw_monitor_classes import mwmon
    import api

    ntdll_breakpoint[proc.get_pgd()].disable()
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        mwmon.printer("Executed first instruction for pgd %x at %x" %
                      (cpu.CR3, cpu.EIP))
    elif TARGET_LONG_SIZE == 8:
        mwmon.printer("Executed first instruction for pgd %x at %x" %
                      (cpu.CR3, cpu.RIP))

    proc.update_symbols()
Exemple #24
0
def opcodes_ret(addr_from, addr_to, data, callback_name, argument_parser, mod,
                fun, proc, cpu_index, cpu):
    from mw_monitor_classes import mwmon
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    try:
        mwmon.cm.rm_callback(callback_name)
        if TARGET_LONG_SIZE == 4:
            argument_parser.update_return(cpu.EAX)
        elif TARGET_LONG_SIZE == 8:
            argument_parser.update_return(cpu.RAX)
        data.out_args = [arg for arg in argument_parser.get_out_args()]
        data.ret = argument_parser.get_ret()
        proc.add_call(addr_from, addr_to, data)
    except Exception as e:
        mwmon.printer("Exception: %s" % str(e))
    finally:
        return
def ntdll_breakpoint_func(proc, params):
    ''' 
        Breakpoint for the first instruction executed in the main module
    '''
    global ntdll_breakpoint
    from mw_monitor_classes import mwmon
    import api

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

    ntdll_breakpoint[proc.get_pgd()].disable()
    TARGET_LONG_SIZE = api.get_os_bits() / 8
    if TARGET_LONG_SIZE == 4:
        mwmon.printer("Executed first instruction for pgd %x at %x" % (cpu.CR3, cpu.EIP))
    elif TARGET_LONG_SIZE == 8:
        mwmon.printer("Executed first instruction for pgd %x at %x" % (cpu.CR3, cpu.RIP))

    proc.update_symbols()
Exemple #26
0
def block_executed(params, proc=None):
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

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

    # Get the overlapping VAD, if we don't have it, update VADs
    if TARGET_LONG_SIZE == 4:
        page = cpu.EIP & 0xFFFFF000
    elif TARGET_LONG_SIZE == 8:
        page = cpu.RIP & 0xFFFFFFFFFFFFF000

    vad = proc.get_overlapping_vad(page)

    if vad is None:
        proc.update_vads()
    return
Exemple #27
0
 def __str__(self):
     import api
     TARGET_LONG_SIZE = api.get_os_bits() / 8
     try:
         outstr = ""
         if TARGET_LONG_SIZE == 4:
             outstr += (
                 "\n\n\n[0x%08x] --> [%s:%s] --> [0x%08x]\n" %
                 (self.__pc, self.__mod, self.__fun, self.__ret_addr))
         elif TARGET_LONG_SIZE == 8:
             outstr += (
                 "\n\n\n[0x%016x] --> [%s:%s] --> [0x%016x]\n" %
                 (self.__pc, self.__mod, self.__fun, self.__ret_addr))
         args = sorted(self.__in_args + self.__out_args)
         for arg in args:
             if arg.is_output_arg():
                 try:
                     outstr += ("[OUT] %s: %s\n" %
                                (arg.get_arg_name(), arg.__str__()))
                 except Exception as e:
                     outstr += ("[OUT] %s: Unable to process: %s\n" %
                                (arg.get_arg_name(), str(e)))
             else:
                 try:
                     outstr += ("[IN ] %s: %s\n" %
                                (arg.get_arg_name(), arg.__str__()))
                 except Exception as e:
                     outstr += ("[IN] %s: Unable to process : %s\n" %
                                (arg.get_arg_name(), str(e)))
         if self.__ret is not None and self.__ret is not "":
             try:
                 outstr += (
                     "[RET] %s: %s\n" %
                     (self.__ret.get_arg_name(), self.__ret.__str__()))
             except Exception as e:
                 outstr += ("[RET] %s: Unable to process: %s\n" %
                            (self.__ret.get_arg_name(), str(e)))
         return outstr
     except Exception as e:
         pyrebox_print(traceback.print_exc())
         pyrebox_print(str(e))
Exemple #28
0
def opcodes_ret(addr_from, addr_to, data, callback_name, argument_parser, mod, fun, proc, params):
    from mw_monitor_classes import mwmon
    import api
    TARGET_LONG_SIZE = api.get_os_bits() / 8

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

    try:
        mwmon.cm.rm_callback(callback_name)
        if TARGET_LONG_SIZE == 4:
            argument_parser.update_return(cpu.EAX)
        elif TARGET_LONG_SIZE == 8:
            argument_parser.update_return(cpu.RAX)
        data.out_args = [arg for arg in argument_parser.get_out_args()]
        data.ret = argument_parser.get_ret()
        proc.add_call(addr_from, addr_to, data)
    except Exception as e:
        mwmon.printer("Exception: %s" % str(e))
    finally:
        return
Exemple #29
0
def opcodes_ret(addr_from, addr_to, data, callback_name, argument_parser, mod,
                fun, proc, params):
    import api
    global cm
    TARGET_LONG_SIZE = api.get_os_bits() / 8

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

    try:
        cm.rm_callback(callback_name)
        if TARGET_LONG_SIZE == 4:
            argument_parser.update_return(cpu.EAX)
        elif TARGET_LONG_SIZE == 8:
            argument_parser.update_return(cpu.RAX)
        data.set_out_args([arg for arg in argument_parser.get_out_args()])
        data.set_ret(argument_parser.get_ret())
    except Exception as e:
        pyrebox_print("Exception: %s" % str(e))
    finally:
        return
Exemple #30
0
 def __str__(self):
     from mw_monitor_classes import mwmon
     import api
     TARGET_LONG_SIZE = api.get_os_bits() / 8
     try:
         outstr = ""
         if TARGET_LONG_SIZE == 4:
             outstr += ("\n\n\n[0x%08x] --> [%s:%s] --> [0x%08x]\n" %
                        (self.pc, self.mod, self.fun, self.ret_addr))
         elif TARGET_LONG_SIZE == 8:
             outstr += ("\n\n\n[0x%016x] --> [%s:%s] --> [0x%016x]\n" %
                        (self.pc, self.mod, self.fun, self.ret_addr))
         args = sorted(self.in_args + self.out_args)
         for arg in args:
             if arg.is_output_arg():
                 try:
                     outstr += ("[OUT] %s: %s\n" %
                                (arg.get_arg_name(), arg.__str__()))
                 except Exception as e:
                     outstr += (
                         "[OUT] %s: Unable to process: %s\n" % (arg.get_arg_name(), str(e)))
             else:
                 try:
                     outstr += ("[IN ] %s: %s\n" %
                                (arg.get_arg_name(), arg.__str__()))
                 except Exception as e:
                     outstr += (
                         "[IN] %s: Unable to process : %s\n" % (arg.get_arg_name(), str(e)))
         if self.ret is not None and self.ret is not "":
             try:
                 outstr += ("[RET] %s: %s\n" %
                            (self.ret.get_arg_name(), self.ret.__str__()))
             except Exception as e:
                 outstr += ("[RET] %s: Unable to process: %s\n" %
                            (self.ret.get_arg_name(), str(e)))
         return outstr
     except Exception as e:
         mwmon.printer(traceback.print_exc())
         mwmon.printer(str(e))
Exemple #31
0
    def populate_args(self):
        import api
        TARGET_LONG_SIZE = api.get_os_bits() / 8

        if self.func_id is None:
            return []
        self.c.execute(
            "select Id,Name,TypeId,TypeClass,IsOutput from FunctionsArgs where FuncId = %d order by Id ASC" % (self.func_id))
        params = self.c.fetchall()

        # Here, we need to use properly the addresses depending on the bitness
        # and the calling convention
        if TARGET_LONG_SIZE == 4:
            # Skip return address
            addr = self.addr + 4
            reg_params = []
        elif TARGET_LONG_SIZE == 8:
            # 4 slots for saving arguments + return address
            addr = self.addr + 8 * 5
            reg_params = [self.cpu.RCX, self.cpu.RDX, self.cpu.R8, self.cpu.R9]

        arg_num = 1
        for param in params:
            # Unfold the argument
            is_out = False if param[4] == 0 else True
            if TARGET_LONG_SIZE == 8 and arg_num <= 4:
                arg = self.generate_arg(param[1], param[2], param[
                                        3], is_out, val=reg_params[arg_num - 1], arg_num=arg_num)
            else:
                arg = self.generate_arg(
                    param[1], param[2], param[3], is_out, addr=addr, arg_num=arg_num)
                addr += len(arg)

            arg_num += 1
            # Point to next parameter in stack
            self.args.append(arg)
Exemple #32
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
Exemple #33
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)
Exemple #34
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()
def log_coverage():
    from mw_monitor_classes import mwmon
    import api
    import ntpath
    # Address and size will have as many bytes as an address
    # in the target architecture
    TARGET_LONG_SIZE = api.get_os_bits() / 8

    for proc in mwmon.data.procs:
        if mwmon.coverage_procs is None or proc.proc_name in mwmon.coverage_procs:
            if os.path.isfile(mwmon.coverage_log_name + (".%x" % proc.pid)):
                try:
                    current_vad = None
                    f = open(
                        mwmon.coverage_text_name + (".%x" % proc.pid), "w")
                    f_in = open(
                        mwmon.coverage_log_name + (".%x" % proc.pid), "rb")

                    data = f_in.read(TARGET_LONG_SIZE + TARGET_LONG_SIZE)
                    last_pc = 0
                    while data is not None and len(data) == 8:

                        if TARGET_LONG_SIZE == 4:
                            pc, size = struct.unpack("<II", data)
                        elif TARGET_LONG_SIZE == 8:
                            pc, size = struct.unpack("<QQ", data)
                        else:
                            raise Exception(
                                "[log_coverage()] Unsupported TARGET_LONG_SIZE: %d" % TARGET_LONG_SIZE)

                        # Locate nearest lower symbol
                        sym = proc.locate_nearest_symbol(pc)
                        sym_text = ""
                        if sym is not None:
                            # mod = sym.get_mod()
                            fun = sym.get_fun()
                            real_api_addr = sym.get_addr()
                            if real_api_addr == pc:
                                sym_text = " - %s" % fun
                            else:
                                sym_text = " - %s(+%x)" % (
                                    fun, (pc - real_api_addr))

                        if current_vad is None:
                            current_vad = proc.get_overlapping_vad(pc)
                            if current_vad is not None:
                                if TARGET_LONG_SIZE == 4:
                                    f.write("VAD: %08x(%08x) %08x --> %08x [%s%s]\n" % (
                                        current_vad.start,
                                        current_vad.size,
                                        last_pc,
                                        pc,
                                        ntpath.basename(current_vad.mapped_file), sym_text))
                                elif TARGET_LONG_SIZE == 8:
                                    f.write("VAD: %16x(%16x) %16x --> %16x [%s%s]\n" % (
                                        current_vad.start,
                                        current_vad.size,
                                        last_pc,
                                        pc,
                                        ntpath.basename(current_vad.mapped_file),
                                        sym_text))
                                else:
                                    raise Exception(
                                        "[log_coverage()] Unsupported TARGET_LONG_SIZE: %d" % TARGET_LONG_SIZE)
                        else:
                            new_vad = proc.get_overlapping_vad(pc)
                            if new_vad != current_vad:
                                current_vad = new_vad
                                if TARGET_LONG_SIZE == 4:
                                    f.write("VAD: %08x(%08x) %08x --> %08x [%s%s]\n" % (
                                        current_vad.start,
                                        current_vad.size,
                                        last_pc,
                                        pc,
                                        ntpath.basename(current_vad.mapped_file), sym_text))
                                elif TARGET_LONG_SIZE == 8:
                                    f.write("VAD: %16x(%16x) %16x --> %16x [%s%s]\n" % (
                                        current_vad.start,
                                        current_vad.size,
                                        last_pc,
                                        pc,
                                        ntpath.basename(current_vad.mapped_file), sym_text))
                                else:
                                    raise Exception(
                                        "[log_coverage()] Unsupported TARGET_LONG_SIZE: %d" % TARGET_LONG_SIZE)

                        data = f_in.read(TARGET_LONG_SIZE + TARGET_LONG_SIZE)
                        # last_pc, last_size = pc, size
                        last_pc = pc
                    f_in.close()
                    f.close()
                except Exception:
                    traceback.print_exc()
Exemple #36
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()
Exemple #37
0
def windows_read_paged_out_memory(pgd, addr, size):
    import api
    import api_internal
    import struct
    from utils import get_addr_space

    VALID_BIT = 0x1
    PROTOTYPE_BIT = 0x1 << 10
    TRANSITION_BIT = 0x1 << 11

    PPTE_VALID_BIT = 0x1
    PPTE_TRANSITION_BIT = 0x1 << 11
    PPTE_DIRTY_BIT = 0x1 << 6
    PPTE_P_BIT = 0x1 << 10  # Thit bit means it is a...
    #...memory mapped file,  instead of "prototype"

    # Get PTE and 'mode'
    pte = api_internal.x86_get_pte(pgd, addr)
    is_pae = api_internal.x86_is_pae()
    bitness = api.get_os_bits()

    addr_space = get_addr_space(pgd)

    # if PTE is None, it could mean that the page directory has not been created.
    # if PTE is 0, it could mean the pte has not been yet created.
    # In these cases, we still check the VAD to see if it corresponds to a
    # memory mapped file, and if so, read that file at the correct offset
    if pte is None or pte == 0:
        return windows_read_memory_mapped(pgd, addr, size, pte, is_pae,
                                          bitness)

    # Make sure the page is invalid and we cannot read it:
    if (pte & VALID_BIT) == 1:
        return api.r_va(pgd, addr, size)

    # The PTE is INVALID. First, we check it doesn't point to a
    # prototype page table entry (PPTE).
    if (pte & PROTOTYPE_BIT) == 0:
        # The page is in the pagefile, or is demand zero, or memory mapped
        if (pte & TRANSITION_BIT) == 0:
            number_bits_offset = 0
            number_bits_number = 0
            page_file_offset = 0
            page_file_number = 0
            if (bitness == 32 and not is_pae) or bitness == 64:
                offset_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileHigh"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileHigh"][1][1]["end_bit"])
                number_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["end_bit"])
                number_bits_offset = addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileHigh"][1][1]["end_bit"] - \
                                     addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileHigh"][1][1]["start_bit"]
                number_bits_number = addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["end_bit"] - \
                                     addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]
                page_file_offset = (
                    pte & offset_mask
                ) >> addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1][
                    "PageFileHigh"][1][1]["start_bit"]
                page_file_number = (
                    pte & number_mask) >> addr_space.profile.vtypes[
                        "_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]
            elif bitness == 32 and is_pae:
                # See Intel manual, consider 24 bits of address for the 4KiB page offset
                # Page file offset should correspond to the same 24 bits
                offset_mask = generate_mask(12, 12 + 24)
                # Reuse the same as for 32/64 bits
                number_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["end_bit"])
                number_bits_offset = 24
                number_bits_number = addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["end_bit"] - \
                                     addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]
                page_file_offset = (pte & offset_mask) >> 12
                page_file_number = (
                    pte & number_mask) >> addr_space.profile.vtypes[
                        "_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]

            else:
                raise NotImplementedError()

            #Demand zero
            if page_file_offset == 0x0:
                return "\x00" * size
            #Check VAD (memory mapped file) (all 1's)
            elif page_file_offset == generate_mask(0, number_bits_offset):
                return windows_read_memory_mapped(pgd, addr, size, pte, is_pae,
                                                  bitness)
            # Page file
            else:
                return windows_read_paged_file(pgd, addr, size,
                                               page_file_offset,
                                               page_file_number)
        # Transition page -> Can be read normally from memory,
        # so proceed with the read even if valid bit is 0.
        else:
            # Get the offset from the PTE, and compute ourselves the physical address
            page_offset = 0
            if (bitness == 32 and not is_pae) or bitness == 64:
                offset_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_HARDWARE"][1]
                    ["PageFrameNumber"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_HARDWARE"][1]
                    ["PageFrameNumber"][1][1]["end_bit"])
                page_offset = (pte & offset_mask)
            elif bitness == 32 and is_pae:
                # See Intel manual, consider 24 bits of address for the 4KiB page offset
                # Page file offset should correspond to the same 24 bits
                offset_mask = generate_mask(12, 12 + 24)
                # Reuse the same as for 32/64 bits
                page_offset = (pte & offset_mask)
            else:
                raise NotImplementedError()
            # Read physical address, always 12 bits for a 4KiB page.
            # XXX: Here, we should should also consider 4Mb pages.
            return api.r_pa(page_offset | (addr & generate_mask(0, 12)), size)
    # The page points to a prototype PTE
    else:
        # We read the PPTE
        ppte_addr = 0
        ppte_size = 0
        if bitness == 32 and not is_pae:
            # In this case, the PPTE pointer is not a pointer, but an index, so it
            # needs some additional computation
            index_low_mask = generate_mask(
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddressLow"][1][1]["start_bit"],
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddressLow"][1][1]["end_bit"])
            index_low = (pte & index_low_mask) >> addr_space.profile.vtypes[
                "_MMPTE_PROTOTYPE"][1]["ProtoAddressLow"][1][1]["start_bit"]

            index_high_mask = generate_mask(
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddressHigh"][1][1]["start_bit"],
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddressHigh"][1][1]["end_bit"])
            index_high = (pte & index_high_mask) >> addr_space.profile.vtypes[
                "_MMPTE_PROTOTYPE"][1]["ProtoAddressHigh"][1][1]["start_bit"]

            number_bits_index_low = addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]["ProtoAddressLow"][1][1]["end_bit"]- \
                                        addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]["ProtoAddressLow"][1][1]["start_bit"]

            ppte_size = addr_space.profile.vtypes["_MMPTE"][0]

            # Formula to compute the index
            index = ((index_high << number_bits_index_low) | index_low) << 2

            # The index is an address relative to the base of a paged pool.
            # By debugging several systems, these bases where fixed (on 32 bit systems)
            # to 0x80000000 or 0xe1000000 (windows 7 and windows xp respectively).
            # This address points to one of the PrototypePTEs that are part of the Segment,
            # pointed out by the ControlArea of the corresponding VAD. Therefore, we should
            # be able to bruteforce the first 8 bits of the address to find the correct base.
            # First, get the Segment, and the first prototype PTE, as well as the number of
            # prototype PTEs for that Segment.
            res = windows_get_prototype_pte_address_range(pgd, addr)
            found = False
            if res is not None:
                start, end = res
                for i in range(0, 255):
                    ppte_addr = (i << 24) | index
                    if ppte_addr >= start and ppte_addr <= end:
                        found = True
                        break
                if not found:
                    raise RuntimeError(
                        "Could not read memory on second chance (using filesystem)"
                    )
            else:
                raise RuntimeError(
                    "Could not read memory on second chance (using filesystem)"
                )

        elif bitness == 32 and is_pae:
            # According to paper: "Windows Operating Systems Agnostic Memory Analysis"
            offset_mask = generate_mask(32, 64)
            ppte_addr = (pte & offset_mask) >> 32
            ppte_size = 64

        elif bitness == 64:
            offset_mask = generate_mask(
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddress"][1][1]["start_bit"],
                addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][1]
                ["ProtoAddress"][1][1]["end_bit"])
            ppte_addr = (pte & offset_mask) >> addr_space.profile.vtypes[
                "_MMPTE_PROTOTYPE"][1]["ProtoAddress"][1][1]["start_bit"]
            ppte_size = addr_space.profile.vtypes["_MMPTE"][0]

        else:
            raise NotImplementedError()

        # Now, read the PPTE given its address. The PPTE address is a virtual address!!!! (on a paged pool)
        if ppte_size == 4:
            ppte = struct.unpack("<I", api.r_va(pgd, ppte_addr, 4))[0]
        elif ppte_size == 8:
            ppte = struct.unpack("<K", api.r_va(pgd, ppte_addr, 8))[0]
        else:
            raise NotImplementedError()

        if (ppte & PPTE_VALID_BIT == 1) or (ppte & PPTE_TRANSITION_BIT == 1):
            # State: Active/Valid - Transision - Modified-no-write
            # The PPTE contains a valid entry, so we can
            # just use the info in it to translate the page.
            # Get the offset from the PTE, and compute ourselves the physical address
            page_offset = 0
            if (bitness == 32 and not is_pae) or bitness == 64:
                offset_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_HARDWARE"][1]
                    ["PageFrameNumber"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_HARDWARE"][1]
                    ["PageFrameNumber"][1][1]["end_bit"])
                page_offset = (ppte & offset_mask)
            elif bitness == 32 and is_pae:
                # See Intel manual, consider 24 bits of address for the 4KiB page offset
                # Page file offset should correspond to the same 24 bits
                offset_mask = generate_mask(12, 12 + 24)
                # Reuse the same as for 32/64 bits
                page_offset = (ppte & offset_mask)
            else:
                raise NotImplementedError()

            # Read physical address, always 12 bits for a 4KiB page.
            # XXX: Here, we should should also consider 4Mb pages.
            return api.r_pa(page_offset | (addr & generate_mask(0, 12)), size)
        elif (ppte & (PPTE_VALID_BIT | PPTE_TRANSITION_BIT | PPTE_P_BIT)) == 0:
            # Demand zero or pagefile
            #Read page_file_offset and page_file_number
            page_file_offset = 0
            page_file_number = 0
            if (bitness == 32 and not is_pae) or bitness == 64:
                offset_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileHigh"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileHigh"][1][1]["end_bit"])
                number_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["end_bit"])
                page_file_offset = (
                    pte & offset_mask
                ) >> addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1][
                    "PageFileHigh"][1][1]["start_bit"]
                page_file_number = (
                    pte & number_mask) >> addr_space.profile.vtypes[
                        "_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]
            elif bitness == 32 and is_pae:
                # See Intel manual, consider 24 bits of address for the 4KiB page offset
                # Page file offset should correspond to the same 24 bits
                offset_mask = generate_mask(12, 12 + 24)
                # Reuse the same as for 32/64 bits
                number_mask = generate_mask(
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["start_bit"],
                    addr_space.profile.vtypes["_MMPTE_SOFTWARE"][1]
                    ["PageFileLow"][1][1]["end_bit"])
                page_file_offset = (pte & offset_mask) >> 12
                page_file_number = (
                    pte & number_mask) >> addr_space.profile.vtypes[
                        "_MMPTE_SOFTWARE"][1]["PageFileLow"][1][1]["start_bit"]
            else:
                raise NotImplementedError()

            if page_file_offset == 0 and page_file_number == 0:
                #Demand zero
                return "\x00" * size
            else:
                # PageFile
                return windows_read_paged_file(pgd, addr, size,
                                               page_file_offset,
                                               page_file_number)
        elif (ppte & PPTE_P_BIT) == 1:
            # Memory mapped file
            return windows_read_memory_mapped(pgd, addr, size, ppte, is_pae,
                                              bitness)
Exemple #38
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)
Exemple #39
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)
Exemple #40
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()
Exemple #41
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
    def __init__(self, pgd, section_object):
        import api

        TARGET_LONG_SIZE = api.get_os_bits() / 8

        # Volatility object representing the section
        self.section_object = section_object

        # Volatility lacks the vtype for _SECTION, which
        # has scarce documentation:

        # http://forum.sysinternals.com/section-object_topic24975.html

        #   These structures seem to remain consistent
        #   across different Windows versions.

        #   typedef struct _MMADDRESS_NODE {
        #   union {
        #       LONG_PTR Balance : 2;
        #       struct _MMADDRESS_NODE *Parent;
        #   } u1;
        #   struct _MMADDRESS_NODE *LeftChild;
        #   struct _MMADDRESS_NODE *RightChild;
        #   ULONG_PTR StartingVpn;
        #   ULONG_PTR EndingVpn;
        #   } MMADDRESS_NODE, *PMMADDRESS_NODE;

        #   typedef struct _SECTION {
        #    MMADDRESS_NODE Address;
        #    PSEGMENT Segment;
        #    LARGE_INTEGER SizeOfSection;
        #    union {
        #     ULONG LongFlags;
        #     MMSECTION_FLAGS Flags;
        #    } u;
        #    MM_PROTECTION_MASK InitialPageProtection;
        #    } SECTION, *PSECTION;

        # As we can see, Volatility has instead a _SECTION_OBJECT
        # vtype, which, consistently across Windows versions,
        # has at the beginning of the structure, 5 pointers, just
        # like the MMADDRESS_NODE for _SECTION. Therefore, the Segment
        # field seems to be at the same offset on both structures:
        # _SECTION and _SECTION_OBJECT, both for 32 and 64 bits.

        # Flags are located after Segment (PSEGMENT) + LARGE_INTEGER (64 bits independently of arch)
        # --> The offset should be the size of 6 pointers + size of LARGE_INTEGER

        # Flags are always 4 bytes

        # Compute FileBacked and  CopyOnWrite
        try:
            self.flags = struct.unpack(
                "I", api.r_va(pgd, self.section_object.obj_offset + ((TARGET_LONG_SIZE * 6) + 8), 0x4))[0]
        except:
            self.flags = 0x00000000
            mwmon.printer("Could not read flags in Section __init__")
        self.cow = ((self.flags & 0x00000800) != 0)
        self.file_backed = ((self.flags & 0x00000080) != 0)

        self.backing_file = None

        # If so, get corresponding file.
        if self.file_backed:
            # Dereference as _SEGMENT, that is different from _SEGMENT_OBJECT
            # This is because the volatility profile lacks the _SECTION object,
            # and instead has the _SECTION_OBJECT. Since the Segment field
            # of _SECTION and _SECTION_OBJECT are aligned, we can just dereference
            # that offset. Nevertheless, _SECTION_OBJECT has a _SEGMENT_OBJECT type
            # Segment, while _SECTION has a _SEGMENT type Segment...

            # http://forum.sysinternals.com/section-object_topic24975.html

            self.segment = self.section_object.Segment.dereference_as(
                "_SEGMENT")
            file_obj = self.segment.ControlArea.FilePointer


            from volatility.plugins.overlays.windows.windows import _FILE_OBJECT
            from volatility.obj import Pointer

            # on winxp file_obj is volatility.obj.Pointer with .target being _FILE_OBJECT
            if not (type(file_obj) is Pointer and type(file_obj.dereference()) is _FILE_OBJECT):
                from volatility.plugins.overlays.windows.windows import _EX_FAST_REF
                if type(file_obj) is _EX_FAST_REF:
                    # on newer volatility profiles, FilePointer is _EX_FAST_REF, needs deref
                    file_obj = file_obj.dereference_as("_FILE_OBJECT")
                else:
                    raise TypeError("The type for self.segment.ControlArea.FilePointer in Section" + \
                                    "class does not match _FILE_OBJECT or _EX_FAST_REF: %r (type %r)" % (file_obj, type(file_obj)))

            for fi in mwmon.data.files:
                if fi.file_name == str(file_obj.FileName):
                    self.backing_file = fi
                    break

            # If we have still not recorded the file, add it to files record
            if self.backing_file is None:
                self.backing_file = File(str(file_obj.FileName))
                mwmon.data.files.append(self.backing_file)
        
        self.unpickled = False
        self.offset = self.section_object.obj_offset
Exemple #43
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()
Exemple #44
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()
Exemple #45
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()
Exemple #46
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
Exemple #47
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)
Exemple #48
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
Exemple #49
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()
Exemple #50
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)
Exemple #51
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)
    def __init__(self, proc_name):
        import api
        self.TARGET_LONG_SIZE = api.get_os_bits() / 8
        self.proc_num = Process.proc_counter
        Process.proc_counter += 1
        self.proc_name = proc_name
        self.pgd = 0
        self.pid = 0
        self.modules = {}
        if self.TARGET_LONG_SIZE == 4:
            self.min_mod_addr = 0xFFFFFFFF
        elif self.TARGET_LONG_SIZE == 8:
            self.min_mod_addr = 0xFFFFFFFFFFFFFFFF
        else:
            raise Exception(
                "[Process::init()] Unsupported TARGET_LONG_SIZE: %d" % self.TARGET_LONG_SIZE)
        self.max_mod_addr = 0x0
        self.symbols = []
        # Record of API calls (related to VADs, and others
        self.vads = []
        self.other_calls = []
        # Chunks of memory injected to other processes
        self.injections = []
        self.file_operations = []
        self.section_maps = []
        # Keep a list with all the calls ordered
        self.all_calls = []

        # Indicates that this instance is a result of unpicking a serialized
        # object
        self.unpickled = False

        # Exited. Indicates that process has already exited.
        self.exited = False

        from interproc import ntcreateprocess
        from interproc import ntopenprocess
        from interproc import ntwritevirtualmemory
        from interproc import ntreadvirtualmemory
        from interproc import ntreadfile
        from interproc import ntwritefile
        from interproc import ntmapviewofsection
        from interproc import ntunmapviewofsection
        from interproc import ntvirtualprotect
        from interproc import ntallocatevirtualmemory
        from utils import ConfigurationManager as conf_m

        if mwmon.interproc:

            # Dictionary to store breakpoints for the following APIs:
            self.breakpoints = {("ntdll.dll", "ZwOpenProcess"): None,
                                ("ntdll.dll", "ZwReadFile"): None,
                                ("ntdll.dll", "ZwWriteFile"): None,
                                ("ntdll.dll", "ZwMapViewOfSection"): None,
                                ("ntdll.dll", "ZwUnmapViewOfSection"): None,
                                ("ntdll.dll", "ZwWriteVirtualMemory"): None,
                                ("ntdll.dll", "ZwReadVirtualMemory"): None,
                                ("ntdll.dll", "ZwProtectVirtualMemory"): None,
                                ("ntdll.dll", "NtAllocateVirtualMemory"): None}

            self.bp_funcs = {
                ("ntdll.dll", "ZwOpenProcess"): (ntopenprocess,
                                                 True and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwReadFile"): (ntreadfile,
                                              False and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwWriteFile"): (ntwritefile,
                                               False and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwMapViewOfSection"): (ntmapviewofsection,
                                                      True and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwUnmapViewOfSection"): (ntunmapviewofsection,
                                                        True and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwWriteVirtualMemory"): (ntwritevirtualmemory,
                                                        False and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwReadVirtualMemory"): (ntreadvirtualmemory,
                                                       False and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "ZwProtectVirtualMemory"): (ntvirtualprotect,
                                                          False and not mwmon.api_tracer and not mwmon.coverage),
                ("ntdll.dll", "NtAllocateVirtualMemory"): (ntallocatevirtualmemory,
                                                           True and not mwmon.api_tracer and not mwmon.coverage)}

            profile = conf_m.vol_profile

            # If before vista:
            if "WinXP" in profile or "Win2003" in profile:
                # We hook both, because although Kernel32 calls the "Ex" version, a
                # program may call directy ZwCreateProcess
                self.breakpoints[("ntdll.dll", "ZwCreateProcessEx")] = None
                self.bp_funcs[("ntdll.dll", "ZwCreateProcessEx")] = (
                    ntcreateprocess, True and not mwmon.api_tracer and not mwmon.coverage)
                self.breakpoints[("ntdll.dll", "ZwCreateProcess")] = None
                self.bp_funcs[("ntdll.dll", "ZwCreateProcess")] = (
                    ntcreateprocess, True and not mwmon.api_tracer and not mwmon.coverage)
            else:
                self.breakpoints[("ntdll.dll", "ZwCreateProcessEx")] = None
                self.bp_funcs[("ntdll.dll", "ZwCreateProcessEx")] = (
                    ntcreateprocess, True and not mwmon.api_tracer and not mwmon.coverage)
                self.breakpoints[("ntdll.dll", "ZwCreateProcess")] = None
                self.bp_funcs[("ntdll.dll", "ZwCreateProcess")] = (
                    ntcreateprocess, True and not mwmon.api_tracer and not mwmon.coverage)
                # On Vista (and onwards), kernel32.dll no longer uses
                # ZwCreateProcess/ZwCreateProcessEx (although these function remain
                # in ntdll.dll. It Uses ZwCreateUserProcess.
                self.breakpoints[("ntdll.dll", "ZwCreateUserProcess")] = None
                self.bp_funcs[("ntdll.dll", "ZwCreateUserProcess")] = (
                    ntcreateprocess, True and not mwmon.api_tracer and not mwmon.coverage)
        else:
            self.breakpoints = {}
            self.bp_funcs = {}
Exemple #53
0
#
#               preserve_filenames: ""
#
# -------------------------------------------------------------------------------

from __future__ import print_function
import os
import shutil
import json
import tarfile
import tempfile
import functools

# Determine TARGET_LONG_SIZE
from api import get_os_bits
TARGET_LONG_SIZE = get_os_bits() / 8

# Script requirements
requirements = ["plugins.guest_agent"]

# Global variables
# Callback manager
cm = None
# Printer
pyrebox_print = None
# Target process name
target_procname = None
target_pgd = None
# Breakpoint for entry point
entry_point_bp = None
Exemple #54
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()
Exemple #55
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("--")
Exemple #56
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