A Hands-On Walkthrough with Linux Ransomware Detection Logic
If you’ve ever opened a production-grade YARA rule from a vendor feed and tried to “just test it quickly,” you’ve probably hit the same wall I did. Rules like ReversingLabs Linux.Ransomware.GwisinLocker.yara and Linux.Ransomware.Helldown.yara are excellent, high-fidelity detections — but they are not built for casual testing.
Why you can’t “just edit a string” to test these rules
Both rules follow the same structure, and it’s worth understanding why before writing your own:
- They don’t match plain-text strings. Every
$stringin these rules is a raw hex byte pattern — disassembled x86/x86-64 machine code with wildcard bytes (??) standing in for values the malware author’s compiler filled in at build time (addresses, offsets, register-specific opcodes). - They require multiple patterns to match together. The
condition:block usesall of (...)across several pattern groups — for example, a key-initialization routine, a file-encryption routine, a file-discovery routine, and a process/VM-killing routine all have to be present at once. - They gate on file type. Both rules start with
uint32(0) == 0x464C457F, which checks that the first four bytes of the file are7F 45 4C 46— the ELF magic number. Feed it a.txtfile and the rule exits before it even looks at the strings.
So if you take one of these rules and try to trigger it by writing a text file containing GwisinLocker or Helldown, nothing happens. There’s no plain-text pattern to match, no ELF header, and none of the compiled-code fragments the condition logic actually requires. This is by design — it’s what makes the rule resistant to trivial evasion — but it also means you can’t validate your understanding of YARA syntax against it without a disassembler and a real (or reconstructed) malware sample.
The goal of this post is different: build a small, safe, your-own YARA rule that mimics the real rules’ structure (multiple required strings, hex patterns with wildcards, meta fields, boolean conditions) — and then deliberately craft a harmless test file that trips it. This gives you a repeatable way to learn and validate YARA mechanics without touching any live malware or reproducing anyone else’s detection logic.
Scope note: everything below creates inert files containing arbitrary bytes and detects them with a rule you write yourself. Nothing here executes code, exploits anything, or reproduces ReversingLabs’ actual signatures.
Step 1 — Install YARA
On Ubuntu:
|
|
This walkthrough was verified against YARA 4.5.0, the version currently shipped in Ubuntu’s repositories.
Step 2 — Write a custom test rule
Instead of trying to reverse-engineer someone else’s compiled-code signature, write a rule that exercises the same features — multiple required strings, a hex pattern with a wildcard byte, and a compound condition — using markers you control.
Save this as test_rules.yar:
|
|
A few things worth noticing, since they mirror the design of the real rules:
all of themrequires both the ASCII string and the hex pattern to be present — just like the real rules require multiple pattern groups to match simultaneously.- The
??wildcard in the hex pattern matches any single byte at that position, the same mechanism ReversingLabs uses to skip over compiler-generated bytes that vary between builds. - The
metablock clearly labels the rule as a demo so it’s never mistaken for a real detection if it ends up in a shared rule set.
Check the syntax compiles cleanly against something harmless before going further:
|
|
No output means no match — which is correct, since /etc/hostname contains neither marker.
Step 3 — Craft test files that trigger the rule
Now build two small files whose only purpose is to contain the exact bytes the rule looks for. This is the injection step, corrected so the commands and their byte-level output match exactly.
A quick but important gotcha: on Ubuntu, /bin/sh is dash, not bash, and dash’s built-in echo does not reliably expand -e/\x hex escapes the way bash’s does. Run these either in a bash shell (bash or a script starting with #!/bin/bash) or use printf with the full path (/usr/bin/printf) — otherwise you’ll end up with the literal characters \x20 written into your file instead of an actual space byte.
GwisinLocker-style test file
|
|
Verify the bytes with od (or xxd/hexdump -C if installed):
|
|
That’s GwisinLockerTest ransom\0lock — 28 bytes total, matching exactly what the two echo commands wrote.
Helldown-style test file
|
|
|
|
That’s HelldownTest ransom\0team — 20 bytes, again matching the commands exactly.
Step 4 — Run YARA against the test files
|
|
Expected output:
|
|
And as a sanity check, confirm a clean file produces no output:
|
|
(No output is the correct, expected result — a false positive here would mean the rule logic is broken.)
Key takeaways
- Vendor YARA rules built from disassembled code can’t be “tested” by editing plain strings. If a rule’s
strings:section is all hex bytes, only hex bytes (matching the wildcard positions) will trigger it. - The
??wildcard and compoundall of (...)/any of (...)conditions are the mechanics to practice, not the specific opcodes of any one malware family. Build your own rule that uses the same mechanics against your own markers. - Shell choice matters when crafting binary test data.
dashandbashhandleecho -e/ndifferently; useprintfor explicitly invoke bash if your test bytes aren’t showing up as expected. - Always verify byte-for-byte with
od/xxd/hexdump -Cbefore assuming a YARA miss is a rule problem rather than a file-creation problem — in practice, most “the rule doesn’t work” issues turn out to be this.
With this workflow, you can iterate on YARA syntax, wildcard placement, and condition logic quickly and safely, then bring the same understanding to reading (not rewriting) real-world rules like ReversingLabs’ when you need to evaluate what they detect and why.