Skip to content

Commit

Permalink
generic packet is now more generic
Browse files Browse the repository at this point in the history
made Generic packet jsut a wrapper for
the packet inspection methods we created
so that they can be shared across SMB1 and SMB2
  • Loading branch information
David Maloney authored and David Maloney committed Sep 14, 2015
1 parent 418645e commit 4890c13
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 202 deletions.
1 change: 1 addition & 0 deletions lib/ruby_smb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# [[MS-SMB2] Server Mesage Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
module RubySMB
require 'ruby_smb/field'
require 'ruby_smb/generic_packet'
autoload :Dispatcher, 'ruby_smb/dispatcher'
autoload :Error, 'ruby_smb/error'
autoload :VERSION, 'ruby_smb/version'
Expand Down
157 changes: 157 additions & 0 deletions lib/ruby_smb/generic_packet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
module RubySMB
# Parent class for all SMB Packets.
class GenericPacket < BinData::Record

# Outputs a nicely formatted string representation
# of the Packet's structure.
#
# @return [String] formatted string representation of the packet structure
def self.describe
description = ''
fields_hashed.each do |field|
description << self.format_field(field)
end
description
end

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

private

# Returns an array of hashes representing the
# fields for this record.
#
# @return [Array<Hash>] the array of hash representations of the record's fields
def self.fields_hashed
walk_fields(self.fields)
end

# Takes a hash representation of a field and spits out a formatted
# string representation.
#
# @param field [Hash] the hash representing the field
# @param depth [Fixnum] the recursive depth level to track indentation
# @return [String] the formatted string representation of the field
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 = sprintf "%-30s %-10s %s", formatted_name, class_str, field[:label]
field[:fields].each do |sub_field|
formatted_string << self.format_field(sub_field,(depth+1))
end
formatted_string
end

# Recursively walks through a field, building a hash representation
# of that field and all of it's sub-fields.
#
# @param fields [Array<BinData::SanitizedField>] an array of fields to walk
# @return [Array<Hash>] an array of hashes representing the fields
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]
if sub_fields.nil?
field_hash[:fields] = []
else
field_hash[:fields] = self.walk_fields(sub_fields)
end
field_hashes << field_hash
end
field_hashes
end

# Takes a hash representation of a field in the packet structure and formats it
# into a string representing the contents of that field.
#
# @param field [Hash] hash representation of the field to display
# @param depth [Fixnum] the recursion depth for setting indent levels
# @param parents [Array<Symbol>] the name of the parent field, if any, of this field
# @return [String] a formatted string representing the field and it's current contents
def display_field(field, depth=0, parents=[])
my_parents = parents.dup
field_str = ''
name = field[:name]
if field[:class] == BinData::Array
field_str = "\n" + ("\t" * depth) + name.to_s.upcase
parent = self
my_parents.each do |pfield|
parent = parent.send(pfield)
end
array_field = parent.send(name)
field_str << process_array_field(array_field,(depth + 1))
else
if my_parents.empty?
field_str = "\n" + ("\t" * depth) + name.to_s.upcase
else
if name.nil?
name = ''
value = ''
elsif field[:class].ancestors.include? BinData::Record
value = ''
else
parent = self
my_parents.each do |pfield|
parent = parent.send(pfield)
end
value = parent.send(name)
end
label = field[:label] || name.to_s.capitalize
label = "\n" + ("\t" * depth) + label
field_str = sprintf "%-30s %s", label, value
end
end
my_parents << name
field[:fields].each do |sub_field|
field_str << display_field(sub_field, (depth + 1), my_parents)
end
field_str
end

# Takes a {BinData::Array} field and processes it to get
# the structure elements and values out since they cannot be
# evaluated at the class level.
#
# @param array_field [BinData::Array] the Array field to be processed
# @return [String] the formatted string representing the contents of the array
def process_array_field(array_field,depth)
array_field_str = ''
array_field.each do |sub_field|
fields = sub_field.class.fields.fields
sub_field_hashes = self.class.walk_fields(fields)
sub_field_hashes.each do |sub_field_hash|
name = sub_field_hash[:name]
label = sub_field_hash[:label]
value = sub_field.send(name)
label ||= name
label = "\n" + "\t" * depth + label
sub_field_str = sprintf "%-30s %s", label, value
array_field_str << sub_field_str
end
end
array_field_str
end

end
end
2 changes: 0 additions & 2 deletions lib/ruby_smb/smb1/packet.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module RubySMB
module SMB1
module Packet

require 'ruby_smb/smb1/packet/generic'
require 'ruby_smb/smb1/packet/negotiate_request'
require 'ruby_smb/smb1/packet/negotiate_response'
require 'ruby_smb/smb1/packet/negotiate_response_extended'
Expand Down
162 changes: 0 additions & 162 deletions lib/ruby_smb/smb1/packet/generic.rb

This file was deleted.

7 changes: 4 additions & 3 deletions lib/ruby_smb/smb1/packet/negotiate_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ module SMB1
module Packet
# A SMB1 SMB_COM_NEGOTIATE Request Packet as defined in
# [2.2.4.52.1](https://msdn.microsoft.com/en-us/library/ee441572.aspx)
class NegotiateRequest < RubySMB::SMB1::Packet::Generic
class NegotiateRequest < RubySMB::GenericPacket

# Represents the specific layout of the DataBlock for a NegotiateRequest Packet.
class DataBlock < RubySMB::SMB1::DataBlock
array :dialects, :label => 'Dialects', :type => :dialect, :read_until => :eof
end

parameter_block :parameter_block
data_block :data_block
smb_header :smb_header
parameter_block :parameter_block
data_block :data_block

def initialize_instance
super
Expand Down
7 changes: 4 additions & 3 deletions lib/ruby_smb/smb1/packet/negotiate_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module SMB1
module Packet
# A SMB1 SMB_COM_NEGOTIATE Non-Extended Security Response Packet as defined in
# [2.2.4.5.2.2 Non-Extended Security Response](https://msdn.microsoft.com/en-us/library/cc246327.aspx)
class NegotiateResponse < RubySMB::SMB1::Packet::Generic
class NegotiateResponse < RubySMB::GenericPacket

# An SMB_Parameters Block as defined by the {NegotiateResponse}.
class ParameterBlock < RubySMB::SMB1::ParameterBlock
Expand All @@ -27,8 +27,9 @@ class DataBlock < RubySMB::SMB1::DataBlock
stringz16 :server_name, :label => 'Server Name'
end

parameter_block :parameter_block
data_block :data_block
smb_header :smb_header
parameter_block :parameter_block
data_block :data_block

def initialize_instance
super
Expand Down

0 comments on commit 4890c13

Please sign in to comment.