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
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
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
Summary: 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
Summary: Evaluates a bit field, returning a hash representing the meaning and state of each bit.
-
#memread(address, size, buffer = nil) ⇒ Object
Summary: 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 of ‘type’ from ‘bufptr’ bufptr is an index in ‘buffer’ or, if buffer is nil, a memory address.
-
#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_struct(definition, buffer, offset = 0) ⇒ Object
construct the data structure described in ‘definition’ from ‘buffer’ starting from the index ‘offset’.
-
#read_wstring(pointer, length = nil) ⇒ Object
Summary: Reads null-terminated unicode strings from memory.
- #required_alignment ⇒ Object
-
#sizeof_struct(struct) ⇒ Object
Calculates the size of the 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
310 311 312 313 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 310 def initialize(railgun, platform) @railgun = railgun @is_64bit = is_64bit_platform?(platform) end |
Instance Method Details
#calc_padding(offset) ⇒ Object
Bytes that needed to be added to be aligned
562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 562 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
594 595 596 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 594 def is_64bit_platform?(platform) platform =~ /win64/ end |
#is_array_type?(type) ⇒ Boolean
475 476 477 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 475 def is_array_type?(type) return type =~ /^\w+\[\w+\]$/ ? true : false end |
#is_null_pointer(pointer) ⇒ Object
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 false otherwise
333 334 335 336 337 338 339 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 333 def is_null_pointer(pointer) if pointer.class == 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
469 470 471 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 469 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
480 481 482 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 480 def is_struct_type?(type) return type.class == Array end |
#judge_bit_field(value, mappings) ⇒ Object
Summary:
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, ... }
610 611 612 613 614 615 616 617 618 619 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 610 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
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’
373 374 375 376 377 378 379 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 373 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
486 487 488 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 486 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
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 431 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
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 387 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) ⇒ Object
Read and unpack a pointer from the given buffer at a given offset
382 383 384 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 382 def read_pointer(buffer, offset = 0) unpack_pointer(buffer[offset, (offset + pointer_size)]) end |
#read_struct(definition, buffer, offset = 0) ⇒ Object
construct the data structure described in ‘definition’ from ‘buffer’ starting from the index ‘offset’
453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 453 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
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
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 347 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
557 558 559 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 557 def required_alignment is_64bit ? 8 : 4 end |
#sizeof_struct(struct) ⇒ Object
Calculates the size of the struct after alignment
524 525 526 527 528 529 530 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 524 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
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 491 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) ⇒ 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
577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 577 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) ⇒ 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
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 535 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
316 317 318 319 320 321 322 323 |
# File 'lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb', line 316 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 |