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 $string in 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 uses all 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 are 7F 45 4C 46 — the ELF magic number. Feed it a .txt file 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:

1
2
3
sudo apt update
sudo apt install yara
yara --version

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
rule Test_Demo_GwisinLocker_Marker : test_only demo
{
    meta:
        author      = "blog-demo"
        purpose     = "EDUCATIONAL TEST RULE ONLY - does not detect real GwisinLocker ransomware"
        description = "Matches a synthetic marker string plus a hex pattern, for practising the YARA testing workflow"

    strings:
        $ascii_marker = "GwisinLockerTest" ascii
        $hex_marker   = { 72 61 6e 73 6f 6d ?? 6c 6f 63 6b }  // " ransom" + any byte + "lock"

    condition:
        all of them
}

rule Test_Demo_Helldown_Marker : test_only demo
{
    meta:
        author      = "blog-demo"
        purpose     = "EDUCATIONAL TEST RULE ONLY - does not detect real Helldown ransomware"
        description = "Matches a synthetic marker string plus a hex pattern, for practising the YARA testing workflow"

    strings:
        $ascii_marker = "HelldownTest" ascii
        $hex_marker   = { 72 61 6e 73 6f 6d ?? 74 65 61 6d }  // " ransom" + any byte + "team"

    condition:
        all of them
}

A few things worth noticing, since they mirror the design of the real rules:

  • all of them requires 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 meta block 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:

1
yara test_rules.yar /etc/hostname

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

1
2
echo -n "GwisinLockerTest" | sudo tee vm_agent.bin > /dev/null
echo -ne '\x20\x72\x61\x6e\x73\x6f\x6d\x00\x6c\x6f\x63\x6b' | sudo tee -a vm_agent.bin > /dev/null

Verify the bytes with od (or xxd/hexdump -C if installed):

1
2
3
4
5
$ od -An -tx1 -c vm_agent.bin
 47  77  69  73  69  6e  4c  6f  63  6b  65  72  54  65  73  74
  G   w   i   s   i   n   L   o   c   k   e   r   T   e   s   t
 20  72  61  6e  73  6f  6d  00  6c  6f  63  6b
      r   a   n   s   o   m  \0   l   o   c   k

That’s GwisinLockerTest ransom\0lock — 28 bytes total, matching exactly what the two echo commands wrote.

Helldown-style test file

1
2
echo -n "HelldownTest" | sudo tee init_exec_lockdown.sh > /dev/null
echo -ne '\x20\x72\x61\x6e\x73\x6f\x6d\x00\x74\x65\x61\x6d' | sudo tee -a init_exec_lockdown.sh > /dev/null
1
2
3
4
5
$ od -An -tx1 -c init_exec_lockdown.sh
 48  65  6c  6c  64  6f  77  6e  54  65  73  74  20  72  61  6e
  H   e   l   l   d   o   w   n   T   e   s   t       r   a   n
 73  6f  6d  00  74  65  61  6d
  s   o   m  \0   t   e   a   m

That’s HelldownTest ransom\0team — 20 bytes, again matching the commands exactly.

Step 4 — Run YARA against the test files

1
2
yara test_rules.yar vm_agent.bin
yara test_rules.yar init_exec_lockdown.sh

Expected output:

1
2
Test_Demo_GwisinLocker_Marker vm_agent.bin
Test_Demo_Helldown_Marker init_exec_lockdown.sh

And as a sanity check, confirm a clean file produces no output:

1
2
echo "just a normal file with no ransomware markers" > clean.txt
yara test_rules.yar clean.txt

(No output is the correct, expected result — a false positive here would mean the rule logic is broken.)

Key takeaways

  1. 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.
  2. The ?? wildcard and compound all 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.
  3. Shell choice matters when crafting binary test data. dash and bash handle echo -e/n differently; use printf or explicitly invoke bash if your test bytes aren’t showing up as expected.
  4. Always verify byte-for-byte with od/xxd/hexdump -C before 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.