turborex 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +38 -0
  4. data/README.rdoc +19 -0
  5. data/examples/alpc_client.rb +15 -0
  6. data/examples/alpc_server.rb +14 -0
  7. data/examples/com_client.rb +19 -0
  8. data/examples/com_finder.rb +39 -0
  9. data/examples/create_instance.rb +15 -0
  10. data/examples/cstruct.rb +19 -0
  11. data/examples/find_com_client_calls.rb +16 -0
  12. data/examples/find_rpc_security_callback.rb +12 -0
  13. data/examples/rpc_finder.rb +117 -0
  14. data/examples/scan_exports.rb +5 -0
  15. data/examples/scan_imports.rb +5 -0
  16. data/examples/tinysdk.rb +17 -0
  17. data/lib/turborex.rb +21 -0
  18. data/lib/turborex/cstruct.rb +565 -0
  19. data/lib/turborex/cstruct/struct_helper.rb +7 -0
  20. data/lib/turborex/exception.rb +65 -0
  21. data/lib/turborex/fuzzer.rb +204 -0
  22. data/lib/turborex/fuzzer/containers.rb +115 -0
  23. data/lib/turborex/fuzzer/coverage.rb +67 -0
  24. data/lib/turborex/fuzzer/mutators.rb +25 -0
  25. data/lib/turborex/fuzzer/seed.rb +30 -0
  26. data/lib/turborex/monkey.rb +11 -0
  27. data/lib/turborex/msrpc.rb +14 -0
  28. data/lib/turborex/msrpc/decompiler.rb +244 -0
  29. data/lib/turborex/msrpc/midl.rb +747 -0
  30. data/lib/turborex/msrpc/ndrtype.rb +167 -0
  31. data/lib/turborex/msrpc/rpcbase.rb +777 -0
  32. data/lib/turborex/msrpc/rpcfinder.rb +1426 -0
  33. data/lib/turborex/msrpc/utils.rb +70 -0
  34. data/lib/turborex/pefile.rb +8 -0
  35. data/lib/turborex/pefile/pe.rb +61 -0
  36. data/lib/turborex/pefile/scanner.rb +82 -0
  37. data/lib/turborex/utils.rb +321 -0
  38. data/lib/turborex/windows.rb +402 -0
  39. data/lib/turborex/windows/alpc.rb +844 -0
  40. data/lib/turborex/windows/com.rb +266 -0
  41. data/lib/turborex/windows/com/client.rb +84 -0
  42. data/lib/turborex/windows/com/com_finder.rb +330 -0
  43. data/lib/turborex/windows/com/com_registry.rb +100 -0
  44. data/lib/turborex/windows/com/interface.rb +522 -0
  45. data/lib/turborex/windows/com/utils.rb +210 -0
  46. data/lib/turborex/windows/constants.rb +82 -0
  47. data/lib/turborex/windows/process.rb +56 -0
  48. data/lib/turborex/windows/security.rb +12 -0
  49. data/lib/turborex/windows/security/ace.rb +76 -0
  50. data/lib/turborex/windows/security/acl.rb +25 -0
  51. data/lib/turborex/windows/security/security_descriptor.rb +118 -0
  52. data/lib/turborex/windows/tinysdk.rb +89 -0
  53. data/lib/turborex/windows/utils.rb +138 -0
  54. data/resources/headers/alpc/ntdef.h +72 -0
  55. data/resources/headers/alpc/ntlpcapi.h +1014 -0
  56. data/resources/headers/rpc/common.h +162 -0
  57. data/resources/headers/rpc/guiddef.h +191 -0
  58. data/resources/headers/rpc/internal_ndrtypes.h +262 -0
  59. data/resources/headers/rpc/rpc.h +10 -0
  60. data/resources/headers/rpc/rpcdce.h +266 -0
  61. data/resources/headers/rpc/rpcdcep.h +187 -0
  62. data/resources/headers/rpc/rpcndr.h +39 -0
  63. data/resources/headers/rpc/v4_x64/rpcinternals.h +154 -0
  64. data/resources/headers/rpc/wintype.h +517 -0
  65. data/resources/headers/tinysdk/tinysdk.h +5 -0
  66. data/resources/headers/tinysdk/tinysdk/comdef.h +645 -0
  67. data/resources/headers/tinysdk/tinysdk/dbghelp.h +118 -0
  68. data/resources/headers/tinysdk/tinysdk/guiddef.h +194 -0
  69. data/resources/headers/tinysdk/tinysdk/memoryapi.h +12 -0
  70. data/resources/headers/tinysdk/tinysdk/poppack.h +12 -0
  71. data/resources/headers/tinysdk/tinysdk/pshpack4.h +13 -0
  72. data/resources/headers/tinysdk/tinysdk/winnt.h +1059 -0
  73. data/resources/headers/tinysdk/tinysdk/wintype.h +326 -0
  74. metadata +290 -0
