Hunting with Strings and Hex
Matching malware artifacts.
Hunting with Strings and Hex is a free Cyber Security Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Cyber Security Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
From Sample to Rule
Hunting starts with a sample. You extract distinctive artifacts, decide which are durable, and encode them into a rule that catches the family without flagging benign files.
The workflow: triage the sample, pull strings and structural traits, separate signal from noise, draft the rule, then test it against both the family and a clean corpus before deploying.
Extracting Candidate Strings
Begin with the strings utility to list printable sequences, capturing both ASCII and UTF-16 (wide) text. Windows malware often stores strings as wide.
Scan the output for C2 URLs, mutex names, registry paths, custom error messages, PDB paths, and oddly specific text. Ignore generic runtime and compiler strings.
strings -a sample.bin > ascii.txt
strings -e l sample.bin > wide.txt # UTF-16LE
grep -iE 'http|mutex|\\\\pipe\\\\|\.pdb' ascii.txt wide.txtPicking Durable Strings
Not every string belongs in a rule. Favor artifacts the author cannot change without effort:
- Hardcoded mutex/pipe names unique to the family
- Custom protocol markers or config keys
- Unusual debug or panic messages
- Embedded PDB paths revealing the build environment
Avoid library boilerplate, common API names, and version strings shared by legitimate software, which generate false positives.
strings:
$mutex = "Global\\Zx7yQ_lock" wide
$cfgkey = "x0r_cfg_begin" ascii
$pdb = "C:\\build\\loader\\release\\loader.pdb"Defeating Simple Obfuscation
Many families XOR or otherwise lightly encode strings. If cleartext strings are sparse, look for the encoded form or the decoder routine.
You can compute the XOR-encoded bytes of a known plaintext and match those, or use YARA's xor modifier to match a string under any single-byte XOR key automatically.
strings:
// matches "http://" under any single-byte XOR key
$u = "http://" xor
// or a fixed key range
$k = "config" xor(0x01-0xff)Hunting with Hex Patterns
When strings are obfuscated but code is not, match byte patterns from the malware's own logic: a decryption stub, an unpacking loop, or a unique constant.
Disassemble the sample, find a distinctive instruction sequence, and translate the opcodes to a hex string. Wildcard the bytes that vary (addresses, immediates) so the pattern survives recompilation.
strings:
// XOR decrypt loop with wildcarded counter/address
$decrypt = { 8A ?? 34 ?? 88 ?? 4? 4? 75 ?? }Wildcards and Jumps in Practice
The art of hex hunting is choosing what to wildcard. Too rigid and a recompile breaks the rule; too loose and it matches everything.
- Wildcard relative offsets and immediates that the compiler changes
- Keep opcodes fixed, since the algorithm is stable
- Use jumps
[n-m]where instruction lengths vary
Aim for a pattern long enough to be unique (often 8+ meaningful bytes) but flexible where it must be.
strings:
$stub = { 55 8B EC 83 EC [1-4] E8 ?? ?? ?? ?? 33 C0 }Structural and PE Indicators
Static traits beyond raw bytes make strong, low-noise conditions. Using the pe module you can match:
- imphash — hash of the import table, often stable across a family's builds
- section names — custom packers add telltale sections
- specific imports — VirtualAllocEx + WriteProcessMemory + CreateRemoteThread signals injection
import "pe"
condition:
pe.imphash() == "4e3a9f..." or
for any s in pe.sections : ( s.name == ".x0rsec" )Entropy as a Signal
Packed or encrypted regions have high entropy. The math module measures it, letting you flag samples whose payload section looks encrypted, a hallmark of packers.
Entropy alone is noisy (compressed installers are also high-entropy), so combine it with other indicators rather than alerting on it by itself.
import "math"
condition:
math.entropy(0, filesize) >= 7.2 and $loader_stubCombining Indicators
The strongest rules require multiple independent indicators so no single coincidence triggers a match. Mix a string, a code pattern, and a structural trait.
This layered condition resists both false positives (all parts must agree) and evasion (the author must change several traits at once).
condition:
uint16(0) == 0x5A4D and
filesize < 800KB and
$mutex and
$decrypt and
pe.imports("kernel32.dll", "CreateRemoteThread")Naming, Meta, and Versioning
A hunting rule is only useful if others can trust and maintain it. Give each rule a clear, namespaced name and complete meta.
- Record the sample hashes the rule was built from
- Note the family, author, date, and a reference
- Bump a version field when you refine the logic
When the rule fires months later, this metadata tells the responder what it means and how much to trust it, turning a one-off hunt into durable, shareable detection.
meta:
family = "X0rLoader"
author = "ir-team"
date = "2026-06-04"
hash = "9f1c...e2"
version = "2"Test Before You Trust
Always validate a new rule against two corpora:
- True positives — every known sample of the family must match
- Goodware — a large clean set (system binaries, common apps) must NOT match
A single false positive on a Windows DLL can quarantine critical files across an estate. Run, count, review the misses and hits, then refine before deploying broadly.
yara -r family.yar /malware_corpus/ # expect all to hit
yara -r family.yar /clean_corpus/ # expect zero hitsQuick Check
Choose the most resilient indicator.
Recap
Practical YARA hunting, end to end:
- Extract ASCII and wide strings; keep durable artifacts (mutexes, config keys, PDB paths)
- Defeat light obfuscation with the xor modifier or encoded patterns
- Match code byte patterns (decrypt/unpack stubs) when strings are hidden
- Wildcard volatile bytes, keep opcodes fixed, use jumps for variable lengths
- Use PE imphash, sections, imports and entropy as structural signals
- Combine multiple indicators to resist false positives and evasion
- Always test against family and goodware corpora before deploying
Next: running these rules across an entire estate.
Frequently asked questions
Is the “Hunting with Strings and Hex” lesson free?
Yes — the full text of “Hunting with Strings and Hex” is free to read here on the web, and the Cyber Security Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Cyber Security Academy course, upgrade to CoddyKit PRO.
What will I learn in “Hunting with Strings and Hex”?
Matching malware artifacts. You practise Cyber Security Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Cyber Security Academy?
No prior experience is required. Cyber Security Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Hunting with Strings and Hex” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Cyber Security Academy lesson?
Yes. Every Cyber Security Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- What YARA Is For
- YARA Rule Syntax
- Hunting with Strings and Hex
- Scaling and Automating Scans