clean up some rdoc comments. odd that rdoc doesn't appear to pick up ApiConstants at all...
git-svn-id: file:///home/svn/framework3/trunk@13576 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
a746067089
commit
f99429138e
|
@ -8,13 +8,21 @@ module Extensions
|
|||
module Stdapi
|
||||
module Railgun
|
||||
|
||||
#
|
||||
# A container holding useful Windows API Constants.
|
||||
#
|
||||
class ApiConstants
|
||||
|
||||
# This will be lazily loaded in self.manager
|
||||
@@manager = nil
|
||||
|
||||
# Mutex to ensure we don't add constants more than once via thread races.
|
||||
@@manager_semaphore = Mutex.new
|
||||
|
||||
# provides a frozen constant manager for the constants defined in self.add_constants
|
||||
#
|
||||
# Provides a frozen constant manager for the constants defined in
|
||||
# self.add_constants
|
||||
#
|
||||
def self.manager
|
||||
|
||||
# The first check for nil is to potentially skip the need to synchronize
|
||||
|
@ -35,6 +43,9 @@ class ApiConstants
|
|||
return @@manager
|
||||
end
|
||||
|
||||
#
|
||||
# Slurp in a giant list of known constants.
|
||||
#
|
||||
def self.add_constants(win_const_mgr)
|
||||
win_const_mgr.add_const('MCI_DGV_SETVIDEO_TINT',0x00004003)
|
||||
win_const_mgr.add_const('EVENT_TRACE_FLAG_PROCESS',0x00000001)
|
||||
|
|
|
@ -36,7 +36,7 @@ module Stdapi
|
|||
module Railgun
|
||||
|
||||
#
|
||||
# represents a DLL, e.g. kernel32.dll
|
||||
# Represents a DLL, e.g. kernel32.dll
|
||||
#
|
||||
class DLL
|
||||
|
||||
|
@ -62,6 +62,15 @@ class DLL
|
|||
return functions[name]
|
||||
end
|
||||
|
||||
#
|
||||
# Perform a function call in this DLL on the remote system.
|
||||
#
|
||||
# Returns a Hash containing the return value, the result of GetLastError(),
|
||||
# and any +inout+ parameters.
|
||||
#
|
||||
# Raises an exception if +func_symbol+ is not a known function in this DLL,
|
||||
# i.e., it hasn't been defined in a Def.
|
||||
#
|
||||
def call_function(func_symbol, args, client)
|
||||
func_name = func_symbol.to_s
|
||||
|
||||
|
@ -74,22 +83,29 @@ class DLL
|
|||
return process_function_call(function, args, client)
|
||||
end
|
||||
|
||||
# syntax for params:
|
||||
# add_function("MessageBoxW", # name
|
||||
# "DWORD", # return value
|
||||
# [["DWORD","hWnd","in"], # params
|
||||
# ["PWCHAR","lpText","in"],
|
||||
# ["PWCHAR","lpCaption","in"],
|
||||
# ["DWORD","uType","in"],
|
||||
# ])
|
||||
#
|
||||
# Define a function for this DLL.
|
||||
#
|
||||
# Every function argument is described by a tuple (type,name,direction)
|
||||
#
|
||||
# windows_name: Use it when the actual windows name is different from the ruby variable
|
||||
# for example when the actual func name is myFunc@4
|
||||
# or when you want to create an alternative version of an existing function
|
||||
# Example:
|
||||
# add_function("MessageBoxW", # name
|
||||
# "DWORD", # return value
|
||||
# [ # params
|
||||
# ["DWORD","hWnd","in"],
|
||||
# ["PWCHAR","lpText","in"],
|
||||
# ["PWCHAR","lpCaption","in"],
|
||||
# ["DWORD","uType","in"],
|
||||
# ])
|
||||
#
|
||||
# Use +windows_name+ when the actual windows name is different from the
|
||||
# ruby variable. You might need to do this for example when the actual
|
||||
# func name is myFunc@4 or when you want to create an alternative version
|
||||
# of an existing function.
|
||||
#
|
||||
# When the new function is called it will return a list containing the
|
||||
# return value and all inout params. See #call_function.
|
||||
#
|
||||
# When new function is called it will return a list containing the return value and all inout params
|
||||
def add_function(name, return_type, params, windows_name=nil)
|
||||
if windows_name == nil
|
||||
windows_name = name
|
||||
|
@ -99,7 +115,6 @@ class DLL
|
|||
|
||||
private
|
||||
|
||||
# called when a function like "MessageBoxW" is called
|
||||
def process_function_call(function, args, client)
|
||||
raise "#{function.params.length} arguments expected. #{args.length} arguments provided." unless args.length == function.params.length
|
||||
|
||||
|
|
|
@ -53,13 +53,18 @@ module Railgun
|
|||
# The Railgun class to dynamically expose the Windows API.
|
||||
#
|
||||
class Railgun
|
||||
# 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'
|
||||
|
||||
#
|
||||
# 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',
|
||||
|
@ -73,27 +78,21 @@ class Railgun
|
|||
].freeze
|
||||
|
||||
##
|
||||
# dlls
|
||||
#
|
||||
# Returns a hash containing DLLs added to this instance with self.add_dll
|
||||
# as well as references to any frozen cached dlls added directly in self.get_dll
|
||||
# and copies of any frozen dlls (added directly with self.add_function)
|
||||
# that the user attempted to modify with self.add_function
|
||||
# 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
|
||||
|
||||
##
|
||||
# client
|
||||
#
|
||||
# Contains a reference to the client that corresponds to this instance of railgun
|
||||
attr_accessor :client
|
||||
|
||||
##
|
||||
# @@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.
|
||||
# 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
|
||||
|
@ -104,6 +103,9 @@ class Railgun
|
|||
self.dlls = {}
|
||||
end
|
||||
|
||||
#
|
||||
# Return this Railgun's Util instance.
|
||||
#
|
||||
def util
|
||||
if @util.nil?
|
||||
@util = Util.new(self, client.platform)
|
||||
|
@ -112,12 +114,19 @@ class Railgun
|
|||
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
|
||||
|
||||
# read data from a memory address on the host (useful for working with LPVOID parameters)
|
||||
#
|
||||
# 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)
|
||||
|
@ -135,7 +144,10 @@ class Railgun
|
|||
return nil
|
||||
end
|
||||
|
||||
# write data to a memory address on the host (useful for working with LPVOID parameters)
|
||||
#
|
||||
# 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)
|
||||
|
@ -154,9 +166,13 @@ class Railgun
|
|||
return false
|
||||
end
|
||||
|
||||
# adds a function to an existing DLL-definition.
|
||||
# if the DLL-definition is frozen (idealy this should be true for all cached dlls)
|
||||
# an unfrozen copy is created and used henceforth for this instance.
|
||||
#
|
||||
# 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)
|
||||
|
||||
unless known_dll_names.include?(dll_name)
|
||||
|
@ -177,9 +193,16 @@ class Railgun
|
|||
dll.add_function(function_name, return_type, params, windows_name)
|
||||
end
|
||||
|
||||
# adds a function to an existing DLL-definition
|
||||
# you can override the dll name if you want to include a path or the DLL name contains
|
||||
# non-ruby-approved characters
|
||||
#
|
||||
# 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
|
||||
|
@ -194,8 +217,11 @@ class Railgun
|
|||
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, then nil is returned
|
||||
#
|
||||
# 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.
|
||||
|
@ -225,11 +251,13 @@ class Railgun
|
|||
return dlls[dll_name]
|
||||
end
|
||||
|
||||
# we fake having members like user32 and kernel32.
|
||||
#
|
||||
# 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
|
||||
|
||||
|
@ -242,12 +270,16 @@ class Railgun
|
|||
return DLLWrapper.new(dll, client)
|
||||
end
|
||||
|
||||
# Give the programmer access to constants
|
||||
#
|
||||
# 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)
|
||||
|
|
|
@ -6,6 +6,10 @@ module Meterpreter
|
|||
module Extensions
|
||||
module Stdapi
|
||||
module Railgun
|
||||
|
||||
#
|
||||
# Utility methods and constants for dealing with most types of variables.
|
||||
#
|
||||
class Util
|
||||
|
||||
# Bring in some useful string manipulation utility functions
|
||||
|
@ -29,8 +33,10 @@ class Util
|
|||
:wchar_t => 2,
|
||||
}
|
||||
|
||||
# Maps a data type to its corresponding primitive or special type :pointer
|
||||
# Note, primitive types are mapped to themselves
|
||||
#
|
||||
# Maps a data type to its corresponding primitive or special type
|
||||
# +:pointer+. Note, primitive types are mapped to themselves.
|
||||
#
|
||||
# typedef info: http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx
|
||||
TYPE_DEFINITIONS = {
|
||||
##
|
||||
|
@ -312,7 +318,9 @@ class Util
|
|||
@is_64bit = is_64bit_platform?(platform)
|
||||
end
|
||||
|
||||
#
|
||||
# Given a packed pointer, unpacks it according to architecture
|
||||
#
|
||||
def unpack_pointer(packed_pointer)
|
||||
if is_64bit
|
||||
# XXX: Only works if attacker and victim are like-endianed
|
||||
|
@ -322,14 +330,15 @@ class Util
|
|||
end
|
||||
end
|
||||
|
||||
###
|
||||
# Summary: Returns true if pointer will be considered a 'null' pointer
|
||||
#
|
||||
# If given nil, returns true
|
||||
# If given 0, returns true
|
||||
# If given a string, if 0 after unpacking, returns true
|
||||
# Returns true if +pointer+ will be considered a 'null' pointer.
|
||||
#
|
||||
# If +pointer+ is nil or 0, returns true
|
||||
# If +pointer+ is a String, if 0 after unpacking, returns true
|
||||
# false otherwise
|
||||
##
|
||||
#
|
||||
# See #unpack_pointer
|
||||
#
|
||||
def is_null_pointer(pointer)
|
||||
if pointer.class == String
|
||||
pointer = unpack_pointer(pointer)
|
||||
|
@ -338,12 +347,13 @@ class Util
|
|||
return pointer.nil? || pointer == 0
|
||||
end
|
||||
|
||||
###
|
||||
# Summary: Reads null-terminated unicode strings from memory.
|
||||
#
|
||||
# Given a pointer to a null terminated array of WCHARs, return a ruby string
|
||||
# Null pointers cause an empty string to be returned
|
||||
##
|
||||
# Reads null-terminated unicode strings from memory.
|
||||
#
|
||||
# Given a pointer to a null terminated array of WCHARs, return a ruby
|
||||
# String. If +pointer+ is NULL (see #is_null_pointer) returns an empty
|
||||
# string.
|
||||
#
|
||||
def read_wstring(pointer, length = nil)
|
||||
# Return an empty string for null pointers
|
||||
if is_null_pointer(pointer)
|
||||
|
@ -364,12 +374,12 @@ class Util
|
|||
return str
|
||||
end
|
||||
|
||||
###
|
||||
# Summary: Read a given number of bytes from memory or from a provided buffer.
|
||||
#
|
||||
# If 'buffer' is not provided, read 'size' bytes from the client's memory
|
||||
# If 'buffer' is provided, reads 'size' characters from the index of 'address'
|
||||
##
|
||||
# Read a given number of bytes from memory or from a provided buffer.
|
||||
#
|
||||
# If +buffer+ is not provided, read +size+ bytes from the client's memory.
|
||||
# If +buffer+ is provided, reads +size+ characters from the index of +address+.
|
||||
#
|
||||
def memread(address, size, buffer = nil)
|
||||
if buffer.nil?
|
||||
return railgun.memread(address, size)
|
||||
|
@ -378,12 +388,16 @@ class Util
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Read and unpack a pointer from the given buffer at a given offset
|
||||
#
|
||||
def read_pointer(buffer, offset = 0)
|
||||
unpack_pointer(buffer[offset, (offset + pointer_size)])
|
||||
end
|
||||
|
||||
#
|
||||
# Reads data structures and several windows data types
|
||||
#
|
||||
def read_data(type, position, buffer = nil)
|
||||
if buffer.nil?
|
||||
buffer = memread(position, sizeof_type(type))
|
||||
|
@ -426,8 +440,11 @@ class Util
|
|||
return raw
|
||||
end
|
||||
|
||||
# Read 'length' number of instances of 'type' from 'bufptr'
|
||||
# bufptr is an index in 'buffer' or, if buffer is nil, a memory address
|
||||
#
|
||||
# Read +length+ number of instances of +type+ from +bufptr+ .
|
||||
#
|
||||
# +bufptr+ is an index in +buffer+ or, if +buffer+ is nil, a memory address
|
||||
#
|
||||
def read_array(type, length, bufptr, buffer = nil)
|
||||
if length <= 0
|
||||
return []
|
||||
|
@ -448,8 +465,10 @@ class Util
|
|||
end
|
||||
end
|
||||
|
||||
# construct the data structure described in 'definition' from 'buffer'
|
||||
# starting from the index 'offset'
|
||||
#
|
||||
# Construct the data structure described in +definition+ from +buffer+
|
||||
# starting from the index +offset+
|
||||
#
|
||||
def read_struct(definition, buffer, offset = 0)
|
||||
data = {}
|
||||
|
||||
|
@ -520,7 +539,9 @@ class Util
|
|||
raise "Unable to determine size for type #{type}."
|
||||
end
|
||||
|
||||
# Calculates the size of the struct after alignment
|
||||
#
|
||||
# Calculates the size of +struct+ after alignment.
|
||||
#
|
||||
def sizeof_struct(struct)
|
||||
offsets = struct_offsets(struct, 0)
|
||||
last_data_size = sizeof_type(struct.last[1])
|
||||
|
@ -529,9 +550,11 @@ class Util
|
|||
return size_no_padding + calc_padding(size_no_padding)
|
||||
end
|
||||
|
||||
# Given a description of a data structure, returns an array containing
|
||||
#
|
||||
# Given a description of a data structure, returns an Array containing
|
||||
# the offset from the beginning for each subsequent element, taking into
|
||||
# consideration alignment and padding
|
||||
# consideration alignment and padding.
|
||||
#
|
||||
def struct_offsets(definition, offset)
|
||||
padding = 0
|
||||
offsets = []
|
||||
|
@ -558,7 +581,9 @@ class Util
|
|||
is_64bit ? 8 : 4
|
||||
end
|
||||
|
||||
# Bytes that needed to be added to be aligned
|
||||
#
|
||||
# Number of bytes that needed to be added to be aligned.
|
||||
#
|
||||
def calc_padding(offset)
|
||||
align = required_alignment
|
||||
|
||||
|
@ -571,9 +596,11 @@ class Util
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Given an explicit array definition (e.g. BYTE[23]) return size (e.g. 23) and
|
||||
# and type (e.g. BYTE). If a constant is given, attempt to resolve it
|
||||
# that constant
|
||||
# and +type+ (e.g. BYTE). If a constant is given, attempt to resolve it
|
||||
# that constant.
|
||||
#
|
||||
def split_array_type(type)
|
||||
if type =~ /^(\w+)\[(\w+)\]$/
|
||||
element_type = $1
|
||||
|
@ -595,18 +622,17 @@ class Util
|
|||
platform =~ /win64/
|
||||
end
|
||||
|
||||
###
|
||||
# Summary:
|
||||
# Evaluates a bit field, returning a hash representing the meaning
|
||||
# and state of each bit.
|
||||
#
|
||||
# Evaluates a bit field, returning a hash representing the meaning and
|
||||
# state of each bit.
|
||||
#
|
||||
# Parameters:
|
||||
# value: a bit field represented by a Fixnum
|
||||
# mappings: { 'WINAPI_CONSTANT_NAME' => :descriptive_symbol, ... }
|
||||
# +value+:: a bit field represented by a Fixnum
|
||||
# +mappings+:: { 'WINAPI_CONSTANT_NAME' => :descriptive_symbol, ... }
|
||||
#
|
||||
# Returns:
|
||||
# { :descriptive_symbol => true/false, ... }
|
||||
##
|
||||
#
|
||||
def judge_bit_field(value, mappings)
|
||||
flags = {}
|
||||
rg = railgun
|
||||
|
|
Loading…
Reference in New Issue