class TurboRex::MSRPC::RPCFinder::ImageFinder

Attributes

client_interfaces[R]
client_routines[R]
dasm[R]
dispatch_funcs[R]
midl_server_infos[R]
midl_stubless_proxy_infos[R]
midl_syntax_infos[R]
ndr_decompiler[R]
pe[R]
server_interfaces[R]
server_routines[R]

Public Class Methods

glob(path, suffixes = nil) { |filename| ... } click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 403
def self.glob(path, suffixes = nil)
  pattern = []
  suffixes&.each { |suffix| pattern << File.join(path, '*') + suffix }

  if block_given?
    Dir.glob(pattern) do |filename|
      yield(filename)
    end
  else
    Dir.glob(pattern)
  end
end
glob_all(root) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 399
def self.glob_all(root)
  Dir.glob(root + '/**/*')
end
new(pe, _opts = {}) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 381
def initialize(pe, _opts = {})
  open_file(pe)

  @server_interfaces = []
  @midl_server_infos = []
  @midl_stub_descs = []
  @midl_syntax_infos = []
  @midl_stubless_proxy_infos = []
  @server_routines = []
  @dispatch_funcs = []
  @client_interfaces = []
  @dasm = new_dasm
  @collection_proxy = _opts[:collection_proxy]

  arch = @pe.ptr_32? ? 'x86' : 'x64'
  @ndr_decompiler = TurboRex::MSRPC::Decompiler.new(arch: arch)
end

Public Instance Methods

auto_find(&block) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 436
def auto_find(&block)
  default = TurboRex::MSRPC::RPCFinder::ImageFinder::AutoFindConf.new
  config = if block_given?
             Docile.dsl_eval(default, &block).build
           else
             default.build
           end

  internal_auto_find(config)
end
close() click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 427
def close
  unless @pe.nil?
    @pe.close
    @pe = nil
  end

  true
end
decompile_func(addr) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 997
def decompile_func(addr)
  dasm = disassemble_fast(addr)[0]
  dasm.decompiler.decompile(addr) # Metasm::C::Parser
