Adds Java serialization support, lands #4327
commit
00590f9f26
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'rex/java/serialization'
|
|
@ -0,0 +1,54 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
# Include constants defining terminal and constant
|
||||||
|
# values expected in a stream.
|
||||||
|
module Serialization
|
||||||
|
STREAM_MAGIC = 0xaced
|
||||||
|
STREAM_VERSION = 5
|
||||||
|
TC_NULL = 0x70
|
||||||
|
TC_REFERENCE = 0x71
|
||||||
|
TC_CLASSDESC = 0x72
|
||||||
|
TC_OBJECT = 0x73
|
||||||
|
TC_STRING = 0x74
|
||||||
|
TC_ARRAY = 0x75
|
||||||
|
TC_CLASS = 0x76
|
||||||
|
TC_BLOCKDATA = 0x77
|
||||||
|
TC_ENDBLOCKDATA = 0x78
|
||||||
|
TC_RESET = 0x79
|
||||||
|
TC_BLOCKDATALONG = 0x7A
|
||||||
|
TC_EXCEPTION = 0x7B
|
||||||
|
TC_LONGSTRING = 0x7C
|
||||||
|
TC_PROXYCLASSDESC = 0x7D
|
||||||
|
TC_ENUM = 0x7E
|
||||||
|
BASE_WIRE_HANDLE = 0x7E0000
|
||||||
|
|
||||||
|
SC_WRITE_METHOD = 0x01 # if SC_SERIALIZABLE
|
||||||
|
SC_BLOCK_DATA = 0x08 # if SC_EXTERNALIZABLE
|
||||||
|
SC_SERIALIZABLE = 0x02
|
||||||
|
SC_EXTERNALIZABLE = 0x04
|
||||||
|
SC_ENUM = 0x10
|
||||||
|
|
||||||
|
PRIMITIVE_TYPE_CODES = {
|
||||||
|
'B' => 'byte',
|
||||||
|
'C' => 'char',
|
||||||
|
'D' => 'double',
|
||||||
|
'F' => 'float',
|
||||||
|
'I' => 'int',
|
||||||
|
'J' => 'long',
|
||||||
|
'S' => 'short',
|
||||||
|
'Z' => 'boolean'
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJECT_TYPE_CODES = {
|
||||||
|
'[' => 'array',
|
||||||
|
'L' => 'object'
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_CODES = PRIMITIVE_TYPE_CODES.merge(OBJECT_TYPE_CODES)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'rex/java/serialization/model'
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
require 'rex/java/serialization/model/element'
|
||||||
|
require 'rex/java/serialization/model/null_reference'
|
||||||
|
require 'rex/java/serialization/model/reference'
|
||||||
|
require 'rex/java/serialization/model/reset'
|
||||||
|
require 'rex/java/serialization/model/utf'
|
||||||
|
require 'rex/java/serialization/model/long_utf'
|
||||||
|
require 'rex/java/serialization/model/block_data'
|
||||||
|
require 'rex/java/serialization/model/block_data_long'
|
||||||
|
require 'rex/java/serialization/model/end_block_data'
|
||||||
|
require 'rex/java/serialization/model/contents'
|
||||||
|
require 'rex/java/serialization/model/new_enum'
|
||||||
|
require 'rex/java/serialization/model/field'
|
||||||
|
require 'rex/java/serialization/model/new_array'
|
||||||
|
require 'rex/java/serialization/model/annotation'
|
||||||
|
require 'rex/java/serialization/model/class_desc'
|
||||||
|
require 'rex/java/serialization/model/new_class_desc'
|
||||||
|
require 'rex/java/serialization/model/new_object'
|
||||||
|
require 'rex/java/serialization/model/stream'
|
|
@ -0,0 +1,69 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides an annotation representation. It's used for both class
|
||||||
|
# annotations (classAnnotation) and object annotations (objectAnnotation).
|
||||||
|
class Annotation < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [Array] The annotation contents
|
||||||
|
attr_accessor :contents
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.contents = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Annotation
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
loop do
|
||||||
|
content = decode_content(io, stream)
|
||||||
|
self.contents << content
|
||||||
|
return self if content.class == EndBlockData
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::Annotation
|
||||||
|
#
|
||||||
|
# @return [String] if serialization suceeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
raise ::RuntimeError, 'Failed to serialize Annotation with empty contents' if contents.empty?
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
|
||||||
|
contents.each do |content|
|
||||||
|
encoded << encode_content(content)
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = '[ '
|
||||||
|
contents_data = contents.collect {|content| "#{print_content(content)}"}
|
||||||
|
str << contents_data.join(', ')
|
||||||
|
str << ' ]'
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,70 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a block data representation
|
||||||
|
class BlockData < Element
|
||||||
|
|
||||||
|
# @!attribute length
|
||||||
|
# @return [Integer] the length of the block
|
||||||
|
attr_accessor :length
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [String] the contents of the block
|
||||||
|
attr_accessor :contents
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
# @param contents [String] the contents of the block
|
||||||
|
def initialize(stream = nil, contents = '')
|
||||||
|
super(stream)
|
||||||
|
self.contents = contents
|
||||||
|
self.length = contents.length
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::BlockData
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
raw_length = io.read(1)
|
||||||
|
raise RuntimeError, 'Failed to unserialize BlockData' if raw_length.nil?
|
||||||
|
self.length = raw_length.unpack('C')[0]
|
||||||
|
|
||||||
|
if length == 0
|
||||||
|
self.contents = ''
|
||||||
|
else
|
||||||
|
self.contents = io.read(length)
|
||||||
|
if contents.nil? || contents.length != length
|
||||||
|
raise RuntimeError, 'Failed to unserialize BlockData'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
contents_hex = []
|
||||||
|
contents.each_byte {|byte| contents_hex << "0x#{byte.to_s(16)}" }
|
||||||
|
|
||||||
|
"[ #{contents_hex.join(', ')} ]"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::BlockData
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def encode
|
||||||
|
encoded = [length].pack('C')
|
||||||
|
encoded << contents
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a block data (long) representation
|
||||||
|
class BlockDataLong < Element
|
||||||
|
|
||||||
|
# @!attribute length
|
||||||
|
# @return [Integer] the length of the block
|
||||||
|
attr_accessor :length
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [String] the contents of the block
|
||||||
|
attr_accessor :contents
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
# @param contents [String] the contents of the block
|
||||||
|
def initialize(stream = nil, contents = '')
|
||||||
|
super(stream)
|
||||||
|
self.contents = contents
|
||||||
|
self.length = contents.length
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::BlockDataLong
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
raw_length = io.read(4)
|
||||||
|
if raw_length.nil? || raw_length.length != 4
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize BlockDataLong'
|
||||||
|
end
|
||||||
|
self.length = raw_length.unpack('N')[0]
|
||||||
|
|
||||||
|
if length == 0
|
||||||
|
self.contents = ''
|
||||||
|
else
|
||||||
|
self.contents = io.read(length)
|
||||||
|
if contents.nil? || contents.length != length
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize BlockData'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::BlockDataLong
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def encode
|
||||||
|
encoded = [length].pack('N')
|
||||||
|
encoded << contents
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
contents_hex = []
|
||||||
|
contents.each_byte {|byte| contents_hex << "0x#{byte.to_s(16)}" }
|
||||||
|
|
||||||
|
"[ #{contents_hex.join(', ')} ]"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,64 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a Java classDesc representation
|
||||||
|
class ClassDesc < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
attr_accessor :description
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.description = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::ClassDesc
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
content = decode_content(io, stream)
|
||||||
|
allowed_contents = [NullReference, NewClassDesc, Reference]
|
||||||
|
|
||||||
|
unless allowed_contents.include?(content.class)
|
||||||
|
raise ::RuntimeError, 'ClassDesc unserialize failed'
|
||||||
|
end
|
||||||
|
|
||||||
|
self.description = content
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::ClassDesc
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
encoded = ''
|
||||||
|
allowed_contents = [NullReference, NewClassDesc, Reference]
|
||||||
|
|
||||||
|
unless allowed_contents.include?(description.class)
|
||||||
|
raise ::RuntimeError, 'Failed to serialize ClassDesc'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded << encode_content(description)
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
print_content(description)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,156 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
module Contents
|
||||||
|
include Rex::Java::Serialization
|
||||||
|
|
||||||
|
# Deserializes a content
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Rex::Java::Serialization::Model::Element] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed or unsupported content
|
||||||
|
def decode_content(io, stream)
|
||||||
|
opcode = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize content' if opcode.nil?
|
||||||
|
opcode = opcode.unpack('C')[0]
|
||||||
|
content = nil
|
||||||
|
|
||||||
|
case opcode
|
||||||
|
when TC_BLOCKDATA
|
||||||
|
content = BlockData.decode(io, stream)
|
||||||
|
when TC_BLOCKDATALONG
|
||||||
|
content = BlockDataLong.decode(io, stream)
|
||||||
|
when TC_ENDBLOCKDATA
|
||||||
|
content = EndBlockData.decode(io, stream)
|
||||||
|
when TC_OBJECT
|
||||||
|
content = NewObject.decode(io, stream)
|
||||||
|
when TC_CLASS
|
||||||
|
content = ClassDesc.decode(io, stream)
|
||||||
|
when TC_ARRAY
|
||||||
|
content = NewArray.decode(io, stream)
|
||||||
|
when TC_STRING
|
||||||
|
content = Utf.decode(io, stream)
|
||||||
|
stream.add_reference(content) unless stream.nil?
|
||||||
|
when TC_LONGSTRING
|
||||||
|
content = LongUtf.decode(io, stream)
|
||||||
|
stream.add_reference(content) unless stream.nil?
|
||||||
|
when TC_ENUM
|
||||||
|
content = NewEnum.decode(io, stream)
|
||||||
|
when TC_CLASSDESC
|
||||||
|
content = NewClassDesc.decode(io, stream)
|
||||||
|
when TC_PROXYCLASSDESC
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize unsupported TC_PROXYCLASSDESC content'
|
||||||
|
when TC_REFERENCE
|
||||||
|
content = Reference.decode(io, stream)
|
||||||
|
when TC_NULL
|
||||||
|
content = NullReference.decode(io, stream)
|
||||||
|
when TC_EXCEPTION
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize unsupported TC_EXCEPTION content'
|
||||||
|
when TC_RESET
|
||||||
|
content = Reset.decode(io, stream)
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize content'
|
||||||
|
end
|
||||||
|
|
||||||
|
content
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes a content
|
||||||
|
#
|
||||||
|
# @param content [Rex::Java::Serialization::Model::Element] the content to serialize
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode_content(content)
|
||||||
|
encoded = ''
|
||||||
|
|
||||||
|
case content
|
||||||
|
when BlockData
|
||||||
|
encoded << [TC_BLOCKDATA].pack('C')
|
||||||
|
when BlockDataLong
|
||||||
|
encoded << [TC_BLOCKDATALONG].pack('C')
|
||||||
|
when EndBlockData
|
||||||
|
encoded << [TC_ENDBLOCKDATA].pack('C')
|
||||||
|
when NewObject
|
||||||
|
encoded << [TC_OBJECT].pack('C')
|
||||||
|
when ClassDesc
|
||||||
|
encoded << [TC_CLASS].pack('C')
|
||||||
|
when NewArray
|
||||||
|
encoded << [TC_ARRAY].pack('C')
|
||||||
|
when Utf
|
||||||
|
encoded << [TC_STRING].pack('C')
|
||||||
|
when LongUtf
|
||||||
|
encoded << [TC_LONGSTRING].pack('C')
|
||||||
|
when NewEnum
|
||||||
|
encoded << [TC_ENUM].pack('C')
|
||||||
|
when NewClassDesc
|
||||||
|
encoded << [TC_CLASSDESC].pack('C')
|
||||||
|
when NullReference
|
||||||
|
encoded << [TC_NULL].pack('C')
|
||||||
|
when Reset
|
||||||
|
encoded << [TC_RESET].pack('C')
|
||||||
|
when Reference
|
||||||
|
encoded << [TC_REFERENCE].pack('C')
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Failed to serialize content'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded << content.encode
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @param content [Rex::Java::Serialization::Model::Element] the content to print
|
||||||
|
# @return [String]
|
||||||
|
def print_content(content)
|
||||||
|
str = ''
|
||||||
|
|
||||||
|
case content
|
||||||
|
when BlockData
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when BlockDataLong
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when EndBlockData
|
||||||
|
str << "#{print_class(content)}"
|
||||||
|
when NewObject
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when ClassDesc
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when NewArray
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when Utf
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when LongUtf
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} } "
|
||||||
|
when NewEnum
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when NewClassDesc
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
when NullReference
|
||||||
|
str << "#{print_class(content)}"
|
||||||
|
when Reset
|
||||||
|
str << "#{print_class(content)}"
|
||||||
|
when Reference
|
||||||
|
str << "#{print_class(content)} { #{content.to_s} }"
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Failed to serialize content'
|
||||||
|
end
|
||||||
|
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation of the content class
|
||||||
|
#
|
||||||
|
# @param content [Rex::Java::Serialization::Model::Element] the content
|
||||||
|
# @return [String]
|
||||||
|
def print_class(content)
|
||||||
|
content.class.name.split('::').last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,44 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
class Element
|
||||||
|
|
||||||
|
attr_accessor :stream
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Element
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Rex::Java::Serialization::Model::Element] if deserialization succeeds
|
||||||
|
# @return [nil] if deserialization doesn't succeed
|
||||||
|
def self.decode(io, stream = nil)
|
||||||
|
elem = self.new(stream)
|
||||||
|
elem.decode(io)
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
self.stream = stream
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode(io)
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def encode
|
||||||
|
''
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
self.class.name.split('::').last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
class EndBlockData < Element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,172 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a field description representation (fieldDesc). It's used for
|
||||||
|
# both primitive descriptions (primitiveDesc) and object descriptions (objectDesc).
|
||||||
|
class Field < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute type
|
||||||
|
# @return [String] The type of the field.
|
||||||
|
attr_accessor :type
|
||||||
|
# @!attribute name
|
||||||
|
# @return [Rex::Java::Serialization::Model::Utf] The name of the field.
|
||||||
|
attr_accessor :name
|
||||||
|
# @!attribute field_type
|
||||||
|
# @return [Rex::Java::Serialization::Model::Utf] The type of the field on object types.
|
||||||
|
attr_accessor :field_type
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.type = ''
|
||||||
|
self.name = nil
|
||||||
|
self.field_type = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Field
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @faise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
code = io.read(1)
|
||||||
|
|
||||||
|
unless code && is_valid?(code)
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Field'
|
||||||
|
end
|
||||||
|
|
||||||
|
self.type = TYPE_CODES[code]
|
||||||
|
self.name = Utf.decode(io, stream)
|
||||||
|
|
||||||
|
if is_object?
|
||||||
|
self.field_type = decode_field_type(io)
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::Field
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
unless name.class == Rex::Java::Serialization::Model::Utf
|
||||||
|
raise ::RuntimeError, 'Failed to serialize Field'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless is_type_valid?
|
||||||
|
raise ::RuntimeError, 'Failed to serialize Field'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
encoded << TYPE_CODES.key(type)
|
||||||
|
encoded << name.encode
|
||||||
|
|
||||||
|
if is_object?
|
||||||
|
encoded << encode_field_type
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether the field type is valid.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def is_type_valid?
|
||||||
|
if TYPE_CODES.values.include?(type)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether the field type is a primitive one.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def is_primitive?
|
||||||
|
if PRIMITIVE_TYPE_CODES.values.include?(type)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether the field type is an object one.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def is_object?
|
||||||
|
if OBJECT_TYPE_CODES.values.include?(type)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = "#{name} "
|
||||||
|
if is_primitive?
|
||||||
|
str << "(#{type})"
|
||||||
|
else
|
||||||
|
str << "(#{field_type})"
|
||||||
|
end
|
||||||
|
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Whether the type opcode is a valid one.
|
||||||
|
#
|
||||||
|
# @param code [String] A type opcode
|
||||||
|
# @return [Boolean]
|
||||||
|
def is_valid?(code)
|
||||||
|
if TYPE_CODES.keys.include?(code)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the `field_type` attribute.
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def encode_field_type
|
||||||
|
allowed_contents = [Utf, Reference]
|
||||||
|
|
||||||
|
unless allowed_contents.include?(field_type.class)
|
||||||
|
raise ::RuntimeError, 'Failed to serialize Field'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = encode_content(field_type)
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes the `field_type` value.
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Java::Serialization::Model::Utf]
|
||||||
|
# @raise [RuntimeError] if unserialization doesn't succeed
|
||||||
|
def decode_field_type(io)
|
||||||
|
allowed_contents = [Utf, Reference]
|
||||||
|
type = decode_content(io, stream)
|
||||||
|
|
||||||
|
unless allowed_contents.include?(type.class)
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Field field_type'
|
||||||
|
end
|
||||||
|
|
||||||
|
type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,48 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a Long Utf string representation
|
||||||
|
class LongUtf < Utf
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::LongUtf
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @return [nil] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
raw_length = io.read(8)
|
||||||
|
if raw_length.nil? || raw_length.length != 8
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize LongUtf'
|
||||||
|
end
|
||||||
|
self.length = raw_length.unpack('Q>')[0]
|
||||||
|
|
||||||
|
if length == 0
|
||||||
|
self.contents = ''
|
||||||
|
else
|
||||||
|
self.contents = io.read(length)
|
||||||
|
if contents.nil? || contents.length != length
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize LongUtf'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::LongUtf
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def encode
|
||||||
|
encoded = [length].pack('Q>')
|
||||||
|
encoded << contents
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,225 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a NewArray (Java Array) representation
|
||||||
|
class NewArray < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute array_description
|
||||||
|
# @return [Java::Serialization::Model::ClassDesc] The description of the array
|
||||||
|
attr_accessor :array_description
|
||||||
|
# @!attribute type
|
||||||
|
# @return [String] The type of the array values
|
||||||
|
attr_accessor :type
|
||||||
|
# @!attribute values
|
||||||
|
# @return [Array] The contents of the java array
|
||||||
|
attr_accessor :values
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.array_description = nil
|
||||||
|
self.type = ''
|
||||||
|
self.values = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::NewArray
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
self.array_description = ClassDesc.decode(io, stream)
|
||||||
|
stream.add_reference(self) unless stream.nil?
|
||||||
|
self.type = array_type
|
||||||
|
|
||||||
|
values_length = decode_values_length(io)
|
||||||
|
|
||||||
|
values_length.times do
|
||||||
|
value = decode_value(io)
|
||||||
|
self.values << value
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::NewArray
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
unless array_description.class == ClassDesc
|
||||||
|
raise ::RuntimeError, 'Failed to serialize NewArray'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
encoded << array_description.encode
|
||||||
|
|
||||||
|
encoded << [values.length].pack('N')
|
||||||
|
|
||||||
|
values.each do |value|
|
||||||
|
encoded << encode_value(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = "#{type}, "
|
||||||
|
values_data = values.collect {|v| "#{v}"}
|
||||||
|
str << "#{values_data}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Deserializes the NewArray length
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Integer] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_values_length(io)
|
||||||
|
values_length = io.read(4)
|
||||||
|
if values_length.nil? || values_length.length != 4
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize NewArray'
|
||||||
|
end
|
||||||
|
|
||||||
|
values_length.unpack('N')[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extracts the NewArray data type
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @raise [RuntimeError] if the NewArray description isn't valid
|
||||||
|
# @raise [RuntimeError] if the NewArray type isn't supported
|
||||||
|
def array_type
|
||||||
|
if array_description.nil?
|
||||||
|
raise ::RuntimeError, 'Empty NewArray description'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless array_description.class == ClassDesc
|
||||||
|
raise ::RuntimeError, 'Unsupported NewArray description class'
|
||||||
|
end
|
||||||
|
|
||||||
|
desc = array_description.description
|
||||||
|
|
||||||
|
unless desc.class_name.contents[0] == '[' # Array
|
||||||
|
raise ::RuntimeError, 'Unsupported NewArray description'
|
||||||
|
end
|
||||||
|
|
||||||
|
decoded_type = desc.class_name.contents[1]
|
||||||
|
if PRIMITIVE_TYPE_CODES.keys.include?(decoded_type)
|
||||||
|
return PRIMITIVE_TYPE_CODES[decoded_type]
|
||||||
|
elsif decoded_type == 'L' # L : Object
|
||||||
|
return desc.class_name.contents[2..desc.class_name.contents.index(';')] # Object class
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Unsupported NewArray Type'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a NewArray value
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Fixnum, Float] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization fails
|
||||||
|
def decode_value(io)
|
||||||
|
value = nil
|
||||||
|
|
||||||
|
case type
|
||||||
|
when 'byte'
|
||||||
|
value = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value' if value.nil?
|
||||||
|
value = value.unpack('c')[0]
|
||||||
|
when 'char'
|
||||||
|
value = io.read(2)
|
||||||
|
unless value && value.length == 2
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('s>')[0]
|
||||||
|
when 'double'
|
||||||
|
value = io.read(8)
|
||||||
|
unless value && value.length == 8
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('G')[0]
|
||||||
|
when 'float'
|
||||||
|
value = io.read(4)
|
||||||
|
unless value && value.length == 4
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('g')[0]
|
||||||
|
when 'int'
|
||||||
|
value = io.read(4)
|
||||||
|
unless value && value.length == 4
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('l>')[0]
|
||||||
|
when 'long'
|
||||||
|
value = io.read(8)
|
||||||
|
unless value && value.length == 8
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('q>')[0]
|
||||||
|
when 'short'
|
||||||
|
value = io.read(2)
|
||||||
|
unless value && value.length == 2
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value = value.unpack('s>')[0]
|
||||||
|
when 'boolean'
|
||||||
|
value = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value' if value.nil?
|
||||||
|
value = value.unpack('c')[0]
|
||||||
|
else # object
|
||||||
|
value = decode_content(io, stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes an NewArray value
|
||||||
|
#
|
||||||
|
# @param value [Fixnum] the value to serialize
|
||||||
|
# @param value [Float] the value to serialize
|
||||||
|
# @return [String] the serialized value
|
||||||
|
# @raise [RuntimeError] if serialization fails
|
||||||
|
def encode_value(value)
|
||||||
|
res = ''
|
||||||
|
|
||||||
|
case type
|
||||||
|
when 'byte'
|
||||||
|
res = [value].pack('c')
|
||||||
|
when 'char'
|
||||||
|
res = [value].pack('s>')
|
||||||
|
when 'double'
|
||||||
|
res = [value].pack('G')
|
||||||
|
when 'float'
|
||||||
|
res = [value].pack('g')
|
||||||
|
when 'int'
|
||||||
|
res = [value].pack('l>')
|
||||||
|
when 'long'
|
||||||
|
res = [value].pack('q>')
|
||||||
|
when 'short'
|
||||||
|
res = [value].pack('s>')
|
||||||
|
when 'boolean'
|
||||||
|
res = [value].pack('c')
|
||||||
|
when Element
|
||||||
|
res = value.encode
|
||||||
|
else # object
|
||||||
|
res = encode_content(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,155 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a newClassDesc representation
|
||||||
|
class NewClassDesc < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization
|
||||||
|
|
||||||
|
# @!attribute class_name
|
||||||
|
# @return [Rex::Java::Serialization::Model::Utf] The name of the class
|
||||||
|
attr_accessor :class_name
|
||||||
|
# @!attribute name
|
||||||
|
# @return [Integer] The java class serial version
|
||||||
|
attr_accessor :serial_version
|
||||||
|
# @!attribute flags
|
||||||
|
# @return [Integer] The java class flags
|
||||||
|
attr_accessor :flags
|
||||||
|
# @!attribute fields
|
||||||
|
# @return [Array] The java class fields
|
||||||
|
attr_accessor :fields
|
||||||
|
# @!attribute fields
|
||||||
|
# @return [Rex::Java::Serialization::Model::Annotation] The java class annotations
|
||||||
|
attr_accessor :class_annotation
|
||||||
|
# @!attribute super_class
|
||||||
|
# @return [Rex::Java::Serialization::Model::ClassDesc] The java class superclass description
|
||||||
|
attr_accessor :super_class
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.class_name = nil
|
||||||
|
self.serial_version = 0
|
||||||
|
self.flags = 0
|
||||||
|
self.fields = []
|
||||||
|
self.class_annotation = nil
|
||||||
|
self.super_class = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::ClassDescription
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
self.class_name = Utf.decode(io, stream)
|
||||||
|
self.serial_version = decode_serial_version(io)
|
||||||
|
stream.add_reference(self) unless stream.nil?
|
||||||
|
self.flags = decode_flags(io)
|
||||||
|
fields_length = decode_fields_length(io)
|
||||||
|
fields_length.times do
|
||||||
|
field = Field.decode(io, stream)
|
||||||
|
self.fields << field
|
||||||
|
end
|
||||||
|
|
||||||
|
self.class_annotation = Annotation.decode(io, stream)
|
||||||
|
self.super_class = ClassDesc.decode(io, stream)
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::ClassDescription
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
unless class_name.class == Rex::Java::Serialization::Model::Utf &&
|
||||||
|
class_annotation.class == Rex::Java::Serialization::Model::Annotation &&
|
||||||
|
super_class.class == Rex::Java::Serialization::Model::ClassDesc
|
||||||
|
raise ::RuntimeError, 'Filed to serialize NewClassDesc'
|
||||||
|
end
|
||||||
|
encoded = ''
|
||||||
|
encoded << class_name.encode
|
||||||
|
encoded << [serial_version].pack('Q>')
|
||||||
|
stream.add_reference(self) unless stream.nil?
|
||||||
|
encoded << [flags].pack('C')
|
||||||
|
encoded << [fields.length].pack('n')
|
||||||
|
fields.each do |field|
|
||||||
|
encoded << field.encode
|
||||||
|
end
|
||||||
|
encoded << class_annotation.encode
|
||||||
|
encoded << super_class.encode
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = "#{class_name}, [ "
|
||||||
|
fields_str = []
|
||||||
|
fields.each do |field|
|
||||||
|
fields_str << field.to_s
|
||||||
|
end
|
||||||
|
str << "#{fields_str.join(', ')} ]"
|
||||||
|
|
||||||
|
case super_class.description
|
||||||
|
when NewClassDesc
|
||||||
|
str << ", @super_class: #{super_class.description.class_name.to_s}"
|
||||||
|
when Reference
|
||||||
|
str << ", @super_class: #{super_class.description.to_s}"
|
||||||
|
end
|
||||||
|
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Deserializes a class serial version
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Integer] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_serial_version(io)
|
||||||
|
raw_serial = io.read(8)
|
||||||
|
if raw_serial.nil? || raw_serial.length != 8
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize ClassDescription'
|
||||||
|
end
|
||||||
|
|
||||||
|
raw_serial.unpack('Q>')[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a class flags
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Integer] if deserialization is possible
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_flags(io)
|
||||||
|
raw_flags = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize ClassDescription' if raw_flags.nil?
|
||||||
|
|
||||||
|
raw_flags.unpack('C')[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a class fields length
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Integer] if deserialization is possible
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_fields_length(io)
|
||||||
|
fields_length = io.read(2)
|
||||||
|
if fields_length.nil? || fields_length.length != 2
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize ClassDescription'
|
||||||
|
end
|
||||||
|
|
||||||
|
fields_length.unpack('n')[0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,79 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a NewEnum (Java Enum) representation
|
||||||
|
class NewEnum < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute enum_description
|
||||||
|
# @return [Rex::Java::Serialization::Model::ClassDescription] The description of the enum
|
||||||
|
attr_accessor :enum_description
|
||||||
|
# @!attribute constant_name
|
||||||
|
# @return [Rex::Java::Serialization::Model::Utf] The constant value in the Java Enum
|
||||||
|
attr_accessor :constant_name
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.enum_description = nil
|
||||||
|
self.constant_name = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::NewEnum
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
self.enum_description = ClassDesc.decode(io, stream)
|
||||||
|
stream.add_reference(self) unless stream.nil?
|
||||||
|
self.constant_name = decode_constant_name(io)
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::NewEnum
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
unless enum_description.class == ClassDesc &&
|
||||||
|
constant_name.class == Utf
|
||||||
|
raise ::RuntimeError, 'Failed to serialize EnumDescription'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
encoded << enum_description.encode
|
||||||
|
encoded << encode_content(constant_name)
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
constant_name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Deserializes the NewEnum constant name
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Rex::Java::Serialization::Model::Utf] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succed
|
||||||
|
def decode_constant_name(io)
|
||||||
|
content = decode_content(io, stream)
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize NewEnum' unless content.class == Rex::Java::Serialization::Model::Utf
|
||||||
|
|
||||||
|
content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,223 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a NewObject (Java Object) representation
|
||||||
|
class NewObject < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute class_desc
|
||||||
|
# @return [Rex::Java::Serialization::Model::ClassDesc] The description of the object
|
||||||
|
attr_accessor :class_desc
|
||||||
|
# @!attribute class_data
|
||||||
|
# @return [Array] The data of the object
|
||||||
|
attr_accessor :class_data
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.class_desc = nil
|
||||||
|
self.class_data = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::NewObject
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
self.class_desc = ClassDesc.decode(io, stream)
|
||||||
|
stream.add_reference(self) unless stream.nil?
|
||||||
|
|
||||||
|
if class_desc.description.class == NewClassDesc
|
||||||
|
self.class_data = decode_class_data(io, class_desc.description)
|
||||||
|
elsif class_desc.description.class == Reference
|
||||||
|
ref = class_desc.description.handle - BASE_WIRE_HANDLE
|
||||||
|
self.class_data = decode_class_data(io, stream.references[ref])
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::NewObject
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
unless class_desc.class == ClassDesc
|
||||||
|
raise ::RuntimeError, 'Failed to serialize NewObject'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
encoded << class_desc.encode
|
||||||
|
|
||||||
|
class_data.each do |value|
|
||||||
|
if value.class == Array
|
||||||
|
encoded << encode_value(value)
|
||||||
|
else
|
||||||
|
encoded << encode_content(value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = ''
|
||||||
|
if class_desc.description.class == NewClassDesc
|
||||||
|
str << class_desc.description.class_name.to_s
|
||||||
|
elsif class_desc.description.class == Reference
|
||||||
|
str << (class_desc.description.handle - BASE_WIRE_HANDLE).to_s(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
str << ' => { '
|
||||||
|
data = class_data.collect { |data| data.to_s }
|
||||||
|
str << data.join(', ')
|
||||||
|
str << ' }'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Deserializes the class_data for a class_desc and its super classes
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @param my_class_desc [Rex::Java::Serialization::Model::NewClassDesc] the class description whose data is being extracted
|
||||||
|
# @return [Array] class_data values if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_class_data(io, my_class_desc)
|
||||||
|
values = []
|
||||||
|
|
||||||
|
unless my_class_desc.super_class.description.class == NullReference
|
||||||
|
values += decode_class_data(io, my_class_desc.super_class.description)
|
||||||
|
end
|
||||||
|
|
||||||
|
values += decode_class_fields(io, my_class_desc)
|
||||||
|
|
||||||
|
values
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes the fields data for a class_desc
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @param my_class_desc [Rex::Java::Serialization::Model::NewClassDesc] the class description whose data is being extracted
|
||||||
|
# @return [Array] class_data values if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_class_fields(io, my_class_desc)
|
||||||
|
values = []
|
||||||
|
|
||||||
|
my_class_desc.fields.each do |field|
|
||||||
|
if field.is_primitive?
|
||||||
|
values << decode_value(io, field.type)
|
||||||
|
else
|
||||||
|
content = decode_content(io, stream)
|
||||||
|
values << content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
values
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a class_data value
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @param type [String] the type of the value to deserialize
|
||||||
|
# @return [Array(String, <Fixnum, Float>)] type and value if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization fails
|
||||||
|
def decode_value(io, type)
|
||||||
|
value = []
|
||||||
|
|
||||||
|
case type
|
||||||
|
when 'byte'
|
||||||
|
value_raw = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value' if value_raw.nil?
|
||||||
|
value.push('byte', value_raw.unpack('c')[0])
|
||||||
|
when 'char'
|
||||||
|
value_raw = io.read(2)
|
||||||
|
unless value_raw && value_raw.length == 2
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('char', value_raw.unpack('s>')[0])
|
||||||
|
when 'double'
|
||||||
|
value_raw = io.read(8)
|
||||||
|
unless value_raw && value_raw.length == 8
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('double', value = value_raw.unpack('G')[0])
|
||||||
|
when 'float'
|
||||||
|
value_raw = io.read(4)
|
||||||
|
unless value_raw && value_raw.length == 4
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('float', value_raw.unpack('g')[0])
|
||||||
|
when 'int'
|
||||||
|
value_raw = io.read(4)
|
||||||
|
unless value_raw && value_raw.length == 4
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('int', value_raw.unpack('l>')[0])
|
||||||
|
when 'long'
|
||||||
|
value_raw = io.read(8)
|
||||||
|
unless value_raw && value_raw.length == 8
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('long', value_raw.unpack('q>')[0])
|
||||||
|
when 'short'
|
||||||
|
value_raw = io.read(2)
|
||||||
|
unless value_raw && value_raw.length == 2
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value'
|
||||||
|
end
|
||||||
|
value.push('short', value_raw.unpack('s>')[0])
|
||||||
|
when 'boolean'
|
||||||
|
value_raw = io.read(1)
|
||||||
|
raise ::RuntimeError, 'Failed to deserialize NewArray value' if value_raw.nil?
|
||||||
|
value.push('boolean', value_raw.unpack('c')[0])
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Unsupported NewArray type'
|
||||||
|
end
|
||||||
|
|
||||||
|
value
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes an class_data value
|
||||||
|
#
|
||||||
|
# @param value [Array] the type and value to serialize
|
||||||
|
# @return [String] the serialized value
|
||||||
|
# @raise [RuntimeError] if serialization fails
|
||||||
|
def encode_value(value)
|
||||||
|
res = ''
|
||||||
|
|
||||||
|
case value[0]
|
||||||
|
when 'byte'
|
||||||
|
res = [value[1]].pack('c')
|
||||||
|
when 'char'
|
||||||
|
res = [value[1]].pack('s>')
|
||||||
|
when 'double'
|
||||||
|
res = [value[1]].pack('G')
|
||||||
|
when 'float'
|
||||||
|
res = [value[1]].pack('g')
|
||||||
|
when 'int'
|
||||||
|
res = [value[1]].pack('l>')
|
||||||
|
when 'long'
|
||||||
|
res = [value[1]].pack('q>')
|
||||||
|
when 'short'
|
||||||
|
res = [value[1]].pack('s>')
|
||||||
|
when 'boolean'
|
||||||
|
res = [value[1]].pack('c')
|
||||||
|
else
|
||||||
|
raise ::RuntimeError, 'Unsupported NewArray type'
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
class NullReference < Element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a Java Reference representation.
|
||||||
|
class Reference < Element
|
||||||
|
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [Fixnum] The stream handle being referenced
|
||||||
|
attr_accessor :handle
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(stream)
|
||||||
|
self.handle = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Reference
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
handle_raw = io.read(4)
|
||||||
|
unless handle_raw && handle_raw.length == 4
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Reference'
|
||||||
|
end
|
||||||
|
|
||||||
|
self.handle = handle_raw.unpack('N')[0]
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::Reference
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
if handle < BASE_WIRE_HANDLE
|
||||||
|
raise ::RuntimeError, 'Failed to serialize Reference'
|
||||||
|
end
|
||||||
|
|
||||||
|
encoded = ''
|
||||||
|
encoded << [handle].pack('N')
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
"0x#{handle.to_s(16)}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
class Reset < Element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,123 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a Java Stream representation
|
||||||
|
class Stream < Element
|
||||||
|
|
||||||
|
include Rex::Java::Serialization::Model::Contents
|
||||||
|
|
||||||
|
# @!attribute magic
|
||||||
|
# @return [Fixnum] The stream signature
|
||||||
|
attr_accessor :magic
|
||||||
|
# @!attribute version
|
||||||
|
# @return [Fixnum] The stream version
|
||||||
|
attr_accessor :version
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [Array] The stream contents
|
||||||
|
attr_accessor :contents
|
||||||
|
# @!attribute references
|
||||||
|
# @return [Array] The stream objects to be referenced through handles
|
||||||
|
attr_accessor :references
|
||||||
|
|
||||||
|
def initialize(stream = nil)
|
||||||
|
super(nil)
|
||||||
|
self.magic = STREAM_MAGIC
|
||||||
|
self.version = STREAM_VERSION
|
||||||
|
self.contents = []
|
||||||
|
self.references = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Stream
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
self.magic = decode_magic(io)
|
||||||
|
self.version = decode_version(io)
|
||||||
|
|
||||||
|
until io.eof?
|
||||||
|
content = decode_content(io, self)
|
||||||
|
self.contents << content
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::Stream
|
||||||
|
#
|
||||||
|
# @return [String] if serialization succeeds
|
||||||
|
# @raise [RuntimeError] if serialization doesn't succeed
|
||||||
|
def encode
|
||||||
|
encoded = ''
|
||||||
|
encoded << [magic].pack('n')
|
||||||
|
encoded << [version].pack('n')
|
||||||
|
contents.each do |content|
|
||||||
|
encoded << encode_content(content)
|
||||||
|
end
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds an element to the references array
|
||||||
|
#
|
||||||
|
# @param io [Rex::Java::Serialization::Model::Element] the object to save as reference dst
|
||||||
|
def add_reference(ref)
|
||||||
|
self.references.push(ref)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
str = "@magic: 0x#{magic.to_s(16)}\n"
|
||||||
|
str << "@version: #{version}\n"
|
||||||
|
str << "@contents: [\n"
|
||||||
|
contents.each do |content|
|
||||||
|
str << " #{print_content(content)}\n"
|
||||||
|
end
|
||||||
|
str << "]\n"
|
||||||
|
str << "@references: [\n"
|
||||||
|
references.each do |ref|
|
||||||
|
str << " [#{(references.index(ref) + BASE_WIRE_HANDLE).to_s(16)}] #{print_content(ref)}\n"
|
||||||
|
end
|
||||||
|
str << "]\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Deserializes the magic stream value
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [String] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_magic(io)
|
||||||
|
magic = io.read(2)
|
||||||
|
|
||||||
|
unless magic && magic.length == 2 && magic.unpack('n')[0] == STREAM_MAGIC
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Stream'
|
||||||
|
end
|
||||||
|
|
||||||
|
STREAM_MAGIC
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes the version stream
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [Fixnum] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode_version(io)
|
||||||
|
version = io.read(2)
|
||||||
|
unless version && version.unpack('n')[0] == STREAM_VERSION
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Stream'
|
||||||
|
end
|
||||||
|
|
||||||
|
STREAM_VERSION
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,69 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
|
module Rex
|
||||||
|
module Java
|
||||||
|
module Serialization
|
||||||
|
module Model
|
||||||
|
# This class provides a Utf string representation
|
||||||
|
class Utf < Element
|
||||||
|
|
||||||
|
# @!attribute length
|
||||||
|
# @return [Integer] the length of the string
|
||||||
|
attr_accessor :length
|
||||||
|
# @!attribute contents
|
||||||
|
# @return [String] the contents of the string
|
||||||
|
attr_accessor :contents
|
||||||
|
|
||||||
|
# @param stream [Rex::Java::Serialization::Model::Stream] the stream where it belongs to
|
||||||
|
# @param contents [String] the contents of the utf string
|
||||||
|
def initialize(stream = nil, contents = '')
|
||||||
|
super(stream)
|
||||||
|
self.contents = contents
|
||||||
|
self.length = contents.length
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Rex::Java::Serialization::Model::Utf
|
||||||
|
#
|
||||||
|
# @param io [IO] the io to read from
|
||||||
|
# @return [self] if deserialization succeeds
|
||||||
|
# @raise [RuntimeError] if deserialization doesn't succeed
|
||||||
|
def decode(io)
|
||||||
|
raw_length = io.read(2)
|
||||||
|
if raw_length.nil? || raw_length.length != 2
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Utf'
|
||||||
|
end
|
||||||
|
self.length = raw_length.unpack('n')[0]
|
||||||
|
|
||||||
|
if length == 0
|
||||||
|
self.contents = ''
|
||||||
|
else
|
||||||
|
self.contents = io.read(length)
|
||||||
|
if contents.nil? || contents.length != length
|
||||||
|
raise ::RuntimeError, 'Failed to unserialize Utf'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
# Serializes the Rex::Java::Serialization::Model::Utf
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def encode
|
||||||
|
encoded = [length].pack('n')
|
||||||
|
encoded << contents
|
||||||
|
|
||||||
|
encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a print-friendly string representation
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def to_s
|
||||||
|
contents
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,105 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::Annotation do
|
||||||
|
subject(:annotation) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:empty_contents) { "\x78" }
|
||||||
|
let(:empty_contents_io) { StringIO.new(empty_contents) }
|
||||||
|
let(:contents) { "\x77\x05\x01\x02\x03\x04\x05\x7a\x00\x00\x00\x05\x01\x02\x03\x04\x05\x78" }
|
||||||
|
let(:contents_io) { StringIO.new(contents) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::Annotation" do
|
||||||
|
expect(annotation).to be_a(Rex::Java::Serialization::Model::Annotation)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes contents with empty array" do
|
||||||
|
expect(annotation.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
|
||||||
|
context "when empty contents" do
|
||||||
|
it do
|
||||||
|
annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
expect(annotation.encode).to eq(empty_contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when block data contents" do
|
||||||
|
it do
|
||||||
|
annotation.contents << Rex::Java::Serialization::Model::BlockData.new(nil, "\x01\x02\x03\x04\x05")
|
||||||
|
annotation.contents << Rex::Java::Serialization::Model::BlockDataLong.new(nil, "\x01\x02\x03\x04\x05")
|
||||||
|
annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
expect(annotation.encode).to eq(contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
|
||||||
|
context "when empty contents" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Annotation" do
|
||||||
|
expect(annotation.decode(empty_contents_io)).to be_a(Rex::Java::Serialization::Model::Annotation)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "unserializes one content" do
|
||||||
|
annotation.decode(empty_contents_io)
|
||||||
|
expect(annotation.contents.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "unserializes one EndBlockData content" do
|
||||||
|
annotation.decode(empty_contents_io)
|
||||||
|
expect(annotation.contents[0]).to be_a(Rex::Java::Serialization::Model::EndBlockData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when block data contents" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Annotation" do
|
||||||
|
expect(annotation.decode(contents_io)).to be_a(Rex::Java::Serialization::Model::Annotation)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes contents" do
|
||||||
|
annotation.decode(contents_io)
|
||||||
|
expect(annotation.contents.length).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes block data contents" do
|
||||||
|
annotation.decode(contents_io)
|
||||||
|
expect(annotation.contents[0]).to be_a_kind_of(Rex::Java::Serialization::Model::BlockData)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes block data long contents" do
|
||||||
|
annotation.decode(contents_io)
|
||||||
|
expect(annotation.contents[1]).to be_a_kind_of(Rex::Java::Serialization::Model::BlockDataLong)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes end block data" do
|
||||||
|
annotation.decode(contents_io)
|
||||||
|
expect(annotation.contents[2]).to be_a_kind_of(Rex::Java::Serialization::Model::EndBlockData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints an empty annotation" do
|
||||||
|
annotation.decode(empty_contents_io)
|
||||||
|
expect(annotation.to_s).to eq('[ EndBlockData ]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an annotation with contents" do
|
||||||
|
annotation.decode(contents_io)
|
||||||
|
expect(annotation.to_s).to eq('[ BlockData { [ 0x1, 0x2, 0x3, 0x4, 0x5 ] }, BlockDataLong { [ 0x1, 0x2, 0x3, 0x4, 0x5 ] }, EndBlockData ]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,107 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::BlockDataLong do
|
||||||
|
subject(:block) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_block) { "\x00\x00\x00\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" }
|
||||||
|
let(:sample_block_io) { StringIO.new(sample_block) }
|
||||||
|
let(:empty_block) { "\x00\x00\x00\x00" }
|
||||||
|
let(:empty_block_io) { StringIO.new(empty_block) }
|
||||||
|
let(:incomplete_block) { "\x00\x00\x00\x10\x01\x02\x03\x04\x05" }
|
||||||
|
let(:incomplete_block_io) { StringIO.new(incomplete_block) }
|
||||||
|
let(:empty_io) { StringIO.new('') }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::BlockDataLong" do
|
||||||
|
expect(block).to be_a(Rex::Java::Serialization::Model::BlockDataLong)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes length to 0" do
|
||||||
|
expect(block.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes contents with empty string" do
|
||||||
|
expect(block.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when empty block" do
|
||||||
|
it { expect(block.encode).to eq(empty_block) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when filled block" do
|
||||||
|
it do
|
||||||
|
block.length = 16
|
||||||
|
block.contents = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
|
||||||
|
expect(block.encode).to eq(sample_block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when stream contains empty string" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect { block.decode(empty_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains empty block" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::BlockDataLong" do
|
||||||
|
expect(block.decode(empty_block_io)).to be_a(Rex::Java::Serialization::Model::BlockDataLong)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to empty string" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains incomplete block" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect { block.decode(incomplete_block_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains correct block" do
|
||||||
|
|
||||||
|
it "returns a Rex::Java::Serialization::Model::BlockDataLong" do
|
||||||
|
expect(block.decode(sample_block_io)).to be_a(Rex::Java::Serialization::Model::BlockDataLong)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.length).to eq(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to sample string" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.contents).to eq("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a block with contents" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.to_s).to eq('[ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10 ]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an empty string for an empty block" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.to_s).to eq('[ ]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,106 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::BlockData do
|
||||||
|
subject(:block) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_block) { "\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" }
|
||||||
|
let(:sample_block_io) { StringIO.new(sample_block) }
|
||||||
|
let(:empty_block) { "\x00" }
|
||||||
|
let(:empty_block_io) { StringIO.new(empty_block) }
|
||||||
|
let(:incomplete_block) { "\x10\x01\x02\x03\x04\x05" }
|
||||||
|
let(:incomplete_block_io) { StringIO.new(incomplete_block) }
|
||||||
|
let(:empty_io) { StringIO.new('') }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::BlockData" do
|
||||||
|
expect(block).to be_a(Rex::Java::Serialization::Model::BlockData)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes length to 0" do
|
||||||
|
expect(block.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes contents with empty string" do
|
||||||
|
expect(block.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when empty block" do
|
||||||
|
it { expect(block.encode).to eq(empty_block) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when filled block" do
|
||||||
|
it do
|
||||||
|
block.length = 16
|
||||||
|
block.contents = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
|
||||||
|
expect(block.encode).to eq(sample_block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when stream contains empty string" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect { block.decode(empty_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains empty block" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::BlockData" do
|
||||||
|
expect(block.decode(empty_block_io)).to be_a(Rex::Java::Serialization::Model::BlockData)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to empty string" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains incomplete block" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect { block.decode(incomplete_block_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains correct block" do
|
||||||
|
|
||||||
|
it "returns a Rex::Java::Serialization::Model::BlockData" do
|
||||||
|
expect(block.decode(sample_block_io)).to be_a(Rex::Java::Serialization::Model::BlockData)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.length).to eq(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to sample string" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.contents).to eq("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a block with contents" do
|
||||||
|
block.decode(sample_block_io)
|
||||||
|
expect(block.to_s).to eq('[ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10 ]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an empty string for an empty block" do
|
||||||
|
block.decode(empty_block_io)
|
||||||
|
expect(block.to_s).to eq('[ ]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,81 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::ClassDesc do
|
||||||
|
subject(:class_desc) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample) do
|
||||||
|
"\x72\x00\x0e\x6a\x61\x76\x61\x2e\x6c\x61\x6e" +
|
||||||
|
"\x67\x2e\x42\x79\x74\x65\x9c\x4e\x60\x84\xee\x50\xf5\x1c\x02\x00" +
|
||||||
|
"\x01\x42\x00\x05\x76\x61\x6c\x75\x65\x78\x72\x00\x10\x6a\x61\x76" +
|
||||||
|
"\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95" +
|
||||||
|
"\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x78\x70"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_io) { StringIO.new(sample) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::NewClassDesc" do
|
||||||
|
expect(class_desc).to be_a(Rex::Java::Serialization::Model::ClassDesc)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes description with nil" do
|
||||||
|
expect(class_desc.description).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::ClassDesc" do
|
||||||
|
expect(class_desc.decode(sample_io)).to be_a(Rex::Java::Serialization::Model::ClassDesc)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the description correctly" do
|
||||||
|
class_desc.decode(sample_io)
|
||||||
|
expect(class_desc.description).to be_a(Rex::Java::Serialization::Model::NewClassDesc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
it "serializes a ClassDesc" do
|
||||||
|
super_class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
super_class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Number')
|
||||||
|
super_class_desc_new.serial_version = 0x86ac951d0b94e08b
|
||||||
|
super_class_desc_new.flags = 2
|
||||||
|
super_class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
super_class_desc_new.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
super_class_desc_new.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
super_class_desc = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
super_class_desc.description = super_class_desc_new
|
||||||
|
|
||||||
|
class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Byte')
|
||||||
|
class_desc_new.serial_version = 0x9c4e6084ee50f51c
|
||||||
|
class_desc_new.flags = 2
|
||||||
|
field = Rex::Java::Serialization::Model::Field.new
|
||||||
|
field.type = 'byte'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'value')
|
||||||
|
class_desc_new.fields << field
|
||||||
|
class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
class_desc_new.super_class = super_class_desc
|
||||||
|
|
||||||
|
class_desc.description = class_desc_new
|
||||||
|
|
||||||
|
expect(class_desc.encode.unpack("C*")).to eq(sample.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a sample ClassDesc" do
|
||||||
|
class_desc.decode(sample_io)
|
||||||
|
expect(class_desc.to_s).to be_a(String)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,108 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::Field do
|
||||||
|
subject(:field) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_primitive) { "I\x00\x06number" }
|
||||||
|
let(:sample_primitive_io) { StringIO.new(sample_primitive) }
|
||||||
|
let(:sample_object) { "[\x00\x0atest_arrayt\x00\x0b[LEmployee;" }
|
||||||
|
let(:sample_object_io) { StringIO.new(sample_object) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::Field" do
|
||||||
|
expect(field).to be_a(Rex::Java::Serialization::Model::Field)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes code with empty string" do
|
||||||
|
expect(field.type).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes name with nil" do
|
||||||
|
expect(field.name).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes field_type with nil" do
|
||||||
|
expect(field.field_type).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when empty field" do
|
||||||
|
it { expect { field.encode }.to raise_error(::RuntimeError) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when primitive field" do
|
||||||
|
it do
|
||||||
|
field.type = 'int'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'number')
|
||||||
|
expect(field.encode).to eq(sample_primitive)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when object field" do
|
||||||
|
it do
|
||||||
|
field.type = 'array'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'test_array')
|
||||||
|
field.field_type = Rex::Java::Serialization::Model::Utf.new(nil, '[LEmployee;')
|
||||||
|
expect(field.encode).to eq(sample_object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when stream contains a primitive field" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Field" do
|
||||||
|
expect(field.decode(sample_primitive_io)).to be_a(Rex::Java::Serialization::Model::Field)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes field type" do
|
||||||
|
field.decode(sample_primitive_io)
|
||||||
|
expect(field.type).to eq('int')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes field name as Utf" do
|
||||||
|
field.decode(sample_primitive_io)
|
||||||
|
expect(field.name.contents).to eq('number')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains an object field" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Field" do
|
||||||
|
expect(field.decode(sample_object_io)).to be_a(Rex::Java::Serialization::Model::Field)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes field type" do
|
||||||
|
field.decode(sample_object_io)
|
||||||
|
expect(field.type).to eq('array')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes field name" do
|
||||||
|
field.decode(sample_object_io)
|
||||||
|
expect(field.name.contents).to eq('test_array')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes field_type string" do
|
||||||
|
field.decode(sample_object_io)
|
||||||
|
expect(field.field_type.contents).to eq('[LEmployee;')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints an stream containing a primitive field" do
|
||||||
|
field.decode(sample_primitive_io)
|
||||||
|
expect(field.to_s).to eq('number (int)')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an stream containing an object field" do
|
||||||
|
field.decode(sample_object_io)
|
||||||
|
expect(field.to_s).to eq('test_array ([LEmployee;)')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,107 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::LongUtf do
|
||||||
|
subject(:long_utf) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_utf) { "\x00\x00\x00\x00\x00\x00\x00\x10java.lang.Number" }
|
||||||
|
let(:sample_utf_io) { StringIO.new(sample_utf) }
|
||||||
|
let(:empty_utf) { "\x00\x00\x00\x00\x00\x00\x00\x00" }
|
||||||
|
let(:empty_utf_io) { StringIO.new(empty_utf) }
|
||||||
|
let(:incomplete_utf) { "\x00\x00\x00\x00\x00\x00\x00\x10java.lang.Numb" }
|
||||||
|
let(:incomplete_utf_io) { StringIO.new(incomplete_utf) }
|
||||||
|
let(:empty_io) { StringIO.new('') }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::LongUtf" do
|
||||||
|
expect(long_utf).to be_a(Rex::Java::Serialization::Model::LongUtf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes length to 0" do
|
||||||
|
expect(long_utf.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes contents with empty string" do
|
||||||
|
expect(long_utf.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when empty long_utf" do
|
||||||
|
it { expect(long_utf.encode).to eq(empty_utf) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when filled utf" do
|
||||||
|
it do
|
||||||
|
long_utf.length = 16
|
||||||
|
long_utf.contents = 'java.lang.Number'
|
||||||
|
expect(long_utf.encode).to eq(sample_utf)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when stream contains empty string" do
|
||||||
|
it "raises RuntimeError" do
|
||||||
|
expect { long_utf.decode(empty_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains empty long_utf" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::LongUtf" do
|
||||||
|
expect(long_utf.decode(empty_utf_io)).to be_a(Rex::Java::Serialization::Model::LongUtf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
long_utf.decode(empty_utf_io)
|
||||||
|
expect(long_utf.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to empty string" do
|
||||||
|
long_utf.decode(empty_utf_io)
|
||||||
|
expect(long_utf.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains incomplete long_utf" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect { long_utf.decode(incomplete_utf_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains correct long_utf" do
|
||||||
|
|
||||||
|
it "returns a Rex::Java::Serialization::Model::LongUtf" do
|
||||||
|
expect(long_utf.decode(sample_utf_io)).to be_a(Rex::Java::Serialization::Model::LongUtf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
long_utf.decode(sample_utf_io)
|
||||||
|
expect(long_utf.length).to eq(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to sample string" do
|
||||||
|
long_utf.decode(sample_utf_io)
|
||||||
|
expect(long_utf.contents).to eq('java.lang.Number')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints an stream containing a sample long utf" do
|
||||||
|
long_utf.decode(sample_utf_io)
|
||||||
|
expect(long_utf.to_s).to eq('java.lang.Number')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an stream containing an empty long utf" do
|
||||||
|
long_utf.decode(empty_utf_io)
|
||||||
|
expect(long_utf.to_s).to eq('')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,469 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::NewArray do
|
||||||
|
subject(:new_array) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:boolean_array) do
|
||||||
|
"\x72\x00\x02\x5b\x5a\x57\x8f\x20" +
|
||||||
|
"\x39\x14\xb8\x5d\xe2\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x0a\x01\x00" +
|
||||||
|
"\x01\x01\x01\x01\x01\x01\x01\x00"
|
||||||
|
end
|
||||||
|
let(:boolean_array_io) { StringIO.new(boolean_array) }
|
||||||
|
|
||||||
|
let(:byte_array) do
|
||||||
|
"\x72\x00\x02\x5b\x42\xac\xf3\x17" +
|
||||||
|
"\xf8\x06\x08\x54\xe0\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\xec\x41"
|
||||||
|
end
|
||||||
|
let(:byte_array_io) { StringIO.new(byte_array) }
|
||||||
|
|
||||||
|
let(:char_array) do
|
||||||
|
"\x72\x00\x02\x5b\x43\xb0\x26\x66" +
|
||||||
|
"\xb0\xe2\x5d\x84\xac\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\x00\x61" +
|
||||||
|
"\x00\x62"
|
||||||
|
end
|
||||||
|
let(:char_array_io) { StringIO.new(char_array) }
|
||||||
|
|
||||||
|
let(:short_array) do
|
||||||
|
"\x72\x00\x02\x5b\x53\xef\x83\x2e" +
|
||||||
|
"\x06\xe5\x5d\xb0\xfa\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\xff\xec" +
|
||||||
|
"\x00\x41"
|
||||||
|
end
|
||||||
|
let(:short_array_io) { StringIO.new(short_array) }
|
||||||
|
|
||||||
|
let(:double_array) do
|
||||||
|
"\x72\x00\x02\x5b\x44\x3e\xa6\x8c" +
|
||||||
|
"\x14\xab\x63\x5a\x1e\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\x3f\xd0" +
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x3f\xca" +
|
||||||
|
"\xe1\x47\xae\x14\x7a\xe1"
|
||||||
|
end
|
||||||
|
let(:double_array_io) { StringIO.new(double_array) }
|
||||||
|
|
||||||
|
let(:float_array) do
|
||||||
|
"\x72\x00\x02\x5b\x46\x0b\x9c\x81" +
|
||||||
|
"\x89\x22\xe0\x0c\x42\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\x3f\x80" +
|
||||||
|
"\x00\x00\x40\x00\x00\x00"
|
||||||
|
end
|
||||||
|
let(:float_array_io) { StringIO.new(float_array) }
|
||||||
|
|
||||||
|
let(:int_array) do
|
||||||
|
"\x72\x00\x02\x5b\x49\x4d\xba\x60" +
|
||||||
|
"\x26\x76\xea\xb2\xa5\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\xff\xff" +
|
||||||
|
"\xff\xec\x00\x00\x00\x41"
|
||||||
|
end
|
||||||
|
let(:int_array_io) { StringIO.new(int_array) }
|
||||||
|
|
||||||
|
let(:long_array) do
|
||||||
|
"\x72\x00\x02\x5b\x4a\x78\x20\x04" +
|
||||||
|
"\xb5\x12\xb1\x75\x93\x02\x00\x00" +
|
||||||
|
"\x78\x70\x00\x00\x00\x02\xff\xff" +
|
||||||
|
"\xff\xff\xff\xff\xff\xec\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00\x00\x41"
|
||||||
|
end
|
||||||
|
let(:long_array_io) { StringIO.new(long_array) }
|
||||||
|
|
||||||
|
let(:string_array) do
|
||||||
|
"\x72\x00\x13\x5b\x4c\x6a\x61\x76" +
|
||||||
|
"\x61\x2e\x6c\x61\x6e\x67\x2e\x53" +
|
||||||
|
"\x74\x72\x69\x6e\x67\x3b\xad\xd2" +
|
||||||
|
"\x56\xe7\xe9\x1d\x7b\x47\x02\x00" +
|
||||||
|
"\x00\x78\x70\x00\x00\x00\x01\x74" +
|
||||||
|
"\x00\x03\x6d\x73\x66"
|
||||||
|
end
|
||||||
|
let(:string_array_io) { StringIO.new(string_array) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::NewArray" do
|
||||||
|
expect(new_array).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes array_description with nil" do
|
||||||
|
expect(new_array.array_description).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes type with an empty String" do
|
||||||
|
expect(new_array.type).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes values with an empty Array" do
|
||||||
|
expect(new_array.values).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
|
||||||
|
context "when boolean Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(boolean_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(boolean_array_io)
|
||||||
|
expect(new_array.type).to eq('boolean')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(boolean_array_io)
|
||||||
|
expect(new_array.values).to eq([1, 0, 1, 1, 1, 1, 1, 1, 1, 0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when byte Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(byte_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(byte_array_io)
|
||||||
|
expect(new_array.type).to eq('byte')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(byte_array_io)
|
||||||
|
expect(new_array.values).to eq([-20, 65])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when char Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(char_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(char_array_io)
|
||||||
|
expect(new_array.type).to eq('char')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(char_array_io)
|
||||||
|
expect(new_array.values).to eq([97, 98])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when short Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(short_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(short_array_io)
|
||||||
|
expect(new_array.type).to eq('short')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(short_array_io)
|
||||||
|
expect(new_array.values).to eq([-20, 65])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when double Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(double_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(double_array_io)
|
||||||
|
expect(new_array.type).to eq('double')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(double_array_io)
|
||||||
|
expect(new_array.values).to eq([0.25, 0.21])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when float Array" do
|
||||||
|
it "deserializes a float Array" do
|
||||||
|
expect(new_array.decode(float_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(float_array_io)
|
||||||
|
expect(new_array.type).to eq('float')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(float_array_io)
|
||||||
|
expect(new_array.values).to eq([1.0, 2.0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when int Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(int_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(int_array_io)
|
||||||
|
expect(new_array.type).to eq('int')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(int_array_io)
|
||||||
|
expect(new_array.values).to eq([-20, 65])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when long Array" do
|
||||||
|
it "deserializes Array" do
|
||||||
|
expect(new_array.decode(long_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(long_array_io)
|
||||||
|
expect(new_array.type).to eq('long')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes values correctly" do
|
||||||
|
new_array.decode(long_array_io)
|
||||||
|
expect(new_array.values).to eq([-20, 65])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when Strings (Objects) array" do
|
||||||
|
it "deserializes the array" do
|
||||||
|
expect(new_array.decode(string_array_io)).to be_a(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes type correctly" do
|
||||||
|
new_array.decode(string_array_io)
|
||||||
|
expect(new_array.type).to eq('java.lang.String;')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes number of members correctly" do
|
||||||
|
new_array.decode(string_array_io)
|
||||||
|
expect(new_array.values.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the members correctly" do
|
||||||
|
new_array.decode(string_array_io)
|
||||||
|
expect(new_array.values[0].contents).to eq('msf')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
it "serializes a boolean Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Z')
|
||||||
|
new_class_desc.serial_version = 0x578f203914b85de2
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'boolean'
|
||||||
|
new_array.values = [1, 0, 1, 1, 1, 1, 1, 1, 1, 0]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(boolean_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a byte Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[B')
|
||||||
|
new_class_desc.serial_version = 0xacf317f8060854e0
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'byte'
|
||||||
|
new_array.values = [-20, 65]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(byte_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a char Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[C')
|
||||||
|
new_class_desc.serial_version = 0xb02666b0e25d84ac
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'char'
|
||||||
|
new_array.values = [97, 98]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(char_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a short Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[S')
|
||||||
|
new_class_desc.serial_version = 0xef832e06e55db0fa
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'short'
|
||||||
|
new_array.values = [-20, 65]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(short_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a double Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[D')
|
||||||
|
new_class_desc.serial_version = 0x3ea68c14ab635a1e
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'double'
|
||||||
|
new_array.values = [0.25, 0.21]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(double_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a float Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[F')
|
||||||
|
new_class_desc.serial_version = 0xb9c818922e00c42
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'float'
|
||||||
|
new_array.values = [1.0, 2.0]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(float_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a int Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[I')
|
||||||
|
new_class_desc.serial_version = 0x4dba602676eab2a5
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'int'
|
||||||
|
new_array.values = [-20, 65]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(int_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a long Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[J')
|
||||||
|
new_class_desc.serial_version = 0x782004b512b17593
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'long'
|
||||||
|
new_array.values = [-20, 65]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(long_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "serializes a String (Objects) Array" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[Ljava.lang.String;')
|
||||||
|
new_class_desc.serial_version = 0xadd256e7e91d7b47
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'java.lang.String;'
|
||||||
|
new_array.values = [ Rex::Java::Serialization::Model::Utf.new(nil, 'msf') ]
|
||||||
|
|
||||||
|
expect(new_array.encode.unpack("C*")).to eq(string_array.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a boolean array stream" do
|
||||||
|
new_array.decode(boolean_array_io)
|
||||||
|
expect(new_array.to_s).to eq('boolean, ["1", "0", "1", "1", "1", "1", "1", "1", "1", "0"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a byte array stream" do
|
||||||
|
new_array.decode(byte_array_io)
|
||||||
|
expect(new_array.to_s).to eq('byte, ["-20", "65"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a char array stream" do
|
||||||
|
new_array.decode(char_array_io)
|
||||||
|
expect(new_array.to_s).to eq('char, ["97", "98"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a short array stream" do
|
||||||
|
new_array.decode(short_array_io)
|
||||||
|
expect(new_array.to_s).to eq('short, ["-20", "65"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a double array stream" do
|
||||||
|
new_array.decode(double_array_io)
|
||||||
|
expect(new_array.to_s).to eq('double, ["0.25", "0.21"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a float array stream" do
|
||||||
|
new_array.decode(float_array_io)
|
||||||
|
expect(new_array.to_s).to eq('float, ["1.0", "2.0"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a int array stream" do
|
||||||
|
new_array.decode(int_array_io)
|
||||||
|
expect(new_array.to_s).to eq('int, ["-20", "65"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a long array stream" do
|
||||||
|
new_array.decode(long_array_io)
|
||||||
|
expect(new_array.to_s).to eq('long, ["-20", "65"]')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a string array stream" do
|
||||||
|
new_array.decode(string_array_io)
|
||||||
|
expect(new_array.to_s).to eq('java.lang.String;, ["msf"]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,143 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::NewClassDesc do
|
||||||
|
subject(:class_desc_new) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample) do
|
||||||
|
"\x00\x0e\x6a\x61\x76\x61\x2e\x6c\x61\x6e" +
|
||||||
|
"\x67\x2e\x42\x79\x74\x65\x9c\x4e\x60\x84\xee\x50\xf5\x1c\x02\x00" +
|
||||||
|
"\x01\x42\x00\x05\x76\x61\x6c\x75\x65\x78\x72\x00\x10\x6a\x61\x76" +
|
||||||
|
"\x61\x2e\x6c\x61\x6e\x67\x2e\x4e\x75\x6d\x62\x65\x72\x86\xac\x95" +
|
||||||
|
"\x1d\x0b\x94\xe0\x8b\x02\x00\x00\x78\x70"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_io) { StringIO.new(sample) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::NewClassDesc" do
|
||||||
|
expect(class_desc_new).to be_a(Rex::Java::Serialization::Model::NewClassDesc)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes class_name with nil" do
|
||||||
|
expect(class_desc_new.class_name).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes serial_version with 0" do
|
||||||
|
expect(class_desc_new.serial_version).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes flags with 0" do
|
||||||
|
expect(class_desc_new.flags).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes fields with empty Array" do
|
||||||
|
expect(class_desc_new.fields).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes class_annotation with nil" do
|
||||||
|
expect(class_desc_new.class_annotation).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes super_class with nil" do
|
||||||
|
expect(class_desc_new.super_class).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::NewClassDesc" do
|
||||||
|
expect(class_desc_new.decode(sample_io)).to be_a(Rex::Java::Serialization::Model::NewClassDesc)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes class_name as Utf" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.class_name).to be_a(Rex::Java::Serialization::Model::Utf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes class_name contents correctly" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.class_name.contents).to eq('java.lang.Byte')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes serial_version correctly" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.serial_version).to eq(0x9c4e6084ee50f51c)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes flags correctly" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.flags).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes fields" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.fields.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes fields contents correctly" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.fields[0].type).to eq('byte')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes class annotation correctly" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.class_annotation).to be_a(Rex::Java::Serialization::Model::Annotation)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes class annotation contents" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.class_annotation.contents[0]).to be_a(Rex::Java::Serialization::Model::EndBlockData)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes super_class" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.super_class).to be_a(Rex::Java::Serialization::Model::ClassDesc)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes super class description" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.super_class.description).to be_a(Rex::Java::Serialization::Model::NewClassDesc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
it "serializes a NewClassDesc" do
|
||||||
|
super_class_desc_new = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
super_class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Number')
|
||||||
|
super_class_desc_new.serial_version = 0x86ac951d0b94e08b
|
||||||
|
super_class_desc_new.flags = 2
|
||||||
|
super_class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
super_class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
super_class_desc_new.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
super_class_desc_new.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
super_class_desc = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
super_class_desc.description = super_class_desc_new
|
||||||
|
|
||||||
|
class_desc_new.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Byte')
|
||||||
|
class_desc_new.serial_version = 0x9c4e6084ee50f51c
|
||||||
|
class_desc_new.flags = 2
|
||||||
|
field = Rex::Java::Serialization::Model::Field.new
|
||||||
|
field.type = 'byte'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'value')
|
||||||
|
class_desc_new.fields << field
|
||||||
|
class_desc_new.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
class_desc_new.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
class_desc_new.super_class = super_class_desc
|
||||||
|
|
||||||
|
expect(class_desc_new.encode.unpack("C*")).to eq(sample.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a sample NewClassDesc stream" do
|
||||||
|
class_desc_new.decode(sample_io)
|
||||||
|
expect(class_desc_new.to_s).to eq('java.lang.Byte, [ value (byte) ], @super_class: java.lang.Number')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,83 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::NewEnum do
|
||||||
|
|
||||||
|
subject(:new_enum) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_enum) do
|
||||||
|
"\x72\x00\x09\x45\x6e\x75\x6d\x73" +
|
||||||
|
"\x24\x44\x61\x79\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00\x12\x00\x00\x78" +
|
||||||
|
"\x72\x00\x0e\x6a\x61\x76\x61\x2e" +
|
||||||
|
"\x6c\x61\x6e\x67\x2e\x45\x6e\x75" +
|
||||||
|
"\x6d\x00\x00\x00\x00\x00\x00\x00" +
|
||||||
|
"\x00\x12\x00\x00\x78\x70\x74\x00" +
|
||||||
|
"\x06\x53\x55\x4e\x44\x41\x59"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_enum_io) { StringIO.new(sample_enum) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::NewEnum" do
|
||||||
|
expect(new_enum).to be_a(Rex::Java::Serialization::Model::NewEnum)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes enum_description with nil" do
|
||||||
|
expect(new_enum.enum_description).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes constant_name with nil" do
|
||||||
|
expect(new_enum.constant_name).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
it "deserializes an Enum" do
|
||||||
|
expect(new_enum.decode(sample_enum_io)).to be_a(Rex::Java::Serialization::Model::NewEnum)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the constant_name correctly" do
|
||||||
|
new_enum.decode(sample_enum_io)
|
||||||
|
expect(new_enum.constant_name.contents).to eq('SUNDAY')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
it "serializes an Enum" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Enums$Day')
|
||||||
|
new_class_desc.serial_version = 0
|
||||||
|
new_class_desc.flags = 18
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.super_class.description.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'java.lang.Enum')
|
||||||
|
new_class_desc.super_class.description.serial_version = 0
|
||||||
|
new_class_desc.super_class.description.flags = 18
|
||||||
|
new_class_desc.super_class.description.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.super_class.description.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class.description.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_enum.enum_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_enum.enum_description.description = new_class_desc
|
||||||
|
new_enum.constant_name = Rex::Java::Serialization::Model::Utf.new(nil, 'SUNDAY')
|
||||||
|
|
||||||
|
expect(new_enum.encode.unpack("C*")).to eq(sample_enum.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a sample NewEnum stream" do
|
||||||
|
new_enum.decode(sample_enum_io)
|
||||||
|
expect(new_enum.to_s).to eq('SUNDAY')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,82 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::NewObject do
|
||||||
|
|
||||||
|
subject(:new_object) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:easy_object) do
|
||||||
|
"\x72\x00\x04\x45\x61\x73\x79\x74" +
|
||||||
|
"\x1d\xe1\xbc\xbb\x2f\xcb\xaa\x02" +
|
||||||
|
"\x00\x01\x49\x00\x03\x53\x53\x4e" +
|
||||||
|
"\x78\x70\x41\x42\x43\x44"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:easy_object_io) { StringIO.new(easy_object) }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::NewObject" do
|
||||||
|
expect(new_object).to be_a(Rex::Java::Serialization::Model::NewObject)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes class_desc with nil" do
|
||||||
|
expect(new_object.class_desc).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes class_data with empty array" do
|
||||||
|
expect(new_object.class_data).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
it "deserializes an object" do
|
||||||
|
expect(new_object.decode(easy_object_io)).to be_a(Rex::Java::Serialization::Model::NewObject)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the object class fields correctly" do
|
||||||
|
new_object.decode(easy_object_io)
|
||||||
|
expect(new_object.class_desc.description.fields.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the object class data correctly" do
|
||||||
|
new_object.decode(easy_object_io)
|
||||||
|
expect(new_object.class_data).to eq([['int', 0x41424344]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
it "serializes an Object" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Easy')
|
||||||
|
new_class_desc.serial_version = 0x741de1bcbb2fcbaa
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
field = Rex::Java::Serialization::Model::Field.new
|
||||||
|
field.type = 'int'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'SSN')
|
||||||
|
new_class_desc.fields << field
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_object.class_desc.description = new_class_desc
|
||||||
|
new_object.class_data = [['int', 0x41424344]]
|
||||||
|
|
||||||
|
expect(new_object.encode.unpack("C*")).to eq(easy_object.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a sample Object stream" do
|
||||||
|
new_object.decode(easy_object_io)
|
||||||
|
expect(new_object.to_s).to eq('Easy => { ["int", 1094861636] }')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,264 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::Stream do
|
||||||
|
|
||||||
|
subject(:stream) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:easy_object_stream) do
|
||||||
|
"\xac\xed\x00\x05\x73\x72\x00\x04" +
|
||||||
|
"\x45\x61\x73\x79\x74\x1d\xe1\xbc" +
|
||||||
|
"\xbb\x2f\xcb\xaa\x02\x00\x01\x49" +
|
||||||
|
"\x00\x03\x53\x53\x4e\x78\x70\x41" +
|
||||||
|
"\x42\x43\x44"
|
||||||
|
end
|
||||||
|
let(:easy_object_stream_io) { StringIO.new(easy_object_stream) }
|
||||||
|
let(:easy_object_stream_to_s) {
|
||||||
|
<<-EOS
|
||||||
|
@magic: 0xaced
|
||||||
|
@version: 5
|
||||||
|
@contents: [
|
||||||
|
NewObject { Easy => { ["int", 1094861636] } }
|
||||||
|
]
|
||||||
|
@references: [
|
||||||
|
[7e0000] NewClassDesc { Easy, [ SSN (int) ] }
|
||||||
|
[7e0001] NewObject { Easy => { ["int", 1094861636] } }
|
||||||
|
]
|
||||||
|
EOS
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:char_array_stream) do
|
||||||
|
"\xac\xed\x00\x05\x75\x72\x00\x02" +
|
||||||
|
"\x5b\x43\xb0\x26\x66\xb0\xe2\x5d" +
|
||||||
|
"\x84\xac\x02\x00\x00\x78\x70\x00" +
|
||||||
|
"\x00\x00\x02\x00\x61\x00\x62"
|
||||||
|
end
|
||||||
|
let(:char_array_stream_io) { StringIO.new(char_array_stream) }
|
||||||
|
let(:char_array_stream_to_s) {
|
||||||
|
<<-EOS
|
||||||
|
@magic: 0xaced
|
||||||
|
@version: 5
|
||||||
|
@contents: [
|
||||||
|
NewArray { char, ["97", "98"] }
|
||||||
|
]
|
||||||
|
@references: [
|
||||||
|
[7e0000] NewClassDesc { [C, [ ] }
|
||||||
|
[7e0001] NewArray { char, ["97", "98"] }
|
||||||
|
]
|
||||||
|
EOS
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:complex_stream) do
|
||||||
|
"\xac\xed\x00\x05\x77\x22\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00" +
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" +
|
||||||
|
"\xf6\xb6\x89\x8d\x8b\xf2\x86\x43\x75\x72\x00\x18\x5b\x4c\x6a\x61" +
|
||||||
|
"\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f\x62" +
|
||||||
|
"\x6a\x49\x44\x3b\x87\x13\x00\xb8\xd0\x2c\x64\x7e\x02\x00\x00\x70" +
|
||||||
|
"\x78\x70\x00\x00\x00\x01\x73\x72\x00\x15\x6a\x61\x76\x61\x2e\x72" +
|
||||||
|
"\x6d\x69\x2e\x73\x65\x72\x76\x65\x72\x2e\x4f\x62\x6a\x49\x44\xa7" +
|
||||||
|
"\x5e\xfa\x12\x8d\xdc\xe5\x5c\x02\x00\x02\x4a\x00\x06\x6f\x62\x6a" +
|
||||||
|
"\x4e\x75\x6d\x4c\x00\x05\x73\x70\x61\x63\x65\x74\x00\x15\x4c\x6a" +
|
||||||
|
"\x61\x76\x61\x2f\x72\x6d\x69\x2f\x73\x65\x72\x76\x65\x72\x2f\x55" +
|
||||||
|
"\x49\x44\x3b\x70\x78\x70\x0d\xc1\x1e\x2a\x94\x5e\x2f\xb2\x73\x72" +
|
||||||
|
"\x00\x13\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e\x73\x65\x72\x76\x65" +
|
||||||
|
"\x72\x2e\x55\x49\x44\x0f\x12\x70\x0d\xbf\x36\x4f\x12\x02\x00\x03" +
|
||||||
|
"\x53\x00\x05\x63\x6f\x75\x6e\x74\x4a\x00\x04\x74\x69\x6d\x65\x49" +
|
||||||
|
"\x00\x06\x75\x6e\x69\x71\x75\x65\x70\x78\x70\x80\x16\x00\x00\x01" +
|
||||||
|
"\x49\xb5\xe4\x92\x78\xd2\x4f\xdf\x47\x77\x08\x80\x00\x00\x00\x00" +
|
||||||
|
"\x00\x00\x01\x73\x72\x00\x12\x6a\x61\x76\x61\x2e\x72\x6d\x69\x2e" +
|
||||||
|
"\x64\x67\x63\x2e\x4c\x65\x61\x73\x65\xb0\xb5\xe2\x66\x0c\x4a\xdc" +
|
||||||
|
"\x34\x02\x00\x02\x4a\x00\x05\x76\x61\x6c\x75\x65\x4c\x00\x04\x76" +
|
||||||
|
"\x6d\x69\x64\x74\x00\x13\x4c\x6a\x61\x76\x61\x2f\x72\x6d\x69\x2f" +
|
||||||
|
"\x64\x67\x63\x2f\x56\x4d\x49\x44\x3b\x70\x78\x70\x00\x00\x00\x00" +
|
||||||
|
"\x00\x09\x27\xc0\x73\x72\x00\x11\x6a\x61\x76\x61\x2e\x72\x6d\x69" +
|
||||||
|
"\x2e\x64\x67\x63\x2e\x56\x4d\x49\x44\xf8\x86\x5b\xaf\xa4\xa5\x6d" +
|
||||||
|
"\xb6\x02\x00\x02\x5b\x00\x04\x61\x64\x64\x72\x74\x00\x02\x5b\x42" +
|
||||||
|
"\x4c\x00\x03\x75\x69\x64\x71\x00\x7e\x00\x03\x70\x78\x70\x75\x72" +
|
||||||
|
"\x00\x02\x5b\x42\xac\xf3\x17\xf8\x06\x08\x54\xe0\x02\x00\x00\x70" +
|
||||||
|
"\x78\x70\x00\x00\x00\x08\x6b\x02\xc7\x72\x60\x1c\xc7\x95\x73\x71" +
|
||||||
|
"\x00\x7e\x00\x05\x80\x01\x00\x00\x01\x49\xb5\xf8\x00\xea\xe9\x62" +
|
||||||
|
"\xc1\xc0"
|
||||||
|
end
|
||||||
|
let(:complex_stream_io) { StringIO.new(complex_stream) }
|
||||||
|
let(:complex_stream_to_s) {
|
||||||
|
<<-EOS
|
||||||
|
@magic: 0xaced
|
||||||
|
@version: 5
|
||||||
|
@contents: [
|
||||||
|
BlockData { [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf6, 0xb6, 0x89, 0x8d, 0x8b, 0xf2, 0x86, 0x43 ] }
|
||||||
|
NewArray { java.rmi.server.ObjID;, ["java.rmi.server.ObjID => { [\\"long\\", 991106561224880050], java.rmi.server.UID => { [\\"short\\", -32746], [\\"long\\", 1416095896184], [\\"int\\", -766517433] } }"] }
|
||||||
|
BlockData { [ 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 ] }
|
||||||
|
NewObject { java.rmi.dgc.Lease => { ["long", 600000], java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } } }
|
||||||
|
]
|
||||||
|
@references: [
|
||||||
|
[7e0000] NewClassDesc { [Ljava.rmi.server.ObjID;, [ ] }
|
||||||
|
[7e0001] NewArray { java.rmi.server.ObjID;, ["java.rmi.server.ObjID => { [\\"long\\", 991106561224880050], java.rmi.server.UID => { [\\"short\\", -32746], [\\"long\\", 1416095896184], [\\"int\\", -766517433] } }"] }
|
||||||
|
[7e0002] NewClassDesc { java.rmi.server.ObjID, [ objNum (long), space (Ljava/rmi/server/UID;) ] }
|
||||||
|
[7e0003] Utf { Ljava/rmi/server/UID; }
|
||||||
|
[7e0004] NewObject { java.rmi.server.ObjID => { ["long", 991106561224880050], java.rmi.server.UID => { ["short", -32746], ["long", 1416095896184], ["int", -766517433] } } }
|
||||||
|
[7e0005] NewClassDesc { java.rmi.server.UID, [ count (short), time (long), unique (int) ] }
|
||||||
|
[7e0006] NewObject { java.rmi.server.UID => { ["short", -32746], ["long", 1416095896184], ["int", -766517433] } }
|
||||||
|
[7e0007] NewClassDesc { java.rmi.dgc.Lease, [ value (long), vmid (Ljava/rmi/dgc/VMID;) ] }
|
||||||
|
[7e0008] Utf { Ljava/rmi/dgc/VMID; }
|
||||||
|
[7e0009] NewObject { java.rmi.dgc.Lease => { ["long", 600000], java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } } }
|
||||||
|
[7e000a] NewClassDesc { java.rmi.dgc.VMID, [ addr ([B), uid (0x7e0003) ] }
|
||||||
|
[7e000b] Utf { [B }
|
||||||
|
[7e000c] NewObject { java.rmi.dgc.VMID => { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"], 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } } }
|
||||||
|
[7e000d] NewClassDesc { [B, [ ] }
|
||||||
|
[7e000e] NewArray { byte, ["107", "2", "-57", "114", "96", "28", "-57", "-107"] }
|
||||||
|
[7e000f] NewObject { 5 => { ["short", -32767], ["long", 1416097169642], ["int", -379403840] } }
|
||||||
|
]
|
||||||
|
EOS
|
||||||
|
}
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::Stream" do
|
||||||
|
expect(stream).to be_a(Rex::Java::Serialization::Model::Stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes magic with java serialized stream signature" do
|
||||||
|
expect(stream.magic).to eq(Rex::Java::Serialization::STREAM_MAGIC)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes version with java serialized stream default version " do
|
||||||
|
expect(stream.version).to eq(Rex::Java::Serialization::STREAM_VERSION)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes references as empty array " do
|
||||||
|
expect(stream.references).to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes stream to nil by default" do
|
||||||
|
expect(stream.stream).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when deserializing a simple Object stream" do
|
||||||
|
it "deserializes an Stream" do
|
||||||
|
expect(stream.decode(easy_object_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the signature correctly" do
|
||||||
|
stream.decode(easy_object_stream_io)
|
||||||
|
expect(stream.magic).to eq(Rex::Java::Serialization::STREAM_MAGIC)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes all the contents" do
|
||||||
|
stream.decode(easy_object_stream_io)
|
||||||
|
expect(stream.contents.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes a simple object correctly" do
|
||||||
|
stream.decode(easy_object_stream_io)
|
||||||
|
expect(stream.contents[0]).to be_an(Rex::Java::Serialization::Model::NewObject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when deserializing a char array" do
|
||||||
|
it "deserializes an Stream" do
|
||||||
|
expect(stream.decode(char_array_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes the char array correctly" do
|
||||||
|
stream.decode(char_array_stream_io)
|
||||||
|
expect(stream.contents[0]).to be_an(Rex::Java::Serialization::Model::NewArray)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when deserializing a complex stream with references" do
|
||||||
|
it "deserializes an Stream" do
|
||||||
|
expect(stream.decode(complex_stream_io)).to be_a(Rex::Java::Serialization::Model::Stream)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes all the contents in the Stream" do
|
||||||
|
stream.decode(complex_stream_io)
|
||||||
|
expect(stream.contents.length).to eq(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deserializes object contents" do
|
||||||
|
stream.decode(complex_stream_io)
|
||||||
|
expect(stream.contents[3]).to be_a(Rex::Java::Serialization::Model::NewObject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints a simple Object stream" do
|
||||||
|
stream.decode(easy_object_stream_io)
|
||||||
|
expect(stream.to_s).to eq(easy_object_stream_to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a char array stream" do
|
||||||
|
stream.decode(char_array_stream_io)
|
||||||
|
expect(stream.to_s).to eq(char_array_stream_to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints a complex stream with references" do
|
||||||
|
stream.decode(complex_stream_io)
|
||||||
|
expect(stream.to_s).to eq(complex_stream_to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when serializing a simple Object stream" do
|
||||||
|
it "serializes the Stream" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, 'Easy')
|
||||||
|
new_class_desc.serial_version = 0x741de1bcbb2fcbaa
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
field = Rex::Java::Serialization::Model::Field.new
|
||||||
|
field.type = 'int'
|
||||||
|
field.name = Rex::Java::Serialization::Model::Utf.new(nil, 'SSN')
|
||||||
|
new_class_desc.fields << field
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_object = Rex::Java::Serialization::Model::NewObject.new
|
||||||
|
new_object.class_desc = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_object.class_desc.description = new_class_desc
|
||||||
|
new_object.class_data = [['int', 0x41424344]]
|
||||||
|
|
||||||
|
stream.contents << new_object
|
||||||
|
expect(stream.encode.unpack("C*")).to eq(easy_object_stream.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when serializing a char array" do
|
||||||
|
it "serializes the Stream" do
|
||||||
|
new_class_desc = Rex::Java::Serialization::Model::NewClassDesc.new
|
||||||
|
new_class_desc.class_name = Rex::Java::Serialization::Model::Utf.new(nil, '[C')
|
||||||
|
new_class_desc.serial_version = 0xb02666b0e25d84ac
|
||||||
|
new_class_desc.flags = 2
|
||||||
|
new_class_desc.class_annotation = Rex::Java::Serialization::Model::Annotation.new
|
||||||
|
new_class_desc.class_annotation.contents << Rex::Java::Serialization::Model::EndBlockData.new
|
||||||
|
new_class_desc.super_class = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_class_desc.super_class.description = Rex::Java::Serialization::Model::NullReference.new
|
||||||
|
|
||||||
|
new_array = Rex::Java::Serialization::Model::NewArray.new
|
||||||
|
new_array.array_description = Rex::Java::Serialization::Model::ClassDesc.new
|
||||||
|
new_array.array_description.description = new_class_desc
|
||||||
|
new_array.type = 'char'
|
||||||
|
new_array.values = [97, 98]
|
||||||
|
|
||||||
|
stream.contents << new_array
|
||||||
|
expect(stream.encode.unpack("C*")).to eq(char_array_stream.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when reserializing a complex stream" do
|
||||||
|
it "reserializes the original stream" do
|
||||||
|
stream.decode(complex_stream_io)
|
||||||
|
expect(stream.encode.unpack("C*")).to eq(complex_stream.unpack("C*"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,107 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
describe Rex::Java::Serialization::Model::Utf do
|
||||||
|
subject(:utf) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:sample_utf) { "\x00\x10java.lang.Number" }
|
||||||
|
let(:sample_utf_io) { StringIO.new(sample_utf) }
|
||||||
|
let(:empty_utf) { "\x00\x00" }
|
||||||
|
let(:empty_utf_io) { StringIO.new(empty_utf) }
|
||||||
|
let(:incomplete_utf) { "\x00\x10java.lang.Numb" }
|
||||||
|
let(:incomplete_utf_io) { StringIO.new(incomplete_utf) }
|
||||||
|
let(:empty_io) { StringIO.new('') }
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "Rex::Java::Serialization::Model::Utf" do
|
||||||
|
expect(utf).to be_a(Rex::Java::Serialization::Model::Utf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes length to 0" do
|
||||||
|
expect(utf.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes contents with empty string" do
|
||||||
|
expect(utf.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#encode" do
|
||||||
|
context "when empty utf" do
|
||||||
|
it { expect(utf.encode).to eq(empty_utf) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when filled utf" do
|
||||||
|
it do
|
||||||
|
utf.length = 16
|
||||||
|
utf.contents = 'java.lang.Number'
|
||||||
|
expect(utf.encode).to eq(sample_utf)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#decode" do
|
||||||
|
context "when stream contains empty string" do
|
||||||
|
it "raises RuntimeError" do
|
||||||
|
expect { utf.decode(empty_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains empty utf" do
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Utf" do
|
||||||
|
expect(utf.decode(empty_utf_io)).to be_a(Rex::Java::Serialization::Model::Utf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
utf.decode(empty_utf_io)
|
||||||
|
expect(utf.length).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to empty string" do
|
||||||
|
utf.decode(empty_utf_io)
|
||||||
|
expect(utf.contents).to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains incomplete utf" do
|
||||||
|
it "raises RuntimeError" do
|
||||||
|
expect { utf.decode(incomplete_utf_io) }.to raise_error(::RuntimeError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when stream contains correct utf" do
|
||||||
|
|
||||||
|
it "returns a Rex::Java::Serialization::Model::Utf" do
|
||||||
|
expect(utf.decode(sample_utf_io)).to be_a(Rex::Java::Serialization::Model::Utf)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets length to 0" do
|
||||||
|
utf.decode(sample_utf_io)
|
||||||
|
expect(utf.length).to eq(16)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets contents to sample string" do
|
||||||
|
utf.decode(sample_utf_io)
|
||||||
|
expect(utf.contents).to eq('java.lang.Number')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#to_s" do
|
||||||
|
it "prints an stream containing a sample utf" do
|
||||||
|
utf.decode(sample_utf_io)
|
||||||
|
expect(utf.to_s).to eq('java.lang.Number')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "prints an stream containing an empty utf" do
|
||||||
|
utf.decode(empty_utf_io)
|
||||||
|
expect(utf.to_s).to eq('')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
require 'rex/java'
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
|
load Metasploit::Framework.root.join('tools/java_deserializer.rb').to_path
|
||||||
|
|
||||||
|
describe JavaDeserializer do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
@out = $stdout
|
||||||
|
@err = $stderr
|
||||||
|
|
||||||
|
$stdout = StringIO.new
|
||||||
|
$stderr = StringIO.new
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
$stdout = @out
|
||||||
|
$stderr = @err
|
||||||
|
end
|
||||||
|
|
||||||
|
subject(:deserializer) do
|
||||||
|
described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:valid_stream) do
|
||||||
|
"\xac\xed\x00\x05\x75\x72\x00\x02" +
|
||||||
|
"\x5b\x43\xb0\x26\x66\xb0\xe2\x5d" +
|
||||||
|
"\x84\xac\x02\x00\x00\x78\x70\x00" +
|
||||||
|
"\x00\x00\x02\x00\x61\x00\x62"
|
||||||
|
end
|
||||||
|
|
||||||
|
describe ".new" do
|
||||||
|
it "returns a JavaDeserializer instance" do
|
||||||
|
expect(deserializer).to be_a(JavaDeserializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "initializes file to nil" do
|
||||||
|
expect(deserializer.file).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#run" do
|
||||||
|
context "when file is nil" do
|
||||||
|
it "returns nil" do
|
||||||
|
expect(deserializer.run).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when file contains a valid stream" do
|
||||||
|
it "prints the stream contents" do
|
||||||
|
expect(File).to receive(:new) do
|
||||||
|
contents = valid_stream
|
||||||
|
StringIO.new(contents)
|
||||||
|
end
|
||||||
|
deserializer.file = 'sample'
|
||||||
|
deserializer.run
|
||||||
|
expect($stdout.string).to include('[7e0001] NewArray { char, ["97", "98"] }')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when file contains an invalid stream" do
|
||||||
|
it "prints the error while deserializing" do
|
||||||
|
expect(File).to receive(:new) do
|
||||||
|
contents = 'invalid_stream'
|
||||||
|
StringIO.new(contents)
|
||||||
|
end
|
||||||
|
deserializer.file = 'sample'
|
||||||
|
deserializer.run
|
||||||
|
expect($stdout.string).to include('[-] Failed to unserialize Stream')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
msf_base = __FILE__
|
||||||
|
while File.symlink?(msf_base)
|
||||||
|
msf_base = File.expand_path(File.readlink(msf_base), File.dirname(msf_base))
|
||||||
|
end
|
||||||
|
|
||||||
|
$:.unshift(File.expand_path(File.join(File.dirname(msf_base), '..', 'lib')))
|
||||||
|
require 'rex/java/serialization'
|
||||||
|
require 'pp'
|
||||||
|
|
||||||
|
# This class allows to deserialize Java Streams from
|
||||||
|
# files
|
||||||
|
class JavaDeserializer
|
||||||
|
|
||||||
|
# @!attribute file
|
||||||
|
# @return [String] the file's path to deserialize
|
||||||
|
attr_accessor :file
|
||||||
|
|
||||||
|
# @param file [String] the file's path to deserialize
|
||||||
|
def initialize(file = nil)
|
||||||
|
self.file = file
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deserializes a Java stream from a file and prints the result.
|
||||||
|
#
|
||||||
|
# @return [Rex::Java::Serialization::Model::Stream] if succeeds
|
||||||
|
# @return [nil] if error
|
||||||
|
def run
|
||||||
|
if file.nil?
|
||||||
|
print_error("file path with serialized java stream required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Deserializing...")
|
||||||
|
print_line
|
||||||
|
|
||||||
|
begin
|
||||||
|
f = File.new(file, 'rb')
|
||||||
|
stream = Rex::Java::Serialization::Model::Stream.decode(f)
|
||||||
|
f.close
|
||||||
|
rescue ::Exception => e
|
||||||
|
print_exception(e)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
puts stream
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# @param [String] string to print as status
|
||||||
|
def print_status(msg='')
|
||||||
|
$stdout.puts "[*] #{msg}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [String] string to print as error
|
||||||
|
def print_error(msg='')
|
||||||
|
$stdout.puts "[-] #{msg}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Exception] exception to print
|
||||||
|
def print_exception(e)
|
||||||
|
print_error(e.message)
|
||||||
|
e.backtrace.each do |line|
|
||||||
|
$stdout.puts("\t#{line}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_line
|
||||||
|
$stdout.puts("\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
deserializer = JavaDeserializer.new(ARGV[0])
|
||||||
|
deserializer.run
|
||||||
|
end
|
Loading…
Reference in New Issue