@@ -0,0 +1,25 @@
1
+ module TurboRex
2
+ module Fuzzer
3
+ module Mutators
4
+ class CharlieMillerMutator
5
+ attr_accessor :factor
6
+
7
+ def initialize(factor=100)
8
+ @factor = factor
9
+ end
10
+
11
+ def mutate(buf)
12
+ numwrites = rand(buf.bytesize.to_f / @factor)+1
13
+ numwrites.to_i.times do |i|
14
+ rbytes = rand(256)
15
+ rn = rand(buf.bytesize)
16
+ buf[rn] = rbytes.chr
17
+ end
18
+
19
+ buf
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,30 @@
1
+ module TurboRex
2
+ module Fuzzer
3
+ class Seed
4
+ attr_reader :seed
5
+
6
+ def initialize(seed)
7
+ @seed = seed
8
+ end
9
+
10
+ def container=(c)
11
+
12
+ end
13
+
14
+ def self.from_file(path, separator="\n")
15
+ File.read(path).split(separator).map {|s| new(s)}
16
+ end
17
+ end
18
+
19
+ class SeedGroup
20
+ attr_reader :seeds
21
+ attr_accessor :energy
22
+
23
+ def initialize(seeds, energy)
24
+ @seeds = seeds
25
+ @energy = energy
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,11 @@
1
+ # Monkey patches
2
+
3
+ module Metasm
4
+ class COFF < ExeFormat
5
+ class LoadConfig < SerialStruct
6
+ # For CFG fields
7
+ xwords :guard_check_icall, :guard_dispatch_icall, :guard_fids_table, :cffunc_count
8
+ word :guard_flags
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ require 'rex/peparsey'
2
+ require 'turborex/cstruct'
3
+ require 'turborex/msrpc/rpcbase'
4
+ require 'turborex/msrpc/utils'
5
+ require 'turborex/msrpc/ndrtype.rb'
6
+ require 'turborex/msrpc/midl.rb'
7
+ require 'turborex/msrpc/decompiler.rb'
8
+ require 'turborex/msrpc/rpcfinder'
9
+
10
+ module TurboRex
11
+ module MSRPC
12
+
13
+ end
14
+ end
@@ -0,0 +1,244 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TurboRex
4
+ module MSRPC
5
+ class IStream
6
+ attr_reader :base
7
+
8
+ def initialize(isource, base)
9
+ @isource = isource
10
+ @base = @init_base = base
11
+ end
12
+
13
+ def read(len, offset=0)
14
+ @isource.read(@base+offset, len)
15
+ end
16
+
17
+ def set_base(base)
18
+ @base = base
19
+ end
20
+
21
+ def base_drift(drift)
22
+ @base += drift
23
+ end
24
+
25
+ def reset
26
+ @base = @init_base
27
+ true
28
+ end
29
+ end
30
+
31
+ class Decompiler
32
+ include TurboRex::MSRPC::RPCBase
33
+ include TurboRex::MSRPC::MIDL
34
+
35
+ attr_reader :parser
36
+
37
+ def initialize(opts = {})
38
+ arch = opts[:arch] || 'x86'
39
+ header_file = TurboRex.root + '/resources/headers/rpc/internal_ndrtypes.h'
40
+ case arch
41
+ when 'x86'
42
+ cpu = Metasm::Ia32
43
+ when 'x64'
44
+ cpu = Metasm::X86_64
45
+ else
46
+ raise 'Unknown architecture'
47
+ end
48
+
49
+ @parser = TurboRex::CStruct::NativeParser.new(nil, file: header_file, cpu: cpu, predefined: true)
50
+ end
51
+
52
+ def decompile(iface)
53
+ return false if iface.client?
54
+ switches = iface.midl_switches
55
+ return false if switches.has_one_of_switches?(%w[Os])
56
+
57
+ mode = :oif
58
+ if switches.has_switch?('Oi')
59
+ mode = :oi
60
+ elsif switches.has_switch?('all') && switches.arch_64?
61
+ return false # TODO: Implement
62
+ end
63
+
64
+ public_send "decompile_#{mode}", iface
65
+ end
66
+
67
+ def decompile_oif(iface)
68
+ OifDecompiler.new(iface, @parser).decompile
69
+ end
70
+
71
+ def parse_proc_fs_header(raw_header, mode = :Oif)
72
+ offset = 0
73
+ header_s = Struct.new(:oi_header, :oif_header, :win2k_ext).new
74
+ oi_header_s = Struct.new(:common, :explicit_handle_desc).new
75
+
76
+ oi_header_p1 = @parser.decode_c_struct('Oi_Header_HType_Flags_t', raw_header)
77
+ oi_header = if (oi_header_p1.OiFlags & Oi_HAS_RPCFLAGS) == Oi_HAS_RPCFLAGS
78
+ @parser.decode_c_struct('Oi_Header_t', raw_header)
79
+ else
80
+ @parser.decode_c_struct('Oi_Header_Without_RPCFlags_t', raw_header)
81
+ end
82
+
83
+ oi_header_s.common = oi_header
84
+ offset += oi_header.sizeof
85
+ if oi_header_p1.HandleType == FC_EXPLICIT_HANDLE
86
+ explicit_hdesc = @parser.decode_c_struct('Handle_Desc_Common_t', raw_header, offset)
87
+ case explicit_hdesc.HandleType
88
+ when FC_BIND_PRIMITIVE
89
+ explicit_handle_desc = @parser.decode_c_struct('ExplicitHandlePrimitive_t', raw_header, offset)
90
+ when FC_BIND_GENERIC
91
+ explicit_handle_desc = @parser.decode_c_struct('ExplicitHandleGeneric_t', raw_header, offset)
92
+ when FC_BIND_CONTEXT
93
+ explicit_handle_desc = @parser.decode_c_struct('ExplicitHandleContext_t', raw_header, offset)
94
+ end
95
+
96
+ offset += explicit_handle_desc.sizeof
97
+ oi_header_s.explicit_handle_desc = explicit_handle_desc
98
+ end
99
+
100
+ header_s.oi_header = oi_header_s
101
+
102
+ case mode
103
+ when :Oi
104
+ return oi_header_s, offset
105
+ when :Oif
106
+ oif_header = @parser.decode_c_struct('Oif_Header_t', raw_header, offset)
107
+ offset += oif_header.sizeof
108
+ header_s.oif_header = oif_header
109
+
110
+ if (oif_header.InterpreterOptFlags.HasExtensions) == 1 # Has win2k extension part
111
+ size = @parser.decode_c_struct('WIN2K_EXT', raw_header, offset).ExtensionVersion
112
+ case size
113
+ when WIN2K_EXT_SIZE
114
+ win2k_ext = @parser.decode_c_struct('WIN2K_EXT', raw_header, offset)
115
+ when WIN2K_EXT64_SIZE
116
+ win2k_ext = @parser.decode_c_struct('WIN2K_EXT64', raw_header, offset)
117
+ end
118
+ offset += win2k_ext.sizeof
119
+ header_s.win2k_ext = win2k_ext
120
+ end
121
+ when :Os
122
+ raise NotImplementedError
123
+ end
124
+
125
+ [header_s, offset]
126
+ end
127
+
128
+ def parse_proc_fs_header_dasm(dasm, addr, mode = :Oif)
129
+ offset = 0
130
+ header_s = Struct.new(:oi_header, :oif_header, :win2k_ext).new
131
+ oi_header_s = Struct.new(:common, :explicit_handle_desc).new
132
+
133
+ oi_header_p1 = dasm.decode_c_struct('Oi_Header_HType_Flags_t', addr + offset)
134
+ oi_header = if (oi_header_p1.OiFlags & Oi_HAS_RPCFLAGS) == Oi_HAS_RPCFLAGS
135
+ dasm.decode_c_struct('Oi_Header_t', addr + offset)
136
+ else
137
+ dasm.decode_c_struct('Oi_Header_Without_RPCFlags_t', addr + offset)
138
+ end
139
+
140
+ oi_header_s.common = oi_header
141
+ offset += oi_header.sizeof
142
+ if oi_header_p1.HandleType == FC_EXPLICIT_HANDLE
143
+ explicit_hdesc = dasm.decode_c_struct('Handle_Desc_Common_t', addr + offset)
144
+ case explicit_hdesc.HandleType
145
+ when FC_BIND_PRIMITIVE
146
+ explicit_handle_desc = dasm.decode_c_struct('ExplicitHandlePrimitive_t', addr + offset)
147
+ when FC_BIND_GENERIC
148
+ explicit_handle_desc = dasm.decode_c_struct('ExplicitHandleGeneric_t', addr + offset)
149
+ when FC_BIND_CONTEXT
150
+ explicit_handle_desc = dasm.decode_c_struct('ExplicitHandleContext_t', addr + offset)
151
+ end
152
+
153
+ offset += explicit_handle_desc.sizeof
154
+ oi_header_s.explicit_handle_desc = explicit_handle_desc
155
+ end
156
+
157
+ header_s.oi_header = oi_header_s
158
+
159
+ case mode
160
+ when :Oi
161
+ raise NotImplementedError
162
+ when :Oif
163
+ oif_header = dasm.decode_c_struct('Oif_Header_t', addr + offset)
164
+ offset += oif_header.sizeof
165
+ header_s.oif_header = oif_header
166
+
167
+ if oif_header.InterpreterOptFlags.HasExtensions == 1 # Has win2k extension part
168
+ size = dasm.decode_c_struct('WIN2K_EXT', addr + offset).ExtensionVersion
169
+ case size
170
+ when WIN2K_EXT_SIZE
171
+ win2k_ext = dasm.decode_c_struct('WIN2K_EXT', addr + offset)
172
+ when WIN2K_EXT64_SIZE
173
+ win2k_ext = dasm.decode_c_struct('WIN2K_EXT64', addr + offset)
174
+ end
175
+ offset += win2k_ext.sizeof
176
+ header_s.win2k_ext = win2k_ext
177
+ end
178
+ when :Os
179
+ raise NotImplementedError
180
+ end
181
+
182
+ [header_s, offset]
183
+ end
184
+ end
185
+
186
+ class OifDecompiler < Decompiler
187
+ FORMAT_STRING_STYLE = {
188
+ proc_fs: OifProcFormatString,
189
+ param_desc: OifParamDesc
190
+ }
191
+
192
+ def initialize(interface, cparser)
193
+ @interface = interface
194
+ @interface.decompiler = self
195
+ @cparser = cparser
196
+
197
+ @procfs_stream = nil
198
+ @typefs_stream = nil
199
+ @offset_table = interface.offset_table
200
+
201
+ make_istream
202
+ end
203
+
204
+ def decompile(interface=nil)
205
+ interface ||= @interface
206
+ midl_interface = Interface.new(interface)
207
+
208
+ @offset_table.each do |offset|
209
+ _procfs = @procfs_stream.dup
210
+ _procfs.base_drift(offset)
211
+ proc_fs = FORMAT_STRING_STYLE[:proc_fs].new(_procfs, @typefs_stream, @cparser)
212
+ procedure = proc_fs.decompile
213
+ midl_interface.push_procedure(procedure)
214
+ midl_interface.push_typedef(procedure.typedefs)
215
+ end
216
+
217
+ midl_interface
218
+ end
219
+
220
+ def parse_proc_fs_header(raw_header, mode = :Oif)
221
+ mode = :Oif
222
+ super(raw_header, mode)
223
+ end
224
+
225
+ def parse_proc_fs_header_dasm(dasm, addr, mode = :Oif)
226
+ mode = :Oif
227
+ super(dasm, addr ,mode)
228
+ end
229
+
230
+ private
231
+
232
+ def make_istream
233
+ unless (@interface.pproc_fs && @interface.ptype_fs && @interface.offset_table)
234
+ raise "The format string is not initialized."
235
+ end
236
+
237
+ isource = @interface.finder.pe._isource
238
+ @procfs_stream = IStream.new(isource, @interface.pproc_fs)
239
+ @typefs_stream = IStream.new(isource, @interface.ptype_fs)
240
+ true
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,747 @@
1
+ module TurboRex
2
+ module MSRPC
3
+ module MIDL
4
+ include NDRType
5
+
6
+ class Interface
7
+ attr_reader :uuid
8
+ attr_reader :typedefs
9
+ attr_reader :if_attrs
10
+ attr_reader :procedures
11
+
12
+ def initialize(interface)
13
+ @uuid = interface.uuid
14
+ @typedefs = []
15
+ @if_attrs = [
16
+ Attribute::EndpointAttr.new(interface.endpoints)
17
+ ]
18
+ @procedures = []
19
+ end
20
+
21
+ def push_procedure(proc)
22
+ @procedures << proc
23
+ end
24
+
25
+ def push_typedef(typedef)
26
+ @typedefs << typedef
27
+ end
28
+
29
+ def human
30
+
31
+ end
32
+ end
33
+
34
+ class Procedure
35
+ attr_reader :proc_num
36
+ attr_accessor :name
37
+ attr_reader :params
38
+ attr_reader :return_type
39
+ attr_reader :arity
40
+
41
+ def initialize(proc_num)
42
+ @proc_num = proc_num
43
+ @name = "Proc#{proc_num}"
44
+ @params = []
45
+ @return_type = nil
46
+ @arity = 0
47
+ end
48
+
49
+ def push_param(param)
50
+ @params << param
51
+ @arity += 1
52
+ end
53
+
54
+ def set_return_type(type)
55
+ @return_type = type
56
+ end
57
+
58
+ def typedefs
59
+
60
+ end
61
+ end
62
+
63
+ class Parameter
64
+ attr_reader :data_type
65
+ attr_accessor :name
66
+ attr_reader :attributes
67
+
68
+ def initialize(name, data_type=nil)
69
+ @data_type = data_type
70
+ @name = name
71
+ @attributes = []
72
+ @type_return = false
73
+ end
74
+
75
+ def push_attribute(attribute)
76
+ @attributes << attribute
77
+ end
78
+
79
+ def set_data_type(type)
80
+ @data_type = type
81
+ end
82
+
83
+ def type_return
84
+ @type_return = true
85
+ end
86
+
87
+ def is_return_type?
88
+ @type_return
89
+ end
90
+ end
91
+
92
+ class Attribute
93
+ def human
94
+
95
+ end
96
+
97
+ class VersionAttr < Attribute
98
+ SYMBOL_NAME = 'version'
99
+
100
+ def initialize(major, minor)
101
+ @major = major
102
+ @minor = minor
103
+ end
104
+
105
+ def human
106
+
107
+ end
108
+ end
109
+
110
+ class EndpointAttr < Attribute
111
+ SYMBOL_NAME = 'endpoint'
112
+
113
+ def initialize(endpoints)
114
+ @endpoints = endpoints
115
+ end
116
+
117
+ def human
118
+
119
+ end
120
+ end
121
+
122
+ class UUIDAttr < Attribute
123
+ SYMBOL_NAME = 'uuid'
124
+
125
+ def initialize(uuid)
126
+ @uuid = uuid
127
+ end
128
+
129
+ def human
130
+
131
+ end
132
+ end
133
+ end
134
+
135
+ class DataType
136
+ attr_reader :symbol_name
137
+ attr_reader :bytesize
138
+
139
+ class BaseType < DataType
140
+ attr_reader :signed
141
+
142
+ SYMBOL_NAME_TABLE = [
143
+ :boolean,
144
+ :byte,
145
+ :char,
146
+ :double,
147
+ :float,
148
+ :handle_t,
149
+ :hyper,
150
+ :__int8,
151
+ :__int16,
152
+ :int,
153
+ :__int32,
154
+ :__int3264,
155
+ :__int64,
156
+ :long,
157
+ :short,
158
+ :small,
159
+ :wchar_t,
160
+ :error_status_t
161
+ ]
162
+
163
+ BYTESIZE_MAPPING = {
164
+ boolean: 1,
165
+ byte: 1,
166
+ char: 1,
167
+ double: 8,
168
+ float: 4,
169
+ handle_t: :variable,
170
+ hyper: 8,
171
+ int: 4,
172
+ __int3264: :variable,
173
+ long: 4,
174
+ short: 2,
175
+ small: 1,
176
+ wchar_t: 2,
177
+ error_status_t: 4
178
+ }
179
+
180
+ def initialize(symbol_name, signed)
181
+ raise TurboRex::Exception::MSRPC::UnknownSymbolName unless index = SYMBOL_NAME_TABLE.index(symbol_name.to_sym)
182
+ @symbol_name ||= SYMBOL_NAME_TABLE[index]
183
+ @signed = signed
184
+ @bytesize = BYTESIZE_MAPPING[@symbol_name]
185
+ end
186
+ end
187
+
188
+ class Pointer < DataType
189
+ attr_reader :pointee
190
+ attr_reader :type
191
+ attr_accessor :level
192
+
193
+ def initialize(pointee, type, level=1)
194
+ @pointee = pointee
195
+ @type = type # ref, full, unique
196
+ @level = level
197
+
198
+ get_level
199
+ end
200
+
201
+ protected
202
+
203
+ def get_level
204
+ @pointee.is_a?(Pointer) ? @level += @pointee.get_level : @level
205
+ end
206
+ end
207
+
208
+ class Enum < DataType
209
+ attr_reader :attributes
210
+ attr_reader :member
211
+
212
+ def initialize(symbol_name, *member)
213
+ @symbol_name = symbol_name
214
+ @member = member
215
+ @attributes = []
216
+ end
217
+ end
218
+
219
+ class TypeDefinition < DataType
220
+ def initialize(symbol_name, type_specifier, declarator_list, attributes=[])
221
+ @symbol_name = symbol_name
222
+ @type_specifier = type_specifier
223
+ @declarator_list = declarator_list
224
+ @attributes = attributes
225
+ end
226
+ end
227
+
228
+ class Array < DataType
229
+ attr_reader :member
230
+ attr_reader :length
231
+
232
+ def initialize(*member)
233
+ @member = member
234
+ @length = member.length
235
+ end
236
+
237
+ def method_missing(m, *args, &block)
238
+ @member.send(m, *args, &block)
239
+ end
240
+ end
241
+ end
242
+
243
+ class ProcFormatString
244
+ include NDRType
245
+
246
+ attr_reader :header
247
+ attr_reader :param_desc
248
+ attr_accessor :cparser
249
+
250
+ def initialize(procfs_stream, typefs_stream, cparser)
251
+ @procfs_stream = procfs_stream
252
+ @typefs_stream = typefs_stream
253
+ @cparser = cparser
254
+ end
255
+
256
+ def decompile
257
+
258
+ end
259
+
260
+ def fs_length
261
+
262
+ end
263
+
264
+ private
265
+
266
+ def parse_proc_fs_header_stream(stream)
267
+
268
+ end
269
+ end
270
+
271
+ class ParamDesc
272
+ attr_reader :stream
273
+ attr_reader :typefs
274
+ attr_reader :stack_offset
275
+
276
+
277
+ def initialize(stream, typefs_stream, cparser, stack_index=nil)
278
+ @stream = stream
279
+ @typefs_stream = typefs_stream # IStream object
280
+ @cparser = cparser
281
+ @stack_index = stack_index
282
+ end
283
+
284
+ def decompile
285
+
286
+ end
287
+
288
+ def fs_length
289
+
290
+ end
291
+ end
292
+
293
+ class OifParamDesc < ParamDesc
294
+ FS_LENGTH = 6
295
+
296
+ attr_reader :param_attrs
297
+ attr_reader :typefs
298
+
299
+ # return Parameter object
300
+ def decompile
301
+ raw = @stream.read(FS_LENGTH)
302
+ header = @cparser.decode_c_struct('Oif_ParamDesc_Header_t', raw)
303
+
304
+ @param_attrs = header.ParamAttributes
305
+ @stack_offset = header.StackOffset
306
+
307
+ case @cparser.cpu.size
308
+ when 32
309
+ ptr_len = 4
310
+ when 64
311
+ ptr_len = 8
312
+ end
313
+
314
+ virtual_stack_index = @stack_offset / ptr_len
315
+ param_name = "arg_#{virtual_stack_index}"
316
+
317
+ parameter = Parameter.new(param_name)
318
+
319
+ if @param_attrs.IsBasetype == 1
320
+ struct = @cparser.decode_c_struct('Oif_Param_Desc_BaseType_t', raw)
321
+ _stream = @stream.dup
322
+ _stream.base_drift(4)
323
+ data_type = TypeFormatString::SimpleType.new(_stream, @cparser).decompile
324
+ else
325
+ struct = @cparser.decode_c_struct('Oif_Param_Desc_Other_t', raw)
326
+ typefs_offset = struct.TypeOffset
327
+ _typefs_stream = @typefs_stream.dup
328
+ _typefs_stream.base_drift(typefs_offset)
329
+ @typefs = TypeFormatString.new(_typefs_stream, @cparser)
330
+
331
+ begin
332
+ data_type = @typefs.decompile
333
+ rescue TurboRex::Exception::MSRPC::InvalidTypeFormatString
334
+ raise TurboRex::Exception::MSRPC::InvalidParamDescriptor
335
+ end
336
+ end
337
+
338
+ if @param_attrs.IsSimpleRef == 1 # First-level refenrence pointer
339
+ data_type = DataType::Pointer.new(data_type, :ref)
340
+ end
341
+
342
+ parameter.set_data_type(data_type)
343
+
344
+ if @param_attrs.IsReturn == 1
345
+ parameter.type_return
346
+ parameter.name = nil
347
+ else
348
+ if @param_attrs.IsIn == 1
349
+ parameter.attributes << :in
350
+ end
351
+
352
+ if @param_attrs.IsOut == 1
353
+ parameter.attributes << :out
354
+ end
355
+ end
356
+
357
+
358
+ parameter
359
+ end
360
+
361
+ def fs_length
362
+ FS_LENGTH
363
+ end
364
+ end
365
+
366
+ class OifProcFormatString < ProcFormatString
367
+ # return Procedure object
368
+ def decompile
369
+ header, hlength = parse_proc_fs_header_stream(@procfs_stream)
370
+ @header = header
371
+ @param_desc = []
372
+ procedure = Procedure.new(header.oi_header.common.ProcNum)
373
+
374
+ offset = hlength
375
+ loop do |i|
376
+ stream = @procfs_stream.dup
377
+ stream.base_drift(offset)
378
+
379
+ param_desc = OifParamDesc.new(stream, @typefs_stream, @cparser)
380
+
381
+ begin
382
+ param = param_desc.decompile # return Parameter object
383
+ rescue TurboRex::Exception::MSRPC::InvalidParamDescriptor
384
+ break
385
+ end
386
+
387
+ @param_desc << param_desc
388
+
389
+ if param.is_return_type?
390
+ procedure.set_return_type(param)
391
+ else
392
+ procedure.push_param(param)
393
+ end
394
+
395
+ offset += param_desc.fs_length
396
+ end
397
+
398
+ procedure
399
+ end
400
+
401
+ def parse_proc_fs_header_stream(stream)
402
+ raw_header = stream.read(28)
403
+ offset = 0
404
+ header_s = Struct.new(:oi_header, :oif_header, :win2k_ext).new
405
+ oi_header_s = Struct.new(:common, :explicit_handle_desc).new
406
+
407
+ oi_header_p1 = @cparser.decode_c_struct('Oi_Header_HType_Flags_t', raw_header)
408
+ oi_header = if (oi_header_p1.OiFlags & Oi_HAS_RPCFLAGS) == Oi_HAS_RPCFLAGS
409
+ @cparser.decode_c_struct('Oi_Header_t', raw_header)
410
+ else
411
+ @cparser.decode_c_struct('Oi_Header_Without_RPCFlags_t', raw_header)
412
+ end
413
+
414
+ oi_header_s.common = oi_header
415
+ offset += oi_header.sizeof
416
+ if oi_header_p1.HandleType == FC_EXPLICIT_HANDLE
417
+ explicit_hdesc = @cparser.decode_c_struct('Handle_Desc_Common_t', raw_header, offset)
418
+ case explicit_hdesc.HandleType
419
+ when FC_BIND_PRIMITIVE
420
+ explicit_handle_desc = @cparser.decode_c_struct('ExplicitHandlePrimitive_t', raw_header, offset)
421
+ when FC_BIND_GENERIC
422
+ explicit_handle_desc = @cparser.decode_c_struct('ExplicitHandleGeneric_t', raw_header, offset)
423
+ when FC_BIND_CONTEXT
424
+ explicit_handle_desc = @cparser.decode_c_struct('ExplicitHandleContext_t', raw_header, offset)
425
+ end
426
+
427
+ offset += explicit_handle_desc.sizeof
428
+ oi_header_s.explicit_handle_desc = explicit_handle_desc
429
+ end
430
+
431
+ header_s.oi_header = oi_header_s
432
+ oif_header = @cparser.decode_c_struct('Oif_Header_t', raw_header, offset)
433
+ offset += oif_header.sizeof
434
+ header_s.oif_header = oif_header
435
+
436
+ if (oif_header.InterpreterOptFlags.HasExtensions) == 1
437
+ size = @cparser.decode_c_struct('WIN2K_EXT', raw_header, offset).ExtensionVersion
438
+ case size
439
+ when WIN2K_EXT_SIZE
440
+ win2k_ext = @cparser.decode_c_struct('WIN2K_EXT', raw_header, offset)
441
+ when WIN2K_EXT64_SIZE
442
+ win2k_ext = @cparser.decode_c_struct('WIN2K_EXT64', raw_header, offset)
443
+ end
444
+ offset += win2k_ext.sizeof
445
+ header_s.win2k_ext = win2k_ext
446
+ end
447
+
448
+
449
+ [header_s, offset]
450
+ end
451
+ end
452
+
453
+ class TypeFormatString
454
+ include NDRType
455
+
456
+ def initialize(typefs_stream, cparser)
457
+ @typefs_stream = typefs_stream
458
+ @cparser = cparser
459
+ end
460
+
461
+ # return an object of the subclass of DataType
462
+ def decompile
463
+ fc = @typefs_stream.read(1).unpack('C').first
464
+ select_handler(fc).new(@typefs_stream, @cparser).decompile
465
+ end
466
+
467
+ def fs_length
468
+
469
+ end
470
+
471
+ def select_handler(type_fc)
472
+ HANDLER_TABLE.each do |h|
473
+ if h[:type].include?(type_fc)
474
+ return h[:handler]
475
+ end
476
+ end
477
+
478
+ raise TurboRex::Exception::MSRPC::InvalidTypeFormatString
479
+ end
480
+
481
+ class SimpleType < TypeFormatString
482
+ MAPPING = [
483
+ {value: FC_BYTE, mapping: :byte},
484
+ {value: FC_CHAR, mapping: :char},
485
+ {value: FC_SMALL, mapping: :small},
486
+ {value: FC_USMALL, mapping: {type: :small, signed: false}},
487
+ {value: FC_WCHAR, mapping: :wchar_t},
488
+ {value: FC_SHORT, mapping: :short},
489
+ {value: FC_USHORT, mapping: {type: :short, signed: false}},
490
+ {value: FC_LONG, mapping: :long},
491
+ {value: FC_ULONG, mapping: {type: :long, signed: false}},
492
+ {value: FC_FLOAT, mapping: :float},
493
+ {value: FC_HYPER, mapping: :hyper},
494
+ {value: FC_DOUBLE, mapping: :double},
495
+ {value: FC_ERROR_STATUS_T, mapping: :error_status_t},
496
+ {value: FC_INT3264, mapping: :__int3264},
497
+ {value: FC_UINT3264, mapping: {type: :__int3264, signed: false}}
498
+ ]
499
+
500
+ def decompile
501
+ type_fc = @typefs_stream.read(1).unpack('C').first
502
+ case type_fc
503
+ when FC_ENUM16
504
+ symbol_name = "DUMMY_ENUM16_#{SecureRandom.hex(2).upcase}".to_sym
505
+ enum = DataType::Enum.new(symbol_name, :dummy_member)
506
+
507
+ return DataType::TypeDefinition.new(symbol_name, enum, [symbol_name])
508
+ when FC_ENUM32
509
+ symbol_name = "DUMMY_ENUM32_#{SecureRandom.hex(2).upcase}".to_sym
510
+ enum = DataType::Enum.new(symbol_name, :dummy_member)
511
+ enum.attributes << :v1_enum
512
+ return DataType::TypeDefinition.new(symbol_name, enum, [symbol_name], enum.attributes)
513
+ else
514
+ MAPPING.each do |m|
515
+ if m[:value] == type_fc
516
+ signed = true
517
+ if m[:mapping].is_a?(Hash)
518
+ symbol_name = m[:mapping][:type]
519
+ signed = m[:mapping][:signed]
520
+ else
521
+ symbol_name = m[:mapping]
522
+ end
523
+ return DataType::BaseType.new(symbol_name, signed)
524
+ end
525
+ end
526
+ end
527
+
528
+ raise TurboRex::Exception::MSRPC::InvalidTypeFormatString
529
+ end
530
+ end
531
+
532
+ class CommonPtr < TypeFormatString
533
+ FC_ALLOCATE_ALL_NODES = 0x01
534
+ FC_DONT_FREE = 0x02
535
+ FC_ALLOCED_ON_STACK = 0x04
536
+ FC_SIMPLE_POINTER = 0x08
537
+ FC_POINTER_DEREF = 0x10
538
+
539
+ def decompile
540
+ raw = @typefs_stream.read(4)
541
+ header = @cparser.decode_c_struct('CommonPtr_Header_t', raw)
542
+
543
+ case header.PointerType
544
+ when FC_RP
545
+ pointer_type = :ref
546
+ when FC_UP
547
+ pointer_type = :unique
548
+ when FC_FP
549
+ pointer_type = :full
550
+ when FC_OP
551
+ pointer_type = :unknown # Not Implement
552
+ end
553
+
554
+ if (header.PointerAttributes & FC_SIMPLE_POINTER) == FC_SIMPLE_POINTER
555
+ struct = @cparser.decode_c_struct('CommonPtr_Simple_t', raw)
556
+ simple_type = struct.SimpleType
557
+ _stream = @typefs_stream.dup
558
+ _stream.base_drift(2)
559
+ pointee = SimpleType.new(_stream, @cparser).decompile
560
+ return DataType::Pointer.new(pointee, pointer_type)
561
+ else
562
+ cstruct = @cparser.find_c_struct('CommonPtr_Complex_t')
563
+ struct = @cparser.decode_c_struct('CommonPtr_Complex_t', raw)
564
+ desc_offset = struct.Offset
565
+ _stream = @typefs_stream.dup
566
+ _stream.base_drift(cstruct.offsetof(@cparser, 'Offset')+desc_offset)
567
+ return TypeFormatString.new(_stream, @cparser).decompile
568
+ end
569
+ end
570
+ end
571
+
572
+ class FixedSizedArray < TypeFormatString
573
+ def decompile
574
+ offset = 0
575
+ type = @typefs_stream.read(1).unpack('C').first
576
+ case type
577
+ when FC_SMFARRAY
578
+ size = @cparser.sizeof(@cparser.find_c_struct('SM_FArray_Header_t'))
579
+ header = @cparser.decode_c_struct('SM_FArray_Header_t', @typefs_stream.read(size))
580
+ when FC_LGFARRAY
581
+ size = @cparser.sizeof(@cparser.find_c_struct('LG_FArray_Header_t'))
582
+ header = @cparser.decode_c_struct('LG_FArray_Header_t', @typefs_stream.read(size))
583
+ end
584
+
585
+ total_size = header.TotalSize
586
+ offset += size
587
+ _stream = @typefs_stream.dup
588
+ _stream.base_drift(offset)
589
+ if @typefs_stream.read(1, offset).unpack('C').first == FC_PP # Pointer layout
590
+ ptr_layout = PointerLayout.new(_stream, @cparser) # TODO: How to handle when the count of pointer instance greater than one?
591
+ layout = ptr_layout.decompile.first
592
+ offset += ptr_layout.fs_length
593
+ _stream.base_drift(ptr_layout.fs_length)
594
+ element = TypeFormatString.new(_stream, @cparser).decompile
595
+ ary = ::Array.new(layout[:repeat], element)
596
+ case layout[:type]
597
+ when :fixed
598
+ return DataType::Array.new(*ary)
599
+ end
600
+ end
601
+
602
+ element = TypeFormatString.new(_stream, @cparser).decompile
603
+ if (element_size = element.bytesize) == :variable
604
+ case @cparser.cpu.size
605
+ when 32
606
+ element_size = 4
607
+ when 64
608
+ element_size = 8
609
+ end
610
+ end
611
+
612
+ ary_len = total_size / element_size
613
+ ary = ::Array.new(ary_len, element)
614
+ DataType::Array.new(*ary)
615
+ end
616
+ end
617
+
618
+ class ConformatArray < TypeFormatString
619
+ def decompile
620
+ size = @cparser.sizeof(@cparser.find_c_struct('Conformant_Array_Header_t'))
621
+ header = @cparser.decode_c_struct('Conformant_Array_Header_t', @typefs_stream.read(size))
622
+
623
+ end
624
+ end
625
+
626
+ class PointerLayout < TypeFormatString
627
+ def decompile
628
+ offset = 2
629
+ layouts = []
630
+ loop do
631
+ begin
632
+ layout, len = decompile_instance_layout(offset)
633
+ offset += len
634
+ layouts << layout
635
+ rescue TurboRex::Exception::MSRPC::InvalidTypeFormatString
636
+ break
637
+ end
638
+ end
639
+
640
+ @fs_length = offset + 1
641
+
642
+ layouts
643
+ end
644
+
645
+ def fs_length
646
+ @fs_length
647
+ end
648
+
649
+ private
650
+
651
+ def decompile_instance_layout(offset)
652
+ length = 0
653
+ ptr_instance_cstruct = @cparser.find_c_struct('Pointer_Instance_t')
654
+ ptr_instance_size = @cparser.sizeof(ptr_instance_cstruct)
655
+
656
+ case @typefs_stream.read(1, offset).unpack('C').first
657
+ when FC_NO_REPEAT
658
+ cstruct = @cparser.find_c_struct('No_Repeat_Layout_t')
659
+ size = @cparser.sizeof(cstruct)
660
+ layout = @cparser.decode_c_struct('No_Repeat_Layout_t', @typefs_stream.read(size))
661
+ ptr_desc = layout.PtrDesc
662
+ _stream = @typefs_stream.dup
663
+ _stream.base_drift(offset+cstruct.offsetof(@cparser, 'Simple'))
664
+ length = layout.sizeof
665
+ pointer = CommonPtr.new(_stream, @cparser).decompile
666
+
667
+ return {repeat: 0, type: :no_repeat, pointer: pointer}, length
668
+ when FC_FIXED_REPEAT
669
+ cstruct = @cparser.find_c_struct('Fixed_Repeat_Layout_Header_t')
670
+ size = @cparser.sizeof(cstruct)
671
+ layout_header = @cparser.decode_c_struct('Fixed_Repeat_Layout_Header_t', @typefs_stream.read(size, offset))
672
+
673
+ ary_size = layout_header.NumberOfPointers
674
+ #ptr_instance_ary = @cparser.decode_c_ary('Pointer_Instance_t', ary_size, @typefs_stream.read(ary_size*ptr_instance_size, offset+size))
675
+
676
+ ptr_ary = []
677
+ ary_size.times do |i|
678
+ _stream = @typefs_stream.dup
679
+ _stream.base_drift(offset+layout_header.sizeof+i*ptr_instance_size+ptr_instance_cstruct.offsetof(@cparser, 'Simple'))
680
+ ptr_ary << CommonPtr.new(_stream, @cparser).decompile
681
+ end
682
+
683
+ length = layout_header.sizeof + ary_size*ptr_instance_size
684
+ return {repeat: layout_header.Iterations, type: :fixed, pointer: ptr_ary}, length
685
+ when FC_VARIABLE_REPEAT
686
+ cstruct = @cparser.find_c_struct('Variable_Repeat_Layout_Header_t')
687
+ size = @cparser.sizeof(cstruct)
688
+ layout_header = @cparser.decode_c_struct('Variable_Repeat_Layout_Header_t', @typefs_stream.read(size, offset))
689
+
690
+ case layout_header.OffsetType
691
+ when FC_FIXED_OFFSET
692
+ offset_type = :fixed
693
+ when FC_VARIABLE_OFFSET
694
+ offset_type = :variable
695
+ end
696
+
697
+ ary_size = layout_header.NumberOfPointers
698
+ ptr_ary = []
699
+ ary_size.times do |i|
700
+ _stream = @typefs_stream.dup
701
+ _stream.base_drift(offset+layout_header.sizeof+i*ptr_instance_size+ptr_instance_cstruct.offsetof(@cparser, 'Simple'))
702
+ ptr_ary << CommonPtr.new(_stream, @cparser).decompile
703
+ end
704
+
705
+ length = layout_header.sizeof + ary_size*ptr_instance_size
706
+ return {repeat: layout_header.Iterations, type: :variable, offset: offset_type, pointer: ptr_ary}, length
707
+ else
708
+ raise TurboRex::Exception::MSRPC::InvalidTypeFormatString
709
+ end
710
+ end
711
+ end
712
+
713
+ HANDLER_TABLE = [
714
+ {
715
+ type: [FC_BYTE,
716
+ FC_CHAR,
717
+ FC_SMALL,
718
+ FC_USMALL,
719
+ FC_WCHAR,
720
+ FC_SHORT,
721
+ FC_USHORT,
722
+ FC_LONG,
723
+ FC_ULONG,
724
+ FC_FLOAT,
725
+ FC_HYPER,
726
+ FC_DOUBLE,
727
+ FC_ENUM16,
728
+ FC_ENUM32,
729
+ FC_ERROR_STATUS_T,
730
+ FC_INT3264,
731
+ FC_UINT3264],
732
+ handler: SimpleType
733
+ },
734
+ {
735
+ type: [FC_RP, FC_UP, FC_FP, FC_OP], handler: CommonPtr,
736
+ },
737
+ {
738
+ type: [FC_SMFARRAY, FC_LGFARRAY], handler: FixedSizedArray
739
+ },
740
+ {
741
+ type: [FC_PP], handler: PointerLayout
742
+ }
743
+ ]
744
+ end
745
+ end
746
+ end
747
+ end