Exemplo n.º 1
0
def module_change_callback(pgd, bp_vaddr, bp_haddr, cpu_index, vaddr, size, haddr, data):
    '''
    Callback function triggered whenever there is a change in the list of linked
    modules for a given process.
 
    Updates the module list for that PGD (or kernel).
    ''' 
    import functools
    import struct
    import api
    from api import BP
    from vmi import update_modules
    from utils import pp_error
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules

    # First, we check if the memory address written points to a module
    # that we have already detected (it is in our list of hooking points).
    # In this way we avoid triggering one update operation for every
    # modified pointer (inserting a module requires to change several
    # pointers, due to the different linked lists).
   
    # Return if it points inside a module that we have already added to our list
    for module_base, hook_addr, hook_size in module_load_remove_breakpoints[pgd]:
        if data >= module_base and data < (hook_addr + hook_size):
            return

    hooking_points = update_modules(pgd)

    if hooking_points is not None:
        # Update hooking points
        # 1) Remove the breakpoints not used anymore
        bps_to_remove = []
        for hp in module_load_remove_breakpoints[pgd]:
            if hp not in hooking_points:
                bps_to_remove.append(hp)

        for hp in bps_to_remove:
            module_load_remove_breakpoints[pgd][hp].disable()
            del module_load_remove_breakpoints[pgd][hp]

        # 2) Add new breakpoints
        for hp in hooking_points:
            if hp not in module_load_remove_breakpoints[pgd]:
                 module_base, addr, size = hp
                 haddr = api.va_to_pa(pgd, addr)
                 bp = BP(haddr,
                         None,
                         size = size,
                         typ = BP.MEM_WRITE_PHYS,
                         func = functools.partial(module_change_callback, pgd, addr, haddr))
                 module_load_remove_breakpoints[pgd][hp] = bp
                 bp.enable()
    else:
        # Just remove all the  modules for the process
        # Mark all modules as non-present
        set_modules_non_present(None, pgd)
        # Remove all the modules that are not marked as present
        clean_non_present_modules(None, pgd)
