> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/fortra/impacket/llms.txt
> Use this file to discover all available pages before exploring further.

# Packet Crafting

> Building custom network packets with Impacket Structure class

## Overview

Impacket's `Structure` class (`impacket/structure.py`) provides a powerful framework for defining and manipulating binary data structures. It's the foundation for all protocol implementations in Impacket.

## The Structure Class

### Basic Concept

The `Structure` class allows you to define data structures declaratively using format specifiers similar to Python's `struct` module, with additional features for complex protocols.

```python theme={null}
from impacket.structure import Structure

class MyPacket(Structure):
    structure = (
        ('field1', 'B'),      # Unsigned byte
        ('field2', 'H'),      # Unsigned short
        ('field3', '16s'),    # 16-byte string
    )
```

### Format Specifiers

#### Standard struct Format

From Python's `struct` module:

```python theme={null}
'B'    # Unsigned byte (1 byte)
'H'    # Unsigned short (2 bytes)
'I'    # Unsigned int (4 bytes)
'Q'    # Unsigned long long (8 bytes)
'b'    # Signed byte
'h'    # Signed short
'i'    # Signed int
'q'    # Signed long long
's'    # String (must specify length: '16s')
'<'    # Little-endian
'>'    # Big-endian
'!'    # Network byte order (big-endian)
```

#### Extended Impacket Specifiers

```python theme={null}
':'    # Raw bytes (copy field as-is)
'z'    # Null-terminated string (ASCIIZ)
'u'    # UTF-16LE null-terminated string
'w'    # DCE-RPC/NDR string format
'_'    # Don't pack this field
```

#### Dynamic Specifiers

```python theme={null}
'?-field'       # Length of 'field' formatted as ?
'?1*?2'         # Array of ?2 elements, count stored as ?1
'?=expression'  # Evaluate expression and pack as ?
'?&fieldname'   # Address/presence of fieldname
```

## Creating Structures

### Simple Packet

```python theme={null}
from impacket.structure import Structure

class EthernetHeader(Structure):
    structure = (
        ('destination', '6s="\x00" * 6'),  # MAC address with default
        ('source', '6s="\x00" * 6'),
        ('type', '>H=0x0800'),              # Network byte order, default 0x0800 (IPv4)
    )

# Create instance
eth = EthernetHeader()
eth['destination'] = b'\xff\xff\xff\xff\xff\xff'  # Broadcast
eth['source'] = b'\x00\x11\x22\x33\x44\x55'
eth['type'] = 0x0800

# Get binary data
packet_data = eth.getData()
print(packet_data.hex())
```

### Variable-Length Fields

```python theme={null}
class SMBHeader(Structure):
    structure = (
        ('Protocol', '4s="\xffSMB"'),
        ('Command', 'B=0'),
        ('ErrorClass', 'B=0'),
        ('Reserved', 'B=0'),
        ('ErrorCode', '<H=0'),
        ('Flags', 'B=0'),
        ('Flags2', '<H=0'),
        ('PIDHigh', '<H=0'),
        ('SecurityFeatures', '8s="\x00" * 8'),
        ('Reserved2', '<H=0'),
        ('TID', '<H=0'),
        ('PIDLow', '<H=0'),
        ('UID', '<H=0'),
        ('MID', '<H=0'),
    )

smb = SMBHeader()
smb['Command'] = 0x72  # SMB_COM_NEGOTIATE
data = smb.getData()
```

### Length-Prefixed Data

```python theme={null}
class MessagePacket(Structure):
    structure = (
        ('MessageLength', '<H-Message'),  # Auto-calculated from Message field
        ('Message', ':'),                 # Raw bytes
    )

msg = MessagePacket()
msg['Message'] = b'Hello, World!'
data = msg.getData()
# MessageLength will automatically be set to len(b'Hello, World!')
```

### Arrays

```python theme={null}
class ArrayPacket(Structure):
    structure = (
        ('Count', '<H'),           # Number of items
        ('Items', '<H*Count'),     # Array of Count items, each <H
    )

pkt = ArrayPacket()
pkt['Items'] = [1, 2, 3, 4, 5]
data = pkt.getData()
# Count will be automatically set to 5

# Fixed-size array
class FixedArrayPacket(Structure):
    structure = (
        ('Items', '10*<H'),  # Exactly 10 unsigned shorts
    )
```

