f4476cb1b7
Instead of deleting all non-symbolics before the re-adding phase of PayloadSet#recalculate, store a list of old module names, populate a list of new ones during the re-adding phase, and finally remove any non-symbolic module that was in the old list but wasn't in the new list. Also includes a minor refactoring to make ModuleManager its own thing instead of being an awkard subclass of ModuleSet. Now PayloadSet doesn't need to know about the existence of framework.modules, which makes the separation a little more natural. [FixRM #7037]
131 lines
3.8 KiB
Ruby
131 lines
3.8 KiB
Ruby
#
|
|
# Gems
|
|
#
|
|
require 'active_support/concern'
|
|
|
|
# Concerns the module cache maintained by the {Msf::ModuleManager}.
|
|
module Msf::ModuleManager::Cache
|
|
extend ActiveSupport::Concern
|
|
|
|
# Returns whether the cache is empty
|
|
#
|
|
# @return [true] if the cache has no entries.
|
|
# @return [false] if the cache has any entries.
|
|
def cache_empty?
|
|
module_info_by_path.empty?
|
|
end
|
|
|
|
# Forces loading of the module with the given type and module reference name from the cache.
|
|
#
|
|
# @param [String] type the type of the module.
|
|
# @param [String] reference_name the module reference name.
|
|
# @return [false] if a module with the given type and reference name does not exist in the cache.
|
|
# @return (see Msf::Modules::Loader::Base#load_module)
|
|
def load_cached_module(type, reference_name)
|
|
loaded = false
|
|
|
|
module_info = self.module_info_by_path.values.find { |inner_info|
|
|
inner_info[:type] == type and inner_info[:reference_name] == reference_name
|
|
}
|
|
|
|
if module_info
|
|
parent_path = module_info[:parent_path]
|
|
|
|
loaders.each do |loader|
|
|
if loader.loadable?(parent_path)
|
|
type = module_info[:type]
|
|
reference_name = module_info[:reference_name]
|
|
|
|
loaded = loader.load_module(parent_path, type, reference_name, :force => true)
|
|
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
loaded
|
|
end
|
|
|
|
# Rebuild the cache for the module set
|
|
#
|
|
# @return [void]
|
|
def refresh_cache_from_module_files(mod = nil)
|
|
if framework_migrated?
|
|
if mod
|
|
framework.db.update_module_details(mod)
|
|
else
|
|
framework.db.update_all_module_details
|
|
end
|
|
|
|
refresh_cache_from_database
|
|
end
|
|
end
|
|
|
|
# Reset the module cache
|
|
#
|
|
# @return [void]
|
|
def refresh_cache_from_database
|
|
self.module_info_by_path_from_database!
|
|
end
|
|
|
|
protected
|
|
|
|
# Returns whether the framework migrations have been run already.
|
|
#
|
|
# @return [true] if migrations have been run
|
|
# @return [false] otherwise
|
|
def framework_migrated?
|
|
if framework.db and framework.db.migrated
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
# @!attribute [rw] module_info_by_path
|
|
# @return (see #module_info_by_path_from_database!)
|
|
attr_accessor :module_info_by_path
|
|
|
|
# Return a module info from Mdm::ModuleDetails in database.
|
|
#
|
|
# @note Also sets module_set(module_type)[module_reference_name] to Msf::SymbolicModule if it is not already set.
|
|
#
|
|
# @return [Hash{String => Hash{Symbol => Object}}] Maps path (Mdm::ModuleDetail#file) to module information. Module
|
|
# information is a Hash derived from Mdm::ModuleDetail. It includes :modification_time, :parent_path, :type,
|
|
# :reference_name.
|
|
def module_info_by_path_from_database!
|
|
self.module_info_by_path = {}
|
|
|
|
if framework_migrated?
|
|
# TODO record module parent_path in {Mdm::ModuleDetail} so it does not need to be derived from file.
|
|
::Mdm::ModuleDetail.find(:all).each do |module_detail|
|
|
path = module_detail.file
|
|
type = module_detail.mtype
|
|
reference_name = module_detail.refname
|
|
|
|
typed_path = Msf::Modules::Loader::Base.typed_path(type, reference_name)
|
|
escaped_typed_path = Regexp.escape(typed_path)
|
|
parent_path = path.gsub(/#{escaped_typed_path}$/, '')
|
|
|
|
module_info_by_path[path] = {
|
|
:reference_name => reference_name,
|
|
:type => type,
|
|
:parent_path => parent_path,
|
|
:modification_time => module_detail.mtime
|
|
}
|
|
|
|
typed_module_set = module_set(type)
|
|
|
|
# Don't want to trigger as {Msf::ModuleSet#create} so check for
|
|
# key instead of using ||= which would call {Msf::ModuleSet#[]}
|
|
# which would potentially call {Msf::ModuleSet#create}.
|
|
unless typed_module_set.has_key? reference_name
|
|
typed_module_set[reference_name] = Msf::SymbolicModule
|
|
end
|
|
end
|
|
end
|
|
|
|
self.module_info_by_path
|
|
end
|
|
end
|