mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-07-10 06:08:42 +02:00
07c8adaf76
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
179 lines
4.1 KiB
Go
179 lines
4.1 KiB
Go
package clienthellod
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"sort"
|
|
|
|
"github.com/gaukas/clienthellod/internal/utils"
|
|
)
|
|
|
|
const (
|
|
QUICFrame_PADDING uint64 = 0 // 0
|
|
QUICFrame_PING uint64 = 1 // 1
|
|
QUICFrame_CRYPTO uint64 = 6 // 6
|
|
)
|
|
|
|
type Frame interface {
|
|
// FrameType returns the type of the frame.
|
|
FrameType() uint64
|
|
|
|
// ReadReader takes a Reader and reads the rest of the frame from it,
|
|
// starting from the first byte after the frame type.
|
|
//
|
|
// The returned io.Reader contains the rest of the frame, it could be
|
|
// the input Reader itself (if no extra bytes are read) or a rewinded
|
|
// Reader (if extra bytes are read and rewinding is needed).
|
|
ReadReader(io.Reader) (io.Reader, error)
|
|
}
|
|
|
|
func ReadAllFrames(r io.Reader) ([]Frame, error) {
|
|
var frames []Frame = make([]Frame, 0)
|
|
|
|
for {
|
|
// Frame Type
|
|
frameType, _, err := ReadNextVLI(r)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return frames, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// Frame
|
|
var frame Frame
|
|
switch frameType {
|
|
case QUICFrame_PADDING:
|
|
frame = &PADDING{}
|
|
case QUICFrame_PING:
|
|
frame = &PING{}
|
|
case QUICFrame_CRYPTO:
|
|
frame = &CRYPTO{}
|
|
default:
|
|
return nil, fmt.Errorf("unknown frame type: 0x%.2x", frameType)
|
|
}
|
|
|
|
// Read the rest of the frame
|
|
r, err = frame.ReadReader(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Append the frame
|
|
frames = append(frames, frame)
|
|
}
|
|
}
|
|
|
|
func ReassembleCRYPTOFrames(frames []Frame) ([]byte, error) {
|
|
var cryptoFrames []Frame = make([]Frame, 0)
|
|
|
|
// Collect all CRYPTO frames
|
|
for _, frame := range frames {
|
|
if frame.FrameType() == QUICFrame_CRYPTO {
|
|
cryptoFrames = append(cryptoFrames, frame)
|
|
}
|
|
}
|
|
|
|
if len(cryptoFrames) == 0 {
|
|
return nil, nil // no CRYPTO frames is not an error
|
|
}
|
|
|
|
// Sort CRYPTO frames by offset
|
|
sort.Slice(cryptoFrames, func(i, j int) bool {
|
|
return cryptoFrames[i].(*CRYPTO).Offset < cryptoFrames[j].(*CRYPTO).Offset
|
|
})
|
|
|
|
// Reassemble CRYPTO frames
|
|
var reassembled []byte = make([]byte, 0)
|
|
for _, frame := range cryptoFrames {
|
|
if uint64(len(reassembled)) == frame.(*CRYPTO).Offset {
|
|
reassembled = append(reassembled, frame.(*CRYPTO).Data...)
|
|
} else {
|
|
return nil, fmt.Errorf("failed to reassemble CRYPTO frames")
|
|
}
|
|
}
|
|
|
|
return reassembled, nil
|
|
}
|
|
|
|
// PADDING frame
|
|
type PADDING struct {
|
|
Length uint64 `json:"length,omitempty"` // count 0x00 bytes until not 0x00
|
|
}
|
|
|
|
// FrameType implements Frame interface.
|
|
func (*PADDING) FrameType() uint64 {
|
|
return QUICFrame_PADDING
|
|
}
|
|
|
|
// ReadFrom implements Frame interface. It keeps reading until it finds a
|
|
// non-zero byte, then the non-zero byte is rewinded back to the reader and
|
|
// the reader is returned.
|
|
func (f *PADDING) ReadReader(r io.Reader) (rr io.Reader, err error) {
|
|
f.Length = 1 // starting from 1, since type is already read
|
|
|
|
var b []byte = make([]byte, 1)
|
|
for {
|
|
_, err = r.Read(b)
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return r, nil // EOF is not an error, it just means all frames are read
|
|
}
|
|
return r, err
|
|
}
|
|
if b[0] != 0x00 {
|
|
// rewind the reader
|
|
rr = utils.RewindReader(r, b)
|
|
return
|
|
}
|
|
f.Length++
|
|
}
|
|
}
|
|
|
|
// PING frame
|
|
type PING struct{}
|
|
|
|
// FrameType implements Frame interface.
|
|
func (*PING) FrameType() uint64 {
|
|
return QUICFrame_PING
|
|
}
|
|
|
|
// ReadFrom implements Frame interface. It does nothing and returns the
|
|
// input reader.
|
|
func (*PING) ReadReader(r io.Reader) (rr io.Reader, err error) {
|
|
return r, nil
|
|
}
|
|
|
|
// CRYPTO frame
|
|
type CRYPTO struct {
|
|
Offset uint64 `json:"offset,omitempty"` // offset of crypto data, from VLI
|
|
Length uint64 `json:"length,omitempty"` // length of crypto data, from VLI
|
|
Data []byte `json:"data,omitempty"` // crypto data
|
|
}
|
|
|
|
// FrameType implements Frame interface.
|
|
func (*CRYPTO) FrameType() uint64 {
|
|
return QUICFrame_CRYPTO
|
|
}
|
|
|
|
// ReadFrom implements Frame interface. It reads the offset, length and
|
|
// crypto data from the input reader.
|
|
func (f *CRYPTO) ReadReader(r io.Reader) (rr io.Reader, err error) {
|
|
// Offset
|
|
f.Offset, _, err = ReadNextVLI(r)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
|
|
// Length
|
|
f.Length, _, err = ReadNextVLI(r)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
|
|
// Crypto Data
|
|
f.Data = make([]byte, f.Length)
|
|
_, err = r.Read(f.Data)
|
|
return r, err
|
|
}
|