Exemple #1
0
def windows_insert_module_from_base(base, size, pid, pgd, name, fullname):
    '''
        Insert a module given its base
    '''
    from vmi import modules
    from utils import get_addr_space

    if pgd != 0:
        addr_space = get_addr_space(pgd)
    else:
        addr_space = get_addr_space()
    nt_header = obj.Object("_IMAGE_DOS_HEADER", offset=base, vm=addr_space)
    checksum = nt_header.OptionalHeader.CheckSum.v()
    if (pid, pgd) not in modules:
        modules[(pid, pgd)] = {}
    windows_insert_module_internal(
        pid,
        pgd,
        base,
        size,
        fullname,
        name,
        checksum,
        nt_header,
        update_symbols=True)
Exemple #2
0
def windows_update_modules(pgd, update_symbols=False):
    '''
        Use volatility to get the modules and symbols for a given process, and
        update the cache accordingly
    '''
    import api
    from utils import get_addr_space
    from vmi import modules

    if pgd != 0:
        addr_space = get_addr_space(pgd)
    else:
        addr_space = get_addr_space()

    if addr_space is None:
        pp_error("Volatility address space not loaded\n")
        return
    # Get EPROC directly from its offset
    procs = api.get_process_list()
    inserted_bases = []
    # Parse/update kernel modules:
    if last_kdbg is not None:
        kdbg = obj.Object(
            "_KDDEBUGGER_DATA64",
            offset=last_kdbg,
            vm=addr_space)
        for module in kdbg.modules():
            if module.DllBase not in inserted_bases:
                inserted_bases.append(module.DllBase)
                windows_insert_module(0, 0, module, update_symbols)
    for proc in procs:
        p_pid = proc["pid"]
        p_pgd = proc["pgd"]
        # p_name = proc["name"]
        p_kernel_addr = proc["kaddr"]
        if p_pgd == pgd:
            task = obj.Object("_EPROCESS", offset=p_kernel_addr, vm=addr_space)
            # Note: we do not erase the modules we have information for from the list,
            # unless we have a different module loaded at the same base address.
            # In this way, if at some point the module gets unmapped from the PEB list
            # but it is still in memory, we do not loose the information.
            if (p_pid, p_pgd) not in modules:
                modules[(p_pid, p_pgd)] = {}
            for module in task.get_init_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
            for module in task.get_mem_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
            for module in task.get_load_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
            return
Exemple #3
0
def windows_insert_module_internal(
        p_pid,
        p_pgd,
        base,
        size,
        fullname,
        basename,
        checksum,
        nt_header,
        update_symbols):

    from utils import get_addr_space
    from vmi import modules
    from vmi import symbols
    from vmi import Module
    from vmi import PseudoLDRDATA

    mod = Module(base, size, p_pid, p_pgd, checksum, basename, fullname)
    if p_pgd != 0:
        addr_space = get_addr_space(p_pgd)
    else:
        addr_space = get_addr_space()

    # Getting symbols, from cache!
    if (checksum, fullname) in symbols:
        mod.set_symbols(symbols[(checksum, fullname)])
    elif update_symbols:
        syms = []
        export_dir = nt_header.OptionalHeader.DataDirectory[0]
        if export_dir:
            expdir = obj.Object(
                '_IMAGE_EXPORT_DIRECTORY',
                offset=base +
                export_dir.VirtualAddress,
                vm=addr_space,
                parent=PseudoLDRDATA(
                    base,
                    basename,
                    export_dir))
            if expdir.valid(nt_header):
                # Ordinal, Function RVA, and Name Object
                for o, f, n in expdir._exported_functions():
                    if not isinstance(o, obj.NoneObject) and \
                       not isinstance(f, obj.NoneObject) and \
                       not isinstance(n, obj.NoneObject):
                        syms.append((o, f.v(), str(n)))
        symbols[(checksum, fullname)] = syms
        mod.set_symbols(syms)

    if base in modules[(p_pid, p_pgd)]:
        del modules[(p_pid, p_pgd)][base]

    modules[(p_pid, p_pgd)][base] = mod
Exemple #4
0
def windows_insert_module_internal(p_pid, p_pgd, base, size, fullname,
                                   basename, checksum, nt_header,
                                   update_symbols):
    import volatility.conf as volconf
    import volatility.registry as registry
    import volatility.commands as commands
    import volatility.addrspace as addrspace
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.scan as scan
    import volatility.plugins.kdbgscan as kdbg
    import volatility.win32.tasks as tasks
    import volatility.utils as utils
    from utils import get_addr_space
    from vmi import modules
    from vmi import symbols
    from vmi import Module
    from vmi import PseudoLDRDATA

    mod = Module(base, size, p_pid, p_pgd, checksum, basename, fullname)
    if p_pgd != 0:
        addr_space = get_addr_space(p_pgd)
    else:
        addr_space = get_addr_space()

    #Getting symbols, from cache!
    if (checksum, fullname) in symbols:
        mod.set_symbols(symbols[(checksum, fullname)])
    elif update_symbols:
        syms = []
        export_dir = nt_header.OptionalHeader.DataDirectory[0]
        if export_dir:
            expdir = obj.Object('_IMAGE_EXPORT_DIRECTORY',
                                offset=base + export_dir.VirtualAddress,
                                vm=addr_space,
                                parent=PseudoLDRDATA(base, basename,
                                                     export_dir))
            if expdir.valid(nt_header):
                # Ordinal, Function RVA, and Name Object
                for o, f, n in expdir._exported_functions():
                    if not type(o) is obj.NoneObject and \
                       not type(f) is obj.NoneObject and \
                       not type(n) is obj.NoneObject:
                        syms.append((o, f.v(), str(n)))
        symbols[(checksum, fullname)] = syms
        mod.set_symbols(syms)

    if base in modules[(p_pid, p_pgd)]:
        del modules[(p_pid, p_pgd)][base]

    modules[(p_pid, p_pgd)][base] = mod
