module TurboRex::Windows::COM::Utils

Public Class Methods

clsid_to_raw(clsid) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 105
def self.clsid_to_raw(clsid)
  pstr_clsid = INTERNAL_APIPROXY.alloc_c_ary('OLECHAR', "{#{clsid}}".chars.push(0).map{|c|c.ord})
  pclsid = INTERNAL_APIPROXY.alloc_c_ptr('CLSID')
  return unless INTERNAL_APIPROXY.clsidfromstring(pstr_clsid, pclsid).nil?
  pclsid
end
create_istorage(name, mode=STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 95
def self.create_istorage(name, mode=STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE)
  wname = Win32API.alloc_c_ary('WCHAR', name.chars.map{|c|c.unpack('C').first}.push(0))
  ppstgOpen = Win32API.alloc_c_ptr('LPSTORAGE')
  hr = Win32API.stgcreatedocfile(wname, mode, 0, ppstgOpen)
  return false unless TinySDK.nt_success?(hr)
  istorage = Interface::IStorage.new
  istorage.this = ppstgOpen[0]
  istorage
end
create_istream() click to toggle source
# File lib/turborex/windows/com/utils.rb, line 86
def self.create_istream
  ppstm = Win32API.alloc_c_ptr('LPSTREAM')
  hr = Win32API.createstreamonhglobal(0, 1, ppstm)
  return false unless TinySDK.nt_success?(hr)
  istream = Interface::IStream.new
  istream.this = ppstm[0]
  istream
end
dll_get_class_object(rclsid, dll, interface=Interface::IClassFactory.new) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 112
        def self.dll_get_class_object(rclsid, dll, interface=Interface::IClassFactory.new)
          _api_proxy = TurboRex::Windows::COM::INTERNAL_APIPROXY.dup
          _api_proxy.new_api_c <<-EOS, dll
            HRESULT DllGetClassObject(
              REFCLSID rclsid,
              REFIID   riid,
              LPVOID   *ppv
            );
          EOS

          rclsid = clsid_to_raw(rclsid)    
          riid = clsid_to_raw(interface.iid)
          ppv = _api_proxy.alloc_c_ptr('PVOID')
          
          unless hr = _api_proxy.dllgetclassobject(rclsid, riid, ppv)
            interface.this = ppv[0]
            return interface
          end

          raise "Failed to call DllGetClassObject(): #{TinySDK.format_hex_ntstatus(hr, hex_str: true)}"
        end
marshal_interface(object, mshctx=MSHCTX_DIFFERENTMACHINE, mshlflags=MSHLFLAGS_NORMAL) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 5
def self.marshal_interface(object, mshctx=MSHCTX_DIFFERENTMACHINE, mshlflags=MSHLFLAGS_NORMAL)
  iid = object.iid
  _iid = "{#{iid}}"
  pstr_iid = Win32API.alloc_c_ary('OLECHAR', _iid.chars.push(0).map{|c|c.ord})
  iid = Win32API.alloc_c_struct('CLSID')
  Win32API.clsidfromstring(pstr_iid, iid)

  istream = create_istream
  hr = Win32API.comarshalinterface(istream.this, iid, object.this, mshctx, 0, mshlflags)
  return false unless TinySDK.nt_success?(hr)
  istream
end
marshal_interface_to_string(object, mshctx=MSHCTX_DIFFERENTMACHINE, mshlflags=MSHLFLAGS_NORMAL) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 18
def self.marshal_interface_to_string(object, mshctx=MSHCTX_DIFFERENTMACHINE, mshlflags=MSHLFLAGS_NORMAL)
  # https://thrysoee.dk/InsideCOM+/ch15c.htm
  istream = marshal_interface(object, mshctx, mshlflags)
  return false unless istream
  phglobal = Win32API.alloc_c_ptr('HGLOBAL') 
  size = Win32API.alloc_c_ptr('ULONG')

  iid = object.iid
  _iid = "{#{iid}}"
  pstr_iid = Win32API.alloc_c_ary('OLECHAR', _iid.chars.push(0).map{|c|c.ord})
  iid = Win32API.alloc_c_struct('CLSID')
  Win32API.clsidfromstring(pstr_iid, iid) 

  hr = Win32API.cogetmarshalsizemax(size, iid, object.this, mshctx, 0, mshlflags)
  return false unless TinySDK.nt_success?(hr)

  Win32API.gethglobalfromstream(istream.this, phglobal)
  addr = Win32API.globallock(phglobal[0])

  objref = Win32API.memory_read(addr, size[0])
  Win32API.globalunlock(phglobal[0])
  istream.Release

  objref
end
unmarshal_interface(stream, riid, interface=nil) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 44
def self.unmarshal_interface(stream, riid, interface=nil)
  riid =~ /\{.+\}/ ? _iid = riid : _iid = "{#{riid}}"

  pstr_iid = Win32API.alloc_c_ary('OLECHAR', _iid.chars.push(0).map{|c|c.ord})
  iid = Win32API.alloc_c_struct('CLSID')
  ppv = Win32API.alloc_c_ptr('PVOID')
  Win32API.clsidfromstring(pstr_iid, iid)

  hr = Win32API.counmarshalinterface(stream.this, iid, ppv)
  raise hr.to_s unless TinySDK.nt_success?(hr)

  pthis = ppv[0]
  return pthis unless interface

  interface.this = pthis
  interface
end
unmarshal_interface_from_string(objref, riid, interface=nil) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 62
def self.unmarshal_interface_from_string(objref, riid, interface=nil)
  istream = create_istream
  return false unless istream

  buf = Win32API.alloc_c_ary('BYTE', objref.bytesize)
  buf.str = objref
  hr = istream.Write(buf, objref.bytesize, 0)
  return false unless TinySDK.nt_success?(hr)

  # WTF? Why dlibMove won't work?
  # dlibMove = Win32API.alloc_c_struct('LARGE_INTEGER')
  # dlibMove.QuadPart = 0
  # istream.Seek(dlibMove, 0, 0)

  istream.Seek(0, 0, 0)

  phglobal = Win32API.alloc_c_ptr('HGLOBAL') 
  Win32API.gethglobalfromstream(istream.this, phglobal)
  addr = Win32API.globallock(phglobal[0])
  objref = Win32API.memory_read(addr, 292)

  unmarshal_interface(istream, riid, interface)
end

Public Instance Methods

get_disptbl_count(proxy_file_info) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 134
def get_disptbl_count(proxy_file_info)
  pcif_stub_vtbl_list = to_ptr(@memory.get_page(proxy_file_info.pStubVtblList, @ptr_len))
  if_stub_vtbl = TurboRex::Windows::COM::INTERNAL_APIPROXY.alloc_c_struct('CInterfaceStubVtbl')
  if_stub_vtbl.str = @memory.get_page(pcif_stub_vtbl_list, if_stub_vtbl.sizeof)
  return if_stub_vtbl.header.DispatchTableCount
end
get_pid_by_std_objref(interface) click to toggle source

Note: The interface stub should be standard.

# File lib/turborex/windows/com/utils.rb, line 159
def get_pid_by_std_objref(interface)
  objref = TurboRex::Windows::Win32API.decode_c_struct('OBJREF', interface.marshal_to_string)
  objref.u_standard.std.ipid.Data2
end
get_proxy_file_info(iid) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 141
def get_proxy_file_info(iid)
  # TODO: Replace to call CoGetPSClsid()
  require 'win32/registry'
  Win32::Registry::HKEY_CLASSES_ROOT.open("Interface\\{#{iid}}") do |reg|
    psclsid32_key = reg.open('ProxyStubClsid32')
    ps_clsid = psclsid32_key.read('').last
    psclsid32_key.close

    Win32::Registry::HKEY_CLASSES_ROOT.open("CLSID\\#{ps_clsid}") do |reg_clsid|
      inproc32_key = reg_clsid.open('InprocServer32') 
      dll_path = inproc32_key.read_s_expand('')
      inproc32_key.close
      return internal_get_proxyfile(dll_path, ps_clsid.delete('{}'))
    end
  end
end
internal_get_proxyfile(path, clsid) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 164
        def internal_get_proxyfile(path, clsid)
          _api_proxy = TurboRex::Windows::COM::INTERNAL_APIPROXY.dup
          _api_proxy.new_api_c <<-EOS, path
            void RPC_ENTRY GetProxyDllInfo( const ProxyFileInfo*** pInfo, const CLSID ** pId );
            HRESULT DllGetClassObject(
              REFCLSID rclsid,
              REFIID   riid,
              LPVOID   *ppv
            );
          EOS

          begin
            ppproxy_fileinfo = _api_proxy.alloc_c_ptr('PVOID')
            proxy_file_info = _api_proxy.alloc_c_struct('ProxyFileInfo')
            ppclsid = _api_proxy.alloc_c_ptr('PVOID')
            _api_proxy.getproxydllinfo(ppproxy_fileinfo, ppclsid)
            pproxy_file_info = to_ptr(@memory.get_page(to_ptr(ppproxy_fileinfo.str), @ptr_len))
            proxy_file_info.str = @memory.get_page(pproxy_file_info, proxy_file_info.sizeof)
          rescue NoMethodError # GetProxyDllInfo() is not exported
            ipsfactory = Interface::IPSFactoryBuffer.new
            Utils.dll_get_class_object(clsid, path, ipsfactory)
            cstd_psfactory = _api_proxy.alloc_c_struct('CStdPSFactoryBuffer')
            cstd_psfactory.str =  @memory.get_page(ipsfactory.this, cstd_psfactory.sizeof)

            pproxy_file_info = to_ptr(@memory.get_page(cstd_psfactory.pProxyFileList, @ptr_len))
            proxy_file_info = _api_proxy.alloc_c_struct('ProxyFileInfo')
            proxy_file_info.str = @memory.get_page(pproxy_file_info, proxy_file_info.sizeof)
            ipsfactory.Release
          end

          proxy_file_info
        end
to_ptr(raw) click to toggle source
# File lib/turborex/windows/com/utils.rb, line 197
def to_ptr(raw)
  format = case @ptr_len
  when 8
    'Q'
  when 4
    'L'
  end

  raw.unpack(format).first
end