Parent

Class/Module Index [+]

Quicksearch

Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Util

Utility methods and constants for dealing with most types of variables.

Constants

PRIMITIVE_TYPE_SIZES

Data type size info: msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx

TYPE_DEFINITIONS

Maps a data type to its corresponding primitive or special type :pointer. Note, primitive types are mapped to themselves.

typedef info: msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx

Attributes

is_64bit[RW]
railgun[RW]

Public Class Methods

new(railgun, platform) click to toggle source

param 'railgun' is a Railgun instance. param 'platform' is a value like client.platform

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 316
def initialize(railgun, platform)
        @railgun = railgun
        @is_64bit = is_64bit_platform?(platform)
end

Public Instance Methods

calc_padding(offset) click to toggle source

Number of bytes that needed to be added to be aligned.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 587
def calc_padding(offset)
        align = required_alignment

        # If offset is not aligned...
        if (offset % align) != 0
                # Calculate padding needed to be aligned
                align - (offset & (align - 1))
        else
                0
        end
end
is_64bit_platform?(platform) click to toggle source

Returns true if given platform has 64bit architecture expects client.platform

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 621
def is_64bit_platform?(platform)
        platform =~ /win64/
end
is_array_type?(type) click to toggle source

Returns whether the given type represents an array of another type For example BYTE, BYTE, or even PDWORD

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 494
def is_array_type?(type)
        return type =~ /^\w+\[\w+\]$/ ? true : false
end
is_null_pointer(pointer) click to toggle source

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

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 342
def is_null_pointer(pointer)
        if pointer.class == String
                pointer = unpack_pointer(pointer)
        end

        return pointer.nil? || pointer == 0
end
is_pointer_type?(type) click to toggle source

Returns true if the data type is a pointer, false otherwise

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 488
def is_pointer_type?(type)
        return TYPE_DEFINITIONS[type] == :pointer
end
is_struct_type?(type) click to toggle source

Returns true if the type passed describes a data structure, false otherwise

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 499
def is_struct_type?(type)
        return type.class == Array
end
judge_bit_field(value, mappings) click to toggle source

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, ... }

Returns:

{ :descriptive_symbol => true/false, ... }
# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 636
def judge_bit_field(value, mappings)
        flags = {}
        rg = railgun

        mappings.each do |constant_name, key|
                flags[key] = (value & rg.const(constant_name)) != 0
        end

        flags
end
memread(address, size, buffer = nil) click to toggle source

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.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 383
def memread(address, size, buffer = nil)
        if buffer.nil?
                return railgun.memread(address, size)
        else
                return buffer[address .. (address + size - 1)]
        end
end
pointer_size() click to toggle source

Returns the pointer size for this architecture

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 505
def pointer_size
        is_64bit ? 8 : 4
end
read_array(type, length, bufptr, buffer = nil) click to toggle source

Read length number of instances of type from bufptr .

bufptr is an index in buffer or, if buffer is nil, a memory address

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 448
def read_array(type, length, bufptr, buffer = nil)
        if length <= 0
                return []
        end

        size = sizeof_type(type)
        # Grab the bytes that the array consists of
        buffer = memread(bufptr, size * length, buffer)

        offset = 0

        1.upto(length).map do |n|
                data = read_data(type, offset, buffer)

                offset = offset + size

                data
        end
end
read_data(type, position, buffer = nil) click to toggle source

Reads data structures and several windows data types

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 401
def read_data(type, position, buffer = nil)
        if buffer.nil?
                buffer = memread(position, sizeof_type(type))
                position = 0
        end

        # If we're asked to read a data structure, deligate to read_struct
        if is_struct_type?(type)
                return read_struct(type, buffer, position)
        end

        # If the type is an array with a given size...
        #    BYTE[3] for example or BYTE[ENCRYPTED_PWLEN] or even PDWORD[23]
        if is_array_type?(type)
                # Separate the element type from the size of the array
                element_type, length = split_array_type(type)

                # Have read_array take care of the rest
                return read_array(element_type, length, position, buffer)
        end

        size = sizeof_type(type)
        raw  = memread(position, size, buffer)

        # read/unpack data for the types we have hard-coded support for
        case type
        when :LPWSTR
                # null-terminated string of 16-bit Unicode characters
                return read_wstring(read_pointer(raw))
        when :DWORD
                # Both on x86 and x64, DWORD is 32 bits
                return raw.unpack('V').first
        when :BOOL
                return raw.unpack('l').first == 1
        when :LONG
                return raw.unpack('l').first
        end

        #If nothing worked thus far, return it raw
        return raw
