turborex 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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