Give ruby Modules that wrap Metasploit modules a name

[#36737359]

active_support/dependencies cannot resolve missing constants in Metasploit
modules because the wrapper module is anonymous.  In order to make the
wrapper module non-anonymous, the module must be assigned to a constant.
Since we don't want modules colliding, the wrapper module needs a unique
name, so use the module lookup name to derive the proper nested module names
to namespace the wrapper module.  All derived modules are nested under
Msf::Modules.  The name derivation handles invalid characters for constant
names such as digits as the first character or non-alphanumeric character.
The invalid constant name characters are converted to their hex value and
prefixed with X, so '-' in a name become 'X2d'.
This commit is contained in:
Luke Imhoff 2012-09-27 12:52:09 -05:00
parent 8b8da0b370
commit 8a2dc0a09f
2 changed files with 65 additions and 1 deletions

6
.gitignore vendored
View File

@ -1,3 +1,7 @@
# Rubymine project directory
.idea
# Mac OS X files
.DS_Store
data/meterpreter/ext_server_pivot.dll
data/meterpreter/ext_server_pivot.x64.dll
external/source/meterpreter/java/bin
@ -5,6 +9,8 @@ external/source/meterpreter/java/build
external/source/meterpreter/java/extensions
external/source/javapayload/bin
external/source/javapayload/build
# Packaging directory
pkg
tags
*.swp
*.orig

View File

@ -860,8 +860,9 @@ protected
added = nil
wrap = self.class.wrapper_module(name)
begin
wrap = ::Module.new
wrap.module_eval(load_module_source(file), file)
if(wrap.const_defined?(:RequiredVersions))
mins = wrap.const_get(:RequiredVersions)
@ -1124,6 +1125,63 @@ protected
attr_accessor :module_failed # :nodoc:
attr_accessor :enabled_types # :nodoc:
# 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.
#
# @return [Module] Msf::Modules::<name>
def self.wrapper_module(name)
relative_module_name = name.camelize
fully_qualified_module_name = "#{parent.name}::Modules::#{relative_module_name}"
wrapper_module = Object
module_names = fully_qualified_module_name.split('::')
until module_names.empty?
parent = wrapper_module
child_name = module_names.shift
# constant names can't contain a leading digit or any non-alphanumeric characters, so convert to hexcode with
# 'X' prefix.
child_name = child_name.gsub(/^[0-9]|[^A-Za-z0-9]/) do |invalid_constant_name_character|
unpacked = invalid_constant_name_character.unpack('H*')
# unpack always returns an array, so get first value to get character's encoding
hex_code = unpacked[0]
# as a convention start each hex-code with X so that it'll make a valid constant name since constants can't
# start with digits.
"X#{hex_code}"
end
# don't look for constants in ancestors since the namespace modules should be defined directly on the parent and
# previously by this same method.
inherit = false
if module_names.empty? and parent.const_defined?(child_name, inherit)
ilog("Removing #{child_name} constant from #{parent.name} so it can be reloaded", 'core', LEV_1)
# if this is the leaf module name then it needs to be destroyed and recreated if it already exists as this is
# a reload
# remove_const is private, so invoke in instance context
parent.instance_eval do
remove_const child_name
end
end
if parent.const_defined?(child_name, inherit)
wrapper_module = parent.const_get(child_name)
else
# stub module to represent namespace
# use ruby Module, not Msf::Module
namespace_module = ::Module.new
ilog("Adding #{child_name} constant to #{parent.name} as a namespace Module", 'core', LEV_1)
# once it's assigned to a constant, then wrapper_module.name will work.
wrapper_module = parent.const_set(child_name, namespace_module)
end
end
wrapper_module
end
end
end