ProtoCrash treats protocols as first-class. Every parser implements a uniform interface: parse(data) -> ProtocolMessage, generate(template) -> bytes, and mutate_field(message, field) -> bytes. This lets HTTP, DNS, SMTP, and custom binary protocols all plug into the same fuzzing loop, using scapy and dpkt for standard protocols and custom parsers plus JSON grammars for binary formats.

A grammar describes typed fields with constraints. The documented example defines a magic uint32 fixed to 0xDEADBEEF, a length uint16 computed as len(payload), a command uint8 restricted to values [1,2,3,4], and a payload bytes field capped at 1024. With this grammar, the fuzzer can hold the magic constant and keep the length consistent while mutating the command and payload, so generated inputs pass the target’s header validation and reach the logic behind it. HTTP fuzzing similarly supports request templates (method, path, headers, body) with a FUZZ_HERE marker, and DNS fuzzing supports binary seed queries and keyword dictionaries.

This structure awareness is what makes the coverage loop productive on real protocols: blind mutation is rejected at parse time, while grammar-aware mutation reaches depth. A measured comparison of coverage reached with versus without grammars is Additional validation required.