lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb in librex-0.0.68 vs lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb in librex-0.0.70
- old
+ new
@@ -53,246 +53,248 @@
#
# The Railgun class to dynamically expose the Windows API.
#
class Railgun
- #
- # Railgun::DLL's that have builtin definitions.
- #
- # If you want to add additional DLL definitions to be preloaded create a
- # definition class 'rex/post/meterpreter/extensions/stdapi/railgun/def/'.
- # Naming is important and should follow convention. For example, if your
- # dll's name was "my_dll"
- # file name: def_my_dll.rb
- # class name: Def_my_dll
- # entry below: 'my_dll'
- #
- BUILTIN_DLLS = [
- 'kernel32',
- 'ntdll',
- 'user32',
- 'ws2_32',
- 'iphlpapi',
- 'advapi32',
- 'shell32',
- 'netapi32',
- 'crypt32',
- 'wlanapi',
- ].freeze
+ #
+ # Railgun::DLL's that have builtin definitions.
+ #
+ # If you want to add additional DLL definitions to be preloaded create a
+ # definition class 'rex/post/meterpreter/extensions/stdapi/railgun/def/'.
+ # Naming is important and should follow convention. For example, if your
+ # dll's name was "my_dll"
+ # file name: def_my_dll.rb
+ # class name: Def_my_dll
+ # entry below: 'my_dll'
+ #
+ BUILTIN_DLLS = [
+ 'kernel32',
+ 'ntdll',
+ 'user32',
+ 'ws2_32',
+ 'iphlpapi',
+ 'advapi32',
+ 'shell32',
+ 'netapi32',
+ 'crypt32',
+ 'wlanapi',
+ 'wldap32',
+ 'version'
+ ].freeze
- ##
- # Returns a Hash containing DLLs added to this instance with #add_dll
- # as well as references to any frozen cached dlls added directly in #get_dll
- # and copies of any frozen dlls (added directly with #add_function)
- # that the user attempted to modify with #add_function.
- #
- # Keys are friendly DLL names and values are the corresponding DLL instance
- attr_accessor :dlls
+ ##
+ # Returns a Hash containing DLLs added to this instance with #add_dll
+ # as well as references to any frozen cached dlls added directly in #get_dll
+ # and copies of any frozen dlls (added directly with #add_function)
+ # that the user attempted to modify with #add_function.
+ #
+ # Keys are friendly DLL names and values are the corresponding DLL instance
+ attr_accessor :dlls
- ##
- # Contains a reference to the client that corresponds to this instance of railgun
- attr_accessor :client
+ ##
+ # Contains a reference to the client that corresponds to this instance of railgun
+ attr_accessor :client
- ##
- # These DLLs are loaded lazily and then shared amongst all railgun instances.
- # For safety reasons this variable should only be read/written within #get_dll.
- @@cached_dlls = {}
+ ##
+ # These DLLs are loaded lazily and then shared amongst all railgun instances.
+ # For safety reasons this variable should only be read/written within #get_dll.
+ @@cached_dlls = {}
- # if you are going to touch @@cached_dlls, wear protection
- @@cache_semaphore = Mutex.new
+ # if you are going to touch @@cached_dlls, wear protection
+ @@cache_semaphore = Mutex.new
- def initialize(client)
- self.client = client
- self.dlls = {}
- end
+ def initialize(client)
+ self.client = client
+ self.dlls = {}
+ end
- def self.builtin_dlls
- BUILTIN_DLLS
- end
+ def self.builtin_dlls
+ BUILTIN_DLLS
+ end
- #
- # Return this Railgun's Util instance.
- #
- def util
- if @util.nil?
- @util = Util.new(self, client.platform)
- end
+ #
+ # Return this Railgun's Util instance.
+ #
+ def util
+ if @util.nil?
+ @util = Util.new(self, client.platform)
+ end
- return @util
- end
+ return @util
+ end
- #
- # Return this Railgun's WinConstManager instance, initially populated with
- # constants defined in ApiConstants.
- #
- def constant_manager
- # Loads lazily
- return ApiConstants.manager
- end
+ #
+ # Return this Railgun's WinConstManager instance, initially populated with
+ # constants defined in ApiConstants.
+ #
+ def constant_manager
+ # Loads lazily
+ return ApiConstants.manager
+ end
- #
- # Read data from a memory address on the host (useful for working with
- # LPVOID parameters)
- #
- def memread(address, length)
+ #
+ # Read data from a memory address on the host (useful for working with
+ # LPVOID parameters)
+ #
+ def memread(address, length)
- raise "Invalid parameters." if(not address or not length)
+ raise "Invalid parameters." if(not address or not length)
- request = Packet.create_request('stdapi_railgun_memread')
+ request = Packet.create_request('stdapi_railgun_memread')
- request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)
- request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)
+ request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)
+ request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)
- response = client.send_request(request)
- if(response.result == 0)
- return response.get_tlv_value(TLV_TYPE_RAILGUN_MEM_DATA)
- end
+ response = client.send_request(request)
+ if(response.result == 0)
+ return response.get_tlv_value(TLV_TYPE_RAILGUN_MEM_DATA)
+ end
- return nil
- end
+ return nil
+ end
- #
- # Write data to a memory address on the host (useful for working with
- # LPVOID parameters)
- #
- def memwrite(address, data, length)
+ #
+ # Write data to a memory address on the host (useful for working with
+ # LPVOID parameters)
+ #
+ def memwrite(address, data, length)
- raise "Invalid parameters." if(not address or not data or not length)
+ raise "Invalid parameters." if(not address or not data or not length)
- request = Packet.create_request('stdapi_railgun_memwrite')
+ request = Packet.create_request('stdapi_railgun_memwrite')
- request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)
- request.add_tlv(TLV_TYPE_RAILGUN_MEM_DATA, data)
- request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)
+ request.add_tlv(TLV_TYPE_RAILGUN_MEM_ADDRESS, address)
+ request.add_tlv(TLV_TYPE_RAILGUN_MEM_DATA, data)
+ request.add_tlv(TLV_TYPE_RAILGUN_MEM_LENGTH, length)
- response = client.send_request(request)
- if(response.result == 0)
- return true
- end
+ response = client.send_request(request)
+ if(response.result == 0)
+ return true
+ end
- return false
- end
+ return false
+ end
- #
- # Adds a function to an existing DLL definition.
- #
- # If the DLL definition is frozen (ideally this should be the case for all
- # cached dlls) an unfrozen copy is created and used henceforth for this
- # instance.
- #
- def add_function(dll_name, function_name, return_type, params, windows_name=nil)
+ #
+ # Adds a function to an existing DLL definition.
+ #
+ # If the DLL definition is frozen (ideally this should be the case for all
+ # cached dlls) an unfrozen copy is created and used henceforth for this
+ # instance.
+ #
+ def add_function(dll_name, function_name, return_type, params, windows_name=nil, calling_conv="stdcall")
- unless known_dll_names.include?(dll_name)
- raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, "")}"
- end
+ unless known_dll_names.include?(dll_name)
+ raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, "")}"
+ end
- dll = get_dll(dll_name)
+ dll = get_dll(dll_name)
- # For backwards compatibility, we ensure the dll is thawed
- if dll.frozen?
- # Duplicate not only the dll, but its functions as well. Frozen status will be lost
- dll = Marshal.load(Marshal.dump(dll))
+ # For backwards compatibility, we ensure the dll is thawed
+ if dll.frozen?
+ # Duplicate not only the dll, but its functions as well. Frozen status will be lost
+ dll = Marshal.load(Marshal.dump(dll))
- # Update local dlls with the modifiable duplicate
- dlls[dll_name] = dll
- end
+ # Update local dlls with the modifiable duplicate
+ dlls[dll_name] = dll
+ end
- dll.add_function(function_name, return_type, params, windows_name)
- end
+ dll.add_function(function_name, return_type, params, windows_name, calling_conv)
+ end
- #
- # Adds a DLL to this Railgun.
- #
- # The +windows_name+ is the name used on the remote system and should be
- # set appropriately if you want to include a path or the DLL name contains
- # non-ruby-approved characters.
- #
- # Raises an exception if a dll with the given name has already been
- # defined.
- #
- def add_dll(dll_name, windows_name=dll_name)
+ #
+ # Adds a DLL to this Railgun.
+ #
+ # The +windows_name+ is the name used on the remote system and should be
+ # set appropriately if you want to include a path or the DLL name contains
+ # non-ruby-approved characters.
+ #
+ # Raises an exception if a dll with the given name has already been
+ # defined.
+ #
+ def add_dll(dll_name, windows_name=dll_name)
- if dlls.has_key? dll_name
- raise "A DLL of name #{dll_name} has already been loaded."
- end
+ if dlls.has_key? dll_name
+ raise "A DLL of name #{dll_name} has already been loaded."
+ end
- dlls[dll_name] = DLL.new(windows_name, constant_manager)
- end
+ dlls[dll_name] = DLL.new(windows_name, constant_manager)
+ end
- def known_dll_names
- return BUILTIN_DLLS | dlls.keys
- end
+ def known_dll_names
+ return BUILTIN_DLLS | dlls.keys
+ end
- #
- # Attempts to provide a DLL instance of the given name. Handles lazy
- # loading and caching. Note that if a DLL of the given name does not
- # exist, returns nil
- #
- def get_dll(dll_name)
+ #
+ # Attempts to provide a DLL instance of the given name. Handles lazy
+ # loading and caching. Note that if a DLL of the given name does not
+ # exist, returns nil
+ #
+ def get_dll(dll_name)
- # If the DLL is not local, we now either load it from cache or load it lazily.
- # In either case, a reference to the dll is stored in the collection "dlls"
- # If the DLL can not be found/created, no actions are taken
- unless dlls.has_key? dll_name
- # We read and write to @@cached_dlls and rely on state consistency
- @@cache_semaphore.synchronize do
- if @@cached_dlls.has_key? dll_name
- dlls[dll_name] = @@cached_dlls[dll_name]
- elsif BUILTIN_DLLS.include? dll_name
- # I highly doubt this case will ever occur, but I am paranoid
- if dll_name !~ /^\w+$/
- raise "DLL name #{dll_name} is bad. Correct Railgun::BUILTIN_DLLS"
- end
+ # If the DLL is not local, we now either load it from cache or load it lazily.
+ # In either case, a reference to the dll is stored in the collection "dlls"
+ # If the DLL can not be found/created, no actions are taken
+ unless dlls.has_key? dll_name
+ # We read and write to @@cached_dlls and rely on state consistency
+ @@cache_semaphore.synchronize do
+ if @@cached_dlls.has_key? dll_name
+ dlls[dll_name] = @@cached_dlls[dll_name]
+ elsif BUILTIN_DLLS.include? dll_name
+ # I highly doubt this case will ever occur, but I am paranoid
+ if dll_name !~ /^\w+$/
+ raise "DLL name #{dll_name} is bad. Correct Railgun::BUILTIN_DLLS"
+ end
- require 'rex/post/meterpreter/extensions/stdapi/railgun/def/def_' << dll_name
- dll = Def.const_get('Def_' << dll_name).create_dll.freeze
+ require 'rex/post/meterpreter/extensions/stdapi/railgun/def/def_' << dll_name
+ dll = Def.const_get('Def_' << dll_name).create_dll.freeze
- @@cached_dlls[dll_name] = dll
- dlls[dll_name] = dll
- end
- end
+ @@cached_dlls[dll_name] = dll
+ dlls[dll_name] = dll
+ end
+ end
- end
+ end
- return dlls[dll_name]
- end
+ return dlls[dll_name]
+ end
- #
- # Fake having members like user32 and kernel32.
- # reason is that
- # ...user32.MessageBoxW()
- # is prettier than
- # ...dlls["user32"].functions["MessageBoxW"]()
- #
- def method_missing(dll_symbol, *args)
- dll_name = dll_symbol.to_s
+ #
+ # Fake having members like user32 and kernel32.
+ # reason is that
+ # ...user32.MessageBoxW()
+ # is prettier than
+ # ...dlls["user32"].functions["MessageBoxW"]()
+ #
+ def method_missing(dll_symbol, *args)
+ dll_name = dll_symbol.to_s
- unless known_dll_names.include? dll_name
- raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, '')}"
- end
+ unless known_dll_names.include? dll_name
+ raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, '')}"
+ end
- dll = get_dll(dll_name)
+ dll = get_dll(dll_name)
- return DLLWrapper.new(dll, client)
- end
+ return DLLWrapper.new(dll, client)
+ end
- #
- # Return a Windows constant matching +str+.
- #
- def const(str)
- return constant_manager.parse(str)
- end
+ #
+ # Return a Windows constant matching +str+.
+ #
+ def const(str)
+ return constant_manager.parse(str)
+ end
- #
- # The multi-call shorthand (["kernel32", "ExitProcess", [0]])
- #
- def multi(functions)
- if @multicaller.nil?
- @multicaller = MultiCaller.new(client, self)
- end
+ #
+ # The multi-call shorthand (["kernel32", "ExitProcess", [0]])
+ #
+ def multi(functions)
+ if @multicaller.nil?
+ @multicaller = MultiCaller.new(client, self, ApiConstants.manager)
+ end
- return @multicaller.call(functions)
- end
+ return @multicaller.call(functions)
+ end
end
end; end; end; end; end; end