Skip to content

Commit e11277f

Browse files
committed
Update reloading.rb
1 parent 9470a8b commit e11277f

File tree

1 file changed

+35
-41
lines changed

1 file changed

+35
-41
lines changed

lib/msf/core/module_manager/reloading.rb

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -43,63 +43,57 @@ def reload_module(mod)
4343

4444
private
4545

46-
# Reload payload modules by clearing and reloading the entire payload set
47-
# This is necessary because payloads have complex interdependencies
46+
# Reloads a payload module. This must be done by reloading the entire parent
47+
# directory to ensure the framework's complex payload "stitching" process
48+
# (combining stages, stagers, and mixins) is correctly executed. This is slower
49+
# but guarantees a fully-functional reloaded module.
4850
def reload_payload_module(metasploit_class, original_instance = nil)
49-
module_type = 'payload'
50-
module_reference_name = metasploit_class.fullname.sub(%r{^payload/}, '')
51-
52-
# Store original datastore if we have an instance
53-
original_datastore = original_instance&.datastore.copy
51+
# Step 1: Get all necessary identifiers from the original module class.
52+
fullname = metasploit_class.fullname
53+
refname = metasploit_class.refname
54+
type = metasploit_class.type
55+
file_path = metasploit_class.file_path
56+
57+
# Store the original datastore so we can restore its state.
58+
original_datastore = original_instance&.datastore&.copy
59+
60+
# Step 2: Manually purge the old module from the framework's caches.
61+
module_set.delete(module_reference_name) if module_set
62+
if (aliases_for_fullname = inv_aliases[fullname])
63+
aliases_for_fullname.each { |a| aliases.delete(a) }
64+
inv_aliases.delete(fullname)
65+
end
5466

55-
# Clear the specific payload from the module set
56-
module_set = module_set_by_type.fetch(module_type,nil)
57-
module_set.delete(module_reference_name) if module_set
67+
# Step 3: Get the module's parent directory path.
68+
module_info = module_info_by_path[file_path]
69+
unless module_info && (parent_path = module_info[:parent_path])
70+
raise Msf::LoadError, "Could not find cached module information for path: #{file_path}"
71+
end
5872

59-
# For payloads, we need to reload the entire payload ecosystem
60-
# because of stage/stager dependencies
61-
reload_payload_set
73+
# Step 4: Use the core framework loader to reload the entire parent directory.
74+
# This is the only way to reliably trigger the payload stitching logic.
75+
load_modules(parent_path, force: true)
6276

63-
# Try to get the reloaded module class
64-
reloaded_module_class = module_set_by_type[module_type][module_reference_name]
77+
# Step 5: Now that the framework has completed its full reload process,
78+
# use the public API to get a new instance of our reloaded module.
79+
new_instance = framework.modules.create(fullname)
6580

66-
if reloaded_module_class.blank?
67-
raise "Failed to reload payload module: #{metasploit_class.fullname} not found after reload"
81+
if new_instance.blank?
82+
raise "Failed to create a new instance of #{fullname} after reloading. The module file may be broken."
6883
end
6984

70-
# Create a new instance of the reloaded module
71-
new_instance = reloaded_module_class.new
72-
73-
# Restore the original datastore if we had one
85+
# Step 6: Restore the datastore to the new, fully-functional instance.
7486
if original_datastore
7587
new_instance.datastore.merge!(original_datastore)
7688
end
7789

90+
# Return the new instance, which the framework will make the active module.
7891
return new_instance
7992
rescue StandardError => e
80-
elog("Failed to reload payload #{metasploit_class.fullname}: #{e.message}")
93+
elog("Failed to reload payload #{fullname}: #{e.message}")
8194
raise "Failed to reload payload: #{e.message}"
8295
end
8396

84-
# Reload the entire payload module set
85-
def reload_payload_set
86-
module_type = 'payload'
87-
88-
# Clear existing payload modules
89-
module_set_by_type.fetch(module_type,nil)&.clear
90-
91-
# Reinitialize the payload module set
92-
init_module_set(module_type)
93-
94-
# Reload payloads from all module paths
95-
module_paths.each do |path|
96-
# Load payloads with force flag to ensure reload
97-
load_modules(path, type: [module_type], force: true)
98-
rescue StandardError => e
99-
wlog("Warning: Could not reload payloads from #{path}: #{e.message}")
100-
end
101-
end
102-
10397
public
10498

10599
# Reloads modules from all module paths

0 commit comments

Comments
 (0)