CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb
Views: 1904
1
# -*- coding: binary -*-
2
require 'rex/post/meterpreter/extensions/stdapi/railgun/library_helper'
3
4
module Rex
5
module Post
6
module Meterpreter
7
module Extensions
8
module Stdapi
9
module Railgun
10
11
#
12
# Utility methods and constants for dealing with most types of variables.
13
#
14
class Util
15
16
# Bring in some useful string manipulation utility functions
17
include LibraryHelper
18
19
# Data type size info: http://msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx
20
PRIMITIVE_TYPE_SIZES = {
21
:int => 4,
22
:__int8 => 1,
23
:__int16 => 2,
24
:__int32 => 4,
25
:__int64 => 8,
26
:bool => 1,
27
:char => 1,
28
:short => 2,
29
:long => 4,
30
:long_long => 8,
31
:float => 4,
32
:double => 8,
33
:long_double => 8,
34
:wchar_t => 2,
35
}
36
37
#
38
# Maps a data type to its corresponding primitive or special type
39
# +:pointer+. Note, primitive types are mapped to themselves.
40
#
41
# typedef info: http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx
42
TYPE_DEFINITIONS = {
43
##
44
# Primitives
45
##
46
:int => :int,
47
:__int8 => :__int8,
48
:__int16 => :__int16,
49
:__int32 => :__int32,
50
:__int64 => :__int64,
51
:bool => :bool,
52
:char => :char,
53
:short => :short,
54
:long => :long,
55
:long_long => :long_long,
56
:float => :float,
57
:double => :double,
58
:long_double => :long_double,
59
:wchar_t => :wchar_t,
60
##
61
# Non-pointers
62
##
63
#typedef WORD ATOM;
64
:ATOM => :short,
65
#typedef int BOOL;
66
:BOOL => :int,
67
#typedef BYTE BOOLEAN;
68
:BOOLEAN => :char,
69
#typedef unsigned char BYTE;
70
:BYTE => :char,
71
#typedef char CHAR;
72
:CHAR => :char,
73
#typedef DWORD COLORREF;
74
:COLORREF => :long,
75
#typedef unsigned long DWORD;
76
:DWORD => :long,
77
#typedef unsigned int DWORD32;
78
:DWORD32 => :int,
79
#typedef unsigned __int64 DWORD64;
80
:DWORD64 => :__int64,
81
#typedef float FLOAT;
82
:FLOAT => :float,
83
#typedef int HFILE;
84
:HFILE => :int,
85
#typedef LONG HRESULT;
86
:HRESULT => :long,
87
#typedef int INT;
88
:INT => :int,
89
#typedef signed int INT32;
90
:INT32 => :int,
91
#typedef signed __int64 INT64;
92
:INT64 => :__int64,
93
#typedef WORD LANGID;
94
:LANGID => :short,
95
#typedef DWORD LCID;
96
:LCID => :long,
97
#typedef DWORD LCTYPE;
98
:LCTYPE => :long,
99
#typedef DWORD LGRPID;
100
:LGRPID => :long,
101
#typedef long LONG;
102
:LONG => :long,
103
#typedef signed int LONG32;
104
:LONG32 => :int,
105
#typedef __int64 LONG64;
106
:LONG64 => :__int64,
107
#typedef PDWORD PLCID;
108
:PLCID => :pointer,
109
#typedef LPVOID SC_LOCK;
110
:SC_LOCK => :pointer,
111
#typedef short SHORT;
112
:SHORT => :short,
113
#typedef unsigned char UCHAR;
114
:UCHAR => :char,
115
#typedef unsigned int UINT;
116
:UINT => :int,
117
#typedef unsigned int UINT32;
118
:UINT32 => :int,
119
#typedef unsigned long ULONG;
120
:ULONG => :long,
121
#typedef unsigned int ULONG32;
122
:ULONG32 => :int,
123
#typedef unsigned __int64 ULONG64;
124
:ULONG64 => :__int64,
125
#typedef unsigned short USHORT;
126
:USHORT => :short,
127
#typedef wchar_t WCHAR;
128
:WCHAR => :wchar_t,
129
#typedef unsigned short WORD;
130
:WORD => :short,
131
##
132
# Pointers declared with *
133
##
134
#typedef DWORD* LPCOLORREF;
135
:LPCOLORREF => :pointer,
136
#typedef void* LPCVOID;
137
:LPCVOID => :pointer,
138
#typedef WCHAR* LPCWSTR;
139
:LPCWSTR => :pointer,
140
#typedef DWORD* LPDWORD;
141
:LPDWORD => :pointer,
142
#typedef HANDLE* LPHANDLE;
143
:LPHANDLE => :pointer,
144
#typedef int* LPINT;
145
:LPINT => :pointer,
146
#typedef long* LPLONG;
147
:LPLONG => :pointer,
148
#typedef CHAR* LPSTR;
149
:LPSTR => :pointer,
150
#typedef void* LPVOID;
151
:LPVOID => :pointer,
152
#typedef WORD* LPWORD;
153
:LPWORD => :pointer,
154
#typedef WCHAR* LPWSTR;
155
:LPWSTR => :pointer,
156
#typedef BOOL* PBOOL;
157
:PBOOL => :pointer,
158
#typedef BOOLEAN* PBOOLEAN;
159
:PBOOLEAN => :pointer,
160
#typedef BYTE* PBYTE;
161
:PBYTE => :pointer,
162
#typedef CHAR* PCHAR;
163
:PCHAR => :pointer,
164
#typedef CHAR* PCSTR;
165
:PCSTR => :pointer,
166
#typedef WCHAR* PCWSTR;
167
:PCWSTR => :pointer,
168
#typedef DWORD* PDWORD;
169
:PDWORD => :pointer,
170
#typedef DWORDLONG* PDWORDLONG;
171
:PDWORDLONG => :pointer,
172
#typedef DWORD_PTR* PDWORD_PTR;
173
:PDWORD_PTR => :pointer,
174
#typedef DWORD32* PDWORD32;
175
:PDWORD32 => :pointer,
176
#typedef DWORD64* PDWORD64;
177
:PDWORD64 => :pointer,
178
#typedef FLOAT* PFLOAT;
179
:PFLOAT => :pointer,
180
#typedef HANDLE* PHANDLE;
181
:PHANDLE => :pointer,
182
#typedef HKEY* PHKEY;
183
:PHKEY => :pointer,
184
#typedef int* PINT;
185
:PINT => :pointer,
186
#typedef INT_PTR* PINT_PTR;
187
:PINT_PTR => :pointer,
188
#typedef INT32* PINT32;
189
:PINT32 => :pointer,
190
#typedef INT64* PINT64;
191
:PINT64 => :pointer,
192
#typedef LONG* PLONG;
193
:PLONG => :pointer,
194
#typedef LONGLONG* PLONGLONG;
195
:PLONGLONG => :pointer,
196
#typedef LONG_PTR* PLONG_PTR;
197
:PLONG_PTR => :pointer,
198
#typedef LONG32* PLONG32;
199
:PLONG32 => :pointer,
200
#typedef LONG64* PLONG64;
201
:PLONG64 => :pointer,
202
#typedef SHORT* PSHORT;
203
:PSHORT => :pointer,
204
#typedef SIZE_T* PSIZE_T;
205
:PSIZE_T => :pointer,
206
#typedef SSIZE_T* PSSIZE_T;
207
:PSSIZE_T => :pointer,
208
#typedef CHAR* PSTR;
209
:PSTR => :pointer,
210
#typedef TBYTE* PTBYTE;
211
:PTBYTE => :pointer,
212
#typedef TCHAR* PTCHAR;
213
:PTCHAR => :pointer,
214
#typedef UCHAR* PUCHAR;
215
:PUCHAR => :pointer,
216
#typedef UINT* PUINT;
217
:PUINT => :pointer,
218
#typedef UINT_PTR* PUINT_PTR;
219
:PUINT_PTR => :pointer,
220
#typedef UINT32* PUINT32;
221
:PUINT32 => :pointer,
222
#typedef UINT64* PUINT64;
223
:PUINT64 => :pointer,
224
#typedef ULONG* PULONG;
225
:PULONG => :pointer,
226
#typedef ULONGLONG* PULONGLONG;
227
:PULONGLONG => :pointer,
228
#typedef ULONG_PTR* PULONG_PTR;
229
:PULONG_PTR => :pointer,
230
#typedef ULONG32* PULONG32;
231
:PULONG32 => :pointer,
232
#typedef ULONG64* PULONG64;
233
:PULONG64 => :pointer,
234
#typedef USHORT* PUSHORT;
235
:PUSHORT => :pointer,
236
#typedef void* PVOID;
237
:PVOID => :pointer,
238
#typedef WCHAR* PWCHAR;
239
:PWCHAR => :pointer,
240
#typedef WORD* PWORD;
241
:PWORD => :pointer,
242
#typedef WCHAR* PWSTR;
243
:PWSTR => :pointer,
244
#typedef HANDLE HACCEL;
245
:HACCEL => :pointer,
246
##
247
# Handles
248
##
249
#typedef PVOID HANDLE;
250
:HANDLE => :pointer,
251
#typedef HANDLE HBITMAP;
252
:HBITMAP => :pointer,
253
#typedef HANDLE HBRUSH;
254
:HBRUSH => :pointer,
255
#typedef HANDLE HCOLORSPACE;
256
:HCOLORSPACE => :pointer,
257
#typedef HANDLE HCONV;
258
:HCONV => :pointer,
259
#typedef HANDLE HCONVLIST;
260
:HCONVLIST => :pointer,
261
#typedef HANDLE HDC;
262
:HDC => :pointer,
263
#typedef HANDLE HDDEDATA;
264
:HDDEDATA => :pointer,
265
#typedef HANDLE HDESK;
266
:HDESK => :pointer,
267
#typedef HANDLE HDROP;
268
:HDROP => :pointer,
269
#typedef HANDLE HDWP;
270
:HDWP => :pointer,
271
#typedef HANDLE HENHMETAFILE;
272
:HENHMETAFILE => :pointer,
273
#typedef HANDLE HFONT;
274
:HFONT => :pointer,
275
#typedef HANDLE HGDIOBJ;
276
:HGDIOBJ => :pointer,
277
#typedef HANDLE HGLOBAL;
278
:HGLOBAL => :pointer,
279
#typedef HANDLE HHOOK;
280
:HHOOK => :pointer,
281
#typedef HANDLE HICON;
282
:HICON => :pointer,
283
#typedef HANDLE HINSTANCE;
284
:HINSTANCE => :pointer,
285
#typedef HANDLE HKEY;
286
:HKEY => :pointer,
287
#typedef HANDLE HKL;
288
:HKL => :pointer,
289
#typedef HANDLE HLOCAL;
290
:HLOCAL => :pointer,
291
#typedef HANDLE HMENU;
292
:HMENU => :pointer,
293
#typedef HANDLE HMETAFILE;
294
:HMETAFILE => :pointer,
295
#typedef HANDLE HPALETTE;
296
:HPALETTE => :pointer,
297
#typedef HANDLE HPEN;
298
:HPEN => :pointer,
299
#typedef HANDLE HRGN;
300
:HRGN => :pointer,
301
#typedef HANDLE HRSRC;
302
:HRSRC => :pointer,
303
#typedef HANDLE HSZ;
304
:HSZ => :pointer,
305
#typedef HANDLE WINSTA;
306
:WINSTA => :pointer,
307
#typedef HANDLE HWND;
308
:HWND => :pointer,
309
#typedef HANDLE SC_HANDLE;
310
:SC_HANDLE => :pointer,
311
#typedef HANDLE SERVICE_STATUS_HANDLE;
312
:SERVICE_STATUS_HANDLE => :pointer,
313
}
314
315
# param 'railgun' is a Railgun instance.
316
# param 'arch' is the client.arch
317
def initialize(railgun, arch)
318
@railgun = railgun
319
@is_64bit = arch == ARCH_X64
320
@process_heap = nil
321
end
322
323
#
324
# Given a packed pointer, unpacks it according to architecture
325
#
326
def unpack_pointer(packed_pointer)
327
if is_64bit
328
# Assume little endian
329
packed_pointer.unpack('Q<')[0]
330
else
331
packed_pointer.unpack('V')[0]
332
end
333
end
334
335
#
336
# Returns true if +pointer+ will be considered a 'null' pointer.
337
#
338
# If +pointer+ is nil or 0, returns true
339
# If +pointer+ is a String, if 0 after unpacking, returns true
340
# false otherwise
341
#
342
# See #unpack_pointer
343
#
344
def is_null_pointer(pointer)
345
if pointer.kind_of? String
346
pointer = unpack_pointer(pointer)
347
end
348
349
return pointer.nil? || pointer == 0
350
end
351
352
def alloc_and_write_data(data)
353
return nil if data.nil? || process_heap.nil?
354
355
result = railgun.kernel32.HeapAlloc(process_heap, railgun.const('HEAP_ZERO'), data.length)
356
return nil if result['return'].nil?
357
358
addr = result['return']
359
return nil unless railgun.memwrite(addr, data, data.length)
360
361
addr
362
end
363
364
def free_data(*ptrs)
365
return false if ptrs.empty?
366
return false if process_heap.nil?
367
368
results = railgun.multi(
369
ptrs.map { |ptr| ['kernel32', 'HeapFree', [process_heap, 0, ptr.to_i]] }
370
)
371
results.map { |res| res['return'] }.all?
372
end
373
374
#
375
# Reads null-terminated unicode strings from memory.
376
#
377
# Given a pointer to a null terminated array of WCHARs, return a ruby
378
# String. If +pointer+ is NULL (see #is_null_pointer) returns an empty
379
# string.
380
#
381
def read_wstring(pointer, length = nil)
382
# Return an empty string for null pointers
383
if is_null_pointer(pointer)
384
return ''
385
end
386
387
# If length not provided, use lstrlenW
388
if length.nil?
389
length = railgun.kernel32.lstrlenW(pointer)['return']
390
end
391
392
# Retrieve the array of characters
393
chars = read_array(:WCHAR, length, pointer)
394
395
# Concatenate the characters and convert to a ruby string
396
str = uniz_to_str(chars.join(''))
397
398
return str
399
end
400
401
#
402
# Write Unicode strings to memory.
403
#
404
# Given a string, returns a pointer to a null terminated WCHARs array.
405
#
406
def alloc_and_write_wstring(value)
407
return nil if value.nil?
408
409
alloc_and_write_data(str_to_uni_z(value))
410
end
411
412
alias free_wstring free_data
413
414
#
415
# Write ASCII strings to memory.
416
#
417
# Given a string, returns a pointer to a null terminated CHARs array.
418
# InitializeStr(&Str,"string");
419
#
420
def alloc_and_write_string(value)
421
return nil if value.nil?
422
423
alloc_and_write_data(str_to_ascii_z(value))
424
end
425
426
alias free_string free_data
427
428
#
429
# Reads null-terminated ASCII strings from memory.
430
#
431
# Given a pointer to a null terminated array of CHARs, return a ruby
432
# String. If +pointer+ is NULL (see #is_null_pointer) returns an empty
433
# string.
434
#
435
def read_string(pointer, length=nil)
436
if is_null_pointer(pointer)
437
return ''
438
end
439
440
unless length
441
length = railgun.kernel32.lstrlenA(pointer)['return']
442
end
443
444
chars = read_array(:CHAR, length, pointer)
445
return chars.join('')
446
end
447
448
#
449
# Read a given number of bytes from memory or from a provided buffer.
450
#
451
# If +buffer+ is not provided, read +size+ bytes from the client's memory.
452
# If +buffer+ is provided, reads +size+ characters from the index of +address+.
453
#
454
def memread(address, size, buffer = nil)
455
if buffer.nil?
456
return railgun.memread(address, size)
457
else
458
return buffer[address .. (address + size - 1)]
459
end
460
end
461
462
#
463
# Read and unpack a pointer from the given buffer at a given offset
464
#
465
def read_pointer(buffer, offset = 0)
466
unpack_pointer(buffer[offset, (offset + pointer_size)])
467
end
468
469
#
470
# Reads data structures and several windows data types
471
#
472
def read_data(type, position, buffer = nil)
473
if buffer.nil?
474
buffer = memread(position, sizeof_type(type))
475
position = 0
476
end
477
478
# If we're asked to read a data structure, deligate to read_struct
479
if is_struct_type?(type)
480
return read_struct(type, buffer, position)
481
end
482
483
# If the type is an array with a given size...
484
# BYTE[3] for example or BYTE[ENCRYPTED_PWLEN] or even PDWORD[23]
485
if is_array_type?(type)
486
# Separate the element type from the size of the array
487
element_type, length = split_array_type(type)
488
489
# Have read_array take care of the rest
490
return read_array(element_type, length, position, buffer)
491
end
492
493
size = sizeof_type(type)
494
raw = memread(position, size, buffer)
495
496
# read/unpack data for the types we have hard-coded support for
497
case type
498
when :LPWSTR
499
# null-terminated string of 16-bit Unicode characters
500
return read_wstring(read_pointer(raw))
501
when :DWORD
502
# Both on x86 and x64, DWORD is 32 bits
503
return raw.unpack('V').first
504
when :BOOL
505
return raw.unpack('V').first == 1
506
when :LONG
507
return raw.unpack('V').first
508
end
509
510
#If nothing worked thus far, return it raw
511
return raw
512
end
513
514
#
515
# Read +length+ number of instances of +type+ from +bufptr+ .
516
#
517
# +bufptr+ is an index in +buffer+ or, if +buffer+ is nil, a memory address
518
#
519
def read_array(type, length, bufptr, buffer = nil)
520
if length <= 0
521
return []
522
end
523
524
size = sizeof_type(type)
525
# Grab the bytes that the array consists of
526
buffer = memread(bufptr, size * length, buffer)
527
528
offset = 0
529
530
1.upto(length).map do |n|
531
data = read_data(type, offset, buffer)
532
533
offset = offset + size
534
535
data
536
end
537
end
538
539
#
540
# Construct the data structure described in +definition+ from +buffer+
541
# starting from the index +offset+
542
#
543
def read_struct(definition, buffer, offset = 0)
544
data = {}
545
546
offsets = struct_offsets(definition, offset)
547
548
definition.each do |mapping|
549
key, data_type = mapping
550
551
data[key] = read_data(data_type, offsets.shift, buffer)
552
end
553
554
data
555
end
556
557
558
# Returns true if the data type is a pointer, false otherwise
559
def is_pointer_type?(type)
560
return TYPE_DEFINITIONS[type] == :pointer
561
end
562
563
# Returns whether the given type represents an array of another type
564
# For example BYTE[3], BYTE[ENCRYPTED_PWLEN], or even PDWORD[23]
565
def is_array_type?(type)
566
return type =~ /^\w+\[\w+\]$/ ? true : false
567
end
568
569
# Returns true if the type passed describes a data structure, false otherwise
570
def is_struct_type?(type)
571
return type.kind_of? Array
572
end
573
574
575
# Returns the pointer size for this architecture
576
def pointer_size
577
is_64bit ? 8 : 4
578
end
579
580
# Return the size, in bytes, of the given type
581
def sizeof_type(type)
582
if is_pointer_type?(type)
583
return pointer_size
584
end
585
586
if type.kind_of? String
587
if is_array_type?(type)
588
element_type, length = split_array_type(type)
589
return length * sizeof_type(element_type)
590
else
591
return sizeof_type(type.to_sym)
592
end
593
end
594
595
if is_struct_type?(type)
596
return sizeof_struct(type)
597
end
598
599
if TYPE_DEFINITIONS.has_key?(type)
600
primitive = TYPE_DEFINITIONS[type]
601
602
if primitive == :pointer
603
return pointer_size
604
end
605
606
if PRIMITIVE_TYPE_SIZES.has_key?(primitive)
607
return PRIMITIVE_TYPE_SIZES[primitive]
608
else
609
raise "Type #{type} was mapped to non-existent primitive #{primitive}"
610
end
611
end
612
613
raise "Unable to determine size for type #{type}."
614
end
615
616
#
617
# Calculates the size of +struct+ after alignment.
618
#
619
def sizeof_struct(struct)
620
offsets = struct_offsets(struct, 0)
621
last_data_size = sizeof_type(struct.last[1])
622
size_no_padding = offsets.last + last_data_size
623
624
return size_no_padding + calc_padding(size_no_padding)
625
end
626
627
#
628
# Given a description of a data structure, returns an Array containing
629
# the offset from the beginning for each subsequent element, taking into
630
# consideration alignment and padding.
631
#
632
def struct_offsets(definition, offset)
633
padding = 0
634
offsets = []
635
definition.each do |mapping|
636
key, data_type = mapping
637
if sizeof_type(data_type) > padding
638
offset = offset + padding
639
end
640
641
offsets.push(offset)
642
643
offset = offset + sizeof_type(data_type)
644
padding = calc_padding(offset)
645
end
646
647
offsets
648
end
649
650
# http://en.wikipedia.org/wiki/Data_structure_alignment
651
def required_alignment
652
is_64bit ? 8 : 4
653
end
654
655
#
656
# Number of bytes that needed to be added to be aligned.
657
#
658
def calc_padding(offset)
659
align = required_alignment
660
661
# If offset is not aligned...
662
if (offset % align) != 0
663
# Calculate padding needed to be aligned
664
align - (offset & (align - 1))
665
else
666
0
667
end
668
end
669
670
#
671
# Given an explicit array definition (e.g. BYTE[23]) return size (e.g. 23) and
672
# and +type+ (e.g. BYTE). If a constant is given, attempt to resolve it
673
# that constant.
674
#
675
def split_array_type(type)
676
if type =~ /^(\w+)\[(\w+)\]$/
677
element_type = $1
678
length = $2
679
unless length =~ /^\d+$/
680
length = railgun.const(length)
681
end
682
683
return element_type.to_sym, length.to_i
684
else
685
raise "Can not split non-array type #{type}"
686
end
687
end
688
689
#
690
# Evaluates a bit field, returning a hash representing the meaning and
691
# state of each bit.
692
#
693
# Parameters:
694
# +value+:: a bit field represented by a Integer
695
# +mappings+:: { 'WINAPI_CONSTANT_NAME' => :descriptive_symbol, ... }
696
#
697
# Returns:
698
# { :descriptive_symbol => true/false, ... }
699
#
700
def judge_bit_field(value, mappings)
701
flags = {}
702
703
mappings.each do |constant_name, key|
704
flags[key] = (value & railgun.const(constant_name)) != 0
705
end
706
707
flags
708
end
709
710
protected
711
712
attr_accessor :railgun, :is_64bit
713
714
private
715
716
def process_heap
717
return @process_heap unless @process_heap.nil?
718
719
handle = railgun.kernel32.GetProcessHeap()['return']
720
return nil if handle == 0
721
@process_heap = handle
722
end
723
end # Util
724
end # Railgun
725
end # Stdapi
726
end # Extensions
727
end # Meterpreter
728
end # Post
729
end # Rex
730
731