Refactor railgun "DLL" references to library
parent
ea83cb0bb6
commit
0da9f4d64a
|
@ -7,10 +7,10 @@ module Windows
|
||||||
module Railgun
|
module Railgun
|
||||||
|
|
||||||
# Go through each dll and add a corresponding convenience method of the same name
|
# Go through each dll and add a corresponding convenience method of the same name
|
||||||
Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun::BUILTIN_DLLS['windows'].each do |api|
|
Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun::BUILTIN_LIBRARIES['windows'].each do |api|
|
||||||
# We will be interpolating within an eval. We exercise due paranoia.
|
# We will be interpolating within an eval. We exercise due paranoia.
|
||||||
unless api.to_s =~ /^\w+$/
|
unless api.to_s =~ /^\w+$/
|
||||||
print_error 'Something is seriously wrong with Railgun.BUILTIN_DLLS list'
|
print_error 'Something is seriously wrong with Railgun.BUILTIN_LIBRARIES list'
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Railgun
|
||||||
# class name: Def_my_dll
|
# class name: Def_my_dll
|
||||||
# entry below: 'my_dll'
|
# entry below: 'my_dll'
|
||||||
#
|
#
|
||||||
BUILTIN_DLLS = {
|
BUILTIN_LIBRARIES = {
|
||||||
'linux' => [
|
'linux' => [
|
||||||
'libc'
|
'libc'
|
||||||
].freeze,
|
].freeze,
|
||||||
|
@ -95,33 +95,34 @@ class Railgun
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns a Hash containing DLLs added to this instance with #add_dll
|
# Returns a Hash containing DLLs added to this instance with #add_library as
|
||||||
# as well as references to any frozen cached dlls added directly in #get_dll
|
# well as references to any frozen cached libraries added directly in
|
||||||
# and copies of any frozen dlls (added directly with #add_function)
|
# #get_library and copies of any frozen libraries (added directly with
|
||||||
# that the user attempted to modify with #add_function.
|
# #add_function) that the user attempted to modify with #add_function.
|
||||||
#
|
#
|
||||||
# Keys are friendly DLL names and values are the corresponding DLL instance
|
# Keys are friendly library names and values are the corresponding library instance
|
||||||
attr_accessor :dlls
|
attr_accessor :libraries
|
||||||
|
|
||||||
##
|
##
|
||||||
# Contains a reference to the client that corresponds to this instance of railgun
|
# Contains a reference to the client that corresponds to this instance of railgun
|
||||||
attr_accessor :client
|
attr_accessor :client
|
||||||
|
|
||||||
##
|
##
|
||||||
# These DLLs are loaded lazily and then shared amongst all railgun instances.
|
# These libraries are loaded lazily and then shared amongst all railgun
|
||||||
# For safety reasons this variable should only be read/written within #get_dll.
|
# instances. For safety reasons this variable should only be read/written
|
||||||
@@cached_dlls = {}
|
# within #get_library.
|
||||||
|
@@cached_libraries = {}
|
||||||
|
|
||||||
# if you are going to touch @@cached_dlls, wear protection
|
# if you are going to touch @@cached_libraries, wear protection
|
||||||
@@cache_semaphore = Mutex.new
|
@@cache_semaphore = Mutex.new
|
||||||
|
|
||||||
def initialize(client)
|
def initialize(client)
|
||||||
self.client = client
|
self.client = client
|
||||||
self.dlls = {}
|
self.libraries = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.builtin_dlls
|
def self.builtin_libraries
|
||||||
BUILTIN_DLLS[client.platform]
|
BUILTIN_LIBRARIES[client.platform]
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -196,106 +197,109 @@ class Railgun
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Adds a function to an existing DLL definition.
|
# Adds a function to an existing library definition.
|
||||||
#
|
#
|
||||||
# If the DLL definition is frozen (ideally this should be the case for all
|
# If the library definition is frozen (ideally this should be the case for all
|
||||||
# cached dlls) an unfrozen copy is created and used henceforth for this
|
# cached libraries) an unfrozen copy is created and used henceforth for this
|
||||||
# instance.
|
# instance.
|
||||||
#
|
#
|
||||||
def add_function(dll_name, function_name, return_type, params, remote_name=nil, calling_conv="stdcall")
|
def add_function(lib_name, function_name, return_type, params, remote_name=nil, calling_conv='stdcall')
|
||||||
|
unless known_library_names.include?(lib_name)
|
||||||
unless known_dll_names.include?(dll_name)
|
raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}"
|
||||||
raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, "")}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
dll = get_dll(dll_name)
|
lib = get_library(lib_name)
|
||||||
|
|
||||||
# For backwards compatibility, we ensure the dll is thawed
|
# For backwards compatibility, we ensure the library is thawed
|
||||||
if dll.frozen?
|
if lib.frozen?
|
||||||
# Duplicate not only the dll, but its functions as well. Frozen status will be lost
|
# Duplicate not only the library, but its functions as well, frozen status will be lost
|
||||||
dll = Marshal.load(Marshal.dump(dll))
|
lib = Marshal.load(Marshal.dump(lib))
|
||||||
|
|
||||||
# Update local dlls with the modifiable duplicate
|
# Update local libraries with the modifiable duplicate
|
||||||
dlls[dll_name] = dll
|
libraries[lib_name] = lib
|
||||||
end
|
end
|
||||||
|
|
||||||
dll.add_function(function_name, return_type, params, remote_name, calling_conv)
|
lib.add_function(function_name, return_type, params, remote_name, calling_conv)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Adds a DLL to this Railgun.
|
# Adds a library to this Railgun.
|
||||||
#
|
#
|
||||||
# The +remote_name+ is the name used on the remote system and should be
|
# The +remote_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
|
# set appropriately if you want to include a path or the library name contains
|
||||||
# non-ruby-approved characters.
|
# non-ruby-approved characters.
|
||||||
#
|
#
|
||||||
# Raises an exception if a dll with the given name has already been
|
# Raises an exception if a library with the given name has already been
|
||||||
# defined.
|
# defined.
|
||||||
#
|
#
|
||||||
def add_dll(dll_name, remote_name=dll_name)
|
def add_library(lib_name, remote_name=lib_name)
|
||||||
|
if libraries.has_key? lib_name
|
||||||
if dlls.has_key? dll_name
|
raise "A library of name #{lib_name} has already been loaded."
|
||||||
raise "A DLL of name #{dll_name} has already been loaded."
|
|
||||||
end
|
end
|
||||||
|
|
||||||
dlls[dll_name] = DLL.new(remote_name, constant_manager)
|
libraries[lib_name] = DLL.new(remote_name, constant_manager)
|
||||||
end
|
end
|
||||||
|
alias_method :add_dll, :add_library
|
||||||
|
|
||||||
|
def known_library_names
|
||||||
def known_dll_names
|
return BUILTIN_LIBRARIES[client.platform] | libraries.keys
|
||||||
return BUILTIN_DLLS[client.platform] | dlls.keys
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Attempts to provide a DLL instance of the given name. Handles lazy
|
# Attempts to provide a library instance of the given name. Handles lazy
|
||||||
# loading and caching. Note that if a DLL of the given name does not
|
# loading and caching. Note that if a library of the given name does not exist
|
||||||
# exist, returns nil
|
# then nil is returned.
|
||||||
#
|
#
|
||||||
def get_dll(dll_name)
|
def get_library(lib_name)
|
||||||
# If the DLL is not local, we now either load it from cache or load it lazily.
|
# If the library is not local, we now either load it from cache or load it
|
||||||
# In either case, a reference to the dll is stored in the collection "dlls"
|
# lazily. In either case, a reference to the library is stored in the
|
||||||
# If the DLL can not be found/created, no actions are taken
|
# collection "libraries". If the library can not be found/created, no
|
||||||
unless dlls.has_key? dll_name
|
# actions are taken.
|
||||||
# We read and write to @@cached_dlls and rely on state consistency
|
unless libraries.has_key? lib_name
|
||||||
|
# use a platform-specific name for caching to avoid conflicts with
|
||||||
|
# libraries that exist on multiple platforms, e.g. libc.
|
||||||
|
cached_lib_name = "#{client.platform}.#{lib_name}"
|
||||||
|
# We read and write to @@cached_libraries and rely on state consistency
|
||||||
@@cache_semaphore.synchronize do
|
@@cache_semaphore.synchronize do
|
||||||
if @@cached_dlls.has_key? dll_name
|
if @@cached_libraries.has_key? cached_lib_name
|
||||||
dlls[dll_name] = @@cached_dlls[dll_name]
|
libraries[lib_name] = @@cached_libraries[cached_lib_name]
|
||||||
elsif BUILTIN_DLLS[client.platform].include? dll_name
|
elsif BUILTIN_LIBRARIES[client.platform].include? lib_name
|
||||||
# I highly doubt this case will ever occur, but I am paranoid
|
# I highly doubt this case will ever occur, but I am paranoid
|
||||||
if dll_name !~ /^\w+$/
|
if lib_name !~ /^\w+$/
|
||||||
raise "DLL name #{dll_name} is bad. Correct Railgun::BUILTIN_DLLS"
|
raise "Library name #{lib_name} is bad. Correct Railgun::BUILTIN_LIBRARIES['#{client.platform}']"
|
||||||
end
|
end
|
||||||
|
|
||||||
require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/def_#{dll_name}"
|
require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/def_#{lib_name}"
|
||||||
dll = Def.const_get("Def_#{client.platform}_#{dll_name}").create_dll(constant_manager).freeze
|
lib = Def.const_get("Def_#{client.platform}_#{lib_name}").create_dll(constant_manager).freeze
|
||||||
|
|
||||||
@@cached_dlls[dll_name] = dll
|
@@cached_libraries[cached_lib_name] = lib
|
||||||
dlls[dll_name] = dll
|
libraries[lib_name] = lib
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return dlls[dll_name]
|
return libraries[lib_name]
|
||||||
end
|
end
|
||||||
|
alias_method :get_dll, :get_library
|
||||||
|
|
||||||
#
|
#
|
||||||
# Fake having members like user32 and kernel32.
|
# Fake having members like user32 and kernel32.
|
||||||
# reason is that
|
# reason is that
|
||||||
# ...user32.MessageBoxW()
|
# ...user32.MessageBoxW()
|
||||||
# is prettier than
|
# is prettier than
|
||||||
# ...dlls["user32"].functions["MessageBoxW"]()
|
# ...libraries["user32"].functions["MessageBoxW"]()
|
||||||
#
|
#
|
||||||
def method_missing(dll_symbol, *args)
|
def method_missing(lib_symbol, *args)
|
||||||
dll_name = dll_symbol.to_s
|
lib_name = lib_symbol.to_s
|
||||||
|
|
||||||
unless known_dll_names.include? dll_name
|
unless known_library_names.include? lib_name
|
||||||
raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, '')}"
|
raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
dll = get_dll(dll_name)
|
lib = get_library(lib_name)
|
||||||
|
|
||||||
return DLLWrapper.new(dll, client)
|
return DLLWrapper.new(lib, client)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -74,8 +74,8 @@ class MetasploitModule < Msf::Post
|
||||||
end
|
end
|
||||||
|
|
||||||
def init_railgun_defs
|
def init_railgun_defs
|
||||||
unless session.railgun.dlls.has_key?('libgnome_keyring')
|
unless session.railgun.libraries.has_key?('libgnome_keyring')
|
||||||
session.railgun.add_dll('libgnome_keyring', 'libgnome-keyring.so.0')
|
session.railgun.add_library('libgnome_keyring', 'libgnome-keyring.so.0')
|
||||||
end
|
end
|
||||||
session.railgun.add_function(
|
session.railgun.add_function(
|
||||||
'libgnome_keyring',
|
'libgnome_keyring',
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MetasploitModule < Msf::Post
|
||||||
|
|
||||||
def add_railgun_urlmon
|
def add_railgun_urlmon
|
||||||
|
|
||||||
if client.railgun.dlls.find_all {|d| d.first == 'urlmon'}.empty?
|
if client.railgun.libraries.find_all {|d| d.first == 'urlmon'}.empty?
|
||||||
session.railgun.add_dll('urlmon','urlmon')
|
session.railgun.add_dll('urlmon','urlmon')
|
||||||
session.railgun.add_function(
|
session.railgun.add_function(
|
||||||
'urlmon', 'URLDownloadToFileW', 'DWORD',
|
'urlmon', 'URLDownloadToFileW', 'DWORD',
|
||||||
|
|
Loading…
Reference in New Issue