end
disassemble(addr, dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 979
def disassemble(addr, dasm = nil)
  dasm ||= (@dasm || new_dasm)
  res = dasm.disassemble addr
  [dasm, res]
end
disassemble_executable_sections(dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1002
def disassemble_executable_sections(dasm = nil)
  exe_sections = @pe.executable_sections
  unless exe_sections.empty?
    dasm ||= (@dasm || new_dasm)
    add_dasm_all_method(dasm)

    exe_sections.each do |s|
      dasm.dasm_all(@pe.rva_to_vma(s.base_rva), s.raw_size)
    end

    addrtolabel(dasm)
    dasm
  end
end
disassemble_fast(addr, dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 991
def disassemble_fast(addr, dasm = nil)
  dasm ||= (@dasm || new_dasm)
  res = dasm.disassemble_fast(addr)
  [dasm, res]
end
disassemble_fast_deep(addr, dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 985
def disassemble_fast_deep(addr, dasm = nil)
  dasm ||= (@dasm || new_dasm)
  res = dasm.disassemble_fast_deep(addr)
  [dasm, res]
end
draw_ifs_xrefs() click to toggle source

Xrefs in the same binary file

# File lib/turborex/msrpc/rpcfinder.rb, line 956
def draw_ifs_xrefs
  @server_interfaces.each do |si|
    @client_interfaces.each do |ci|
      calls = []
      ci.routines.each do |cr|
        unless (res = si.func_in_server_routines(cr.addr)).empty?
          calls << { caller: res, called: cr }
        end
      end

      next if calls.empty?

      si.xrefs_from << [ci, calls]
      ci.xrefs_to << [si, calls]

      si.xrefs_from.uniq!
      si.xrefs_to.uniq!
    end
  end
end
find_client_disp_functions(va, dasm, expr, *funcs) { |addr, dasm| ... } click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 587
def find_client_disp_functions(va, dasm, expr, *funcs)
  disassemble_executable_sections(dasm)
  # addrtolabel(dasm)
  dispatch_funcs = []

  if expr.nil?
    case dasm.cpu.size
    when 64
      expr = 'rcx'
    when 32
      expr = '[esp]'
    end
  end

  funcs.each do |func|
    callers = dasm.call_sites(Metasm::Expression[func])
    callers.each do |addr|
      found, log = backtrace(addr, dasm, expr)
      next unless found.include?(va)

      # Finding proc number
      proc_num = nil
      case func
      when 'NdrClientCall' # Oi, conflict with 64-bit platform
        expr_procnum = '[esp+4]'
        switch = :Oi
      when 'NdrClientCall2' # Oicf
        expr_procnum = dasm.cpu.size == 64 ? 'rdx' : '[esp+4]'
        switch = :Oicf
      when 'NdrClientCall3'
        expr_procnum = 'rdx'
      when 'NdrClientCall4' # ?
        expr_procnum = dasm.cpu.size == 64 ? 'rdx' : '[esp+4]'
      end

      _found, _log = backtrace(addr, dasm, expr_procnum)

      unless _found.empty?
        if func == 'NdrClientCall3'
          proc_num = _found.first
        else
          _dasm = dasm.dup
          _dasm.c_parser = @ndr_decompiler.parser
          fs_header, header_len = @ndr_decompiler.parse_proc_fs_header_dasm(_dasm, _found[0])
          proc_num = fs_header.oi_header.common.ProcNum
        end
      end

      yield(addr, dasm) if block_given?
      func_start = dasm.find_function_start(addr)
      dispatch_funcs << {
        dispatch_func: func_start,
        backtrace: [func, va, log],
        proc_num: proc_num
      }
    end
  end

  dispatch_funcs
end
find_client_routines(client_if, client_if_addr, dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 648
def find_client_routines(client_if, client_if_addr, dasm = nil)
  dasm = @dasm || (@dasm = new_dasm)
  disp_funcs = []

  if has_proxy_info?(client_if) # stubless proxy, no dispatch table and thunk table
    if proxy_info = get_stubless_pinfo_from_client_if(client_if)
      pi_obj = TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO_Klass.new(proxy_info)
      pinterpreter_info = client_if.InterpreterInfo_Value
      @midl_stubless_proxy_infos << pi_obj
      client_if.midl_switches << %w[all win64 amd64 ia64]
      client_if.link_to pi_obj
      disp_funcs = find_client_disp_functions(pinterpreter_info, dasm, nil, 'NdrClientCall3')
    end
  else
    xrefs = scan_xrefs_immediate(client_if_addr, dasm)
    xrefs.each do |xref|
      midl_stub_desc = make_midl_stub_desc(@pe)
      reconstruct_struct_from_pe(@pe, @pe.vma_to_rva(xref), midl_stub_desc)
      next unless validate_midl_stub_desc(@pe, midl_stub_desc)

      stub_desc_obj = MIDL_STUB_DESC_Klass.new(midl_stub_desc)
      stub_desc_obj.link_to client_if
      @midl_stub_descs << stub_desc_obj

      disp_funcs = find_client_disp_functions(xref, dasm, nil, 'NdrClientCall', 'NdrClientCall2', 'NdrClientCall4')

      # TODO: detect switches when using NdrClientCall4
      next unless b = disp_funcs[0]&.fetch(:backtrace) { }

      client_if.midl_switches << %w[Oi Oic] if b[0] == 'NdrClientCall'
      if b[0] == 'NdrClientCall2'
        client_if.midl_switches << %w[Oif Oicf]
      end
    end
  end

  disp_funcs.map do |m|
    r = TurboRex::MSRPC::RPCBase::CLIENT_ROUTINE_Klass.new(m[:dispatch_func])
    r.proc_num = m[:proc_num]
    r
  end.uniq(&:addr)
end
find_rpc_server_interface(opts = {}) { |rpc_server_interface, r| ... } click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 553
def find_rpc_server_interface(opts = {})
  rpc_server_interface = make_rpc_server_interface(@pe)
  regexp = Regexp.new [rpc_server_interface.slength].pack('V')
  res = []
  opts[:only_data_section] ||= true

  if opts[:only_data_section]
    @pe.data_sections.each do |s|
      TurboRex::PEFile::Scanner.scan_section(s, regexp).each do |r|
        rpc_server_interface = make_rpc_server_interface(@pe)
        next unless reconstruct_struct_from_pe(@pe, r[0], rpc_server_interface) > 0
        
        if validate_rpc_server_interface(@pe, rpc_server_interface)
          yield(rpc_server_interface, r[0]) if block_given?
          res << rpc_server_interface
        end
      end
    end
  else
    addr_info = TurboRex::PEFile::Scanner.scan_all_sections(@pe, regexp)
    unless addr_info.empty?
      addr_info.each do |addr|
        rpc_server_interface = make_rpc_server_interface(@pe)
        if reconstruct_struct_from_pe(@pe, addr[0], rpc_server_interface) > 0
          yield(rpc_server_interface, addr[0]) if block_given?
          res << rpc_server_interface
        end
      end
    end
  end

  res
end
get_disp_functions(rpc_dispatch_table) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 535
def get_disp_functions(rpc_dispatch_table)
  reconstruct_disp_functions(@pe, rpc_dispatch_table)
end
get_dispatch_table(rpc_server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 519
def get_dispatch_table(rpc_server_if)
  reconstruct_disptbl_for_server_interface(@pe, rpc_server_if)
end
get_endpoint_info(rpc_server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 531
def get_endpoint_info(rpc_server_if)
  reconstruct_endpoint_info(@pe, rpc_server_if)
end
get_midl_server_info(rpc_server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 503
def get_midl_server_info(rpc_server_if)
  reconstruct_midl_server_info(@pe, rpc_server_if)
end
get_midl_stub_desc(midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 507
def get_midl_stub_desc(midl_server_info)
  reconstruct_midl_stub_desc(@pe, midl_server_info)
end
get_midl_syntax_info(midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 515
def get_midl_syntax_info(midl_server_info)
  reconstruct_midl_syntax_info(@pe, midl_server_info)
end
get_offset_table(rpc_server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 523
def get_offset_table(rpc_server_if)
  reconstruct_offset_table(@pe, rpc_server_if)
end
get_offset_table2(disptbl, midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 527
def get_offset_table2(disptbl, midl_server_info)
  reconstruct_offset_table2(@pe, disptbl, midl_server_info)
end
get_routines_from_server_interface(rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 543
def get_routines_from_server_interface(rpc_server_interface)
  if has_interpreter_info?(rpc_server_interface)
    disptbl = get_dispatch_table(rpc_server_interface)
    midl_server_info = get_midl_server_info(rpc_server_interface)
    count = disptbl['dispatchTableCount'].value

    get_rpc_server_routines(midl_server_info, count) if count > 0
  end
end
get_rpc_server_routines(midl_server_info, count) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 539
def get_rpc_server_routines(midl_server_info, count)
  reconstruct_disptbl_for_midl_server_info(@pe, midl_server_info, count)
end
get_stubless_pinfo_from_client_if(rpc_client_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 511
def get_stubless_pinfo_from_client_if(rpc_client_if)
  reconstruct_stubless_pinfo(@pe, rpc_client_if)
end
make_midl_server_info(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 455
def make_midl_server_info(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO32.make
  else
    TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO64.make
  end
end
make_midl_stub_desc(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 495
def make_midl_stub_desc(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC64.make(pack: 8, align: true)
  end
end
make_midl_stubless_proxy_info(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 463
def make_midl_stubless_proxy_info(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO32.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::MIDL_STUBLESS_PROXY_INFO64.make(pack: 8, align: true)
  end
end
make_midl_syntax_info(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 471
def make_midl_syntax_info(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO32.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO64.make(pack: 8, align: true)
  end
end
make_rpc_dispatch_table_t(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 479
def make_rpc_dispatch_table_t(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_T.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_T64.make(pack: 8, align: true)
  end
end
make_rpc_protseq_endpoint(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 487
def make_rpc_protseq_endpoint(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::RPC_PROTSEQ_ENDPOINT32.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::RPC_PROTSEQ_ENDPOINT64.make(pack: 8, align: true)
  end
end
make_rpc_server_interface(pe) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 447
def make_rpc_server_interface(pe)
  if pe.ptr_32?
    TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE32.make(pack: 4, align: true)
  else
    TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE64.make(pack: 8, align: true)
  end
end
new_dasm() click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 930
def new_dasm
  exe = Metasm::PE.decode_file @pe.image_path.to_s

  exe.disassembler
end
open_file(filename) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 416
def open_file(filename)
  begin
    @pe = TurboRex::PEFile::PE.new_from_file(filename)
    @pe.image_path = Pathname.new(filename)
  rescue FileHeaderError
    return false
  end

  pe
end
reconstruct_disp_functions(pe, rpc_dispatch_table) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 882
def reconstruct_disp_functions(pe, rpc_dispatch_table)
  count = rpc_dispatch_table['dispatchTableCount'].value
  pdispatch_table = pe.vma_to_rva(rpc_dispatch_table['dispatchTable'].value)
  dispatch_funcs = []

  if pe.ptr_32?
    ptr_len = 4
    format = 'V'
    func_name = 'read_dword'
  else
    ptr_len = 8
    format = 'Q<'
    func_name = 'read_qword'
  end

  unless pdispatch_table == 0
    count.times do |i|
      code = "#{func_name}(pe._isource, pe.rva_to_file_offset(pdispatch_table + #{i * ptr_len})).unpack('#{format}')[0]"
      begin
        dispatch_funcs << eval(code)
      rescue StandardError
        next
      end
    end
  end

  dispatch_funcs
end
reconstruct_disptbl_for_midl_server_info(pe, midl_server_info, count) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 911
def reconstruct_disptbl_for_midl_server_info(pe, midl_server_info, count)
  rva = pe.vma_to_rva(midl_server_info['dispatchTable'].value)
  server_routines = []

  if pe.ptr_32?
    count.times do
      server_routines << read_dword(pe._isource, pe.rva_to_file_offset(rva)).unpack('V')[0]
      rva += 4
    end
  else
    count.times do
      server_routines << read_qword(pe._isource, pe.rva_to_file_offset(rva)).unpack('Q<')[0]
      rva += 8
    end
  end

  server_routines
end
reconstruct_disptbl_for_server_interface(pe, rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 870
def reconstruct_disptbl_for_server_interface(pe, rpc_server_interface)
  rva = pe.vma_to_rva(rpc_server_interface['dispatchTable'].value)
  reconstruct_disptbl_from_addr(pe, rva)
end
reconstruct_disptbl_from_addr(pe, addr) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 875
def reconstruct_disptbl_from_addr(pe, addr)
  rpc_dispatch_table = make_rpc_dispatch_table_t(pe)
  reconstruct_struct_from_pe(pe, addr, rpc_dispatch_table)

  rpc_dispatch_table
end
reconstruct_endpoint_info(pe, server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 794
def reconstruct_endpoint_info(pe, server_if)
  endpoints = []

  if (count = server_if['rpcProtseqEndpointCount'].value) > 0
    rva = pe.vma_to_rva(server_if['rpcProtseqEndpoint'].value)

    count.times do |i|
      ep = make_rpc_protseq_endpoint(pe)
      reconstruct_struct_from_pe(pe, rva+i*ep.slength, ep)
      pprotseq = pe.vma_to_file_offset(ep['rpcProtocolSequence'].value)
      pendpoint = pe.vma_to_file_offset(ep['endpoint'].value)

      protseq = TurboRex::MSRPC::Utils.read_cstring(pe._isource, pprotseq)[0]
      ep_name = TurboRex::MSRPC::Utils.read_cstring(pe._isource, pendpoint)[0]
      endpoints << {protseq: protseq, ep_name: ep_name}
      i+=ep.slength
    end

  end

  endpoints
end
reconstruct_midl_server_info(pe, rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 851
def reconstruct_midl_server_info(pe, rpc_server_interface)
  if validate_rpc_server_interface(pe, rpc_server_interface) && has_interpreter_info?(rpc_server_interface)
    rva = pe.vma_to_rva(rpc_server_interface['interpreterInfo'].value)
    midl_server_info = make_midl_server_info(pe)
    reconstruct_struct_from_pe(pe, rva, midl_server_info)

    midl_server_info
  end
end
reconstruct_midl_stub_desc(pe, midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 861
def reconstruct_midl_stub_desc(pe, midl_server_info)
  unless midl_server_info['pStubDesc'].value == 0
    rva = pe.vma_to_rva(midl_server_info['pStubDesc'].value)
    midl_stub_desc = make_midl_stub_desc(@pe)
    reconstruct_struct_from_pe(pe, rva, midl_stub_desc)
    midl_stub_desc if validate_midl_stub_desc(pe, midl_stub_desc)
  end
end
reconstruct_midl_syntax_info(pe, midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 825
def reconstruct_midl_syntax_info(pe, midl_server_info)
  pSyntaxInfo = midl_server_info['pSyntaxInfo'].value
  count = midl_server_info['nCount'].value
  return nil if count < 0

  syntax_infos = []

  if pe.ptr_32?
    len = TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO32.make(pack: 4, align: true).slength
  else
    len = TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO64.make(pack: 8, align: true).slength
  end

  unless pSyntaxInfo == 0
    count.times do |i|
      rva = pe.vma_to_rva(pSyntaxInfo + i * len)
      midl_syntax_info = make_midl_syntax_info(pe)
      reconstruct_struct_from_pe(pe, rva, midl_syntax_info)

      syntax_infos << midl_syntax_info
    end
  end

  syntax_infos
end
reconstruct_offset_table(pe, server_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 775
def reconstruct_offset_table(pe, server_if)   
  if server_if['interpreterInfo'].value != 0
    server_info = reconstruct_midl_server_info(pe, server_if)

    unless server_info.nil?
      pdisptbl = pe.vma_to_rva(server_if['dispatchTable'].value)
      disptbl = reconstruct_disptbl_from_addr(pe, pdisptbl)

      reconstruct_offset_table2(pe, disptbl, server_info)
    end
  end
end
reconstruct_offset_table2(pe, disptbl, midl_server_info) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 788
def reconstruct_offset_table2(pe, disptbl, midl_server_info)
  poffset_table = pe.vma_to_file_offset(midl_server_info['fmtStringOffset'].value)
  count = disptbl['dispatchTableCount'].value
  pe._isource.read(poffset_table, count).unpack('C'*count)
end
reconstruct_struct_from_pe(pe, rva, cstruct) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 769
def reconstruct_struct_from_pe(pe, rva, cstruct)
  length = cstruct.slength
  data = pe._isource.read(pe.rva_to_file_offset(rva), length)
  cstruct.from_s data
end
reconstruct_stubless_pinfo(pe, client_if) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 817
def reconstruct_stubless_pinfo(pe, client_if)
  proxy_info = make_midl_stubless_proxy_info(pe)
  pinterpreter_info = client_if.InterpreterInfo_Value
  rva = pe.vma_to_rva(pinterpreter_info)
  reconstruct_struct_from_pe(pe, rva, proxy_info)
  proxy_info if validate_stubless_proxy_info(pe, proxy_info)
end
scan_xrefs_immediate(addr, dasm = nil) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 936
def scan_xrefs_immediate(addr, dasm = nil)
  dasm ||= (@dasm || new_dasm)
  cpu_size = dasm.cpu.size
  mask = (1 << cpu_size) - 1
  format = (cpu_size == 64 ? 'q' : 'V')
  res = []

  dasm.sections.sort.each do |start_addr, encoded_data|
    raw = encoded_data.data.to_str
    (0..raw.length - cpu_size / 8).each do |offset|
      data = raw[offset, cpu_size / 8].unpack(format).first
      res << (start_addr + offset) if data == addr
    end
  end

  res
end
validate_midl_stub_desc(pe, struct) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 727
def validate_midl_stub_desc(pe, struct)
  pfnAllocate = struct['pfnAllocate'].value
  pfnFree = struct['pfnFree'].value
  phandle = struct['implicit_handle_info'].value
  bounds_flag = struct['fCheckBounds'].value

  # TODO: more check(version)
  pointer_check = pe.valid_vma?(pfnAllocate) && pe.valid_vma?(pfnFree)
  # && pe.valid_vma?(phandle)
  # Rex library valid_vma? method make a mistake here.
  bounds_flag_check = (bounds_flag == 1 || bounds_flag == 0)

  pointer_check && bounds_flag
end
validate_rpc_server_interface(pe, rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 695
def validate_rpc_server_interface(pe, rpc_server_interface)
  length = rpc_server_interface.slength
  return false unless rpc_server_interface['length'].value == length
  unless validate_transfer_syntax(rpc_server_interface['transferSyntax'])
    return false
  end

  itpInfo = rpc_server_interface['interpreterInfo'].value # vma
  if itpInfo == 0
    # TODO: Inline stub check
  else
    section = pe._find_section_by_rva(pe.vma_to_rva(itpInfo))
    return false if section.nil?
    return false unless TurboRex::PEFile::Scanner.data_section?(section)
  end

  dispTable = rpc_server_interface['dispatchTable'].value
  unless dispTable == 0
    section = pe._find_section_by_rva(pe.vma_to_rva(dispTable))
    return false if section.nil?
    return false unless TurboRex::PEFile::Scanner.data_section?(section)
  end

  true
end
validate_server_interface_from_pe(pe, address) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 721
def validate_server_interface_from_pe(pe, address)
  make_rpc_server_interface(pe)
  reconstruct_struct_from_pe(pe, address, rpc_server_interface)
  validate_rpc_server_interface(pe, rpc_server_interface)
end
validate_stubless_proxy_info(pe, stubless_proxy_info, strict_check = true) click to toggle source

The “strict_check” option will use the algorithm of NdrClientCall3

# File lib/turborex/msrpc/rpcfinder.rb, line 743
def validate_stubless_proxy_info(pe, stubless_proxy_info, strict_check = true)
  pTransferSyntax = stubless_proxy_info['pTransferSyntax'].value
  pSyntaxInfo = stubless_proxy_info['pSyntaxInfo'].value
  nCount = stubless_proxy_info['nCount'].value
  dce_transfer = DCE_TransferSyntax.to_s
  ndr64_transfer = NDR64_TransferSyntax.to_s
  len = make_midl_syntax_info(pe).slength

  return false if pTransferSyntax == 0

  transfer_syntax = pe._isource.read(pe.vma_to_file_offset(pTransferSyntax), DCE_TransferSyntax.slength)
  unless transfer_syntax == dce_transfer || transfer_syntax == ndr64_transfer
    return false
  end

  if strict_check
    nCount.times do |i|
      syntaxinfo_trans = pe._isource.read(pe.vma_to_file_offset(pSyntaxInfo + i * len), DCE_TransferSyntax.slength)
      break if syntaxinfo_trans == transfer_syntax
      return false if i + 1 == nCount
    end
  end

  true
end
validate_transfer_syntax(transfer_syntax) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 691
def validate_transfer_syntax(transfer_syntax)
  transfer_syntax.to_s == DCE_TransferSyntax.to_s || transfer_syntax.to_s == NDR64_TransferSyntax.to_s
end

Private Instance Methods

has_interpreter_info?(rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1027
def has_interpreter_info?(rpc_server_interface)
  # Don't assume when flag is set. Must check if InterpreterInfo is a null pointer.
  (rpc_server_interface['flags'].value & 0x4000000) == 0x4000000 && \
    rpc_server_interface['interpreterInfo'].value != 0
end
has_proxy_info?(rpc_server_interface) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1033
def has_proxy_info?(rpc_server_interface)
  flags = (begin
             rpc_server_interface['flags'].value
           rescue StandardError
             rpc_server_interface.Flags
           end)
  interpreter_info = (begin
                        rpc_server_interface['interpreterInfo'].value
                      rescue StandardError
                        rpc_server_interface.InterpreterInfo
                      end)
  (flags & 0x2000000) == 0x2000000 && \
    interpreter_info != 0
end
internal_auto_find(config = {}) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1048
def internal_auto_find(config = {})
  @server_interfaces = []
  @dispatch_funcs = []
  @server_routines = []
  @client_routines = []
  @client_interfaces = []
  @midl_stub_descs = []

  find_rpc_server_interface do |r, s_addr|
    next if r.nil?
    si_obj = TurboRex::MSRPC::RPCBase::RPC_SERVER_INTERFACE_Klass.new(r)
    interface = InterfaceModel.new si_obj, self
    interface.endpoints = get_endpoint_info(r)

    if interface.dispatch_table_nullptr? # maybe client
      next unless config[:include_client]

      @client_interfaces << interface
      @collection_proxy&.push_client(interface)

      if config[:find_client_routines]
        cr = find_client_routines(interface, @pe.rva_to_vma(s_addr))
        @client_routines |= cr
        interface.routines = cr
      end

    else # server
      next if config[:only_client]

      @server_interfaces << interface
      @collection_proxy&.push_server(interface)

      disp_table = get_dispatch_table(r)
      disp_func = get_disp_functions(disp_table)
      @dispatch_funcs |= disp_func

      disp_table_obj = TurboRex::MSRPC::RPCBase::RPC_DISPATCH_TABLE_Klass.new(disp_table)
      disp_table_obj.link_to disp_func
      interface.link_to disp_table_obj

      msi = get_midl_server_info(r)
      if msi.nil? # Inline stub(-Os mode)
        @dispatch_funcs |= disp_func
      else
        msi_obj = TurboRex::MSRPC::RPCBase::MIDL_SERVER_INFO_Klass.new(msi)
        @midl_server_infos << msi_obj
        interface.link_to msi_obj

        # find all server routines
        routines = get_routines_from_server_interface(r)
        unless routines.nil?
          r_objs = routines.map { |r| TurboRex::MSRPC::RPCBase::SERVER_ROUTINE_Klass.new(r) }
          @server_routines |= r_objs
          interface.routines = r_objs
          msi_obj.link_to r_objs
        end

        # reconstruct MIDL_SYNTAX_INFO
        midl_syntax_info = get_midl_syntax_info(msi)
        unless midl_syntax_info.nil? || midl_syntax_info.empty?
          objs = []
          midl_syntax_info.each do |m|
            syntax_info_obj = TurboRex::MSRPC::RPCBase::MIDL_SYNTAX_INFO_Klass.new(m)
            pdisp_tbl = syntax_info_obj.DispatchTable
            unless pdisp_tbl == 0
              disptbl = reconstruct_disptbl_from_addr(@pe, @pe.vma_to_rva(pdisp_tbl))
              disp_funcs =  reconstruct_disp_functions(@pe, disptbl)
              disptbl_obj = RPC_DISPATCH_TABLE_Klass.new(disptbl)
              disptbl_obj.link_to disp_funcs
              syntax_info_obj.link_to disptbl_obj
            end

            @midl_syntax_infos << syntax_info_obj
            objs << syntax_info_obj
          end

          msi_obj.link_to objs
        end

        # reconstruct MIDL_STUB_DESC
        midl_stub_desc = get_midl_stub_desc(msi)
        unless midl_stub_desc.nil?
          stub_desc_obj = TurboRex::MSRPC::RPCBase::MIDL_STUB_DESC_Klass.new(midl_stub_desc)
          msi_obj.link_to stub_desc_obj
        end

        # reconstruct offset_table
        interface.offset_table = get_offset_table2(disp_table, msi)
      end
    end

    interface.analysis_midl_switches if config[:analysis_switches]
  end
end
read_dword(isource, address) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1019
def read_dword(isource, address)
  isource.read(address, 4)
end
read_qword(isource, address) click to toggle source
# File lib/turborex/msrpc/rpcfinder.rb, line 1023
def read_qword(isource, address)
  isource.read(address, 8)
end