class TurboRex::MSRPC::RPCFinder::MemoryFinder
Attributes
header[R]
process[R]
Public Class Methods
list_process_pid()
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1193 def self.list_process_pid TurboRex::Windows.list_all_process_pid end
new(pid, opts = {})
click to toggle source
# 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
Public Instance Methods
close()
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1197 def close @process.close end
enum_rpc_interfaces(rpc_server_t)
click to toggle source
# 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_server()
click to toggle source
# 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_server()
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1205 def find_rpc_server @gRpcServer = find_global_rpc_server end
get_com_interface_name(interface_id)
click to toggle source
# 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)
click to toggle source
# 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)
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1279 def get_location(_addr) raise NotImplementedError end
get_rpc_interfaces_info(rpc_interface)
click to toggle source
# 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_handle()
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1201 def process_handle @process.handle end
scan_marker(marker, range, size = marker.size, step = 1) { |data, va| ... }
click to toggle source
# 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
Private Instance Methods
force_load_file(opts)
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1420 def force_load_file(opts) @header = TurboRex::CStruct::NativeParser.new(nil, opts) end
load_headers(force_load = {})
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1370 def load_headers(force_load = {}) headers_path = TurboRex.root + '/resources/headers/rpc' include_path = TurboRex::Utils.get_all_subdir(headers_path) version_hl = get_version('rpcrt4.dll') version = ((version_hl[0] << 32) + version_hl[1]) opts = {} distance = 0 approximation = nil opts[:include_path] = include_path if force_load[:file] && force_load[:cpu] return force_load_file(force_load) end if @process.addrsz == 32 opts[:cpu] = Metasm::Ia32 pattern = '/v*_x86/rpcinternals.h' elsif @process.addrsz == 64 opts[:cpu] = Metasm::X86_64 pattern = '/v*_x64/rpcinternals.h' end Dir.glob(headers_path + pattern).each do |f| opts[:file] = f native_parser = TurboRex::CStruct::NativeParser.new(nil, opts) initializer = native_parser.parser.toplevel.symbol['RPC_CORE_RUNTIME_VERSION'].initializer initializer.each do |i| if i.rexpr == version @header = native_parser return true else d = (version - i.rexpr).abs distance = d if distance == 0 if d < distance approximation = [i.rexpr, native_parser] distance = d end end end end if force_load[:approximation] @header = approximation[1] @approximation = approximation end true end
open_process(pid)
click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1356 def open_process(pid) p = TurboRex::Windows.open_process(pid, Metasm::WinAPI::PROCESS_VM_READ) raise "Unable to open process #{pid}" if p.nil? case p.addrsz when 32 @arch = 'x86' when 64 @arch = 'x64' end p end