class TurboRex::Windows::ALPC::Transport

Constants

DupObjectTypes
Flags
ImpersonationLevel
Length
MaxMessageLength
MaxPoolUsage
MaxSectionSize
MaxTotalSectionSize
MaxViewSize
MemoryBandwidth

Public Class Methods

new(opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 119
def initialize(opts = {})
  @conn_handle = nil
  @communication_handle = []
end

Public Instance Methods

accept(opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 324
def accept(opts = {})
  communication_handle = APIProxy.alloc_c_type('HANDLE')
  alpc_port_attr = APIProxy.alloc_c_struct('ALPC_PORT_ATTRIBUTES')
  alpc_port_attr.Flags = 0
  alpc_port_attr.MaxMessageLength = 0x1000
  alpc_port_attr.MemoryBandwidth = 0
  alpc_port_attr.MaxPoolUsage = 0xFFFFFFFF
  alpc_port_attr.MaxSectionSize = 0xFFFFFFFF
  alpc_port_attr.MaxViewSize = 0xFFFFFFFF
  alpc_port_attr.MaxTotalSectionSize = 0xFFFFFFFF
  alpc_port_attr.DupObjectTypes = 0xFFFFFFFF

  port_context = opts[:port_context] || 0
  flags = opts[:flags] || 0
  uniq_process = opts[:uniq_process]
  uniq_thread = opts[:uniq_thread]
  message_id = opts[:message_id]
  accept = 1
  port_message = opts[:port_message]

  if port_message.nil?
    raise TurboRex::Exception::ALPC::ReplyMessageMismatch if uniq_process.nil? || uniq_thread.nil? || message_id.nil?
    port_message = PortMessage.new(alloc_size: 1)
    port_message.client_id = [uniq_process, uniq_thread]
    port_message.message_id = message_id
  end

  accept = 0 if opts[:refuse]

  ntstatus = APIProxy.ntalpcacceptconnectport(communication_handle,
                                              @conn_handle,
                                              flags,
                                              0,
                                              alpc_port_attr,
                                              port_context,
                                              port_message.message,
                                              0,
                                              accept)

  unless opts[:refuse]                                         
    @communication_handle << communication_handle[0]
    [communication_handle[0], TinySDK.format_hex_ntstatus(ntstatus)]
  else
    TinySDK.format_hex_ntstatus(ntstatus)
  end
end
close() click to toggle source
# File lib/turborex/windows/alpc.rb, line 376
def close
  APIProxy.ntalpcdisconnectport(@conn_handle, 0)
  Metasm::WinAPI.closehandle @conn_handle
  @conn_handle = nil
  @communication_handle = []
end
connect(opts = {}, &block) click to toggle source
# File lib/turborex/windows/alpc.rb, line 257
def connect(opts = {}, &block)
  unless wport_name = TurboRex::Windows::Utils.multibyte_to_widechar(opts[:port_name])
    raise "Unable to convert characters to utf-16le encoding."
  end

  dest_str = APIProxy.alloc_c_ptr('UNICODE_STRING')
  APIProxy.rtlinitunicodestring(dest_str, wport_name)

  handle = APIProxy.alloc_c_type('HANDLE')
  alpc_port_attr = APIProxy.alloc_c_struct('ALPC_PORT_ATTRIBUTES')
  alpc_port_attr.Flags = TurboRex::Windows::ALPC::ALPC_PORFLG_ALLOW_LPC_REQUESTS
  alpc_port_attr.MaxMessageLength = 0x1000
  alpc_port_attr.MemoryBandwidth = 0
  alpc_port_attr.MaxPoolUsage = 0xFFFFFFFF
  alpc_port_attr.MaxSectionSize = 0xFFFFFFFF
  alpc_port_attr.MaxViewSize = 0xFFFFFFFF
  alpc_port_attr.MaxTotalSectionSize = 0xFFFFFFFF
  alpc_port_attr.DupObjectTypes = 0xFFFFFFFF

  alpc_port_attr.SecurityQos.Length = alpc_port_attr.SecurityQos.sizeof
  alpc_port_attr.SecurityQos.ImpersonationLevel = opts[:impersonation_level] || 
                                                  TurboRex::Windows::Constants::SecurityIdentification

  # timeout
  #large_integer = APIProxy.alloc_c_struct('LARGE_INTEGER')
  #large_integer.HighPart
  #large_integer.LowPart

  kport_message = PortMessage.new(payload: opts[:payload], alloc_size: (opts[:alloc_size]||3800))
  obj_attr = opts[:obj_attr] || 0
  flags = opts[:flags] || TurboRex::Windows::ALPC::ALPC_MSGFLG_SYNC_REQUEST # Don't use the ALPC_MSGFLG_SYNC_REQUEST flag when specific attributes
  timeout = opts[:timeout] || 0
  retry_count = opts[:retry_count] || 0

  buf_len = nil
  if message_size = kport_message.message_size
    buf_len = APIProxy.alloc_c_type('SIZE_T')
    buf_len[0] = message_size
  end

  out_msg_attr = 0
  in_msg_attr = 0

  if opts[:client_obj_attr] # perform to call NtAlpcConnectPortEx
    raise NotImplementedError
  else
    ntstatus = APIProxy.ntalpcconnectport(handle, dest_str, obj_attr, alpc_port_attr, flags, 0, kport_message.message,
                                          buf_len, out_msg_attr, in_msg_attr, timeout)
    kport_message.refresh_message
    formatted_status = TinySDK.format_hex_ntstatus(ntstatus)
    if formatted_status == 0xC0000041
      puts "[-] The server refused the connection.(STATUS_PORT_CONNECTION_REFUSED)"
      retry_count.times do |i|
        puts "[*] Retrying..."
        ntstatus = APIProxy.ntalpcconnectport(handle, dest_str, obj_attr, alpc_port_attr, flags, 0, kport_message.message,
                                              buf_len, out_msg_attr, in_msg_attr, timeout)
        break unless TinySDK.format_hex_ntstatus(ntstatus) == 0xC0000041
      end
    elsif !TinySDK.nt_success?(ntstatus)
      raise TurboRex::Exception::NotNTSuccess.new("0x#{formatted_status.to_s(16).upcase}")
    end
  end

  @communication_handle << handle[0]
  return handle[0], kport_message          
end
listen(conn_handle, opts = {}) { |port_message, buf_len, message_attr, format_hex_ntstatus(ntstatus, hex_str: true)| ... } click to toggle source
# File lib/turborex/windows/alpc.rb, line 124
def listen(conn_handle, opts = {}, &block)
  @conn_handle = conn_handle
  #port_message = APIProxy.alloc_c_struct('PORT_MESSAGE')
  port_message = APIProxy.alloc_c_ary('BYTE', 0x1000)
  message_attr = MessageAttribute.new.struct
  buf_len = APIProxy.alloc_c_type('SIZE_T')
  buf_len[0] = port_message.sizeof
  retry_count = 0

  while true
    begin
      # call NtAlpcSendWaitReceivePort will cause interpreter blocks, until you kill it.
      ntstatus = APIProxy.ntalpcsendwaitreceiveport(@conn_handle,
                                                    opts[:flag] || 0,
                                                    0,
                                                    0,
                                                    port_message,
                                                    buf_len,
                                                    message_attr,
                                                    0)
      yield(port_message, buf_len, message_attr, TinySDK.format_hex_ntstatus(ntstatus, hex_str: true)) if block_given?
      unless TinySDK.nt_success? ntstatus
        unless buf_len[0] == port_message.sizeof
          port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
          raise TurboRex::Exception::ALPC::BufferTooSmall
        else
          raise
        end
      end
    rescue => e
      if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
        raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
        retry_count += 1
        retry
      else
        raise TurboRex::Exception::UnknownError
      end
    end

    kport_message = PortMessage.new(raw_message: port_message)
    break if (kport_message.type & 0xFFF) == TurboRex::Windows::ALPC::LPC_CONNECTION_REQUEST
  end

  return kport_message
end
recv(handle, opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 185
def recv(handle, opts = {})
  port_message = opts.fetch(:port_message) { APIProxy.alloc_c_ary('BYTE', 0x1000) }
  buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
  buf_len[0] = port_message.sizeof
  #message_attr = opts.fetch(:message_attr) { APIProxy.alloc_c_struct('ALPC_MESSAGE_ATTRIBUTES') }
  message_attr = MessageAttribute.new.struct
  flag = opts[:flag] || 0
  retry_count = opts[:retry_count] || 0
  timeout = opts[:timeout] || 0

  begin
    ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle, flag, 0, 0, port_message, buf_len, message_attr, timeout)
    unless TinySDK.nt_success? ntstatus
      unless buf_len[0] == port_message.sizeof
        port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
        raise TurboRex::Exception::ALPC::BufferTooSmall
      else
        raise
      end
    end
  rescue => e
    if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
      raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
      retry_count += 1
      retry
    else
      raise TurboRex::Exception::NotNTSuccess.new(TinySDK.format_hex_ntstatus(ntstatus, hex_str: true))
    end
  end

  PortMessage.new(raw_message: port_message)
end
refuse_connect(opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 371
def refuse_connect(opts = {})
  opts[:refuse] = true
  accept(opts)
end
send(handle, port_message, message_attr, opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 170
def send(handle, port_message, message_attr, opts = {})
  flag = opts[:flag] || 0
  timeout = opts[:timeout] || 0
  #buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
  #buf_len = port_message.sizeof

  ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle, flag, port_message, message_attr, 0, 0, 0, timeout)
  unless TinySDK.nt_success?(ntstatus)
    raise TurboRex::Exception::NotNTSuccess.new TinySDK.format_hex_ntstatus(ntstatus, hex_str: true)
  end

  TinySDK.format_hex_ntstatus ntstatus
end
send_recv(handle, send_message, send_message_attr, recv_message_attr, opts = {}) click to toggle source
# File lib/turborex/windows/alpc.rb, line 218
def send_recv(handle, send_message, send_message_attr, recv_message_attr, opts = {})
  port_message = opts.fetch(:port_message) { APIProxy.alloc_c_ary('BYTE', 0x1000) }
  buf_len = opts.fetch(:buf_len) { APIProxy.alloc_c_type('SIZE_T') }
  buf_len[0] = port_message.sizeof
  message_attr = recv_message_attr
  flag = opts[:flag] || TurboRex::Windows::ALPC::ALPC_MSGFLG_SYNC_REQUEST
  retry_count = opts[:retry_count] || 0
  timeout = opts[:timeout] || 0

  begin
    ntstatus = APIProxy.ntalpcsendwaitreceiveport(handle, 
                                                  flag, 
                                                  send_message, 
                                                  send_message_attr, 
                                                  port_message, 
                                                  buf_len, 
                                                  recv_message_attr, 
                                                  timeout)
    unless TinySDK.nt_success? ntstatus
      unless buf_len[0] == port_message.sizeof
        port_message = APIProxy.alloc_c_ary('BYTE', buf_len[0])
        raise TurboRex::Exception::ALPC::BufferTooSmall
      else
        raise
      end
    end
  rescue => e
    if e.is_a? TurboRex::Exception::ALPC::BufferTooSmall
      raise TurboRex::Exception::ALPC::TooManyRetries if retry_count >= 2
      retry_count += 1
      retry
    else
      raise TurboRex::Exception::NotNTSuccess.new(TinySDK.format_hex_ntstatus(ntstatus, hex_str: true))
    end
  end

  PortMessage.new(raw_message: port_message)
end