Skip to content

Commit

Permalink
#4 Fixed the problem that sometimes resource pointer parse failed.
Browse files Browse the repository at this point in the history
Sometimes the Offset of the resource pointer exceeds 255, resulting in an error in the analysis. After two days of research, the problem has been fixed.
  • Loading branch information
636f7374 committed Jan 21, 2021
1 parent 288e627 commit 187df5d
Showing 1 changed file with 61 additions and 19 deletions.
80 changes: 61 additions & 19 deletions src/durian/durian.cr
Original file line number Diff line number Diff line change
Expand Up @@ -133,54 +133,63 @@ module Durian
end

enum ChunkFlag : UInt8
BadLength = 0_u8
IndexOutOfBounds = 1_u8
ResourcePointer = 2_u8
Successed = 3_u8
BadLength = 0_u8
IndexOutOfBounds = 1_u8
UInt16ResourcePointer = 2_u8
ResourcePointer = 3_u8
Successed = 4_u8
end

def self.decode_chunk(buffer : IO::Memory) : Tuple(ChunkFlag, Array(String))
def self.decode_chunk(buffer : IO::Memory) : Tuple(ChunkFlag, Array(String), UInt8)
chunk_parts = [] of String

loop do
chunk_length_buffer = uninitialized UInt8[1_i32]
read_length = buffer.read chunk_length_buffer.to_slice
chunk_length = chunk_length_buffer.to_slice[0_i32]

return Tuple.new ChunkFlag::BadLength, chunk_parts if 1_i32 != read_length
return Tuple.new ChunkFlag::BadLength, chunk_parts, chunk_length if 1_i32 != read_length
break if chunk_length.zero?

if 0b00000011 == (chunk_length >> 6_i32)
return Tuple.new ChunkFlag::ResourcePointer, chunk_parts
unless (chunk_length - 0b11000000).zero?
return Tuple.new ChunkFlag::UInt16ResourcePointer, chunk_parts, chunk_length
end

return Tuple.new ChunkFlag::ResourcePointer, chunk_parts, chunk_length
end

return Tuple.new ChunkFlag::IndexOutOfBounds, chunk_parts if chunk_length > buffer.size
if chunk_length > buffer.size
return Tuple.new ChunkFlag::IndexOutOfBounds, chunk_parts, chunk_length
end

temporary = IO::Memory.new chunk_length
copy_length = IO.copy buffer, temporary, chunk_length
return Tuple.new ChunkFlag::BadLength, chunk_parts if copy_length.zero?

return Tuple.new ChunkFlag::BadLength, chunk_parts, chunk_length if copy_length.zero?

chunk_parts << String.new temporary.to_slice[0_i32, copy_length]
end

Tuple.new ChunkFlag::Successed, chunk_parts
Tuple.new ChunkFlag::Successed, chunk_parts, 0_u8
end

def self.update_chunk_resource_pointer_position(protocol : Protocol, buffer : IO::Memory)
def self.update_chunk_resource_pointer_position(protocol : Protocol, buffer : IO::Memory, chunk_length : UInt8, question : Bool = false)
offset_buffer = uninitialized UInt8[1_i32]
read_length = buffer.read offset_buffer.to_slice

if 1_i32 != read_length
return ResourcePointer::BadLength
end
return ResourcePointer::BadLength if 1_i32 != read_length

offset = offset_buffer.to_slice[0_i32]
return ResourcePointer::OffsetZero if offset.zero?
return ResourcePointer::BadLength if offset > buffer.size

unless (chunk_length - 0b11000000).zero?
offset = (((chunk_length - 0b11000000).to_i32 << 8_u8) | offset)
end

before_buffer_pos = buffer.pos
buffer.pos = offset
buffer.pos += 2_i32 if protocol.tcp? || protocol.tls?
buffer.pos += 2_i32 unless question if protocol.tcp? || protocol.tls?

ResourcePointer::Successed
end
Expand All @@ -204,6 +213,39 @@ module Durian
raise MalformedPacket.new "Expecting one bytes" if offset.zero?
raise MalformedPacket.new "Offset index out Of bounds" if offset > buffer.size

# My goodness, I was here and there for two days.
# Sometimes the resource pointer is not necessarily 0xc0, maybe 0xc1, maybe other.
# I consulted various information to no avail, guessing that the offset may exceed 255.
# So replace the first two high bits of the pointer head with 0, and then merge it with the offset into UInt16.
# This will get a correct Offset.
# This is terrible, So with this code comment.
#
# payload_size = 493
# ns1_offset = 464 - 42 (Wireshark layer) = 422
# 422 - 256 (UInt8 Max 0-255) = offset 166
#
# pointer = [\xc1 (0b11000001), \xa6(0b10100110)] = [193, 166]
# 166 + (UInt8 (0..255).size) = 422
#
#
# 422 UInt16 = 0b0000000110100110
#
# \xc1 - \xc0
# 0b11000001 - 0b11000000
#
# first_two_high_bitwise = 0xc0 # => 0b11000000 / 192_u8
# pointer = 0xc1 # => 0b11000001 / 193_u8
# offset = 0xa6 # => 0b10100110 / 166_u8
# (<< 8) = uint8 -> uint16
# real_offset = ((pointer - first_two_high_bitwise) << 8) | offset
# equal: 0000000100000000 |
# 0000000010100110
# = 0000000110100110 = 422

unless (pointer_flag - 0b11000000).zero?
offset = (((pointer_flag - 0b11000000).to_i32 << 8_u8) | offset)
end

depth_decode_by_resource_pointer! protocol, buffer, offset, maximum_depth: maximum_depth
end

Expand All @@ -217,16 +259,16 @@ module Durian
depth = maximum_depth

while !(maximum_depth -= 1_i32).zero?
flag, chunk_parts = decode_chunk buffer
flag, chunk_parts, chunk_length = decode_chunk buffer
chunk_list << chunk_parts unless chunk_parts.empty?

if flag.successed?
buffer.pos = before_buffer_pos
return chunk_list.flatten.join "."
end

if flag.resource_pointer?
next update_chunk_resource_pointer_position protocol, buffer
if flag.resource_pointer? || flag.u_int16_resource_pointer?
next update_chunk_resource_pointer_position protocol, buffer, chunk_length, question
end

buffer.pos = before_buffer_pos
Expand Down

0 comments on commit 187df5d

Please sign in to comment.