### Nested Structures

```python theme={null}
class InnerStruct(Structure):
    structure = (
        ('value1', '<I'),
        ('value2', '<I'),
    )

class OuterStruct(Structure):
    structure = (
        ('header', '<I'),
        ('inner', ':', InnerStruct),  # Nested structure
        ('trailer', '<I'),
    )

outer = OuterStruct()
inner = InnerStruct()
inner['value1'] = 100
inner['value2'] = 200

outer['header'] = 1
outer['inner'] = inner
outer['trailer'] = 2

data = outer.getData()
```

## Parsing Packets

### From Binary Data

```python theme={null}
class TCPHeader(Structure):
    structure = (
        ('srcPort', '>H'),
        ('dstPort', '>H'),
        ('seqNum', '>I'),
        ('ackNum', '>I'),
        ('dataOff', 'B'),
        ('flags', 'B'),
        ('window', '>H'),
        ('checksum', '>H'),
        ('urgPtr', '>H'),
    )

# Parse from bytes
raw_data = b'\x00\x50\x1f\x90...'  # TCP packet bytes
tcp = TCPHeader(raw_data)

print(f"Source Port: {tcp['srcPort']}")
print(f"Dest Port: {tcp['dstPort']}")
print(f"Seq: {tcp['seqNum']}")
```

### Conditional Fields

```python theme={null}
class ConditionalPacket(Structure):
    structure = (
        ('hasData', 'B'),
        ('_dataPresence', '_', 'B&data'),  # Mark data as conditional
        ('data', ':'),                      # Only present if hasData is set
    )

# With data
pkt1 = ConditionalPacket()
pkt1['hasData'] = 1
pkt1['data'] = b'Some data'

# Without data
pkt2 = ConditionalPacket()
pkt2['hasData'] = 0
# Don't set data field
```

## Real-World Examples

### SMB Packet Construction

```python theme={null}
from impacket.structure import Structure

class SMB2Header(Structure):
    structure = (
        ('ProtocolId', '4s="\xfeSMB"'),
        ('StructureSize', '<H=64'),
        ('CreditCharge', '<H=0'),
        ('Status', '<I=0'),
        ('Command', '<H=0'),
        ('CreditRequest', '<H=0'),
        ('Flags', '<I=0'),
        ('NextCommand', '<I=0'),
        ('MessageId', '<Q=0'),
        ('Reserved', '<I=0'),
        ('TreeId', '<I=0'),
        ('SessionId', '<Q=0'),
        ('Signature', '16s="\x00" * 16'),
    )

class SMB2NegotiateRequest(Structure):
    structure = (
        ('StructureSize', '<H=36'),
        ('DialectCount', '<H-Dialects'),
        ('SecurityMode', '<H=0'),
        ('Reserved', '<H=0'),
        ('Capabilities', '<I=0'),
        ('ClientGuid', '16s="\x00" * 16'),
        ('NegotiateContextOffset', '<I=0'),
        ('NegotiateContextCount', '<H=0'),
        ('Reserved2', '<H=0'),
        ('Dialects', '<H*DialectCount'),
    )

# Create SMB2 NEGOTIATE packet
header = SMB2Header()
header['Command'] = 0  # SMB2_NEGOTIATE
header['MessageId'] = 1

negotiate = SMB2NegotiateRequest()
negotiate['Dialects'] = [0x0202, 0x0210, 0x0300, 0x0302, 0x0311]  # SMB 2.0.2, 2.1, 3.0, 3.0.2, 3.1.1
negotiate['SecurityMode'] = 1  # Signing enabled

packet = header.getData() + negotiate.getData()
```

### NTLM Authentication Packet

