Class: TurboRex::MSRPC::RPCFinder::MemoryFinder

Inherits:
Object
  • Object
show all
Includes:
Utils, Windows::Utils
Defined in:
lib/turborex/msrpc/rpcfinder.rb

Defined Under Namespace

Classes: RPC_AuthInfo, RPC_Endpoint, RPC_Interface

Constant Summary

Constants included from TurboRex::MSRPC::RPCBase

TurboRex::MSRPC::RPCBase::DCE_TransferSyntax, TurboRex::MSRPC::RPCBase::GUID, TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO, TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO32, TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO64, TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO, TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO32, TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO64, TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC, TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC32, TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC64, TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO, TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO32, TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO64, TurboRex::MSRPC::RPCBase::NDR64_TransferSyntax, TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_T, TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_T32, TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_T64, TurboRex::MSRPC::RPCBase::RPC_IF_ID, TurboRex::MSRPC::RPCBase::RPC_PROTSEQ_ENDPOINT, TurboRex::MSRPC::RPCBase::RPC_PROTSEQ_ENDPOINT32, TurboRex::MSRPC::RPCBase::RPC_PROTSEQ_ENDPOINT64, TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE, TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE32, TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE64, TurboRex::MSRPC::RPCBase::RPC_SYNTAX_IDENTIFIER, TurboRex::MSRPC::RPCBase::RPC_SYNTAX_IDENTIFIER64, TurboRex::MSRPC::RPCBase::RPC_Struct_Mgr32, TurboRex::MSRPC::RPCBase::RPC_Struct_Mgr64, TurboRex::MSRPC::RPCBase::RPC_VERSION

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Utils

#gen_script_rpc_client_np, raw_to_guid_str, read_cstring

Methods included from TurboRex::MSRPC::RPCBase

from_guid_str, make_transferSyntax

Methods included from CStruct

#define_structs

Methods included from Windows::Utils

find_export_func, find_import_func, #get_version, is_wow64?, multibyte_to_widechar, process_arch, process_arch_x64?, read_memory

Constructor Details

#initialize(pid, opts = {}) ⇒ MemoryFinder

Returns a new instance of MemoryFinder.



1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1168

def initialize(pid, opts = {})
  raise 'Not work on non-Windows os.' unless ::OS.windows?

  if opts[:debug_priv]
    unless Metasm::WinOS.get_debug_privilege
      raise 'Unable to get SeDebugPrivilege.'
    end
  end

  @process = open_process(pid)
  @mem = @process.memory
  opts[:force_load] ||= {}

  unless load_headers(opts[:force_load])
    raise 'Unable to load RPC structure definitions.'
  end

  @header.prepare_visualstudio

  @gRpcServer = nil
  @rpc_interfaces = []
  @server_interfaces = []
  @endpoints = []
end

Instance Attribute Details

#headerObject (readonly)

Returns the value of attribute header.



1146
1147
1148
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1146

def header
  @header
end

#processObject (readonly)

Returns the value of attribute process.



1145
1146
1147
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1145

def process
  @process
end

Class Method Details

.list_process_pidObject



1193
1194
1195
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1193

def self.list_process_pid
  TurboRex::Windows.list_all_process_pid
end

Instance Method Details

#closeObject



1197
1198
1199
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1197

def close
  @process.close
end

#enum_rpc_interfaces(rpc_server_t) ⇒ Object



1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1209

def enum_rpc_interfaces(rpc_server_t)
  num_entries = rpc_server_t.InterfaceDict.NumberOfEntries
  dictsize = num_entries * ptr_len

  rpc_interface_t = @header['RPC_INTERFACE_T'] # read data as RPC_INTERFACE_T
  begin
    data = @mem.get_page(rpc_server_t.InterfaceDict.pArray, dictsize)
    return false if data.nil?

    (0..dictsize).step(ptr_len) do |p|
      prpc_interface_t = if pe.ptr_32?
                           data[p, ptr_len].unpack('V')[0]
                         else
                           data[p, ptr_len].unpack('Q<')[0]
                         end

      interface_t = rpc_interface_t.from_str(@mem.get_page(prpc_interface_t, rpc_interface_t.size))
      get_rpc_interfaces_info(interface_t)
    end
  rescue StandardError
    false
  end
end

#find_global_rpc_serverObject



1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1299

