class Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun

The Railgun class to dynamically expose the Windows API.

Constants

BUILTIN_DLLS

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'

Attributes

client[RW]

Contains a reference to the client that corresponds to this instance of railgun

dlls[RW]

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

Public Class Methods

builtin_dlls() click to toggle source
# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 110
def self.builtin_dlls
  BUILTIN_DLLS
end
new(client) click to toggle source
# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 105
def initialize(client)
  self.client = client
  self.dlls = {}
end

Public Instance Methods

add_dll(dll_name, windows_name=dll_name) click to toggle source

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.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 214
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

  dlls[dll_name] = DLL.new(windows_name, constant_manager)
end
add_function(dll_name, function_name, return_type, params, windows_name=nil, calling_conv="stdcall") click to toggle source

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.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 184
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

  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))

    # Update local dlls with the modifiable duplicate
    dlls[dll_name] = dll
  end

  dll.add_function(function_name, return_type, params, windows_name, calling_conv)
end
const(str) click to toggle source

Return a Windows constant matching str.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 284
def const(str)
  return constant_manager.parse(str)
end
constant_manager() click to toggle source

Return this Railgun's WinConstManager instance, initially populated with constants defined in ApiConstants.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 129
def constant_manager
  # Loads lazily
  return ApiConstants.manager
end
get_dll(dll_name) click to toggle source

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

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 233
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

        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

  end

  return dlls[dll_name]
end
known_dll_names() click to toggle source
# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 224
def known_dll_names
  return BUILTIN_DLLS | dlls.keys
end
memread(address, length) click to toggle source

Read data from a memory address on the host (useful for working with LPVOID parameters)

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 138
def memread(address, length)

  raise "Invalid parameters." if(not address or not length)

  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)

  response = client.send_request(request)
  if(response.result == 0)
    return response.get_tlv_value(TLV_TYPE_RAILGUN_MEM_DATA)
  end

  return nil
end
memwrite(address, data, length) click to toggle source

Write data to a memory address on the host (useful for working with LPVOID parameters)

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 159
def memwrite(address, data, length)

  raise "Invalid parameters." if(not address or not data or not length)

  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)

  response = client.send_request(request)
  if(response.result == 0)
    return true
  end

  return false
end
method_missing(dll_symbol, *args) click to toggle source

Fake having members like user32 and kernel32. reason is that

...user32.MessageBoxW()

is prettier than

...dlls["user32"].functions["MessageBoxW"]()
# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 269
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

  dll = get_dll(dll_name)

  return DLLWrapper.new(dll, client)
end
multi(functions) click to toggle source

The multi-call shorthand ([“kernel32”, “ExitProcess”, [0]])

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 291
def multi(functions)
  if @multicaller.nil?
    @multicaller = MultiCaller.new(client, self, ApiConstants.manager)
  end

  return @multicaller.call(functions)
end
util() click to toggle source

Return this Railgun's Util instance.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb, line 117
def util
  if @util.nil?
    @util = Util.new(self, client.platform)
  end

  return @util
end