```python theme={null}
from impacket.structure import Structure

class NTLMAuthNegotiate(Structure):
    structure = (
        ('Signature', '8s="NTLMSSP\\x00"'),
        ('MessageType', '<I=1'),  # NEGOTIATE_MESSAGE
        ('NegotiateFlags', '<I=0'),
        ('DomainNameLen', '<H-DomainName'),
        ('DomainNameMaxLen', '<H-DomainName'),
        ('DomainNameOffset', '<I=0'),
        ('WorkstationLen', '<H-WorkstationName'),
        ('WorkstationMaxLen', '<H-WorkstationName'),
        ('WorkstationOffset', '<I=0'),
        ('VersionLen', '_-Version', '8 if self["NegotiateFlags"] & 0x02000000 else 0'),
        ('Version', '8s=""'),
        ('DomainName', ':'),
        ('WorkstationName', ':'),
    )

ntlm = NTLMAuthNegotiate()
ntlm['NegotiateFlags'] = 0xb2808205  # Typical flags
ntlm['DomainName'] = b'DOMAIN'
ntlm['WorkstationName'] = b'WORKSTATION'

auth_data = ntlm.getData()
```

### Custom Protocol

```python theme={null}
class CustomProtocolHeader(Structure):
    structure = (
        ('magic', '4s="CUST"'),
        ('version', 'B=1'),
        ('type', 'B=0'),
        ('flags', '<H=0'),
        ('payloadLength', '<I-payload'),
        ('checksum', '<I=0'),
        ('payload', ':'),
    )

def create_packet(msg_type, flags, payload):
    pkt = CustomProtocolHeader()
    pkt['type'] = msg_type
    pkt['flags'] = flags
    pkt['payload'] = payload
    
    # Calculate checksum
    data = pkt.getData()
    checksum = sum(data) & 0xffffffff
    pkt['checksum'] = checksum
    
    return pkt.getData()

packet = create_packet(1, 0x0001, b'Hello')
```

## Advanced Techniques

### Evaluated Fields

```python theme={null}
class DynamicPacket(Structure):
    structure = (
        ('dataSize', '<I=len(self["data"]) if "data" in self.fields else 0'),
        ('flags', '<I=(1 if self["dataSize"] > 0 else 0)'),
        ('data', ':'),
    )
```

### Common Header Pattern

```python theme={null}
class BasePacket(Structure):
    commonHdr = (
        ('signature', '4s="BASE"'),
        ('version', 'B=1'),
    )
    structure = (
        ('data', ':'),
    )

# commonHdr is automatically prepended to structure
pkt = BasePacket()
pkt['data'] = b'payload'
data = pkt.getData()
# Result: b'BASE\x01' + b'payload'
```

### Alignment

```python theme={null}
class AlignedPacket(Structure):
    def __init__(self, data=None, alignment=4):
        Structure.__init__(self, data, alignment)
    
    structure = (
        ('field1', 'B'),
        ('field2', 'B'),
        # Will be padded to 4-byte alignment
    )

pkt = AlignedPacket()
pkt['field1'] = 1
pkt['field2'] = 2
data = pkt.getData()
# Result: b'\x01\x02\x00\x00' (padded to 4 bytes)
```

## Debugging

```python theme={null}
from impacket.structure import Structure, hexdump

# Enable debug output
class DebugPacket(Structure):
    debug = 1  # Print packing operations
    structure = (
        ('field1', '<I'),
        ('field2', '<H'),
    )

pkt = DebugPacket()
pkt['field1'] = 0x12345678
pkt['field2'] = 0xabcd

data = pkt.getData()

# Hexdump the result
print("Packet data:")
hexdump(data)
```

## Best Practices

1. **Use type hints in field names**: `('length', '<H')` is clearer than `('len', '<H')`
2. **Specify default values**: `('type', 'B=1')` prevents uninitialized fields
3. **Use length prefixes**: `('<H-Data')` auto-calculates lengths
4. **Document complex formats**: Add comments for protocol-specific fields
5. **Test with real data**: Parse actual packets to validate structure definitions
6. **Handle endianness**: Explicitly specify `<` (little) or `>` (big) endian

## Common Pitfalls

1. **String encoding**: Use `b''` for byte strings, not regular strings
2. **Array lengths**: Ensure count field is set before packing arrays
3. **Field order**: Structure fields are packed in definition order
4. **Alignment**: Be aware of padding in binary protocols
5. **Nested structures**: Use `:` format specifier, not direct structure assignment

## References

* Python `struct` module documentation
* Impacket source: `impacket/structure.py`
* Protocol RFCs and Microsoft specifications for real-world examples