def find_global_rpc_server
  rpcrt4 = @process.modules.select { |m| m.path =~ /rpcrt4.dll/i }[0]

  pe = TurboRex::PEFile::PE.new_from_file(rpcrt4.path)
  data_section = pe.sections.select { |s| s.name == '.data' }[0]
  startaddr = rpcrt4.addr + data_section.vma
  endaddr = startaddr + data_section._section_header.v['Misc']
  ptr_len = pe.ptr_32? ? 4 : 8 && @header.llp64
  max_entries = @header.numeric_constants.assoc('MAX_SIMPLE_DICT_ENTRIES')[1]
  pe.close

  scan_marker(nil, startaddr..endaddr, ptr_len) do |data|
    pointer = if pe.ptr_32?
                data.unpack('V')[0]
              else
                data.unpack('Q<')[0]
              end

    rpc_server_t = @header['RPC_SERVER_T'] # read data as RPC_SERVER_T
    begin
      data = @mem.get_page(pointer, rpc_server_t.size)
    rescue StandardError
      next
    end
    rpc_server_t.from_str data

    num_entries = rpc_server_t.InterfaceDict.NumberOfEntries
    dictsize = num_entries * ptr_len
    next if num_entries > max_entries || num_entries <= 0

    rpc_interface_t = @header['RPC_INTERFACE_T'] # read data as RPC_INTERFACE_T
    begin
      data = @mem.get_page(rpc_server_t.InterfaceDict.pArray, dictsize)
      next if data.nil?

      (0..dictsize).step(ptr_len) do |p|
        prpc_interface_t = if pe.ptr_32?
                             data[p, ptr_len].unpack('V')[0]
                           else
                             data[p, ptr_len].unpack('Q<')[0]
                           end

        interface_t = rpc_interface_t.from_str(@mem.get_page(prpc_interface_t, rpc_interface_t.size))
        if interface_t.pRpcServer == pointer
          if interface_t.RpcServerInterface.TransferSyntax.to_string == TurboRex::MSRPC::RPCBase::DCE_TransferSyntax.to_s
            return rpc_server_t
          end
        end
      end
    rescue StandardError
      next
    end
  end
end

#find_rpc_serverObject



1205
1206
1207
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1205

def find_rpc_server
  @gRpcServer = find_global_rpc_server
end

#get_com_interface_name(interface_id) ⇒ Object



1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1262

def get_com_interface_name(interface_id)
  require 'win32/registry'
  case @arch
  when 'x86'
    prefix = ''
  when 'x64'
    prefix = 'Wow6432Node\\'
  end
  begin
    Win32::Registry::HKEY_CLASSES_ROOT.open(prefix + "Interface\\{#{interface_id}}") do |reg|
      return reg.read('')[1] # default value
    end
  rescue StandardError
    false
  end
end

#get_interface_type(rpc_interface) ⇒ Object



1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1249

def get_interface_type(rpc_interface)
  if rpc_interface.Flags == @header.numeric_constants.assoc('RPC_IF_OLE')[1]
    return TurboRex::MSRPC::RPCBase::InterfaceType::OLE
  end

  uuid = TurboRex::MSRPC::Utils.raw_to_guid_str(rpc_interface.RpcServerInterface.InterfaceId.to_string)
  if get_com_interface_name(uuid)
    return TurboRex::MSRPC::RPCBase::InterfaceType::DCOM
  end

  TurboRex::MSRPC::RPCBase::InterfaceType::RPC
end

#get_location(_addr) ⇒ Object

Raises:

  • (NotImplementedError)


1279
1280
1281
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1279

def get_location(_addr)
  raise NotImplementedError
end

#get_rpc_interfaces_info(rpc_interface) ⇒ Object



1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1233

def get_rpc_interfaces_info(rpc_interface)
  info = TurboRex::MSRPC::RPCFinder::MemoryFinder::RPC_Interface.new
  info.flags = rpc_interface.Flags
  info.interface_type = get_interface_type(rpc_interface)
  info.interface_id = TurboRex::MSRPC::Utils.raw_to_guid_str(rpc_interface.RpcServerInterface.InterfaceId.to_string)
  if info.interface_type == TurboRex::MSRPC::RPCBase::InterfaceType::DCOM
    info.name = get_com_interface_name(info.interface_id)
  end
  info.syntax = TurboRex::MSRPC::Utils.raw_to_guid_str(rpc_interface.RpcServerInterface.TransferSyntax.to_string)

  case info.interface_type
  when TurboRex::MSRPC::RPCBase::InterfaceType::RPC
    get_location(rpc_interface.RpcServerInterface.DispatchTable)
  end
end

#process_handleObject



1201
1202
1203
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1201

def process_handle
  @process.handle
end

#scan_marker(marker, range, size = marker.size, step = 1) ⇒ Object



1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
# File 'lib/turborex/msrpc/rpcfinder.rb', line 1283

def scan_marker(marker, range, size = marker.size, step = 1)
  mem = @mem
  res = []

  range.step(step) do |va|
    data = mem.get_page(va, size)
    yield(data, va) if block_given?

    unless data.nil?
      res << va if data == marker
    end
  end

  res
end