Exemple #5
0
def get_stacks(pgd):
    '''
        Get list of VAD regions using volatility
    '''
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    stack_list = []

    # Get volatility address space using the function in utils
    addr_space = get_addr_space(pgd)

    # Get list of Task objects using volatility (EPROCESS executive objects)
    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    # Traverse the list of selected EPROCESSes
    for task in eprocs:
        # Get Stack base for every THREAD

        for thread in task.ThreadListHead.list_of_type("_ETHREAD",
                                                       "ThreadListEntry"):
            teb = obj.Object("_TEB",
                             offset=thread.Tcb.Teb,
                             vm=task.get_process_address_space())
            if teb:
                stack_list.append(
                    (teb.NtTib.StackBase.v(), teb.NtTib.StackLimit.v()))

    return stack_list
Exemple #6
0
def dump(pgd_list, path = "/tmp/"):
    '''
    Dump the process, modules, vads..., given a list of process address spaces and a path.
    '''
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    from utils import get_addr_space
    import api

    # Delete contents, and create directory under path
    if os.path.isdir(path):
        shutil.rmtree(path)
    os.mkdir(path)

    try:
        # Get volatility address space
        addr_space = get_addr_space()

        # Get list of processes (tasks) from volatility
        eprocs = [t for t in tasks.pslist(
            addr_space) if t.Pcb.DirectoryTableBase.v() in pgd_list]

        # For every selected task
        for task in eprocs:
            # Code adapted from procdump (volatility)
            task_space = task.get_process_address_space()
            if task_space is None:
                print("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
                print(
                    "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:
                print(
                    "Error: ImageBaseAddress at {0:#x} is unavailable" +
                    "(possibly due to paging)".format(task.Peb.ImageBaseAddress))
                return
            else:
                dump_file = os.path.join(
                    path, "PID_%x.executable.ex_" % (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:
                    print("Error: {0}".format(ve))
                    return
                except exceptions.SanityCheckException, ve:
                    print("Error: {0} Try -u/--unsafe".format(ve))
                    return
Exemple #7
0
def windows_get_prototype_pte_address_range(pgd, address):
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    addr_space = get_addr_space(pgd)

    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    if len(eprocs) != 1:
        return None

    task = eprocs[0]
    vad = None
    # File name and offset
    for vad in task.VadRoot.traverse():
        if address >= vad.Start and address < vad.End:
            break

    if vad is None:
        return None

    if vad.ControlArea is not None and vad.ControlArea.Segment is not None:
        start = vad.ControlArea.Segment.PrototypePte.v()
        end = start + (vad.ControlArea.Segment.TotalNumberOfPtes.v() *
                       addr_space.profile.vtypes["_MMPTE_SOFTWARE"][0])
        return (start, end)
    else:
        return None
Exemple #8
0
    def update_from_peb(self):
        '''
        Update several variables based on info extracted from peb
        '''
        import volatility.win32.tasks as tasks
        from utils import get_addr_space

        addr_space = get_addr_space(self.get_pgd())

        eprocs = [
            t for t in tasks.pslist(addr_space)
            if t.UniqueProcessId == self.__pid
        ]
        if len(eprocs) != 1:
            self.__commandline = None
            self.__current_directory = None
            self.__image_path = None
        else:
            task = eprocs[0]
            self.__commandline = str(task.Peb.ProcessParameters.CommandLine
                                     or '')
            self.__current_directory = str(
                task.Peb.ProcessParameters.CurrentDirectory.DosPath or '')
            self.__image_path = str(task.Peb.ProcessParameters.ImagePathName
                                    or '')
Exemple #9
0
def get_system_time():
    from volatility import obj
    from utils import get_addr_space
    addr_space = get_addr_space()
    k = obj.Object("_KUSER_SHARED_DATA",
                   offset=obj.VolMagic(addr_space).KUSER_SHARED_DATA.v(),
                   vm=addr_space)
    return k.SystemTime.as_datetime()
Exemple #10
0
def new_proc(pid,pgd,name):
    global cm
    pyrebox_print("Process %x started with pgd: %x. Name: %s" % (pid,pgd,name))
    #Get the volatility address space, adjusted for our current pgd
    addr_space = get_addr_space(pgd)
    #Use the pslist function to retrieve the process list with volatility
    procs = [t for t in tasks.pslist(addr_space)]
    #Just print the process list
    for p in procs:
        pyrebox_print("Process %s PID:%x" % (p.ImageFileName,p.UniqueProcessId))
Exemple #11
0
def windows_insert_module_from_base(base, size, pid, pgd, name, fullname):
    '''
        Insert a module given its base
    '''
    import volatility.conf as volconf
    import volatility.registry as registry
    import volatility.commands as commands
    import volatility.addrspace as addrspace
    import volatility.constants as constants
    import volatility.exceptions as exceptions
    import volatility.obj as obj
    import volatility.scan as scan
    import volatility.plugins.kdbgscan as kdbg
    import volatility.win32.tasks as tasks
    import volatility.utils as utils
    from utils import get_addr_space
    from vmi import modules
    from vmi import symbols
    from vmi import Module
    from vmi import PseudoLDRDATA

    if pgd != 0:
        addr_space = get_addr_space(pgd)
    else:
        addr_space = get_addr_space()
    nt_header = obj.Object("_IMAGE_DOS_HEADER", offset=base, vm=addr_space)
    checksum = nt_header.OptionalHeader.CheckSum.v()
    if (pid, pgd) not in modules:
        modules[(pid, pgd)] = {}
    windows_insert_module_internal(pid,
                                   pgd,
                                   base,
                                   size,
                                   fullname,
                                   name,
                                   checksum,
                                   nt_header,
                                   update_symbols=True)
def new_proc(params):
    global cm

    pid = params["pid"]
    pgd = params["pgd"] 
    name = params["name"]

    pyrebox_print("Process %x started with pgd: %x. Name: %s" % (pid, pgd, name))
    # Get the volatility address space, adjusted for our current pgd
    addr_space = get_addr_space(pgd)
    # Use the pslist function to retrieve the process list with volatility
    procs = [t for t in tasks.pslist(addr_space)]
    # Just print the process list
    for p in procs:
        pyrebox_print("Process %s PID:%x" % (p.ImageFileName, p.UniqueProcessId))
    def update_from_peb(self):
        '''
        Update several variables based on info extracted from peb
        '''
        import volatility.win32.tasks as tasks
        from utils import get_addr_space

        addr_space = get_addr_space(self.get_pgd())

        eprocs = [t for t in tasks.pslist(
            addr_space) if t.UniqueProcessId == self.pid]
        if len(eprocs) != 1:
            self.commandline = None
            self.current_directory = None
            self.image_path = None
        else:
            task = eprocs[0]
            self.commandline = str(
                task.Peb.ProcessParameters.CommandLine or '')
            self.current_directory = str(
                task.Peb.ProcessParameters.CurrentDirectory.DosPath or '')
            self.image_path = str(
                task.Peb.ProcessParameters.ImagePathName or '')
Exemple #14
0
def module_entry_point(proc, params):
    '''
        Callback on the entry point of the main module being monitored
    '''
    global cm
    global entry_point_bps
    global interproc_data

    from api import CallbackManager
    import api
    from utils import get_addr_space
    import volatility.win32.tasks as tasks

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

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

    # Disable the entrypoint
    entry_point_bps[pgd].disable()

    # Call all our internal callbacks
    interproc_data.deliver_entry_point_callback(params)

    # Use volatility to check if it is a Wow64 process

    # Get volatility address space using the function in utils
    addr_space = get_addr_space(pgd)

    # Get list of Task objects using volatility (EPROCESS executive objects)
    eprocs = [t for t in tasks.pslist(
        addr_space) if t.Pcb.DirectoryTableBase.v() == pgd]

    if len(eprocs) > 0:
        proc.set_wow64(eprocs[0].IsWow64)
Exemple #15
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 #16
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 #17
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 #18
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 #19
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 #20
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 #21
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 #22
0
    def update_vads(self):
        '''
        Call volatility to obtain VADS.
        '''
        if self.__unpickled:
            return
        import volatility.obj as obj
        import volatility.win32.tasks as tasks
        import volatility.plugins.vadinfo as vadinfo
        from utils import get_addr_space

        addr_space = get_addr_space(self.get_pgd())

        eprocs = [
            t for t in tasks.pslist(addr_space)
            if t.UniqueProcessId == self.__pid
        ]
        for task in eprocs:
            heaps = task.Peb.ProcessHeaps.dereference()
            modules = [mod.DllBase for mod in task.get_load_modules()]
            stacks = []
            for thread in task.ThreadListHead.list_of_type(
                    "_ETHREAD", "ThreadListEntry"):
                teb = obj.Object("_TEB",
                                 offset=thread.Tcb.Teb,
                                 vm=task.get_process_address_space())
                if teb:
                    stacks.append(teb.NtTib.StackBase)
            for vad in task.VadRoot.traverse():
                if vad is not None:
                    vad_type = ""
                    if vad.Start in heaps:
                        # Heaps
                        vad_type = "H"
                    elif vad.Start in modules:
                        # Module
                        vad_type = "M"
                    elif vad.Start in stacks:
                        # Stacks
                        vad_type = "S"
                    else:
                        vad_type = "-"

                    try:
                        protection = vadinfo.PROTECT_FLAGS.get(
                            vad.VadFlags.Protection.v(), "")
                    except Exception:
                        traceback.print_exc()

                    fileNameWithDevice = ""
                    try:
                        control_area = vad.ControlArea
                        # even if the ControlArea is not NULL, it is only meaningful
                        # for shared (non private) memory sections.
                        if vad.VadFlags.PrivateMemory != 1 and control_area:
                            if control_area:
                                file_object = vad.FileObject
                                if file_object:
                                    fileNameWithDevice = file_object.file_name_with_device(
                                    )
                    except AttributeError:
                        pass

                    try:
                        new_vad = VADRegion(vad.Start, (vad.End - vad.Start),
                                            self, fileNameWithDevice,
                                            str(vad.Tag), vad_type,
                                            (vad.VadFlags.PrivateMemory == 1),
                                            protection)
                    except Exception:
                        traceback.print_exc()

                    if new_vad not in self.__vads:
                        self.__vads.append(new_vad)
Exemple #23
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 #24
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 #25
0
def windows_insert_module_internal(p_pid, p_pgd, base, size, fullname,
                                   basename, checksum, nt_header,
                                   update_symbols):

    from utils import get_addr_space
    from vmi import modules
    from vmi import symbols
    from vmi import Module
    from vmi import PseudoLDRDATA
    from api_internal import dispatch_module_load_callback
    from api_internal import dispatch_module_remove_callback

    mod = Module(base, size, p_pid, p_pgd, checksum, basename, fullname)

    if p_pgd != 0:
        addr_space = get_addr_space(p_pgd)
    else:
        addr_space = get_addr_space()

    # First, we try to get the symbols from the cache
    if (checksum, fullname) in symbols:
        mod.set_symbols(symbols[(checksum, fullname)])

    # If we are updating symbols (a simple module retrieval would
    # not require symbol extraction), and, either we dont have any
    # symbols on the cache, or we have an empty list (symbols could
    # not be retrieved for some reason, such as a missing memory page,
    # we try symbol resolution
    if update_symbols and ((checksum, fullname) not in symbols
                           or len(symbols[(checksum, fullname)]) == 0):
        syms = {}
        export_dir = nt_header.OptionalHeader.DataDirectory[0]

        if export_dir:
            expdir = obj.Object('_IMAGE_EXPORT_DIRECTORY',
                                offset=base + export_dir.VirtualAddress,
                                vm=addr_space,
                                parent=PseudoLDRDATA(base, basename,
                                                     export_dir))
            if expdir.valid(nt_header):
                # Ordinal, Function RVA, and Name Object
                for o, f, n in expdir._exported_functions():
                    if not isinstance(o, obj.NoneObject) and \
                       not isinstance(f, obj.NoneObject) and \
                       not isinstance(n, obj.NoneObject):
                        syms[str(n)] = f.v()

                # If we managed to parse export table, update symbols,
                # no matter if it is empty
                if (checksum, fullname) not in symbols or len(syms) > len(
                        symbols[(checksum, fullname)]):
                    symbols[(checksum, fullname)] = syms
                    # Even if it is empty, the module symbols are set
                    # to an empty list, and thus are 'resolved'.
                    # Anyway, in future updates, they could be resolved,
                    # as we allow this in the first condition.
                    mod.set_symbols(symbols[(checksum, fullname)])
                    # Add module to mods_pending, or
                    # Update modules that may we might not have been
                    # able to resolve symbols in the past
                    if len(syms) == 0:
                        if (checksum, fullname) not in mods_pending:
                            mods_pending[(checksum, fullname)] = []
                        mods_pending[(checksum, fullname)].append(mod)
                    else:
                        if (checksum, fullname) in mods_pending and len(
                                mods_pending[(checksum, fullname)]) > 0:
                            for mod in mods_pending[(checksum, fullname)]:
                                mod.set_symbols(syms)
                            del mods_pending[(checksum, fullname)]

        else:
            # Since there is no export dir, we assume that it does
            # not have any symbols
            if (checksum, fullname) not in symbols:
                symbols[(checksum, fullname)] = []
                # Even if it is empty, the module symbols are set
                # to an empty list, and thus are 'resolved'.
                # Anyway, in future updates, they could be resolved,
                # as we allow this in the first condition.
                mod.set_symbols(symbols[(checksum, fullname)])
                # Add module to mods_pending, or
                if (checksum, fullname) not in mods_pending:
                    mods_pending[(checksum, fullname)] = []
                mods_pending[(checksum, fullname)].append(mod)

    #Module load/del notification
    if base in modules[(p_pid, p_pgd)]:
        if modules[(p_pid, p_pgd)][base].get_size() != size or \
           modules[(p_pid, p_pgd)][base].get_checksum() != checksum or \
           modules[(p_pid, p_pgd)][base].get_name() != basename or \
           modules[(p_pid, p_pgd)][base].get_fullname() != fullname:
            # Notify of module deletion and module load
            dispatch_module_remove_callback(
                p_pid, p_pgd, base, modules[(p_pid, p_pgd)][base].get_size(),
                modules[(p_pid, p_pgd)][base].get_name(),
                modules[(p_pid, p_pgd)][base].get_fullname())
            del modules[(p_pid, p_pgd)][base]
            modules[(p_pid, p_pgd)][base] = mod
            dispatch_module_load_callback(p_pid, p_pgd, base, size, basename,
                                          fullname)
        # If we updated the symbols and have a bigger list now, dont substitute the module
        # but update its symbols instead
        elif len(mod.get_symbols()) > len(
                modules[(p_pid, p_pgd)][base].get_symbols()):
            modules[(p_pid, p_pgd)][base].set_symbols(mod.get_symbols())
    else:
        # Just notify of module load
        modules[(p_pid, p_pgd)][base] = mod
        dispatch_module_load_callback(p_pid, p_pgd, base, size, basename,
                                      fullname)

    # Mark the module as present
    modules[(p_pid, p_pgd)][base].set_present()
Exemple #26
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 #27
0
def windows_update_modules(pgd, update_symbols=False):
    '''
        Use volatility to get the modules and symbols for a given process, and
        update the cache accordingly
    '''
    global last_kdbg
    global symbol_cache_must_be_saved

    import api
    from utils import get_addr_space
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules
    from vmi import add_module
    from vmi import get_module
    from vmi import has_module

    if pgd != 0:
        addr_space = get_addr_space(pgd)
    else:
        addr_space = get_addr_space()

    if addr_space is None:
        pp_error("Volatility address space not loaded\n")
        return []

    # Get EPROC directly from its offset
    procs = api.get_process_list()
    inserted_bases = []
    # Parse/update kernel modules if pgd 0 is requested:
    if pgd == 0 and last_kdbg is not None:
        kdbg = obj.Object(
            "_KDDEBUGGER_DATA64",
            offset=last_kdbg,
            vm=addr_space)
        
        # List entries are returned, so that
        # we can monitor memory writes to these
        # entries and detect when a module is added
        # or removed
        list_entry_size = None
        list_entry_regions = []

        # Add the initial list pointer as a list entry
        list_entry_regions.append((kdbg.obj_offset, kdbg.PsLoadedModuleList.obj_offset, kdbg.PsLoadedModuleList.size()))

        # Mark all modules as non-present
        set_modules_non_present(0, 0)
        for module in kdbg.modules():
            if module.DllBase not in inserted_bases:
                inserted_bases.append(module.DllBase)
                windows_insert_module(0, 0, module, update_symbols)
                if list_entry_size is None:
                    list_entry_size = module.InLoadOrderLinks.size()
                list_entry_regions.append((module.obj_offset, module.InLoadOrderLinks.obj_offset, list_entry_size * 3))

        # Remove all the modules that are not marked as present
        clean_non_present_modules(0, 0)
  
        if symbol_cache_must_be_saved:
            from vmi import save_symbols_to_cache_file
            save_symbols_to_cache_file()
            symbol_cache_must_be_saved = False

        return list_entry_regions

    for proc in procs:
        p_pid = proc["pid"]
        p_pgd = proc["pgd"]
        # p_name = proc["name"]
        p_kernel_addr = proc["kaddr"]
        if p_pgd == pgd:
            task = obj.Object("_EPROCESS", offset=p_kernel_addr, vm=addr_space)

            # List entries are returned, so that
            # we can monitor memory writes to these
            # entries and detect when a module is added
            # or removed
            list_entry_size = None
            list_entry_regions = []

            scan_peb = True
            if task.Peb is None or not task.Peb.is_valid():
                if isinstance(task.Peb.obj_offset, int):
                    list_entry_regions.append((task.obj_offset, task.Peb.obj_offset, task.Peb.size()))
                scan_peb = False

            if task.Peb.Ldr is None or not task.Peb.Ldr.is_valid():
                list_entry_regions.append((task.Peb.v(), task.Peb.Ldr.obj_offset, task.Peb.Ldr.size()))
                scan_peb = False

            if scan_peb:
                # Add the initial list pointer as a list entry if we already have a PEB and LDR
                list_entry_regions.append((task.Peb.Ldr.dereference().obj_offset, task.Peb.Ldr.InLoadOrderModuleList.obj_offset, task.Peb.Ldr.InLoadOrderModuleList.size() * 3))
                
                # Note: we do not erase the modules we have information for from the list,
                # unless we have a different module loaded at the same base address.
                # In this way, if at some point the module gets unmapped from the PEB list
                # but it is still in memory, we do not loose the information.

                # Mark all modules as non-present
                set_modules_non_present(p_pid, p_pgd)

                for module in task.get_init_modules():
                    if module.DllBase not in inserted_bases:
                        inserted_bases.append(module.DllBase)
                        windows_insert_module(p_pid, p_pgd, module, update_symbols)
                        if list_entry_size is None:
                            list_entry_size = module.InLoadOrderLinks.size()
                        list_entry_regions.append((module.obj_offset, module.InLoadOrderLinks.obj_offset, list_entry_size * 3))

                for module in task.get_mem_modules():
                    if module.DllBase not in inserted_bases:
                        inserted_bases.append(module.DllBase)
                        windows_insert_module(p_pid, p_pgd, module, update_symbols)
                        if list_entry_size is None:
                            list_entry_size = module.InLoadOrderLinks.size()
                        list_entry_regions.append((module.obj_offset, module.InLoadOrderLinks.obj_offset, list_entry_size * 3))

                for module in task.get_load_modules():
                    if module.DllBase not in inserted_bases:
                        inserted_bases.append(module.DllBase)
                        windows_insert_module(p_pid, p_pgd, module, update_symbols)
                        if list_entry_size is None:
                            list_entry_size = module.InLoadOrderLinks.size()
                        list_entry_regions.append((module.obj_offset, module.InLoadOrderLinks.obj_offset, list_entry_size * 3))

                # Now, if we are a 64bit system and the process is a Wow64 process, traverse VAD 
                # to find the 32 bit modules

                if api.get_os_bits() == 64 and task.IsWow64:
                    for vad in task.VadRoot.traverse():
                        if vad is not None:
                            if hasattr(vad, "FileObject"):
                                f = vad.FileObject
                                if f is not None:
                                    fname = f.file_name_with_device()
                                    if fname and "Windows\\SysWOW64".lower() in fname.lower() and ".dll" == fname[-4:].lower():
                                        fname_starts = fname.find("Windows\\SysWOW64")
                                        fname = fname[fname_starts:]
                                        windows_insert_module_internal(p_pid, p_pgd, vad.Start,
                                                                       vad.End - vad.Start,
                                                                       fname,
                                                                       fname.split("\\")[-1],
                                                                       "",
                                                                       update_symbols,
                                                                       do_stop = True)
                # Remove all the modules that are not marked as present
                clean_non_present_modules(p_pid, p_pgd)

            if symbol_cache_must_be_saved:
                from vmi import save_symbols_to_cache_file
                save_symbols_to_cache_file()
                symbol_cache_must_be_saved = False

            return list_entry_regions

    return None 
Exemple #28
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 #29
0
def windows_insert_module_internal(p_pid, p_pgd, base, size, fullname,
                                   basename, checksum, nt_header,
                                   update_symbols):

    from utils import get_addr_space
    from vmi import modules
    from vmi import symbols
    from vmi import Module
    from vmi import PseudoLDRDATA
    from api_internal import dispatch_module_load_callback
    from api_internal import dispatch_module_remove_callback

    mod = Module(base, size, p_pid, p_pgd, checksum, basename, fullname)
    if p_pgd != 0:
        addr_space = get_addr_space(p_pgd)
    else:
        addr_space = get_addr_space()

    # Getting symbols, from cache!
    if (checksum, fullname) in symbols:
        mod.set_symbols(symbols[(checksum, fullname)])
    elif update_symbols:
        syms = {}
        export_dir = nt_header.OptionalHeader.DataDirectory[0]
        if export_dir:
            expdir = obj.Object('_IMAGE_EXPORT_DIRECTORY',
                                offset=base + export_dir.VirtualAddress,
                                vm=addr_space,
                                parent=PseudoLDRDATA(base, basename,
                                                     export_dir))
            if expdir.valid(nt_header):
                # Ordinal, Function RVA, and Name Object
                for o, f, n in expdir._exported_functions():
                    if not isinstance(o, obj.NoneObject) and \
                       not isinstance(f, obj.NoneObject) and \
                       not isinstance(n, obj.NoneObject):
                        syms[str(n)] = f.v()
        if len(syms) > 0:
            symbols[(checksum, fullname)] = syms
            mod.set_symbols(syms)
            if (checksum, fullname) in mods_pending:
                for m in mods_pending[(checksum, fullname)]:
                    m.set_symbols(syms)
                del mods_pending[(checksum, fullname)]
        else:
            if (checksum, fullname) in mods_pending:
                mods_pending[(checksum, fullname)].append(mod)
            else:
                mods_pending[(checksum, fullname)] = [mod]

    #Module load/del notification
    if base in modules[(p_pid, p_pgd)]:
        if modules[(p_pid, p_pgd)][base].get_size() != size or \
           modules[(p_pid, p_pgd)][base].get_checksum() != checksum or \
           modules[(p_pid, p_pgd)][base].get_name() != basename or \
           modules[(p_pid, p_pgd)][base].get_fullname() != fullname:
            # Notify of module deletion and module load
            dispatch_module_remove_callback(
                p_pid, p_pgd, base, modules[(p_pid, p_pgd)][base].get_size(),
                modules[(p_pid, p_pgd)][base].get_name(),
                modules[(p_pid, p_pgd)][base].get_fullname())
            del modules[(p_pid, p_pgd)][base]
            dispatch_module_load_callback(p_pid, p_pgd, base, size, basename,
                                          fullname)
            modules[(p_pid, p_pgd)][base] = mod
    else:
        # Just notify of module load
        dispatch_module_load_callback(p_pid, p_pgd, base, size, basename,
                                      fullname)
        modules[(p_pid, p_pgd)][base] = mod

    # Mark the module as present
    modules[(p_pid, p_pgd)][base].set_present()
Exemple #30
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 #31
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 #32
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 #33
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 #34
0
def windows_update_modules(pgd, update_symbols=False):
    '''
        Use volatility to get the modules and symbols for a given process, and
        update the cache accordingly
    '''
    global last_kdbg

    import api
    from utils import get_addr_space
    from vmi import modules
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules

    if pgd != 0:
        addr_space = get_addr_space(pgd)
    else:
        addr_space = get_addr_space()

    if addr_space is None:
        pp_error("Volatility address space not loaded\n")
        return []

    # Get EPROC directly from its offset
    procs = api.get_process_list()
    inserted_bases = []
    # Parse/update kernel modules if pgd 0 is requested:
    if pgd == 0 and last_kdbg is not None:
        if (0, 0) not in modules:
            modules[(0, 0)] = {}

        kdbg = obj.Object("_KDDEBUGGER_DATA64",
                          offset=last_kdbg,
                          vm=addr_space)

        # List entries are returned, so that
        # we can monitor memory writes to these
        # entries and detect when a module is added
        # or removed
        list_entry_size = None
        list_entry_regions = []

        # Add the initial list pointer as a list entry
        list_entry_regions.append(
            (kdbg.obj_offset, kdbg.PsLoadedModuleList.obj_offset,
             kdbg.PsLoadedModuleList.size()))

        # Mark all modules as non-present
        set_modules_non_present(0, 0)
        for module in kdbg.modules():
            if module.DllBase not in inserted_bases:
                inserted_bases.append(module.DllBase)
                windows_insert_module(0, 0, module, update_symbols)
                if list_entry_size is None:
                    list_entry_size = module.InLoadOrderLinks.size()
                list_entry_regions.append(
                    (module.obj_offset, module.InLoadOrderLinks.obj_offset,
                     list_entry_size * 3))

        # Remove all the modules that are not marked as present
        clean_non_present_modules(0, 0)

        return list_entry_regions

    for proc in procs:
        p_pid = proc["pid"]
        p_pgd = proc["pgd"]
        # p_name = proc["name"]
        p_kernel_addr = proc["kaddr"]
        if p_pgd == pgd:
            task = obj.Object("_EPROCESS", offset=p_kernel_addr, vm=addr_space)

            # List entries are returned, so that
            # we can monitor memory writes to these
            # entries and detect when a module is added
            # or removed
            list_entry_size = None
            list_entry_regions = []

            if task.Peb is None or not task.Peb.is_valid():
                if isinstance(task.Peb.obj_offset, int):
                    list_entry_regions.append(
                        (task.obj_offset, task.Peb.obj_offset,
                         task.Peb.size()))
                return list_entry_regions
            if task.Peb.Ldr is None or not task.Peb.Ldr.is_valid():
                list_entry_regions.append(
                    (task.Peb.v(), task.Peb.Ldr.obj_offset,
                     task.Peb.Ldr.size()))
                return list_entry_regions

            # Add the initial list pointer as a list entry if we already have a PEB and LDR
            list_entry_regions.append(
                (task.Peb.Ldr.dereference().obj_offset,
                 task.Peb.Ldr.InLoadOrderModuleList.obj_offset,
                 task.Peb.Ldr.InLoadOrderModuleList.size() * 3))

            # Note: we do not erase the modules we have information for from the list,
            # unless we have a different module loaded at the same base address.
            # In this way, if at some point the module gets unmapped from the PEB list
            # but it is still in memory, we do not loose the information.

            if (p_pid, p_pgd) not in modules:
                modules[(p_pid, p_pgd)] = {}

            # Mark all modules as non-present
            set_modules_non_present(p_pid, p_pgd)

            for module in task.get_init_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
                    if list_entry_size is None:
                        list_entry_size = module.InLoadOrderLinks.size()
                    list_entry_regions.append(
                        (module.obj_offset, module.InLoadOrderLinks.obj_offset,
                         list_entry_size * 3))

            for module in task.get_mem_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
                    if list_entry_size is None:
                        list_entry_size = module.InLoadOrderLinks.size()
                    list_entry_regions.append(
                        (module.obj_offset, module.InLoadOrderLinks.obj_offset,
                         list_entry_size * 3))

            for module in task.get_load_modules():
                if module.DllBase not in inserted_bases:
                    inserted_bases.append(module.DllBase)
                    windows_insert_module(p_pid, p_pgd, module, update_symbols)
                    if list_entry_size is None:
                        list_entry_size = module.InLoadOrderLinks.size()
                    list_entry_regions.append(
                        (module.obj_offset, module.InLoadOrderLinks.obj_offset,
                         list_entry_size * 3))

            # Remove all the modules that are not marked as present
            clean_non_present_modules(p_pid, p_pgd)

            return list_entry_regions

    return None
Exemple #35
0
def get_vads(pgd):
    '''
        Get list of VAD regions using volatility
    '''
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    # Get volatility address space using the function in utils
    addr_space = get_addr_space(pgd)

    # Get list of Task objects using volatility (EPROCESS executive objects)
    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    # Traverse the list of selected EPROCESSes
    for task in eprocs:
        # Get heap base for every process HEAP
        heaps = task.Peb.ProcessHeaps.dereference()

        # Get base for every DLL
        modules = [mod.DllBase for mod in task.get_load_modules()]

        # Get Stack base for every THREAD
        stacks = []
        for thread in task.ThreadListHead.list_of_type("_ETHREAD",
                                                       "ThreadListEntry"):
            teb = obj.Object("_TEB",
                             offset=thread.Tcb.Teb,
                             vm=task.get_process_address_space())
            if teb:
                stacks.append(teb.NtTib.StackBase)

        # Traverse VAD tree
        for vad in task.VadRoot.traverse():
            if vad is not None:
                # Determine if the VAD is a HEAP, STACK, or MODULE
                vad_type = ""
                if vad.Start in heaps:
                    # Heaps
                    vad_type = "H"
                elif vad.Start in modules:
                    # Module
                    vad_type = "M"
                elif vad.Start in stacks:
                    # Stacks
                    vad_type = "S"
                else:
                    vad_type = "-"

                # Get protection flags
                try:
                    protection = vadinfo.PROTECT_FLAGS.get(
                        vad.VadFlags.Protection.v(), "")
                except Exception:
                    traceback.print_exc()

                # Get mapped file
                file_name = ""
                try:
                    control_area = vad.ControlArea
                    # even if the ControlArea is not NULL, it is only meaningful
                    # for shared (non private) memory sections.
                    if vad.VadFlags.PrivateMemory != 1 and control_area:
                        if control_area:
                            file_object = vad.FileObject
                            if file_object:
                                file_name = file_object.file_name_with_device()
                except AttributeError:
                    pass

                # Return VAD regions
                yield VADRegion(vad.Start, vad.End, file_name, str(vad.Tag),
                                vad_type, (vad.VadFlags.PrivateMemory == 1),
                                protection)
Exemple #36
0
def windows_read_memory_mapped(pgd, addr, size, pte, is_pae, bitness):
    # Step 1: Traverse the VAD tree for the process with PGD,
    #         and get the VAD that overlaps addr (if any)
    # Step 2: Check if the VAD has a ControlArea and a FilePointer,
    #         and get the file path.
    # Step 3: Get Segment (pointed to by ControlArea), and get the pointer
    #         to the first PrototypePTE.
    # Step 4: Compute offset of address with respect to the beginning
    #         of the VAD, and compute which PrototypePTE corresponds to the address
    #         No need to consider if the PTE points to the Prototype PTE here.
    # Step 6: Compute the offset in file for such PrototypePTE by looking at the
    #         subsections pointed by the ControlArea.
    # Step 7: Finally, open the file, read the contents, and return them.
    import volatility.obj as obj
    import volatility.win32.tasks as tasks
    import volatility.plugins.vadinfo as vadinfo
    from utils import get_addr_space

    addr_space = get_addr_space(pgd)

    eprocs = [
        t for t in tasks.pslist(addr_space)
        if t.Pcb.DirectoryTableBase.v() == pgd
    ]

    if len(eprocs) != 1:
        return None

    task = eprocs[0]
    vad = None
    # File name and offset
    for vad in task.VadRoot.traverse():
        if addr >= vad.Start and addr < vad.End:
            break
    if vad is None:
        return None

    filename = None
    if vad.ControlArea is not None and vad.FileObject is not None:
        filename = str(vad.ControlArea.FileObject.FileName)

    if vad.ControlArea.Segment is None:
        return None

    # Compute page offset with respect to Start of the VAD,
    # and the corresponding prototype Page Table Entry pointed
    # by the Segment
    offset_on_vad = addr - vad.Start
    page_offset_on_vad = (offset_on_vad - (offset_on_vad & 0xFFF))
    # Consider 4 KiB pages
    ppte_index = page_offset_on_vad / 0x1000

    if ppte_index >= vad.ControlArea.Segment.TotalNumberOfPtes.v():
        return None

    if bitness == 32 and is_pae:
        ppte_addr = vad.ControlArea.Segment.PrototypePte.v() + (ppte_index * 8)
    else:
        ppte_addr = vad.ControlArea.Segment.PrototypePte.v() + (
            ppte_index * addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][0])

    # Read Subsections pointed by ControlArea
    visited_subsections = {}
    if "Subsection" in vad.members:
        subsect = vad.Subsection
    # There is no Subsection pointer in VAD
    # structure, so we just read after the ControlArea
    else:
        subsect = obj.Object(
            "_SUBSECTION",
            offset=(vad.ControlArea.v() +
                    addr_space.profile.vtypes["_CONTROL_AREA"][0]),
            vm=addr_space)

    file_offset_to_read = None
    while file_offset_to_read is None and subsect is not None or subsect.v(
    ) != 0 and subsect.v() not in visited_subsections:
        visited_subsections.append(subsect.v())
        # Get the PPTE address where the Subsection starts,
        # and compute the virtual address that it corresponds
        # to.
        ppte_addr = subsect.SubsectionBase.v()
        if bitness == 32 and is_pae:
            ppte_index = (subsect.SubsectionBase.v() -
                          vad.ControlArea.Segment.PrototypePte.v()) / 8
        else:
            ppte_index = (subsect.SubsectionBase.v() -
                          vad.ControlArea.Segment.PrototypePte.v()
                          ) / addr_space.profile.vtypes["_MMPTE_PROTOTYPE"][0]

        subsection_base = vad.Start + (ppte_index * 0x1000)
        subsection_size = subsect.PtesInSubsection.v() * 0x1000
        subsection_file_offset = subsect.StartingSector.v() * 512
        subsection_file_size = vad.Subsection.NumberOfFullSectors.v() * 512

        visited_subsections[subsect.v()] = (subsection_base, subsection_size,
                                            subsection_file_offset,
                                            subsection_file_size)

        if (addr >= subsection_base) and (addr <
                                          (subsection_base + subsection_size)):
            file_offset_to_read = (addr -
                                   subsection_base) + subsection_file_offset

        subsect = subsect.NextSubsection

    f = None
    for fs in api.get_filesystems():
        try:
            f = api.open_guest_path(fs["index"], filename)
            break
        except:
            # The file cannot be open on such filesystem
            pass
    if not f:
        raise RuntimeError(
            "Could not read memory from pagefile: file not found")

    print("Reading file %s at offset %x - Size: %x" %
          (filename, file_offset_to_read, size))
    f.seek(file_offset_to_read)
    data = f.read(size=size)
    f.close()
    def update_vads(self):
        '''
        Call volatility to obtain VADS.
        '''
        if self.unpickled:
            return
        import volatility.obj as obj
        import volatility.win32.tasks as tasks
        import volatility.plugins.vadinfo as vadinfo
        from utils import get_addr_space

        addr_space = get_addr_space(self.get_pgd())

        eprocs = [t for t in tasks.pslist(
            addr_space) if t.UniqueProcessId == self.pid]
        for task in eprocs:
            heaps = task.Peb.ProcessHeaps.dereference()
            modules = [mod.DllBase for mod in task.get_load_modules()]
            stacks = []
            for thread in task.ThreadListHead.list_of_type("_ETHREAD", "ThreadListEntry"):
                teb = obj.Object("_TEB",
                                 offset=thread.Tcb.Teb,
                                 vm=task.get_process_address_space())
                if teb:
                    stacks.append(teb.NtTib.StackBase)
            for vad in task.VadRoot.traverse():
                if vad is not None:
                    vad_type = ""
                    if vad.Start in heaps:
                        # Heaps
                        vad_type = "H"
                    elif vad.Start in modules:
                        # Module
                        vad_type = "M"
                    elif vad.Start in stacks:
                        # Stacks
                        vad_type = "S"
                    else:
                        vad_type = "-"

                    try:
                        protection = vadinfo.PROTECT_FLAGS.get(
                            vad.VadFlags.Protection.v(), "")
                    except Exception:
                        traceback.print_exc()

                    fileNameWithDevice = ""
                    try:
                        control_area = vad.ControlArea
                        # even if the ControlArea is not NULL, it is only meaningful
                        # for shared (non private) memory sections.
                        if vad.VadFlags.PrivateMemory != 1 and control_area:
                            if control_area:
                                file_object = vad.FileObject
                                if file_object:
                                    fileNameWithDevice = file_object.file_name_with_device(
                                    )
                    except AttributeError:
                        pass

                    try:
                        new_vad = VADRegion(vad.Start, (vad.End - vad.Start), self, fileNameWithDevice, str(
                            vad.Tag), vad_type, (vad.VadFlags.PrivateMemory == 1), protection)
                    except Exception:
                        traceback.print_exc()

                    if new_vad not in self.vads:
                        self.vads.append(new_vad)
Exemple #38
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 #39
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