Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb
Views: 11792
# -*- coding: binary -*-1require 'rex/post/meterpreter/extensions/stdapi/railgun/library_helper'23module Rex4module Post5module Meterpreter6module Extensions7module Stdapi8module Railgun910#11# Utility methods and constants for dealing with most types of variables.12#13class Util1415# Bring in some useful string manipulation utility functions16include LibraryHelper1718# Data type size info: http://msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx19PRIMITIVE_TYPE_SIZES = {20:int => 4,21:__int8 => 1,22:__int16 => 2,23:__int32 => 4,24:__int64 => 8,25:bool => 1,26:char => 1,27:short => 2,28:long => 4,29:long_long => 8,30:float => 4,31:double => 8,32:long_double => 8,33:wchar_t => 2,34}3536#37# Maps a data type to its corresponding primitive or special type38# +:pointer+. Note, primitive types are mapped to themselves.39#40# typedef info: http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx41TYPE_DEFINITIONS = {42##43# Primitives44##45:int => :int,46:__int8 => :__int8,47:__int16 => :__int16,48:__int32 => :__int32,49:__int64 => :__int64,50:bool => :bool,51:char => :char,52:short => :short,53:long => :long,54:long_long => :long_long,55:float => :float,56:double => :double,57:long_double => :long_double,58:wchar_t => :wchar_t,59##60# Non-pointers61##62#typedef WORD ATOM;63:ATOM => :short,64#typedef int BOOL;65:BOOL => :int,66#typedef BYTE BOOLEAN;67:BOOLEAN => :char,68#typedef unsigned char BYTE;69:BYTE => :char,70#typedef char CHAR;71:CHAR => :char,72#typedef DWORD COLORREF;73:COLORREF => :long,74#typedef unsigned long DWORD;75:DWORD => :long,76#typedef unsigned int DWORD32;77:DWORD32 => :int,78#typedef unsigned __int64 DWORD64;79:DWORD64 => :__int64,80#typedef float FLOAT;81:FLOAT => :float,82#typedef int HFILE;83:HFILE => :int,84#typedef LONG HRESULT;85:HRESULT => :long,86#typedef int INT;87:INT => :int,88#typedef signed int INT32;89:INT32 => :int,90#typedef signed __int64 INT64;91:INT64 => :__int64,92#typedef WORD LANGID;93:LANGID => :short,94#typedef DWORD LCID;95:LCID => :long,96#typedef DWORD LCTYPE;97:LCTYPE => :long,98#typedef DWORD LGRPID;99:LGRPID => :long,100#typedef long LONG;101:LONG => :long,102#typedef signed int LONG32;103:LONG32 => :int,104#typedef __int64 LONG64;105:LONG64 => :__int64,106#typedef PDWORD PLCID;107:PLCID => :pointer,108#typedef LPVOID SC_LOCK;109:SC_LOCK => :pointer,110#typedef short SHORT;111:SHORT => :short,112#typedef unsigned char UCHAR;113:UCHAR => :char,114#typedef unsigned int UINT;115:UINT => :int,116#typedef unsigned int UINT32;117:UINT32 => :int,118#typedef unsigned long ULONG;119:ULONG => :long,120#typedef unsigned int ULONG32;121:ULONG32 => :int,122#typedef unsigned __int64 ULONG64;123:ULONG64 => :__int64,124#typedef unsigned short USHORT;125:USHORT => :short,126#typedef wchar_t WCHAR;127:WCHAR => :wchar_t,128#typedef unsigned short WORD;129:WORD => :short,130##131# Pointers declared with *132##133#typedef DWORD* LPCOLORREF;134:LPCOLORREF => :pointer,135#typedef void* LPCVOID;136:LPCVOID => :pointer,137#typedef WCHAR* LPCWSTR;138:LPCWSTR => :pointer,139#typedef DWORD* LPDWORD;140:LPDWORD => :pointer,141#typedef HANDLE* LPHANDLE;142:LPHANDLE => :pointer,143#typedef int* LPINT;144:LPINT => :pointer,145#typedef long* LPLONG;146:LPLONG => :pointer,147#typedef CHAR* LPSTR;148:LPSTR => :pointer,149#typedef void* LPVOID;150:LPVOID => :pointer,151#typedef WORD* LPWORD;152:LPWORD => :pointer,153#typedef WCHAR* LPWSTR;154:LPWSTR => :pointer,155#typedef BOOL* PBOOL;156:PBOOL => :pointer,157#typedef BOOLEAN* PBOOLEAN;158:PBOOLEAN => :pointer,159#typedef BYTE* PBYTE;160:PBYTE => :pointer,161#typedef CHAR* PCHAR;162:PCHAR => :pointer,163#typedef CHAR* PCSTR;164:PCSTR => :pointer,165#typedef WCHAR* PCWSTR;166:PCWSTR => :pointer,167#typedef DWORD* PDWORD;168:PDWORD => :pointer,169#typedef DWORDLONG* PDWORDLONG;170:PDWORDLONG => :pointer,171#typedef DWORD_PTR* PDWORD_PTR;172:PDWORD_PTR => :pointer,173#typedef DWORD32* PDWORD32;174:PDWORD32 => :pointer,175#typedef DWORD64* PDWORD64;176:PDWORD64 => :pointer,177#typedef FLOAT* PFLOAT;178:PFLOAT => :pointer,179#typedef HANDLE* PHANDLE;180:PHANDLE => :pointer,181#typedef HKEY* PHKEY;182:PHKEY => :pointer,183#typedef int* PINT;184:PINT => :pointer,185#typedef INT_PTR* PINT_PTR;186:PINT_PTR => :pointer,187#typedef INT32* PINT32;188:PINT32 => :pointer,189#typedef INT64* PINT64;190:PINT64 => :pointer,191#typedef LONG* PLONG;192:PLONG => :pointer,193#typedef LONGLONG* PLONGLONG;194:PLONGLONG => :pointer,195#typedef LONG_PTR* PLONG_PTR;196:PLONG_PTR => :pointer,197#typedef LONG32* PLONG32;198:PLONG32 => :pointer,199#typedef LONG64* PLONG64;200:PLONG64 => :pointer,201#typedef SHORT* PSHORT;202:PSHORT => :pointer,203#typedef SIZE_T* PSIZE_T;204:PSIZE_T => :pointer,205#typedef SSIZE_T* PSSIZE_T;206:PSSIZE_T => :pointer,207#typedef CHAR* PSTR;208:PSTR => :pointer,209#typedef TBYTE* PTBYTE;210:PTBYTE => :pointer,211#typedef TCHAR* PTCHAR;212:PTCHAR => :pointer,213#typedef UCHAR* PUCHAR;214:PUCHAR => :pointer,215#typedef UINT* PUINT;216:PUINT => :pointer,217#typedef UINT_PTR* PUINT_PTR;218:PUINT_PTR => :pointer,219#typedef UINT32* PUINT32;220:PUINT32 => :pointer,221#typedef UINT64* PUINT64;222:PUINT64 => :pointer,223#typedef ULONG* PULONG;224:PULONG => :pointer,225#typedef ULONGLONG* PULONGLONG;226:PULONGLONG => :pointer,227#typedef ULONG_PTR* PULONG_PTR;228:PULONG_PTR => :pointer,229#typedef ULONG32* PULONG32;230:PULONG32 => :pointer,231#typedef ULONG64* PULONG64;232:PULONG64 => :pointer,233#typedef USHORT* PUSHORT;234:PUSHORT => :pointer,235#typedef void* PVOID;236:PVOID => :pointer,237#typedef WCHAR* PWCHAR;238:PWCHAR => :pointer,239#typedef WORD* PWORD;240:PWORD => :pointer,241#typedef WCHAR* PWSTR;242:PWSTR => :pointer,243#typedef HANDLE HACCEL;244:HACCEL => :pointer,245##246# Handles247##248#typedef PVOID HANDLE;249:HANDLE => :pointer,250#typedef HANDLE HBITMAP;251:HBITMAP => :pointer,252#typedef HANDLE HBRUSH;253:HBRUSH => :pointer,254#typedef HANDLE HCOLORSPACE;255:HCOLORSPACE => :pointer,256#typedef HANDLE HCONV;257:HCONV => :pointer,258#typedef HANDLE HCONVLIST;259:HCONVLIST => :pointer,260#typedef HANDLE HDC;261:HDC => :pointer,262#typedef HANDLE HDDEDATA;263:HDDEDATA => :pointer,264#typedef HANDLE HDESK;265:HDESK => :pointer,266#typedef HANDLE HDROP;267:HDROP => :pointer,268#typedef HANDLE HDWP;269:HDWP => :pointer,270#typedef HANDLE HENHMETAFILE;271:HENHMETAFILE => :pointer,272#typedef HANDLE HFONT;273:HFONT => :pointer,274#typedef HANDLE HGDIOBJ;275:HGDIOBJ => :pointer,276#typedef HANDLE HGLOBAL;277:HGLOBAL => :pointer,278#typedef HANDLE HHOOK;279:HHOOK => :pointer,280#typedef HANDLE HICON;281:HICON => :pointer,282#typedef HANDLE HINSTANCE;283:HINSTANCE => :pointer,284#typedef HANDLE HKEY;285:HKEY => :pointer,286#typedef HANDLE HKL;287:HKL => :pointer,288#typedef HANDLE HLOCAL;289:HLOCAL => :pointer,290#typedef HANDLE HMENU;291:HMENU => :pointer,292#typedef HANDLE HMETAFILE;293:HMETAFILE => :pointer,294#typedef HANDLE HPALETTE;295:HPALETTE => :pointer,296#typedef HANDLE HPEN;297:HPEN => :pointer,298#typedef HANDLE HRGN;299:HRGN => :pointer,300#typedef HANDLE HRSRC;301:HRSRC => :pointer,302#typedef HANDLE HSZ;303:HSZ => :pointer,304#typedef HANDLE WINSTA;305:WINSTA => :pointer,306#typedef HANDLE HWND;307:HWND => :pointer,308#typedef HANDLE SC_HANDLE;309:SC_HANDLE => :pointer,310#typedef HANDLE SERVICE_STATUS_HANDLE;311:SERVICE_STATUS_HANDLE => :pointer,312}313314# param 'railgun' is a Railgun instance.315# param 'arch' is the client.arch316def initialize(railgun, arch)317@railgun = railgun318@is_64bit = arch == ARCH_X64319@process_heap = nil320end321322#323# Given a packed pointer, unpacks it according to architecture324#325def unpack_pointer(packed_pointer)326if is_64bit327# Assume little endian328packed_pointer.unpack('Q<')[0]329else330packed_pointer.unpack('V')[0]331end332end333334#335# Returns true if +pointer+ will be considered a 'null' pointer.336#337# If +pointer+ is nil or 0, returns true338# If +pointer+ is a String, if 0 after unpacking, returns true339# false otherwise340#341# See #unpack_pointer342#343def is_null_pointer(pointer)344if pointer.kind_of? String345pointer = unpack_pointer(pointer)346end347348return pointer.nil? || pointer == 0349end350351def alloc_and_write_data(data)352return nil if data.nil? || process_heap.nil?353354result = railgun.kernel32.HeapAlloc(process_heap, railgun.const('HEAP_ZERO'), data.length)355return nil if result['return'].nil?356357addr = result['return']358return nil unless railgun.memwrite(addr, data, data.length)359360addr361end362363def free_data(*ptrs)364return false if ptrs.empty?365return false if process_heap.nil?366367results = railgun.multi(368ptrs.map { |ptr| ['kernel32', 'HeapFree', [process_heap, 0, ptr.to_i]] }369)370results.map { |res| res['return'] }.all?371end372373#374# Reads null-terminated unicode strings from memory.375#376# Given a pointer to a null terminated array of WCHARs, return a ruby377# String. If +pointer+ is NULL (see #is_null_pointer) returns an empty378# string.379#380def read_wstring(pointer, length = nil)381# Return an empty string for null pointers382if is_null_pointer(pointer)383return ''384end385386# If length not provided, use lstrlenW387if length.nil?388length = railgun.kernel32.lstrlenW(pointer)['return']389end390391# Retrieve the array of characters392chars = read_array(:WCHAR, length, pointer)393394# Concatenate the characters and convert to a ruby string395str = uniz_to_str(chars.join(''))396397return str398end399400#401# Write Unicode strings to memory.402#403# Given a string, returns a pointer to a null terminated WCHARs array.404#405def alloc_and_write_wstring(value)406return nil if value.nil?407408alloc_and_write_data(str_to_uni_z(value))409end410411alias free_wstring free_data412413#414# Write ASCII strings to memory.415#416# Given a string, returns a pointer to a null terminated CHARs array.417# InitializeStr(&Str,"string");418#419def alloc_and_write_string(value)420return nil if value.nil?421422alloc_and_write_data(str_to_ascii_z(value))423end424425alias free_string free_data426427#428# Reads null-terminated ASCII strings from memory.429#430# Given a pointer to a null terminated array of CHARs, return a ruby431# String. If +pointer+ is NULL (see #is_null_pointer) returns an empty432# string.433#434def read_string(pointer, length=nil)435if is_null_pointer(pointer)436return ''437end438439unless length440length = railgun.kernel32.lstrlenA(pointer)['return']441end442443chars = read_array(:CHAR, length, pointer)444return chars.join('')445end446447#448# Read a given number of bytes from memory or from a provided buffer.449#450# If +buffer+ is not provided, read +size+ bytes from the client's memory.451# If +buffer+ is provided, reads +size+ characters from the index of +address+.452#453def memread(address, size, buffer = nil)454if buffer.nil?455return railgun.memread(address, size)456else457return buffer[address .. (address + size - 1)]458end459end460461#462# Read and unpack a pointer from the given buffer at a given offset463#464def read_pointer(buffer, offset = 0)465unpack_pointer(buffer[offset, (offset + pointer_size)])466end467468#469# Reads data structures and several windows data types470#471def read_data(type, position, buffer = nil)472if buffer.nil?473buffer = memread(position, sizeof_type(type))474position = 0475end476477# If we're asked to read a data structure, deligate to read_struct478if is_struct_type?(type)479return read_struct(type, buffer, position)480end481482# If the type is an array with a given size...483# BYTE[3] for example or BYTE[ENCRYPTED_PWLEN] or even PDWORD[23]484if is_array_type?(type)485# Separate the element type from the size of the array486element_type, length = split_array_type(type)487488# Have read_array take care of the rest489return read_array(element_type, length, position, buffer)490end491492size = sizeof_type(type)493raw = memread(position, size, buffer)494495# read/unpack data for the types we have hard-coded support for496case type497when :LPWSTR498# null-terminated string of 16-bit Unicode characters499return read_wstring(read_pointer(raw))500when :DWORD501# Both on x86 and x64, DWORD is 32 bits502return raw.unpack('V').first503when :BOOL504return raw.unpack('V').first == 1505when :LONG506return raw.unpack('V').first507end508509#If nothing worked thus far, return it raw510return raw511end512513#514# Read +length+ number of instances of +type+ from +bufptr+ .515#516# +bufptr+ is an index in +buffer+ or, if +buffer+ is nil, a memory address517#518def read_array(type, length, bufptr, buffer = nil)519if length <= 0520return []521end522523size = sizeof_type(type)524# Grab the bytes that the array consists of525buffer = memread(bufptr, size * length, buffer)526527offset = 05285291.upto(length).map do |n|530data = read_data(type, offset, buffer)531532offset = offset + size533534data535end536end537538#539# Construct the data structure described in +definition+ from +buffer+540# starting from the index +offset+541#542def read_struct(definition, buffer, offset = 0)543data = {}544545offsets = struct_offsets(definition, offset)546547definition.each do |mapping|548key, data_type = mapping549550data[key] = read_data(data_type, offsets.shift, buffer)551end552553data554end555556557# Returns true if the data type is a pointer, false otherwise558def is_pointer_type?(type)559return TYPE_DEFINITIONS[type] == :pointer560end561562# Returns whether the given type represents an array of another type563# For example BYTE[3], BYTE[ENCRYPTED_PWLEN], or even PDWORD[23]564def is_array_type?(type)565return type =~ /^\w+\[\w+\]$/ ? true : false566end567568# Returns true if the type passed describes a data structure, false otherwise569def is_struct_type?(type)570return type.kind_of? Array571end572573574# Returns the pointer size for this architecture575def pointer_size576is_64bit ? 8 : 4577end578579# Return the size, in bytes, of the given type580def sizeof_type(type)581if is_pointer_type?(type)582return pointer_size583end584585if type.kind_of? String586if is_array_type?(type)587element_type, length = split_array_type(type)588return length * sizeof_type(element_type)589else590return sizeof_type(type.to_sym)591end592end593594if is_struct_type?(type)595return sizeof_struct(type)596end597598if TYPE_DEFINITIONS.has_key?(type)599primitive = TYPE_DEFINITIONS[type]600601if primitive == :pointer602return pointer_size603end604605if PRIMITIVE_TYPE_SIZES.has_key?(primitive)606return PRIMITIVE_TYPE_SIZES[primitive]607else608raise "Type #{type} was mapped to non-existent primitive #{primitive}"609end610end611612raise "Unable to determine size for type #{type}."613end614615#616# Calculates the size of +struct+ after alignment.617#618def sizeof_struct(struct)619offsets = struct_offsets(struct, 0)620last_data_size = sizeof_type(struct.last[1])621size_no_padding = offsets.last + last_data_size622623return size_no_padding + calc_padding(size_no_padding)624end625626#627# Given a description of a data structure, returns an Array containing628# the offset from the beginning for each subsequent element, taking into629# consideration alignment and padding.630#631def struct_offsets(definition, offset)632padding = 0633offsets = []634definition.each do |mapping|635key, data_type = mapping636if sizeof_type(data_type) > padding637offset = offset + padding638end639640offsets.push(offset)641642offset = offset + sizeof_type(data_type)643padding = calc_padding(offset)644end645646offsets647end648649# http://en.wikipedia.org/wiki/Data_structure_alignment650def required_alignment651is_64bit ? 8 : 4652end653654#655# Number of bytes that needed to be added to be aligned.656#657def calc_padding(offset)658align = required_alignment659660# If offset is not aligned...661if (offset % align) != 0662# Calculate padding needed to be aligned663align - (offset & (align - 1))664else6650666end667end668669#670# Given an explicit array definition (e.g. BYTE[23]) return size (e.g. 23) and671# and +type+ (e.g. BYTE). If a constant is given, attempt to resolve it672# that constant.673#674def split_array_type(type)675if type =~ /^(\w+)\[(\w+)\]$/676element_type = $1677length = $2678unless length =~ /^\d+$/679length = railgun.const(length)680end681682return element_type.to_sym, length.to_i683else684raise "Can not split non-array type #{type}"685end686end687688#689# Evaluates a bit field, returning a hash representing the meaning and690# state of each bit.691#692# Parameters:693# +value+:: a bit field represented by a Integer694# +mappings+:: { 'WINAPI_CONSTANT_NAME' => :descriptive_symbol, ... }695#696# Returns:697# { :descriptive_symbol => true/false, ... }698#699def judge_bit_field(value, mappings)700flags = {}701702mappings.each do |constant_name, key|703flags[key] = (value & railgun.const(constant_name)) != 0704end705706flags707end708709protected710711attr_accessor :railgun, :is_64bit712713private714715def process_heap716return @process_heap unless @process_heap.nil?717718handle = railgun.kernel32.GetProcessHeap()['return']719return nil if handle == 0720@process_heap = handle721end722end # Util723end # Railgun724end # Stdapi725end # Extensions726end # Meterpreter727end # Post728end # Rex729730731