@@ -43,63 +43,57 @@ def reload_module(mod)
43
43
44
44
private
45
45
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.
48
50
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
54
66
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
58
72
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 )
62
76
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 )
65
80
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. "
68
83
end
69
84
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.
74
86
if original_datastore
75
87
new_instance . datastore . merge! ( original_datastore )
76
88
end
77
89
90
+ # Return the new instance, which the framework will make the active module.
78
91
return new_instance
79
92
rescue StandardError => e
80
- elog ( "Failed to reload payload #{ metasploit_class . fullname } : #{ e . message } " )
93
+ elog ( "Failed to reload payload #{ fullname } : #{ e . message } " )
81
94
raise "Failed to reload payload: #{ e . message } "
82
95
end
83
96
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
-
103
97
public
104
98
105
99
# Reloads modules from all module paths
0 commit comments