Class: TurboRex::MSRPC::RPCFinder::ImageFinder

Inherits:
Object
  • Object
show all
Includes:
Rex::PeParsey, TurboRex::MSRPC::RPCBase, StaticRPCBacktracer, PEFile, PEFile::Scanner, Utils::DisassemblerHelper
Defined in:
lib/turborex/msrpc/rpcfinder.rb

Defined Under Namespace

Classes: AutoFindConf, InterfaceModel

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 StaticRPCBacktracer

#bt_security_callback

Methods included from Utils::DisassemblerHelper

#_disassemble_executable_sections, #add_dasm_all_method, #addrtolabel, #backtrace, #solve_cppobj_call, #solve_guard_icall

Methods included from PEFile::Scanner

data_section?, #draw_xrefs_dg, #has_path?, scan_all_sections, scan_section

Methods included from TurboRex::MSRPC::RPCBase

from_guid_str, make_transferSyntax

Methods included from CStruct

#define_structs

Constructor Details

#initialize(pe, _opts = {}) ⇒ ImageFinder

Returns a new instance of ImageFinder.



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# 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

Instance Attribute Details

#client_interfacesObject (readonly)

Returns the value of attribute client_interfaces.



378
379
380
# File 'lib/turborex/msrpc/rpcfinder.rb', line 378

def client_interfaces
  @client_interfaces
end

#client_routinesObject (readonly)

Returns the value of attribute client_routines.



379
380
381
# File 'lib/turborex/msrpc/rpcfinder.rb', line 379

def client_routines
  @client_routines
end

#dasmObject (readonly)

Returns the value of attribute dasm.



369
370
371
# File 'lib/turborex/msrpc/rpcfinder.rb', line 369

def dasm
  @dasm
end

#dispatch_funcsObject (readonly)

Returns the value of attribute dispatch_funcs.



375
376
377
# File 'lib/turborex/msrpc/rpcfinder.rb', line 375

def dispatch_funcs
  @dispatch_funcs
end

#midl_server_infosObject (readonly)

Returns the value of attribute midl_server_infos.



372
373
374
# File 'lib/turborex/msrpc/rpcfinder.rb', line 372

def midl_server_infos
  @midl_server_infos
end

#midl_stubless_proxy_infosObject (readonly)

Returns the value of attribute midl_stubless_proxy_infos.



374
375
376
# File 'lib/turborex/msrpc/rpcfinder.rb', line 374

def midl_stubless_proxy_infos
  @midl_stubless_proxy_infos
end

#midl_syntax_infosObject (readonly)

Returns the value of attribute midl_syntax_infos.



373
374
375
# File 'lib/turborex/msrpc/rpcfinder.rb', line 373

def midl_syntax_infos
  @midl_syntax_infos
end

#ndr_decompilerObject (readonly)

Returns the value of attribute ndr_decompiler.



370
371
372
# File 'lib/turborex/msrpc/rpcfinder.rb', line 370

def ndr_decompiler
  @ndr_decompiler
end

#peObject (readonly)

Returns the value of attribute pe.



368
369
370
# File 'lib/turborex/msrpc/rpcfinder.rb', line 368

def pe
  @pe
end

#server_interfacesObject (readonly)

Returns the value of attribute server_interfaces.



371
372
373
# File 'lib/turborex/msrpc/rpcfinder.rb', line 371

def server_interfaces
  @server_interfaces
end

#server_routinesObject (readonly)

Returns the value of attribute server_routines.



376
377
378
# File 'lib/turborex/msrpc/rpcfinder.rb', line 376

def server_routines
  @server_routines
end

Class Method Details

.glob(path, suffixes = nil) ⇒ Object



403
404
405
406
407
408
409
410
411
412
413
414
# 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) ⇒ Object



399
400
401
# File 'lib/turborex/msrpc/rpcfinder.rb', line 399

def self.glob_all(root)
  Dir.glob(root + '/**/*')
end

Instance Method Details

#auto_find(&block) ⇒ Object



436
437
438
439
440
441
442
443
444
445
# 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

#closeObject



427
428
429
430
431
432
433
434
# File 'lib/turborex/msrpc/rpcfinder.rb', line 427

def close
  unless @pe.nil?
    @pe.close
    @pe = nil
  end

  true
end

#decompile_func(addr) ⇒ Object



997
998
999
1000
# 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) ⇒ Object



979
980
981
982
983
# 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) ⇒ Object



1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
# 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) ⇒ Object



991
992
993
994
995
# 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) ⇒ Object



985
986
987
988
989
# 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_xrefsObject

Xrefs in the same binary file



956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
# 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) ⇒ Object



587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# 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) ⇒ Object



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
# 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 = {}) ⇒ Object



553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# 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) ⇒ Object



535
536
537
# 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) ⇒ Object



519
520
521
# 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) ⇒ Object



531
532
533
# 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) ⇒ Object



503
504
505
# 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) ⇒ Object



507
508
509
# 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) ⇒ Object



515
516
517
# 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) ⇒ Object



523
524
525
# 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) ⇒ Object



527
528
529
# 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) ⇒ Object



543
544
545
546
547
548
549
550
551
# 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) ⇒ Object



539
540
541
# 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) ⇒ Object



511
512
513
# 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) ⇒ Object



455
456
457
458
459
460
461
# 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) ⇒ Object



495
496
497
498
499
500
501
# 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) ⇒ Object



463
464
465
466
467
468
469
# 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) ⇒ Object



471
472
473
474
475
476
477
# 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) ⇒ Object



479
480
481
482
483
484
485
# 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) ⇒ Object



487
488
489
490
491
492
493
# 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) ⇒ Object



447
448
449
450
451
452
453
# 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_dasmObject



930
931
932
933
934
# 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) ⇒ Object



416
417
418
419
420
421
422
423
424
425
# 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) ⇒ Object



882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# 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) ⇒ Object



911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# 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) ⇒ Object



870
871
872
873
# 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) ⇒ Object



875
876
877
878
879
880
# 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) ⇒ Object



794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
# 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) ⇒ Object



851
852
853
854
855
856
857
858
859
# 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) ⇒ Object



861
862
863
864
865
866
867
868
# 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) ⇒ Object



825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
# 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) ⇒ Object



775
776
777
778
779
780
781
782
783
784
785
786
# 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) ⇒ Object



788
789
790
791
792
# 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) ⇒ Object



769
770
771
772
773
# 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) ⇒ Object



817
818
819
820
821
822
823
# 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) ⇒ Object



936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
# 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) ⇒ Object



727
728
729
730
731
732
733
734
735
736
737
738
739
740
# 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) ⇒ Object



695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# 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) ⇒ Object



721
722
723
724
725
# 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) ⇒ Object

The “strict_check” option will use the algorithm of NdrClientCall3



743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
# 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) ⇒ Object



691
692
693
# 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