Body-based Signature Content Format
ClamAV stores all body-based (content-based) signatures in a hexadecimal format, with exception to ClamAV’s YARA rule support. In this section by a hex-signature we mean a fragment of malware’s body converted into a hexadecimal string which can be additionally extended using various wildcards.
Hexadecimal format
You can use sigtool --hex-dump to convert any data into a hex-string:
zolw@localhost:/tmp/test$ sigtool --hex-dump
How do I look in hex?
486f7720646f2049206c6f6f6b20696e206865783f0a
Wildcards
ClamAV supports the following wildcards for hex-signatures:
-
??Match any byte.
-
a?Match a high nibble (the four high bits).
-
?aMatch a low nibble (the four low bits).
-
*Match any number of bytes.
-
{n}Match
nbytes. -
{-n}Match
nor less bytes. -
{n-}Match
nor more bytes. -
{n-m}Match between
nandmbytes (wherem > n). -
HEXSIG[x-y]aaoraa[x-y]HEXSIGThe
[x-y]notation enables matching on a range of any bytes where one side is just a single-byte (two nibbles), represented by “aa”. The other side, represented by “HEXSIG” must be at least 2 bytes (4 nibbles).The similar notation
{n-m}requires that both sides have at least 2 bytes. The difference here is that [x-y] enables matching of just one byte.A second, unfortunate, difference is that
ycannot be greater than 32.Example logical signature:
testsig;Target:0;0;64[4-4]61616161{2}6262[3-6]65:27In the example signature “testsig”, there are two examples of this wildcard variant:
-
64[4-4]61616161: This will search for the byte “64” followed by the hex sequence “61616161” with exactly 4 arbitrary bytes in between. -
6262[3-6]65: This will search for the hex sequence “6262” followed by the byte “65” with 3 to 6 arbitrary bytes in between.
(Note that the “{2}” in between is the other wildcard variant meaning to match 2 arbitrary bytes.)
Thus the signature matches many variations such as these. Braces and brackets are added in this hex to illustrate the boundaries of the wildcard matches:
64[61616161]616161616{4646}6262[0102]6564[67676767]616161616{0102}6262[262626]6564[00000000]616161616{9696}6262[26262636]65
-
The range signatures * and {} virtually separate a hex-signature into two parts, eg. aabbcc*bbaacc is treated as two sub-signatures aabbcc and bbaacc with any number of bytes between them. It’s a requirement that each sub-signature includes a block of two static characters somewhere in its body. Note that there is one exception to this restriction; that is when the range wildcard is of the form {n} with n<128. In this case, ClamAV uses an optimization and translates {n} to the string consisting of n number of ?? character wildcards. Character wildcards do not divide hex signatures into two parts and so the two static character requirement does not apply.
Character classes
ClamAV supports the following character classes for hex-signatures:
-
(B)Match word boundary (including file boundaries).
-
(L)Match CR, CRLF or file boundaries.
-
(W)Match a non-alphanumeric character.
Alternate strings
-
Single-byte alternates (clamav-0.96)
(aa|bb|cc|...)or!(aa|bb|cc|...)Match a member from a set of bytes (eg:aa,bb,cc, …).- Negation operation can be applied to match any non-member, assumed to be one-byte in length.
- Signature modifiers and wildcards cannot be applied.
-
Multi-byte fixed length alternates
(aaaa|bbbb|cccc|...)or!(aaaa|bbbb|cccc|...)Match a member from a set of multi-byte alternates (eg: aaaa, bbbb, cccc, …) of n-length.- All set members must be the same length.
- Negation operation can be applied to match any non-member, assumed to be n-bytes in length (clamav-0.98.2).
- Signature modifiers and wildcards cannot be applied.
-
Generic alternates (clamav-0.99)
(alt1|alt2|alt3|...)Match a member from a set of alternates (eg: alt1, alt2, alt3, …) that can be of variable lengths.- Negation operation cannot be applied.
- Signature modifiers and nibble wildcards (eg:
??, a?, ?a) can be applied. - Ranged wildcards (eg:
{n-m}) are limited to a fixed range of less than 128 bytes (eg:{1} -> {127}).
Note: Using signature modifiers and wildcards classifies the alternate type to be a generic alternate. Thus single-byte alternates and multi-byte fixed length alternates can use signature modifiers and wildcards but will be classified as generic alternate. This means that negation cannot be applied in this situation and there is a slight performance impact.
Hex Negation
ClamAV supports YARA-compatible hexadecimal byte and nibble negation using the ~ operator (ClamAV 1.6+, functionality level 240). This allows matching any byte except a specific value or nibble pattern:
-
~HHMatch any byte except
0xHH. Example:~00matches any byte except0x00. -
~H?Match any byte whose high nibble (the four high bits) is not
H. Example:~0?matches any byte where the high nibble is not0x0. -
~?HMatch any byte whose low nibble (the four low bits) is not
H. Example:~?0matches any byte where the low nibble is not0x0.
Examples
41~0042matches the sequence41, followed by any byte except0x00, followed by42.41~?042matches the sequence41, followed by any byte whose low nibble is not0x0, followed by42.41~0?42matches the sequence41, followed by any byte whose high nibble is not0x0, followed by42.
Invalid Forms
The following forms are not supported and will be rejected:
~~00(double negation)~??(negating all bytes)~without hex digits~applied to character classes or alternates~[1-2](negation combined with gap ranges)
Minimum Functionality Level Requirement
Databases using hex negation syntax must declare a minimum functionality level of 240.
For logical signatures (.ldb files), place the Engine directive first in the target-description block with a functionality-level range:
MySignature;Engine:240-255,Target:0;0;41~0042
For extended .ndb signatures, use the optional min and max functionality-level fields:
MalwareName:TargetType:Offset:HexSignature[:min_flevel:[max_flevel]]
Example of an extended .ndb signature gated to ClamAV 1.6 (FLEVEL 240):
MySignature:0:*:41~0042:240
Difference from ClamAV Alternates
Hex negation (~HH, ~H?, and ~?H) negates exactly one byte or nibble predicate. ClamAV’s existing !(...) syntax negates a fixed set of alternate byte sequences, which may contain one or multiple bytes:
~HHmatches one byte wherebyte != 0xHH!(aa|bb|cc)matches one byte that is not in the set{0xaa, 0xbb, 0xcc}!(aaaa|bbbb)matches a two-byte sequence that is not0xaaaaor0xbbbb