Mikhael Goikhman

NAME

SMB::Packer - Convenient data packer for network protocols like SMB

SYNOPSIS

        use SMB::Packer;

        # Pack an imaginative packet of the following structure:
        #   protocol signature (2 bytes in big-endian), header (48),
        #   secret key (8), flags (1), mode (2 in little-endian),
        #   payload offset (4) and length (4),
        #   filename prefixed with length (2 + length),
        #   payload
        # SMB::Parser documentation shows how it can be parsed back.

        my $packer = SMB::Packer->new;

        $packer
                ->uint16_be(0xFACE)
                ->zero(48)
                ->mark('body-start')
                ->bytes([ map { chr(rand(0x100)) } 1 .. 8 ]),
                ->uint8(1)
                ->uint16($mode)
                ->stub('payload-offset', 'uint32')
                ->uint32(bytes::length($payload))
                ->uint16(length($filename) * 2)  # 2-byte chars in utf16
                ->utf16($filename)
                ->fill('payload-offset', $packer->diff('body-start'))
                ->bytes($payload)
        ;

        # send the packet
        send_tcp_payload($packer->data, $packer->size);

DESCRIPTION

This class allows to pack a binary data, like a network packet data.

It supports packing blobs, unsigned integers of different lengths, text in arbitrary encoding (SMB uses UTF-16LE), defining named marks inside the data for later reference/jumping, defining named stubs for later filling and more.

The current data pointer is normally at the data end, but may be between 0 and the currently packed data size. The data is automatically extended when needed, and the pointer is advanced accordingly. This is different from SMB::Parser where the initially set data is never extended even when the pointer is over its size.

This class inherits from SMB, so msg, err, mem, dump, auto-created field accessor and other methods are available as well.

METHODS

new

Class constructor. Returns an SMB::Packer instance with initially empty data and state using reset.

reset

Resets the gathered data, the current data pointer, as well as the named marks and stubs.

data

Returns the data packed so far (binary scalar).

size

Returns length of the data packed so far (in bytes).

offset

Returns the current data pointer (integer starting from 0).

Please use the mechanisms of named marks or gaps (see below) instead of manipulating the current data pointer directly.

skip N_BYTES

Advances the pointer in N_BYTES.

If the data needs to be extended over the currently packed data (for example, when the current data pointer is at or near the end), it is appended with the missing number of zeros using zero method.

Returns the object, to allow chaining.

zero N_BYTES

Packs N_BYTES of "\0" bytes starting from the current data pointer and advances the pointer in N_BYTES.

The data is extended if needed.

bytes BYTES

Packs a sub-buffer of BYTES (where BYTES is either a binary scalar or an array ref of 1-byte scalars) and advances the pointer in length of BYTES.

The data is extended if needed.

The following packing methods use this method internally, so they share the same logic about extending the data and advancing the pointer.

str STRING [ENCODING='UTF-16LE']

Encodes STRING (potentially with utf8 flag set) as the text in the requested encoding starting from the current data pointer.

utf16 STRING

The same as str with encoding 'UTF-16LE'.

utf16_be STRING

The same as str with encoding 'UTF-16BE'.

uint8
uint16
uint32
uint16_be
uint32_be
uint64

Packs an unsigned integer of the specified length in bits (i.e. 1, 2, 4, 8 bytes).

By default, the byte order is little-endian (since it is used in SMB). The method suffix "_be" denotes the big-endian byte order for packing.

fid1 FID1

Packs a file id used in SMB 1, that is an unsigned integer of 2 bytes.

fid2 FID2

Packs a file id used in SMB 2, that is an array ref of two unsigned integers of 8 bytes each.

mark MARK_NAME

Labels the current data position as MARK_NAME (human readable string).

jump MARK_NAME

Changes the current data position to the one previously labeled with MARK_NAME (if any, otherwise defaults to 0).

diff MARK_NAME

Returns the difference between the current data position and the one previously labeled with MARK_NAME (if any, otherwise defaults to 0).

stub STUB_NAME TYPE

Labels the current data position as STUB_NAME (human readable string), advances the data pointer according to TYPE by temporarily filling this region with a zero equivalent, according to TYPE.

TYPE may be either a number matching /^\d+$/, in which case the stub type is taken to be "bytes" of this size; or "uint8", "uint16" and so on, then this is the stub type (see the corresponding "uint*" methods above).

fill STUB_NAME DATA

Fills the previously set stub with DATA. The DATA should correspond to the TYPE previously specified in stub(STUB_NAME, TYPE) method call. I.e. if the TYPE was size of bytes, then DATA should correspond to the bytes method argument of size TYPE (scalar or array ref of this size). And if the TYPE is, say, "uint16", then DATA should be 2-byte integer.

The packing is done at the previously stored data pointer position. The current data pointer is not changed after this method!

If no STUB_NAME was previously set using stub method, the fatal exception is thrown.

SEE ALSO

SMB::Parser, SMB.

AUTHOR

Mikhael Goikhman <migo@cpan.org>