end
read_pointer(buffer, offset = 0) click to toggle source

Read and unpack a pointer from the given buffer at a given offset

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 394
def read_pointer(buffer, offset = 0)
        unpack_pointer(buffer[offset, (offset + pointer_size)])
end
read_struct(definition, buffer, offset = 0) click to toggle source

Construct the data structure described in definition from buffer starting from the index offset

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 472
def read_struct(definition, buffer, offset = 0)
        data = {}

        offsets = struct_offsets(definition, offset)

        definition.each do |mapping|
                key, data_type = mapping

                data[key] = read_data(data_type, offsets.shift, buffer)
        end

        data
end
read_wstring(pointer, length = nil) click to toggle source

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.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 357
def read_wstring(pointer, length = nil)
        # Return an empty string for null pointers
        if is_null_pointer(pointer)
                return ''
        end

        # If length not provided, use lstrlenW
        if length.nil?
                length = railgun.kernel32.lstrlenW(pointer)['return']
        end

        # Retrieve the array of characters
        chars = read_array(:WCHAR, length, pointer)

        # Concatenate the characters and convert to a ruby string
        str = uniz_to_str(chars.join(''))

        return str
end
required_alignment() click to toggle source

en.wikipedia.org/wiki/Data_structure_alignment

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 580
def required_alignment
        is_64bit ? 8 : 4
end
sizeof_struct(struct) click to toggle source

Calculates the size of struct after alignment.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 545
def sizeof_struct(struct)
        offsets = struct_offsets(struct, 0)
        last_data_size = sizeof_type(struct.last[1])
        size_no_padding = offsets.last + last_data_size

        return size_no_padding + calc_padding(size_no_padding)
end
sizeof_type(type) click to toggle source

Return the size, in bytes, of the given type

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 510
def sizeof_type(type)
        if is_pointer_type?(type)
                return pointer_size
        end

        if is_array_type?(type)
                element_type, length = split_array_type(type)

                return length * sizeof_type(element_type)
        end

        if is_struct_type?(type)
                return sizeof_struct(type)
        end

        if TYPE_DEFINITIONS.has_key?(type)
                primitive = TYPE_DEFINITIONS[type]

                if primitive == :pointer
                        return pointer_size
                end

                if PRIMITIVE_TYPE_SIZES.has_key?(primitive)
                        return PRIMITIVE_TYPE_SIZES[primitive]
                else
                        raise "Type #{type} was mapped to non-existent primitive #{primitive}"
                end
        end

        raise "Unable to determine size for type #{type}."
end
split_array_type(type) click to toggle source

Given an explicit array definition (e.g. BYTE) return size (e.g. 23) and and type (e.g. BYTE). If a constant is given, attempt to resolve it that constant.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 604
def split_array_type(type)
        if type =~ /^(\w+)\[(\w+)\]$/
                element_type = $1
                length = $2

                unless length =~ /^\d+$/
                        length = railgun.const(length)
                end

                return element_type, length
        else
                raise "Can not split non-array type #{type}"
        end
end
struct_offsets(definition, offset) click to toggle source

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.

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 558
def struct_offsets(definition, offset)
        padding = 0
        offsets = []

        definition.each do |mapping|
                key, data_type = mapping

                if sizeof_type(data_type) > padding
                        offset = offset + padding
                end

                offsets.push(offset)

                offset = offset + sizeof_type(data_type)

                padding = calc_padding(offset)
        end

        offsets
end
unpack_pointer(packed_pointer) click to toggle source

Given a packed pointer, unpacks it according to architecture

# File lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb, line 324
def unpack_pointer(packed_pointer)
        if is_64bit
                # XXX: Only works if attacker and victim are like-endianed
                packed_pointer.unpack('Q')[0]
        else
                packed_pointer.unpack('V')[0]
        end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.