Exemplo n.º 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
    '''
    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
Exemplo n.º 3
0
def linux_update_modules(pgd, update_symbols=False):
    from utils import ConfigurationManager as conf_m
    import volatility.obj as obj
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules

    if conf_m.addr_space is None:
        linux_init_address_space()

    # pgd == 0 means that kernel modules have been requested
    if pgd == 0:

        # 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 = []

        # Now, update the kernel modules
        modules_addr = conf_m.addr_space.profile.get_symbol("modules")
        modules = obj.Object("list_head",
                             vm=conf_m.addr_space,
                             offset=modules_addr)

        # Add the initial list pointer as a list entry
        # modules_addr is the offset of a list_head (2 pointers) that points to the
        # first entry of a module list of type module.
        list_entry_regions.append((modules_addr, modules_addr, modules.size()))

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

        for module in modules.list_of_type("module", "list"):
            """
            pp_debug("Module: %s - %x - %x - %x - %x - %x\n" % (module.name,
                                                                module.obj_offset,
                                                                module.module_init,
                                                                module.init_size,
                                                                module.module_core,
                                                                module.core_size))

            secs = []
            for section in module.get_sections():
                secs.append({"name": section.sect_name, "addr": section.address })

            for section in sorted(secs, key = lambda k: k["addr"]):
                pp_debug("    %s - %x\n" % (section["name"],section["addr"]))
            """

            if list_entry_size is None:
                list_entry_size = module.list.size()
            # The 'module' type has a field named list of type list_head, that points
            # to the next module in the linked list.
            entry = (module.obj_offset, module.list.obj_offset,
                     list_entry_size)
            if entry not in list_entry_regions:
                list_entry_regions.append(entry)

            # First, create a module for the "module_core", that contains
            # .text, readonly data and writable data
            if module.module_core != 0 and module.core_size != 0:
                linux_insert_kernel_module(module,
                                           long(module.module_core.v()),
                                           long(module.core_size.v()),
                                           str(module.name), str(module.name),
                                           update_symbols)
            # Now, check if there is "module_init" region, which will contain init sections such as .init.text , init
            # readonly and writable data...
            if module.module_init != 0 and module.init_size != 0:
                linux_insert_kernel_module(module, module.module_init.v(),
                                           module.init_size.v(),
                                           module.name + "/module_init",
                                           module.name + "/module_init",
                                           update_symbols)
            else:
                # If there is no module_init, check if there is any section
                # outside the module_core region
                secs = []
                for section in module.get_sections():
                    if section.address < module.module_core or section.address >= (
                            module.module_core + module.core_size):
                        secs.append(section)
                if len(secs) > 0:
                    # Now, compute the range of sections and put them into a
                    # module_init module block
                    secs = sorted(secs, key=lambda k: k.address)
                    start = secs[0].address
                    # Address of the last section + 0x4000 cause we do not know
                    # the size
                    size = (secs[-1].address + 0x4000) - secs[0].address
                    linux_insert_kernel_module(module, start, size,
                                               module.name + "/module_init",
                                               module.name + "/module_init",
                                               update_symbols)

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

    # If pgd != 0 was requested

    tasks = []

    init_task_addr = conf_m.addr_space.profile.get_symbol("init_task")
    init_task = obj.Object("task_struct",
                           vm=conf_m.addr_space,
                           offset=init_task_addr)

    # walk the ->tasks list, note that this will *not* display "swapper"
    for task in init_task.tasks:
        tasks.append(task)

    # List of tasks (threads) whose pgd is equal to the pgd to update
    tasks_to_update = []

    # First task in the list with a valid pgd
    for task in tasks:
        # Certain kernel threads do not have a memory map (they just take the pgd / memory map of
        # the thread that was previously executed, because the kernel is mapped
        # in all the threads.
        if task.mm:
            phys_pgd = conf_m.addr_space.vtop(task.mm.pgd) or task.mm.pgd
            if phys_pgd == pgd:
                tasks_to_update.append(task)

    # 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 = []

    for task in tasks_to_update:
        phys_pgd = conf_m.addr_space.vtop(task.mm.pgd) or task.mm.pgd

        # Mark all modules as non-present
        set_modules_non_present(task.pid.v(), phys_pgd)

        # Add the initial list pointer as a list entry
        list_entry_regions.append(
            (task.mm.mmap.obj_offset, task.mm.mmap.obj_offset,
             task.mm.mmap.size()))

        for vma in task.get_proc_maps():
            if list_entry_size is None:
                list_entry_size = vma.vm_next.size()
            entry = (vma.obj_offset, vma.vm_next.obj_offset, list_entry_size)
            if entry not in list_entry_regions:
                list_entry_regions.append(entry)

            (fname, major, minor, ino, pgoff) = vma.info(task)
            # Only add the module if the inode is not 0 (it is an actual module
            # and not a heap region
            if ino != 0:
                # Checksum
                linux_insert_module(
                    task, task.pid.v(), Address(phys_pgd),
                    Address(vma.vm_start),
                    Address(vma.vm_end) - Address(vma.vm_start),
                    os.path.basename(fname), fname, update_symbols)

        # Remove all the modules that are not marked as present
        clean_non_present_modules(task.pid.v(), phys_pgd)

    return list_entry_regions
Exemplo n.º 4
0
def linux_update_modules(pgd, update_symbols=False):
    from utils import ConfigurationManager as conf_m
    import volatility.obj as obj
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules

    if conf_m.addr_space is None:
        linux_init_address_space()

    # pgd == 0 means that kernel modules have been requested
    if pgd == 0:

        # 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 = []

        # Now, update the kernel modules
        modules_addr = conf_m.addr_space.profile.get_symbol("modules")
        modules = obj.Object(
            "list_head", vm=conf_m.addr_space, offset=modules_addr)

        # Add the initial list pointer as a list entry
        # modules_addr is the offset of a list_head (2 pointers) that points to the
        # first entry of a module list of type module.
        list_entry_regions.append((modules_addr, modules_addr, modules.size()))

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

        for module in modules.list_of_type("module", "list"):
            """
            pp_debug("Module: %s - %x - %x - %x - %x - %x\n" % (module.name,
                                                                module.obj_offset,
                                                                module.module_init,
                                                                module.init_size,
                                                                module.module_core,
                                                                module.core_size))

            secs = []
            for section in module.get_sections():
                secs.append({"name": section.sect_name, "addr": section.address })

            for section in sorted(secs, key = lambda k: k["addr"]):
                pp_debug("    %s - %x\n" % (section["name"],section["addr"]))
            """

            if list_entry_size is None:
                list_entry_size = module.list.size()
            # The 'module' type has a field named list of type list_head, that points
            # to the next module in the linked list.
            entry = (module.obj_offset, module.list.obj_offset, list_entry_size)
            if entry not in list_entry_regions:
                list_entry_regions.append(entry)

            # First, create a module for the "module_core", that contains
            # .text, readonly data and writable data
            if module.module_core != 0 and module.core_size != 0:
                linux_insert_kernel_module(module, long(module.module_core.v()), long(
                    module.core_size.v()), str(module.name), str(module.name), update_symbols)
            # Now, check if there is "module_init" region, which will contain init sections such as .init.text , init
            # readonly and writable data...
            if module.module_init != 0 and module.init_size != 0:
                linux_insert_kernel_module(module, module.module_init.v(), module.init_size.v(),
                                           module.name + "/module_init", module.name + "/module_init",
                                           update_symbols)
            else:
                # If there is no module_init, check if there is any section
                # outside the module_core region
                secs = []
                for section in module.get_sections():
                    if section.address < module.module_core or section.address >= (module.module_core + module.core_size):
                        secs.append(section)
                if len(secs) > 0:
                    # Now, compute the range of sections and put them into a
                    # module_init module block
                    secs = sorted(secs, key=lambda k: k.address)
                    start = secs[0].address
                    # Address of the last section + 0x4000 cause we do not know
                    # the size
                    size = (secs[-1].address + 0x4000) - secs[0].address
                    linux_insert_kernel_module(module, start, size,
                                               module.name + "/module_init", module.name + "/module_init", update_symbols)

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

    # If pgd != 0 was requested
    
    tasks = []

    init_task_addr = conf_m.addr_space.profile.get_symbol("init_task")
    init_task = obj.Object(
        "task_struct", vm=conf_m.addr_space, offset=init_task_addr)

    # walk the ->tasks list, note that this will *not* display "swapper"
    for task in init_task.tasks:
        tasks.append(task)

    # List of tasks (threads) whose pgd is equal to the pgd to update
    tasks_to_update = []

    # First task in the list with a valid pgd
    for task in tasks:
        # Certain kernel threads do not have a memory map (they just take the pgd / memory map of
        # the thread that was previously executed, because the kernel is mapped
        # in all the threads.
        if task.mm:
            phys_pgd = conf_m.addr_space.vtop(task.mm.pgd) or task.mm.pgd
            if phys_pgd == pgd:
                tasks_to_update.append(task)

    # 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 = []

    for task in tasks_to_update:
        phys_pgd = conf_m.addr_space.vtop(task.mm.pgd) or task.mm.pgd

        # Mark all modules as non-present
        set_modules_non_present(task.pid.v(), phys_pgd)

        # Add the initial list pointer as a list entry
        list_entry_regions.append((task.mm.mmap.obj_offset, task.mm.mmap.obj_offset, task.mm.mmap.size()))

        for vma in task.get_proc_maps():
            if list_entry_size is None:
                list_entry_size = vma.vm_next.size()
            entry = (vma.obj_offset, vma.vm_next.obj_offset, list_entry_size)
            if entry not in list_entry_regions:
                list_entry_regions.append(entry)

            (fname, major, minor, ino, pgoff) = vma.info(task)
            # Only add the module if the inode is not 0 (it is an actual module
            # and not a heap region
            if ino != 0:
                # Checksum
                linux_insert_module(task, task.pid.v(),
                                    Address(phys_pgd),
                                    Address(vma.vm_start),
                                    Address(vma.vm_end) - Address(
                                        vma.vm_start),
                                    os.path.basename(fname),
                                    fname,
                                    update_symbols)

        # Remove all the modules that are not marked as present
        clean_non_present_modules(task.pid.v(), phys_pgd)

    return list_entry_regions
Exemplo n.º 5
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 
Exemplo n.º 6
0
def module_change_callback(pgd, bp_vaddr, bp_haddr, params):
    '''
    Callback function triggered whenever there is a change in the list of linked
    modules for a given process.
 
    Updates the module list for that PGD (or kernel).
    ''' 
    import functools
    import struct
    import api
    from api import BP
    from vmi import update_modules
    from utils import pp_error
    from vmi import set_modules_non_present
    from vmi import clean_non_present_modules

    cpu_index = params["cpu_index"]
    vaddr = params["vaddr"]
    size = params["size"]
    haddr = params["haddr"]
    data = params["data"]

    # First, we check if the memory address written points to a module
    # that we have already detected (it is in our list of hooking points).
    # In this way we avoid triggering one update operation for every
    # modified pointer (inserting a module requires to change several
    # pointers, due to the different linked lists).
   
    # Return if it points inside a module that we have already added to our list
    for module_base, hook_addr, hook_size in module_load_remove_breakpoints[pgd]:
        if data >= module_base and data < (hook_addr + hook_size):
            return

    hooking_points = update_modules(pgd)

    if hooking_points is not None:
        # Update hooking points
        # 1) Remove the breakpoints not used anymore
        bps_to_remove = []
        for hp in module_load_remove_breakpoints[pgd]:
            if hp not in hooking_points:
                bps_to_remove.append(hp)

        for hp in bps_to_remove:
            module_load_remove_breakpoints[pgd][hp].disable()
            del module_load_remove_breakpoints[pgd][hp]

        # 2) Add new breakpoints
        for hp in hooking_points:
            if hp not in module_load_remove_breakpoints[pgd]:
                 module_base, addr, size = hp
                 haddr = api.va_to_pa(pgd, addr)
                 bp = BP(haddr,
                         None,
                         size = size,
                         typ = BP.MEM_WRITE_PHYS,
                         func = functools.partial(module_change_callback, pgd, addr, haddr),
                         new_style = True)
                 module_load_remove_breakpoints[pgd][hp] = bp
                 bp.enable()
    else:
        # Just remove all the  modules for the process
        # Mark all modules as non-present
        set_modules_non_present(None, pgd)
        # Remove all the modules that are not marked as present
        clean_non_present_modules(None, pgd)