Class: RubySMB::GenericPacket

Inherits:
BinData::Record
  • Object
show all
Defined in:
lib/ruby_smb/generic_packet.rb

Overview

Parent class for all SMB Packets.

Direct Known Subclasses

SMB1::Packet::CloseRequest, SMB1::Packet::CloseResponse, SMB1::Packet::EchoRequest, SMB1::Packet::EchoResponse, SMB1::Packet::EmptyPacket, SMB1::Packet::LogoffRequest, SMB1::Packet::LogoffResponse, SMB1::Packet::NegotiateRequest, SMB1::Packet::NegotiateResponse, SMB1::Packet::NegotiateResponseExtended, SMB1::Packet::NtCreateAndxRequest, SMB1::Packet::NtCreateAndxResponse, SMB1::Packet::NtTrans::CreateRequest, SMB1::Packet::NtTrans::CreateResponse, SMB1::Packet::NtTrans::Request, SMB1::Packet::NtTrans::Response, SMB1::Packet::ReadAndxRequest, SMB1::Packet::ReadAndxResponse, SMB1::Packet::SessionSetupLegacyRequest, SMB1::Packet::SessionSetupLegacyResponse, SMB1::Packet::SessionSetupRequest, SMB1::Packet::SessionSetupResponse, SMB1::Packet::Trans2::FindFirst2Request, SMB1::Packet::Trans2::FindFirst2Response, SMB1::Packet::Trans2::FindNext2Request, SMB1::Packet::Trans2::FindNext2Response, SMB1::Packet::Trans2::Open2Request, SMB1::Packet::Trans2::Open2Response, SMB1::Packet::Trans2::Request, SMB1::Packet::Trans2::RequestSecondary, SMB1::Packet::Trans2::Response, SMB1::Packet::Trans2::SetFileInformationRequest, SMB1::Packet::Trans2::SetFileInformationResponse, SMB1::Packet::Trans::PeekNmpipeResponse, SMB1::Packet::Trans::Request, SMB1::Packet::Trans::Response, SMB1::Packet::Trans::TransactNmpipeRequest, SMB1::Packet::Trans::TransactNmpipeResponse, SMB1::Packet::TreeConnectRequest, SMB1::Packet::TreeConnectResponse, SMB1::Packet::TreeDisconnectRequest, SMB1::Packet::TreeDisconnectResponse, SMB1::Packet::WriteAndxRequest, SMB1::Packet::WriteAndxResponse, SMB2::Packet::CloseRequest, SMB2::Packet::CloseResponse, SMB2::Packet::CreateRequest, SMB2::Packet::CreateResponse, SMB2::Packet::EchoRequest, SMB2::Packet::EchoResponse, SMB2::Packet::ErrorPacket, SMB2::Packet::IoctlRequest, SMB2::Packet::IoctlResponse, SMB2::Packet::LogoffRequest, SMB2::Packet::LogoffResponse, SMB2::Packet::NegotiateRequest, SMB2::Packet::NegotiateResponse, SMB2::Packet::QueryDirectoryRequest, SMB2::Packet::QueryDirectoryResponse, SMB2::Packet::ReadRequest, SMB2::Packet::ReadResponse, SMB2::Packet::SessionSetupRequest, SMB2::Packet::SessionSetupResponse, SMB2::Packet::SetInfoRequest, SMB2::Packet::SetInfoResponse, SMB2::Packet::TreeConnectRequest, SMB2::Packet::TreeConnectResponse, SMB2::Packet::TreeDisconnectRequest, SMB2::Packet::TreeDisconnectResponse, SMB2::Packet::WriteRequest, SMB2::Packet::WriteResponse

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.describeString

Outputs a nicely formatted string representation of the Packet's structure.

Returns:

  • (String)

    formatted string representation of the packet structure



8
9
10
11
12
13
14
# File 'lib/ruby_smb/generic_packet.rb', line 8

def self.describe
  description = ''
  fields_hashed.each do |field|
    description << format_field(field)
  end
  description
end

.fields_hashedArray<Hash>

