Tools · Forensics tools · 12 / 25
YARA: strings and conditions that stay specific
Text, wide text, and hex are different needles. The condition is where you decide how many of them must be present, and where most false positives are either invited or refused.
ASCII, wide, and case
A plain string in quotes is bytes. Windows often stores the same phrase as UTF-16LE, which YARA calls wide. If the command line or a log might hold either form, say ascii wide on that string so both representations count. nocase folds Latin case for text strings. Use it for names a person could have typed in either case, such as a hostname. Leave it off for a token that is case-sensitive in the format you are matching, and for any string where folding would make it collide with an ordinary word.
fullword asks that the match not sit in the middle of a longer alphanumeric run. It is useful for a short token like p4 that would otherwise match inside an unrelated identifier. It is the wrong tool for a path fragment that is supposed to be glued to neighboring characters. Read the modifier against the bytes you actually saw in Autopsy or in the Sysmon line, and copy that representation on purpose.
Hex when the content is not text
A hex string is for bytes that are not a readable phrase: a file header, a fixed record, a GUID. You write it in braces. A question mark masks a nibble you do not care about. A jump, written as a range, allows a gap you have measured. Masks and jumps should come from a specimen you already have in the case, where you can point at the offset and say why those bytes vary. A mask that is mostly wildcards matches the world. If you cannot explain a wildcard from the file you hold, keep the byte fixed or drop it.
Hex is also how you avoid dragging a huge binary into a text string you do not understand. You do not need a page of unknown bytes in the rule. Take the stable header or the stable identifier, keep it short, and let the condition require a second fact, such as filesize or a text string you can read aloud. A rule you cannot read aloud is a rule you cannot defend in the report.
- ascii wide when Windows may have stored UTF-16LE.
- nocase for hostnames and other case-folded names.
- fullword for short tokens that must stand alone.
- Hex masks only on bytes you have seen vary in a file you hold.
Conditions are where the rule gets honest
all of them is strict and brittle. any of them is wide. 2 of ($s*) is the middle when you have a family of related strings and one of them might be renamed. You can also mix: $path and 1 of ($names*). Parentheses work the way they do in other boolean expressions. filesize is the cheapest extra fact you have, and it stops a rule written for a script from lighting up a hibernation file because a fragment happened to occur.
Anchor a string when the format puts it at a known offset. $mz at 0 is the classic check that a PE starts with its header, and you only add it when you mean “this file is a PE,” which the PE module can also say more clearly. Anchors on the wrong offset create a silent rule that never hits. Test the anchor on the one file you know should match before you scan the folder.
A miss is data too
If the Temp extract should contain a string and the rule misses, the string is different from what you wrote, or the encoding is, or you are scanning a hash-identical file that never contained that text. Go look at the bytes. Do not loosen the rule with any of them until you can say what true file you just excluded. A rule edited in response to one miss, with no note, is how a careful pattern becomes a single wildcard.
Keep a one-line test list in the case folder: this extract must hit, this stock powershell.exe must not, this timeline CSV may hit because it mentions the path. The list is small on purpose. It is the regression suite for a single case rule, and it is enough.
Worked case: wide text in a command-line export
The Sysmon CSV stores the command line as ordinary text, and a second export from the same event is UTF-16LE because of the way it was saved. Version 1 of the rule, ascii only, hits the CSV and misses the UTF-16LE copy of the same line. You add ascii wide to $staged and $temp, bump meta to version 2, and rescan. Both exports hit. The stock powershell.exe from the image still does not, because it does not contain those path fragments.
You write the modifier change in the log as an encoding fix, not as a broader theory. The condition stays filesize < 5MB and all of them. A hex mask is not needed. The bytes you care about are readable.
Diagram
A loose string and a condition you can explain
Same folder, two rules
Strings. A three-character name with no fullword and no companion string.
Condition. any of them, with no filesize cap.
Hits. Dozens of unrelated binaries and documents. The queue is the folder.
Strings. $staged ascii wide $temp ascii wide
Condition. all of them, and a size cap taken from the exports you actually scan.
Hits. The files that carry both fragments, ready for a human to label as content or mention.
Check yourself
1. The same command line is stored once as ASCII and once as UTF-16LE. The rule uses a plain quoted string with no modifier and misses the second file. What change matches the evidence?