Class: Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Util
- Inherits:
-
Object
- Object
- Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Util
- Includes:
- DLLHelper
- Defined in:
- lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb
Overview
Utility methods and constants for dealing with most types of variables.
Constant Summary collapse
- PRIMITIVE_TYPE_SIZES =
Data type size info: msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx
{ :int => 4, :__int8 => 1, :__int16 => 2, :__int32 => 4, :__int64 => 8, :bool => 1, :char => 1, :short => 2, :long => 4, :long_long => 8, :float => 4, :double => 8, :long_double => 8, :wchar_t => 2, }
- 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
{ ## # Primitives ## :int => :int, :__int8 => :__int8, :__int16 => :__int16, :__int32 => :__int32, :__int64 => :__int64, :bool => :bool, :char => :char, :short => :short, :long => :long, :long_long => :long_long, :float => :float, :double => :double, :long_double => :long_double, :wchar_t => :wchar_t, ## # Non-pointers ## #typedef WORD ATOM; :ATOM => :short, #typedef int BOOL; :BOOL => :int, #typedef BYTE BOOLEAN; :BOOLEAN => :char, #typedef unsigned char BYTE; :BYTE => :char, #typedef char CHAR; :CHAR => :char, #typedef DWORD COLORREF; :COLORREF => :long, #typedef unsigned long DWORD; :DWORD => :long, #typedef unsigned int DWORD32; :DWORD32 => :int, #typedef unsigned __int64 DWORD64; :DWORD64 => :__int64, #typedef float FLOAT; :FLOAT => :float, #typedef int HFILE; :HFILE => :int, #typedef LONG HRESULT; :HRESULT => :long, #typedef int INT; :INT => :int, #typedef signed int INT32; :INT32 => :int, #typedef signed __int64 INT64; :INT64 => :__int64, #typedef WORD LANGID; :LANGID => :short, #typedef DWORD LCID; :LCID => :long, #typedef DWORD LCTYPE; :LCTYPE => :long, #typedef DWORD LGRPID; :LGRPID => :long, #typedef long LONG; :LONG => :long, #typedef signed int LONG32; :LONG32 => :int, #typedef __int64 LONG64; :LONG64 => :__int64, #typedef PDWORD PLCID; :PLCID => :pointer, #typedef LPVOID SC_LOCK; :SC_LOCK => :pointer, #typedef short SHORT; :SHORT => :short, #typedef unsigned char UCHAR; :UCHAR => :char, #typedef unsigned int UINT; :UINT => :int, #typedef unsigned int UINT32; :UINT32 => :int, #typedef unsigned long ULONG; :ULONG => :long, #typedef unsigned int ULONG32; :ULONG32 => :int, #typedef unsigned __int64 ULONG64; :ULONG64 => :__int64, #typedef unsigned short USHORT; :USHORT => :short, #typedef wchar_t WCHAR; :WCHAR => :wchar_t, #typedef unsigned short WORD; :WORD => :short, ## # Pointers declared with * ## #typedef DWORD* LPCOLORREF; :LPCOLORREF => :pointer, #typedef void* LPCVOID; :LPCVOID => :pointer, #typedef WCHAR* LPCWSTR; :LPCWSTR => :pointer, #typedef DWORD* LPDWORD; :LPDWORD => :pointer, #typedef HANDLE* LPHANDLE; :LPHANDLE => :pointer, #typedef int* LPINT; :LPINT => :pointer, #typedef long* LPLONG; :LPLONG => :pointer, #typedef CHAR* LPSTR; :LPSTR => :pointer, #typedef void* LPVOID; :LPVOID => :pointer, #typedef WORD* LPWORD; :LPWORD => :pointer, #typedef WCHAR* LPWSTR; :LPWSTR => :pointer, #typedef BOOL* PBOOL; :PBOOL => :pointer, #typedef BOOLEAN* PBOOLEAN; :PBOOLEAN => :pointer, #typedef BYTE* PBYTE; :PBYTE => :pointer, #typedef CHAR* PCHAR; :PCHAR => :pointer, #typedef CHAR* PCSTR; :PCSTR => :pointer, #typedef WCHAR* PCWSTR; :PCWSTR => :pointer, #typedef DWORD* PDWORD; :PDWORD => :pointer, #typedef DWORDLONG* PDWORDLONG; :PDWORDLONG => :pointer, #typedef DWORD_PTR* PDWORD_PTR; :PDWORD_PTR => :pointer, #typedef DWORD32* PDWORD32; :PDWORD32 => :pointer, #typedef DWORD64* PDWORD64; :PDWORD64 => :pointer, #typedef FLOAT* PFLOAT; :PFLOAT => :pointer, #typedef HANDLE* PHANDLE; :PHANDLE => :pointer, #typedef HKEY* PHKEY; :PHKEY => :pointer, #typedef int* PINT; :PINT => :pointer, #typedef INT_PTR* PINT_PTR; :PINT_PTR => :pointer, #typedef INT32* PINT32; :PINT32 => :pointer, #typedef INT64* PINT64; :PINT64 => :pointer, #typedef LONG* PLONG; :PLONG => :pointer, #typedef LONGLONG* PLONGLONG; :PLONGLONG => :pointer, #typedef LONG_PTR* PLONG_PTR; :PLONG_PTR => :pointer, #typedef LONG32* PLONG32; :PLONG32 => :pointer, #typedef LONG64* PLONG64; :PLONG64 => :pointer, #typedef SHORT* PSHORT; :PSHORT => :pointer, #typedef SIZE_T* PSIZE_T; :PSIZE_T => :pointer, #typedef SSIZE_T* PSSIZE_T; :PSSIZE_T => :pointer, #typedef CHAR* PSTR; :PSTR => :pointer, #typedef TBYTE* PTBYTE; :PTBYTE => :pointer, #typedef TCHAR* PTCHAR; :PTCHAR => :pointer, #typedef UCHAR* PUCHAR; :PUCHAR => :pointer, #typedef UINT* PUINT; :PUINT => :pointer, #typedef UINT_PTR* PUINT_PTR; :PUINT_PTR => :pointer, #typedef UINT32* PUINT32; :PUINT32 => :pointer, #typedef UINT64* PUINT64; :PUINT64 => :pointer, #typedef ULONG* PULONG; :PULONG => :pointer, #typedef ULONGLONG* PULONGLONG; :PULONGLONG => :pointer, #typedef ULONG_PTR* PULONG_PTR; :PULONG_PTR => :pointer, #typedef ULONG32* PULONG32; :PULONG32 => :pointer, #typedef ULONG64* PULONG64; :PULONG64 => :pointer, #typedef USHORT* PUSHORT; :PUSHORT => :pointer, #typedef void* PVOID; :PVOID => :pointer, #typedef WCHAR* PWCHAR; :PWCHAR => :pointer, #typedef WORD* PWORD; :PWORD => :pointer, #typedef WCHAR* PWSTR; :PWSTR => :pointer, #typedef HANDLE HACCEL; :HACCEL => :pointer, ## # Handles ## #typedef PVOID HANDLE; :HANDLE => :pointer, #typedef HANDLE HBITMAP; :HBITMAP => :pointer, #typedef HANDLE HBRUSH; :HBRUSH => :pointer, #typedef HANDLE HCOLORSPACE; :HCOLORSPACE => :pointer, #typedef HANDLE HCONV; :HCONV => :pointer, #typedef HANDLE HCONVLIST; :HCONVLIST => :pointer, #typedef HANDLE HDC; :HDC => :pointer, #typedef HANDLE HDDEDATA; :HDDEDATA => :pointer, #typedef HANDLE HDESK; :HDESK => :pointer, #typedef HANDLE HDROP; :HDROP => :pointer, #typedef HANDLE HDWP; :HDWP => :pointer, #typedef HANDLE HENHMETAFILE; :HENHMETAFILE => :pointer, #typedef HANDLE HFONT; :HFONT => :pointer, #typedef HANDLE HGDIOBJ; :HGDIOBJ => :pointer, #typedef HANDLE HGLOBAL; :HGLOBAL => :pointer, #typedef HANDLE HHOOK; :HHOOK => :pointer, #typedef HANDLE HICON; :HICON => :pointer, #typedef HANDLE HINSTANCE; :HINSTANCE => :pointer, #typedef HANDLE HKEY; :HKEY => :pointer, #typedef HANDLE HKL; :HKL => :pointer, #typedef HANDLE HLOCAL; :HLOCAL => :pointer, #typedef HANDLE HMENU; :HMENU => :pointer, #typedef HANDLE HMETAFILE; :HMETAFILE => :pointer, #typedef HANDLE HPALETTE; :HPALETTE => :pointer, #typedef HANDLE HPEN; :HPEN => :pointer, #typedef HANDLE HRGN; :HRGN => :pointer, #typedef HANDLE HRSRC; :HRSRC => :pointer, #typedef HANDLE HSZ; :HSZ => :pointer, #typedef HANDLE WINSTA; :WINSTA => :pointer, #typedef HANDLE HWND; :HWND => :pointer, #typedef HANDLE SC_HANDLE; :SC_HANDLE => :pointer, #typedef HANDLE SERVICE_STATUS_HANDLE; :SERVICE_STATUS_HANDLE => :pointer, }
Instance Method Summary collapse
-
#calc_padding(offset) ⇒ Object
Number of bytes that needed to be added to be aligned.
-
#initialize(railgun, platform) ⇒ Util
constructor
param ‘railgun’ is a Railgun instance.
-
#is_64bit_platform?(platform) ⇒ Boolean
Returns true if given platform has 64bit architecture expects client.platform.
- #is_array_type?(type) ⇒ Boolean
-
#is_null_pointer(pointer) ⇒ Object
Returns true if
pointer
will be considered a ‘null’ pointer. -
#is_pointer_type?(type) ⇒ Boolean
Returns true if the data type is a pointer, false otherwise.
-
#is_struct_type?(type) ⇒ Boolean
Returns true if the type passed describes a data structure, false otherwise.
-
#judge_bit_field(value, mappings) ⇒ Object
Evaluates a bit field, returning a hash representing the meaning and state of each bit.
-
#memread(address, size, buffer = nil) ⇒ Object
Read a given number of bytes from memory or from a provided buffer.
-
#pointer_size ⇒ Object
Returns the pointer size for this architecture.
-
#read_array(type, length, bufptr, buffer = nil) ⇒ Object
Read
length
number of instances oftype
frombufptr
. -
#read_data(type, position, buffer = nil) ⇒ Object
Reads data structures and several windows data types.
-
#read_pointer(buffer, offset = 0) ⇒ Object
Read and unpack a pointer from the given buffer at a given offset.
-
#read_string(pointer, length = nil) ⇒ Object
Reads null-terminated ASCII strings from memory.
-
#read_struct(definition, buffer, offset = 0) ⇒ Object
Construct the data structure described in
definition
frombuffer
starting from the indexoffset
. -
#read_wstring(pointer, length = nil) ⇒ Object
Reads null-terminated unicode strings from memory.
- #required_alignment ⇒ Object
-
#sizeof_struct(struct) ⇒ Object
Calculates the size of
struct
after alignment. -
#sizeof_type(type) ⇒ Object
Return the size, in bytes, of the given type.
-
#split_array_type(type) ⇒ Object
Given an explicit array definition (e.g. BYTE) return size (e.g. 23) and and
type
(e.g. BYTE). -
#struct_offsets(definition, offset) ⇒ Object
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.
-
#unpack_pointer(packed_pointer) ⇒ Object
Given a packed pointer, unpacks it according to architecture.
Methods included from DLLHelper
#asciiz_to_str, #assemble_buffer, #param_to_number, #str_to_ascii_z, #str_to_uni_z, #uniz_to_str
Constructor Details
#initialize(railgun, platform) ⇒ Util
param ‘railgun’ is a Railgun instance. param ‘platform’ is a value like client.platform
317 318 319 320 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 317 def initialize(railgun, platform) @railgun = railgun @is_64bit = is_64bit_platform?(platform) end |
Instance Method Details
#calc_padding(offset) ⇒ Object
Number of bytes that needed to be added to be aligned.
608 609 610 611 612 613 614 615 616 617 618 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 608 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) ⇒ Boolean
Returns true if given platform has 64bit architecture expects client.platform
641 642 643 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 641 def is_64bit_platform?(platform) platform =~ /win64/ end |
#is_array_type?(type) ⇒ Boolean
515 516 517 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 515 def is_array_type?(type) return type =~ /^\w+\[\w+\]$/ ? true : false end |
#is_null_pointer(pointer) ⇒ Object
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
343 344 345 346 347 348 349 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 343 def is_null_pointer(pointer) if pointer.kind_of? String pointer = unpack_pointer(pointer) end return pointer.nil? || pointer == 0 end |
#is_pointer_type?(type) ⇒ Boolean
Returns true if the data type is a pointer, false otherwise
509 510 511 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 509 def is_pointer_type?(type) return TYPE_DEFINITIONS[type] == :pointer end |
#is_struct_type?(type) ⇒ Boolean
Returns true if the type passed describes a data structure, false otherwise
520 521 522 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 520 def is_struct_type?(type) return type.kind_of? Array end |
#judge_bit_field(value, mappings) ⇒ Object
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, ... }
656 657 658 659 660 661 662 663 664 665 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 656 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) ⇒ Object
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
.
404 405 406 407 408 409 410 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 404 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 ⇒ Object
Returns the pointer size for this architecture
526 527 528 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 526 def pointer_size is_64bit ? 8 : 4 end |
#read_array(type, length, bufptr, buffer = nil) ⇒ Object
Read length
number of instances of type
from bufptr
.
bufptr
is an index in buffer
or, if buffer
is nil, a memory address
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 469 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) ⇒ Object
Reads data structures and several windows data types
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 422 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('V').first == 1 when :LONG return raw.unpack('V').first end #If nothing worked thus far, return it raw return raw end |
#read_pointer(buffer, offset = 0) ⇒ Object
Read and unpack a pointer from the given buffer at a given offset
415 416 417 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 415 def read_pointer(buffer, offset = 0) unpack_pointer(buffer[offset, (offset + pointer_size)]) end |
#read_string(pointer, length = nil) ⇒ Object
Reads null-terminated ASCII strings from memory.
Given a pointer to a null terminated array of CHARs, return a ruby String. If pointer
is NULL (see #is_null_pointer) returns an empty string.
385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 385 def read_string(pointer, length=nil) if is_null_pointer(pointer) return '' end unless length length = railgun.kernel32.lstrlenA(pointer)['return'] end chars = read_array(:CHAR, length, pointer) return chars.join('') end |
#read_struct(definition, buffer, offset = 0) ⇒ Object
Construct the data structure described in definition
from buffer
starting from the index offset
493 494 495 496 497 498 499 500 501 502 503 504 505 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 493 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) ⇒ Object
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.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 358 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 ⇒ Object
601 602 603 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 601 def required_alignment is_64bit ? 8 : 4 end |
#sizeof_struct(struct) ⇒ Object
Calculates the size of struct
after alignment.
569 570 571 572 573 574 575 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 569 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) ⇒ Object
Return the size, in bytes, of the given type
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 531 def sizeof_type(type) if is_pointer_type?(type) return pointer_size end if type.kind_of? String if is_array_type?(type) element_type, length = split_array_type(type) return length * sizeof_type(element_type) else return sizeof_type(type.to_sym) end 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) ⇒ Object
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.
625 626 627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 625 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.to_sym, length.to_i else raise "Can not split non-array type #{type}" end end |
#struct_offsets(definition, offset) ⇒ Object
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.
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 582 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) ⇒ Object
Given a packed pointer, unpacks it according to architecture
325 326 327 328 329 330 331 332 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 325 def unpack_pointer(packed_pointer) if is_64bit # Assume little endian packed_pointer.unpack('Q<')[0] else packed_pointer.unpack('V')[0] end end |