Returns an array of hashes representing the fields for this record.

Returns:

  • (Array<Hash>)

    the array of hash representations of the record's fields



79
80
81
# File 'lib/ruby_smb/generic_packet.rb', line 79

def self.fields_hashed
  walk_fields(fields)
end

.format_field(field, depth = 0) ⇒ String

Takes a hash representation of a field and spits out a formatted string representation.

Parameters:

  • field (Hash)

    the hash representing the field

  • depth (Fixnum) (defaults to: 0)

    the recursive depth level to track indentation

Returns:

  • (String)

    the formatted string representation of the field



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/ruby_smb/generic_packet.rb', line 89

def self.format_field(field, depth = 0)
  name = field[:name].to_s
  if field[:class].ancestors.include? BinData::Record
    class_str = ''
    name.upcase!
  else
    class_str = field[:class].to_s.split('::').last
    class_str = "(#{class_str})"
    name.capitalize!
  end
  formatted_name = "\n" + ("\t" * depth) + name
  formatted_string = format '%-30s %-10s %s', formatted_name, class_str, field[:label]
  field[:fields].each do |sub_field|
    formatted_string << format_field(sub_field, (depth + 1))
  end
  formatted_string
end

.read(val) ⇒ Object

Overrides the class #read method with some automatic exception handling. If an EOFError is thrown, it will try to read the data into the protocol specific empty ErrorPacket so that the NTstatus code can be read. We re-raise the exception in the event that it is not an SMB1 or SMB2 packet, or if it is already an error packet.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ruby_smb/generic_packet.rb', line 42

def self.read(val)
  begin
    super(val)
  rescue EOFError => e
    case self.to_s
      when /EmptyPacket|ErrorPacket/
        raise e
      when /SMB1/
        RubySMB::SMB1::Packet::EmptyPacket.read(val)
      when /SMB2/
        RubySMB::SMB2::Packet::ErrorPacket.read(val)
      else
        raise e
    end
  end
end

.walk_fields(fields) ⇒ Array<Hash>

Recursively walks through a field, building a hash representation of that field and all of it's sub-fields.

Parameters:

  • fields (Array<BinData::SanitizedField>)

    an array of fields to walk

Returns:

  • (Array<Hash>)

    an array of hashes representing the fields



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/ruby_smb/generic_packet.rb', line 112

def self.walk_fields(fields)
  field_hashes = []
  fields.each do |field|
    field_hash = {}
    field_hash[:name] = field.name
    prototype = field.prototype
    field_hash[:class] = prototype.instance_variable_get(:@obj_class)
    params = prototype.instance_variable_get(:@obj_params)
    field_hash[:label] = params[:label]
    field_hash[:value] = params[:value]
    sub_fields = params[:fields]
    field_hash[:fields] = if sub_fields.nil?
                            []
                          else
                            walk_fields(sub_fields)
                          end
    field_hashes << field_hash
  end
  field_hashes
end

Instance Method Details

#displayObject



16
17
18
19
20
21
22
# File 'lib/ruby_smb/generic_packet.rb', line 16

def display
  display_str = ''
  self.class.fields_hashed.each do |field|
    display_str << display_field(field)
  end
  display_str
end

#packet_smb_versionObject



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ruby_smb/generic_packet.rb', line 24

def packet_smb_version
  class_name = self.class.to_s
  case class_name
  when /SMB1/
    'SMB1'
  when /SMB2/
    'SMB2'
  else
    ''
  end
end

#status_codeObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ruby_smb/generic_packet.rb', line 59

def status_code
  value = -1
  smb_version = packet_smb_version
  case smb_version
  when 'SMB1'
    value = smb_header.nt_status.value
  when 'SMB2'
    value = smb2_header.nt_status.value
  end
  status_code = WindowsError::NTStatus.find_by_retval(value).first
  if status_code.nil?
    status_code = WindowsError::ErrorCode.new("0x#{value.to_s(16)}", value, "Unknown 0x#{value.to_s(16)}")
  end
  status_code
end