Fix module reloading
[#36737359] The merging of reload_module and the various load_module methods resulted in the module loading from disk, but because the Hash entry in the module manager was not deleted before on_module_load was called, the newly reloaded module was logged as an ambiguous module name instead of a reload. In order to report the reload errors correctly, I determined that module_load_error_by_reference_name should really be module_load_error_by_path. I eliminated faild in favor of this new name since failed was just calling the attribute and the attribute's name is clearer about the format of the data. Tested by run rexploit and then exiting over and over with ms08_067_netapi. When I messed up the file so it couldn't load, by adding `inclde Exploit` (note mispelling of `include`), it reported the error to msfconsole. When I removed the bad line and added a puts "RELOADING <n>", where I kept incrementing n and saving the file, the new number appeared during each rexploit.unstable
parent
daf9f9abe8
commit
df9db42c32
|
@ -100,7 +100,7 @@ module Msf
|
||||||
|
|
||||||
self.module_info_by_path = {}
|
self.module_info_by_path = {}
|
||||||
self.enablement_by_type = {}
|
self.enablement_by_type = {}
|
||||||
self.module_load_error_by_reference_name = {}
|
self.module_load_error_by_path = {}
|
||||||
self.module_paths = []
|
self.module_paths = []
|
||||||
self.module_set_by_type = {}
|
self.module_set_by_type = {}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,6 @@ module Msf::ModuleManager::Loading
|
||||||
Msf::Modules::Loader::Directory
|
Msf::Modules::Loader::Directory
|
||||||
]
|
]
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the set of modules that failed to load.
|
|
||||||
#
|
|
||||||
def failed
|
|
||||||
return module_load_error_by_reference_name
|
|
||||||
end
|
|
||||||
|
|
||||||
def file_changed?(path)
|
def file_changed?(path)
|
||||||
changed = false
|
changed = false
|
||||||
|
|
||||||
|
@ -58,7 +51,7 @@ module Msf::ModuleManager::Loading
|
||||||
changed
|
changed
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_accessor :module_load_error_by_reference_name
|
attr_accessor :module_load_error_by_path
|
||||||
|
|
||||||
# Called when a module is initially loaded such that it can be
|
# Called when a module is initially loaded such that it can be
|
||||||
# categorized accordingly.
|
# categorized accordingly.
|
||||||
|
|
|
@ -77,6 +77,7 @@ class Msf::Modules::Loader::Base
|
||||||
raise ::NotImplementedError
|
raise ::NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Loads a module from the supplied path and module_reference_name.
|
# Loads a module from the supplied path and module_reference_name.
|
||||||
#
|
#
|
||||||
# @param [String] parent_path The path under which the module exists. This is not necessarily the same path as passed
|
# @param [String] parent_path The path under which the module exists. This is not necessarily the same path as passed
|
||||||
|
@ -88,6 +89,7 @@ class Msf::Modules::Loader::Base
|
||||||
# @option options [Boolean] :force (false) whether to force loading of the module even if the module has not changed.
|
# @option options [Boolean] :force (false) whether to force loading of the module even if the module has not changed.
|
||||||
# @option options [Hash{String => Boolean}] :recalculate_by_type Maps type to whether its
|
# @option options [Hash{String => Boolean}] :recalculate_by_type Maps type to whether its
|
||||||
# {Msf::ModuleManager::ModuleSets#module_set} needs to be recalculated.
|
# {Msf::ModuleManager::ModuleSets#module_set} needs to be recalculated.
|
||||||
|
# @option options [Boolean] :reload (false) whether this is a reload.
|
||||||
# @return [false] if :force is false and parent_path has not changed.
|
# @return [false] if :force is false and parent_path has not changed.
|
||||||
# @return [false] if exception encountered while parsing module content
|
# @return [false] if exception encountered while parsing module content
|
||||||
# @return [false] if the module is incompatible with the Core or API version.
|
# @return [false] if the module is incompatible with the Core or API version.
|
||||||
|
@ -98,8 +100,9 @@ class Msf::Modules::Loader::Base
|
||||||
# @see #read_module_content
|
# @see #read_module_content
|
||||||
# @see Msf::ModuleManager::Loading#file_changed?
|
# @see Msf::ModuleManager::Loading#file_changed?
|
||||||
def load_module(parent_path, type, module_reference_name, options={})
|
def load_module(parent_path, type, module_reference_name, options={})
|
||||||
options.assert_valid_keys(:count_by_type, :force, :recalculate_by_type)
|
options.assert_valid_keys(:count_by_type, :force, :recalculate_by_type, :reload)
|
||||||
force = options[:force] || false
|
force = options[:force] || false
|
||||||
|
reload = options[:reload] || false
|
||||||
|
|
||||||
unless force or module_manager.file_changed?(parent_path)
|
unless force or module_manager.file_changed?(parent_path)
|
||||||
dlog("Cached module from #{parent_path} has not changed.", 'core', LEV_2)
|
dlog("Cached module from #{parent_path} has not changed.", 'core', LEV_2)
|
||||||
|
@ -107,13 +110,14 @@ class Msf::Modules::Loader::Base
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace_module = self.namespace_module(module_reference_name)
|
metasploit_class = nil
|
||||||
|
module_path = self.module_path(parent_path, type, module_reference_name)
|
||||||
|
|
||||||
|
loaded = namespace_module_transaction(module_reference_name, :reload => reload) { |namespace_module|
|
||||||
# set the parent_path so that the module can be reloaded with #load_module
|
# set the parent_path so that the module can be reloaded with #load_module
|
||||||
namespace_module.parent_path = parent_path
|
namespace_module.parent_path = parent_path
|
||||||
|
|
||||||
module_content = read_module_content(parent_path, type, module_reference_name)
|
module_content = read_module_content(parent_path, type, module_reference_name)
|
||||||
module_path = self.module_path(parent_path, type, module_reference_name)
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
namespace_module.module_eval_with_lexical_scope(module_content, module_path)
|
namespace_module.module_eval_with_lexical_scope(module_content, module_path)
|
||||||
|
@ -130,7 +134,8 @@ class Msf::Modules::Loader::Base
|
||||||
error_message = "#{error.class} #{error}"
|
error_message = "#{error.class} #{error}"
|
||||||
end
|
end
|
||||||
|
|
||||||
module_manager.module_load_error_by_reference_name[module_reference_name] = error_message
|
# record the error message without the backtrace for the console
|
||||||
|
module_manager.module_load_error_by_path[module_path] = error_message
|
||||||
|
|
||||||
error_message_with_backtrace = "#{error_message}:\n#{error.backtrace.join("\n")}"
|
error_message_with_backtrace = "#{error_message}:\n#{error.backtrace.join("\n")}"
|
||||||
elog(error_message_with_backtrace)
|
elog(error_message_with_backtrace)
|
||||||
|
@ -144,7 +149,7 @@ class Msf::Modules::Loader::Base
|
||||||
error_message = version_compatibility_error.to_s
|
error_message = version_compatibility_error.to_s
|
||||||
|
|
||||||
elog(error_message)
|
elog(error_message)
|
||||||
module_manager.module_load_error_by_reference_name[module_reference_name] = error_message
|
module_manager.module_load_error_by_path[module_path] = error_message
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -155,19 +160,38 @@ class Msf::Modules::Loader::Base
|
||||||
error_message = "Missing Metasploit class constant"
|
error_message = "Missing Metasploit class constant"
|
||||||
|
|
||||||
elog(error_message)
|
elog(error_message)
|
||||||
module_manager.module_load_error_by_reference_name[module_reference_name] = error_message
|
module_manager.module_load_error_by_path[module_path] = error_message
|
||||||
|
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
unless usable?(metasploit_class)
|
unless usable?(metasploit_class)
|
||||||
ilog("Skipping module #{module_reference_name} under #{parent_path} because is_usable returned false.", 'core', LEV_1)
|
ilog(
|
||||||
|
"Skipping module #{module_reference_name} under #{parent_path} because is_usable returned false.",
|
||||||
|
'core',
|
||||||
|
LEV_1
|
||||||
|
)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
ilog("Loaded #{type} module #{module_reference_name} under #{parent_path}", 'core', LEV_2)
|
ilog("Loaded #{type} module #{module_reference_name} under #{parent_path}", 'core', LEV_2)
|
||||||
|
|
||||||
# if this is a reload, then there may be a pre-existing error that should now be cleared
|
module_manager.module_load_error_by_path.delete(module_path)
|
||||||
module_manager.module_load_error_by_reference_name.delete(module_reference_name)
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
unless loaded
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if reload
|
||||||
|
# Delete the original copy of the module so that module_manager.on_load_module called from inside load_module does
|
||||||
|
# not trigger an ambiguous name warning, which would cause the reloaded module to not be stored in the
|
||||||
|
# ModuleManager.
|
||||||
|
module_manager.delete(module_reference_name)
|
||||||
|
end
|
||||||
|
|
||||||
# Do some processing on the loaded module to get it into the right associations
|
# Do some processing on the loaded module to get it into the right associations
|
||||||
module_manager.on_module_load(
|
module_manager.on_module_load(
|
||||||
|
@ -266,7 +290,8 @@ class Msf::Modules::Loader::Base
|
||||||
|
|
||||||
dlog("Reloading module #{module_reference_name}...", 'core')
|
dlog("Reloading module #{module_reference_name}...", 'core')
|
||||||
|
|
||||||
if load_module(parent_path, type, module_reference_name, :force => true)
|
|
||||||
|
if load_module(parent_path, type, module_reference_name, :force => true, :reload => true)
|
||||||
# Create a new instance of the module
|
# Create a new instance of the module
|
||||||
reloaded_module_instance = module_manager.create(module_reference_name)
|
reloaded_module_instance = module_manager.create(module_reference_name)
|
||||||
|
|
||||||
|
@ -278,14 +303,13 @@ class Msf::Modules::Loader::Base
|
||||||
else
|
else
|
||||||
elog("Failed to create instance of #{refname} after reload.", 'core')
|
elog("Failed to create instance of #{refname} after reload.", 'core')
|
||||||
|
|
||||||
# Return the old module instance to avoid a strace trace
|
# Return the old module instance to avoid an strace trace
|
||||||
return original_metasploit_class_or_instance
|
return original_metasploit_class_or_instance
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
elog("Failed to reload #{module_reference_name}")
|
elog("Failed to reload #{module_reference_name}")
|
||||||
|
|
||||||
# Return the old module isntance to avoid a strace trace
|
return nil
|
||||||
return original_metasploit_class_or_instance
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Let the specific module sets have an opportunity to handle the fact
|
# Let the specific module sets have an opportunity to handle the fact
|
||||||
|
@ -301,6 +325,66 @@ class Msf::Modules::Loader::Base
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
# Returns a nested module to wrap the Metasploit(1|2|3) class so that it doesn't overwrite other (metasploit)
|
||||||
|
# module's classes. The wrapper module must be named so that active_support's autoloading code doesn't break when
|
||||||
|
# searching constants from inside the Metasploit(1|2|3) class.
|
||||||
|
#
|
||||||
|
# @param [String] namespace_module_names (see #{namespace_module_names})
|
||||||
|
# @return [Module] module that can wrap the module content from {#read_module_content} using
|
||||||
|
# module_eval_with_lexical_scope.
|
||||||
|
#
|
||||||
|
# @see NAMESPACE_MODULE_CONTENT
|
||||||
|
def create_namespace_module(namespace_module_names)
|
||||||
|
# In order to have constants defined in Msf resolve without the Msf qualifier in the module_content, the
|
||||||
|
# Module.nesting must resolve for the entire nesting. Module.nesting is strictly lexical, and can't be faked with
|
||||||
|
# module_eval(&block). (There's actually code in ruby's implementation to stop module_eval from being added to
|
||||||
|
# Module.nesting when using the block syntax.) All this means is the modules have to be declared as a string that
|
||||||
|
# gets module_eval'd.
|
||||||
|
|
||||||
|
nested_module_names = namespace_module_names.reverse
|
||||||
|
|
||||||
|
namespace_module_content = nested_module_names.inject(NAMESPACE_MODULE_CONTENT) { |wrapped_content, module_name|
|
||||||
|
lines = []
|
||||||
|
lines << "module #{module_name}"
|
||||||
|
lines << wrapped_content
|
||||||
|
lines << "end"
|
||||||
|
|
||||||
|
lines.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
# - because the added wrap lines have to act like they were written before NAMESPACE_MODULE_CONTENT
|
||||||
|
line_with_wrapping = NAMESPACE_MODULE_LINE - nested_module_names.length
|
||||||
|
Object.module_eval(namespace_module_content, __FILE__, line_with_wrapping)
|
||||||
|
|
||||||
|
# The namespace_module exists now, so no need to use constantize to do const_missing
|
||||||
|
namespace_module = current_module(namespace_module_names)
|
||||||
|
# record the loader, so that the namespace module and its metasploit_class can be reloaded
|
||||||
|
namespace_module.loader = self
|
||||||
|
|
||||||
|
namespace_module
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the module with {#module_names} if it exists.
|
||||||
|
#
|
||||||
|
# @param [Array<String>] module_names a list of module names to resolve from Object downward.
|
||||||
|
# @return [Module] module that wraps the previously loaded content from {#read_module_content}.
|
||||||
|
# @return [nil] if any module name along the chain does not exist.
|
||||||
|
def current_module(module_names)
|
||||||
|
# don't look at ancestors for constant
|
||||||
|
inherit = false
|
||||||
|
|
||||||
|
# Don't want to trigger ActiveSupport's const_missing, so can't use constantize.
|
||||||
|
named_module = module_names.inject(Object) { |parent, module_name|
|
||||||
|
if parent.const_defined?(module_name, inherit)
|
||||||
|
parent.const_get(module_name, inherit)
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
named_module
|
||||||
|
end
|
||||||
|
|
||||||
# Yields module reference names under path.
|
# Yields module reference names under path.
|
||||||
#
|
#
|
||||||
# @abstract Override and search the path for modules.
|
# @abstract Override and search the path for modules.
|
||||||
|
@ -362,76 +446,8 @@ class Msf::Modules::Loader::Base
|
||||||
path.gsub(/#{MODULE_EXTENSION}$/, '')
|
path.gsub(/#{MODULE_EXTENSION}$/, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a nested module to wrap the Metasploit(1|2|3) class so that it doesn't overwrite other (metasploit)
|
# Returns the fully-qualified name to the {#create_namespace_module} that wraps the module with the given module
|
||||||
# module's classes. The wrapper module must be named so that active_support's autoloading code doesn't break when
|
# reference name.
|
||||||
# searching constants from inside the Metasploit(1|2|3) class.
|
|
||||||
#
|
|
||||||
# @param [String] module_reference_name The canonical name for referring to the module that this namespace_module will
|
|
||||||
# wrap.
|
|
||||||
# @return [Module] module that can wrap the module content from {#read_module_content} using
|
|
||||||
# module_eval_with_lexical_scope.
|
|
||||||
#
|
|
||||||
# @see NAMESPACE_MODULE_CONTENT
|
|
||||||
def namespace_module(module_reference_name)
|
|
||||||
namespace_module_names = self.namespace_module_names(module_reference_name)
|
|
||||||
|
|
||||||
# If this is a reload, then the pre-existing namespace_module needs to be removed.
|
|
||||||
|
|
||||||
# don't check ancestors for the constants
|
|
||||||
inherit = false
|
|
||||||
|
|
||||||
# Don't want to trigger ActiveSupport's const_missing, so can't use constantize.
|
|
||||||
namespace_module = namespace_module_names.inject(Object) { |parent, module_name|
|
|
||||||
if parent.const_defined?(module_name, inherit)
|
|
||||||
parent.const_get(module_name, inherit)
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
# if a reload
|
|
||||||
unless namespace_module.nil?
|
|
||||||
parent_module = namespace_module.parent
|
|
||||||
|
|
||||||
# remove_const is private, so invoke in instance context
|
|
||||||
parent_module.instance_eval do
|
|
||||||
remove_const namespace_module_names.last
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# In order to have constants defined in Msf resolve without the Msf qualifier in the module_content, the
|
|
||||||
# Module.nesting must resolve for the entire nesting. Module.nesting is strictly lexical, and can't be faked with
|
|
||||||
# module_eval(&block). (There's actually code in ruby's implementation to stop module_eval from being added to
|
|
||||||
# Module.nesting when using the block syntax.) All this means is the modules have to be declared as a string that
|
|
||||||
# gets module_eval'd.
|
|
||||||
|
|
||||||
nested_module_names = namespace_module_names.reverse
|
|
||||||
|
|
||||||
namespace_module_content = nested_module_names.inject(NAMESPACE_MODULE_CONTENT) { |wrapped_content, module_name|
|
|
||||||
lines = []
|
|
||||||
lines << "module #{module_name}"
|
|
||||||
lines << wrapped_content
|
|
||||||
lines << "end"
|
|
||||||
|
|
||||||
lines.join("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
# - because the added wrap lines have to act like they were written before NAMESPACE_MODULE_CONTENT
|
|
||||||
line_with_wrapping = NAMESPACE_MODULE_LINE - nested_module_names.length
|
|
||||||
Object.module_eval(namespace_module_content, __FILE__, line_with_wrapping)
|
|
||||||
|
|
||||||
# The namespace_module exists now, so no need to use constantize to do const_missing
|
|
||||||
namespace_module = namespace_module_names.inject(Object) { |parent, module_name|
|
|
||||||
parent.const_get(module_name, inherit)
|
|
||||||
}
|
|
||||||
# record the loader, so that the namespace module and its metasploit_class can be reloaded
|
|
||||||
namespace_module.loader = self
|
|
||||||
|
|
||||||
namespace_module
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the fully-qualified name to the {#namespace_module} that wraps the module with the given module reference
|
|
||||||
# name.
|
|
||||||
#
|
#
|
||||||
# @param [String] module_reference_name The canonical name for referring to the module.
|
# @param [String] module_reference_name The canonical name for referring to the module.
|
||||||
# @return [String] name of module.
|
# @return [String] name of module.
|
||||||
|
@ -478,6 +494,49 @@ class Msf::Modules::Loader::Base
|
||||||
namespace_module_names
|
namespace_module_names
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def namespace_module_transaction(module_reference_name, options={}, &block)
|
||||||
|
options.assert_valid_keys(:reload)
|
||||||
|
|
||||||
|
reload = options[:reload] || false
|
||||||
|
namespace_module_names = self.namespace_module_names(module_reference_name)
|
||||||
|
|
||||||
|
previous_namespace_module = current_module(namespace_module_names)
|
||||||
|
|
||||||
|
if previous_namespace_module and not reload
|
||||||
|
elog("Reloading namespace_module #{previous_namespace_module} when :reload => false")
|
||||||
|
end
|
||||||
|
|
||||||
|
if previous_namespace_module
|
||||||
|
parent_module = previous_namespace_module.parent
|
||||||
|
relative_name = namespace_module_names.last
|
||||||
|
|
||||||
|
# remove_const is private, so invoke in instance context
|
||||||
|
parent_module.instance_eval do
|
||||||
|
remove_const relative_name
|
||||||
|
end
|
||||||
|
else
|
||||||
|
parent_module = nil
|
||||||
|
relative_name = namespace_module_names.last
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace_module = create_namespace_module(namespace_module_names)
|
||||||
|
|
||||||
|
begin
|
||||||
|
loaded = block.call(namespace_module)
|
||||||
|
rescue Exception
|
||||||
|
restore_namespace_module(parent_module, relative_name, previous_namespace_module)
|
||||||
|
|
||||||
|
# re-raise the original exception in the original context
|
||||||
|
raise
|
||||||
|
else
|
||||||
|
unless loaded
|
||||||
|
restore_namespace_module(parent_module, relative_name, previous_namespace_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
loaded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Read the content of the module from under path.
|
# Read the content of the module from under path.
|
||||||
#
|
#
|
||||||
# @abstract Override to read the module content based on the method of the loader subclass and return a string.
|
# @abstract Override to read the module content based on the method of the loader subclass and return a string.
|
||||||
|
@ -485,11 +544,30 @@ class Msf::Modules::Loader::Base
|
||||||
# @param parent_path (see #load_module)
|
# @param parent_path (see #load_module)
|
||||||
# @param type (see #load_module)
|
# @param type (see #load_module)
|
||||||
# @param module_reference_name (see #load_module)
|
# @param module_reference_name (see #load_module)
|
||||||
# @return [String] module content that can be module_evaled into the {#namespace_module}
|
# @return [String] module content that can be module_evaled into the {#create_namespace_module}
|
||||||
def read_module_content(parent_path, type, module_reference_name)
|
def read_module_content(parent_path, type, module_reference_name)
|
||||||
raise ::NotImplementedError
|
raise ::NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Restores the namespace module to it's original name under it's original parent Module if there was a previous
|
||||||
|
# namespace module.
|
||||||
|
#
|
||||||
|
# @param [Module] parent_module The .parent of namespace_module before it was removed from the constant tree.
|
||||||
|
# @param [String] relative_name The name of the constant under parent_module where namespace_module was attached.
|
||||||
|
# @param [Module] namespace_module The previous namespace module containing the old module content.
|
||||||
|
# @return [void]
|
||||||
|
def restore_namespace_module(parent_module, relative_name, namespace_module)
|
||||||
|
if parent_module and namespace_module
|
||||||
|
# the const may have been redefined by {#create_namespace_module}, in which case that new namespace_module needs
|
||||||
|
# to be removed so the original can replace it.
|
||||||
|
if parent_module.const_defined? relative_name
|
||||||
|
remove_const relative_name
|
||||||
|
end
|
||||||
|
|
||||||
|
parent_module.const_set(relative_name, namespace_module)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# The path to the module qualified by the type directory.
|
# The path to the module qualified by the type directory.
|
||||||
#
|
#
|
||||||
# @param [String] type The type of the module.
|
# @param [String] type The type of the module.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Error raised by {Msf::Modules::Namespace#version_compatible!} on {Msf::Modules::Loader::Base#namespace_module} if the
|
# Error raised by {Msf::Modules::Namespace#version_compatible!} on {Msf::Modules::Loader::Base#create_namespace_module}
|
||||||
# API or Core version does not meet the minimum requirements defined in the RequiredVersions constant in the
|
# if the API or Core version does not meet the minimum requirements defined in the RequiredVersions constant in the
|
||||||
# {Msf::Modules::Loader::Base#read_module_content module content}.
|
# {Msf::Modules::Loader::Base#read_module_content module content}.
|
||||||
class Msf::Modules::VersionCompatibilityError < StandardError
|
class Msf::Modules::VersionCompatibilityError < StandardError
|
||||||
# @param [Hash{Symbol => Float}] attributes
|
# @param [Hash{Symbol => Float}] attributes
|
||||||
|
|
|
@ -525,12 +525,14 @@ class Driver < Msf::Ui::Driver
|
||||||
#
|
#
|
||||||
def on_startup(opts = {})
|
def on_startup(opts = {})
|
||||||
# Check for modules that failed to load
|
# Check for modules that failed to load
|
||||||
if (framework.modules.failed.length > 0)
|
if framework.modules.module_load_error_by_path.length > 0
|
||||||
print_error("WARNING! The following modules could not be loaded!")
|
print_error("WARNING! The following modules could not be loaded!")
|
||||||
framework.modules.failed.each_pair do |file, err|
|
|
||||||
print_error("\t#{file}: #{err}")
|
framework.modules.module_load_error_by_path.each do |path, error|
|
||||||
|
print_error("\t#{path}: #{error}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
framework.events.on_ui_start(Msf::Framework::Revision)
|
framework.events.on_ui_start(Msf::Framework::Revision)
|
||||||
|
|
||||||
run_single("banner") unless opts['DisableBanner']
|
run_single("banner") unless opts['DisableBanner']
|
||||||
|
|
|
@ -88,17 +88,22 @@ module ModuleCommandDispatcher
|
||||||
|
|
||||||
print_status('Reloading module...')
|
print_status('Reloading module...')
|
||||||
|
|
||||||
omod = self.mod
|
original_mod = self.mod
|
||||||
self.mod = framework.modules.reload_module(mod)
|
reloaded_mod = framework.modules.reload_module(original_mod)
|
||||||
|
|
||||||
if(not self.mod)
|
unless reloaded_mod
|
||||||
print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
error = framework.modules.module_load_error_by_path[original_mod.file_path]
|
||||||
self.mod = omod
|
|
||||||
return
|
print_error("Failed to reload module: #{error}")
|
||||||
end
|
|
||||||
|
self.mod = original_mod
|
||||||
|
else
|
||||||
|
self.mod = reloaded_mod
|
||||||
|
|
||||||
self.mod.init_ui(driver.input, driver.output)
|
self.mod.init_ui(driver.input, driver.output)
|
||||||
mod
|
end
|
||||||
|
|
||||||
|
reloaded_mod
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -496,14 +496,18 @@ class Console::CommandDispatcher::Core
|
||||||
# Framework instance. If we don't, or if no such module exists,
|
# Framework instance. If we don't, or if no such module exists,
|
||||||
# fall back to using the scripting interface.
|
# fall back to using the scripting interface.
|
||||||
if (msf_loaded? and mod = client.framework.modules.create(script_name))
|
if (msf_loaded? and mod = client.framework.modules.create(script_name))
|
||||||
omod = mod
|
original_mod = mod
|
||||||
mod = client.framework.modules.reload_module(mod)
|
reloaded_mod = client.framework.modules.reload_module(original_mod)
|
||||||
if (not mod)
|
|
||||||
print_error("Failed to reload module: #{client.framework.modules.failed[omod.file_path]}")
|
unless reloaded_mod
|
||||||
|
error = client.framework.modules.module_load_error_by_path[original_mod.file_path]
|
||||||
|
print_error("Failed to reload module: #{error}")
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
opts = (args + [ "SESSION=#{client.sid}" ]).join(',')
|
opts = (args + [ "SESSION=#{client.sid}" ]).join(',')
|
||||||
mod.run_simple(
|
reloaded_mod.run_simple(
|
||||||
#'RunAsJob' => true,
|
#'RunAsJob' => true,
|
||||||
'LocalInput' => shell.input,
|
'LocalInput' => shell.input,
|
||||||
'LocalOutput' => shell.output,
|
'LocalOutput' => shell.output,
|
||||||
|
|
7
msfcli
7
msfcli
|
@ -67,10 +67,11 @@ end
|
||||||
$stderr.puts "[*] Please wait while we load the module tree..."
|
$stderr.puts "[*] Please wait while we load the module tree..."
|
||||||
$framework = Msf::Simple::Framework.create
|
$framework = Msf::Simple::Framework.create
|
||||||
|
|
||||||
if ($framework.modules.failed.length > 0)
|
if ($framework.modules.module_load_error_by_path.length > 0)
|
||||||
print("Warning: The following modules could not be loaded!\n\n")
|
print("Warning: The following modules could not be loaded!\n\n")
|
||||||
$framework.modules.failed.each_pair do |file, err|
|
|
||||||
print("\t#{file}: #{err}\n\n")
|
$framework.modules.module_load_error_by_path.each do |path, error|
|
||||||
|
print("\t#{path}: #{error}\n\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue