<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>HYCU on MangoGeek</title>
    <link>https://blog.mangogeek.in/tags/hycu/</link>
    <description>Recent content in HYCU on MangoGeek</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 26 Jul 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://blog.mangogeek.in/tags/hycu/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Fake Custom Yara Rule</title>
      <link>https://blog.mangogeek.in/posts/writing-and-testing-yara-rules-for-linux-ransomware/</link>
      <pubDate>Sun, 26 Jul 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.mangogeek.in/posts/writing-and-testing-yara-rules-for-linux-ransomware/</guid>
      <description>Injecting fake custom yara rules for testing</description>
      <content:encoded><![CDATA[<h1 id="a-hands-on-walkthrough-with-linux-ransomware-detection-logic">A Hands-On Walkthrough with Linux Ransomware Detection Logic</h1>
<p>If you&rsquo;ve ever opened a production-grade YARA rule from a vendor feed and tried to &ldquo;just test it quickly,&rdquo; you&rsquo;ve probably hit the same wall I did. Rules like <a href="https://github.com/reversinglabs/reversinglabs-yara-rules/blob/develop/yara/ransomware/Linux.Ransomware.GwisinLocker.yara"><strong>ReversingLabs</strong> <code>Linux.Ransomware.GwisinLocker.yara</code></a> and <a href="https://github.com/reversinglabs/reversinglabs-yara-rules/blob/develop/yara/ransomware/Linux.Ransomware.Helldown.yara"><code>Linux.Ransomware.Helldown.yara</code></a> are excellent, high-fidelity detections — but they are not built for casual testing.</p>
<h1 id="why-you-cant-just-edit-a-string-to-test-these-rules">Why you can&rsquo;t &ldquo;just edit a string&rdquo; to test these rules</h1>
<p>Both rules follow the same structure, and it&rsquo;s worth understanding <em>why</em> before writing your own:</p>
<ul>
<li><strong>They don&rsquo;t match plain-text strings.</strong> Every <code>$string</code> in these rules is a raw hex byte pattern — disassembled x86/x86-64 machine code with wildcard bytes (<code>??</code>) standing in for values the malware author&rsquo;s compiler filled in at build time (addresses, offsets, register-specific opcodes).</li>
<li><strong>They require multiple patterns to match together.</strong> The <code>condition:</code> block uses <code>all of (...)</code> 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.</li>
<li><strong>They gate on file type.</strong> Both rules start with <code>uint32(0) == 0x464C457F</code>, which checks that the first four bytes of the file are <code>7F 45 4C 46</code> — the ELF magic number. Feed it a <code>.txt</code> file and the rule exits before it even looks at the strings.</li>
</ul>
<p>So if you take one of these rules and try to trigger it by writing a text file containing <strong>GwisinLocker</strong> or <strong>Helldown</strong>, nothing happens. There&rsquo;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&rsquo;s what makes the rule resistant to trivial evasion — but it also means you can&rsquo;t validate your understanding of YARA syntax against it without a disassembler and a real (or reconstructed) malware sample.</p>
<p><strong>The goal of this post is different: build a small, safe, <em>your-own</em> YARA rule that mimics the real rules&rsquo; structure (multiple required strings, hex patterns with wildcards, <code>meta</code> fields, boolean conditions) — and then deliberately craft a harmless test file that trips it.</strong> This gives you a repeatable way to learn and validate YARA mechanics without touching any live malware or reproducing anyone else&rsquo;s detection logic.</p>
<blockquote>
<p><strong>Scope note:</strong> 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&rsquo; actual signatures.</p></blockquote>
<h3 id="step-1--install-yara">Step 1 — Install YARA</h3>
<p>On Ubuntu:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo apt update
</span></span><span class="line"><span class="cl">sudo apt install yara
</span></span><span class="line"><span class="cl">yara --version
</span></span></code></pre></td></tr></table>
</div>
</div><p>This walkthrough was verified against YARA <strong>4.5.0</strong>, the version currently shipped in Ubuntu&rsquo;s repositories.</p>
<h3 id="step-2--write-a-custom-test-rule">Step 2 — Write a custom test rule</h3>
<p>Instead of trying to reverse-engineer someone else&rsquo;s compiled-code signature, write a rule that exercises the <em>same features</em> — multiple required strings, a hex pattern with a wildcard byte, and a compound condition — using markers you control.</p>
<p>Save this as <code>test_rules.yar</code>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">rule Test_Demo_GwisinLocker_Marker : test_only demo
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl">    meta:
</span></span><span class="line"><span class="cl">        <span class="nv">author</span>      <span class="o">=</span> <span class="s2">&#34;blog-demo&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">purpose</span>     <span class="o">=</span> <span class="s2">&#34;EDUCATIONAL TEST RULE ONLY - does not detect real GwisinLocker ransomware&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">description</span> <span class="o">=</span> <span class="s2">&#34;Matches a synthetic marker string plus a hex pattern, for practising the YARA testing workflow&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    strings:
</span></span><span class="line"><span class="cl">        <span class="nv">$ascii_marker</span> <span class="o">=</span> <span class="s2">&#34;GwisinLockerTest&#34;</span> ascii
</span></span><span class="line"><span class="cl">        <span class="nv">$hex_marker</span>   <span class="o">=</span> <span class="o">{</span> <span class="m">72</span> <span class="m">61</span> 6e <span class="m">73</span> 6f 6d ?? 6c 6f <span class="m">63</span> 6b <span class="o">}</span>  // <span class="s2">&#34; ransom&#34;</span> + any byte + <span class="s2">&#34;lock&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    condition:
</span></span><span class="line"><span class="cl">        all of them
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">rule Test_Demo_Helldown_Marker : test_only demo
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl">    meta:
</span></span><span class="line"><span class="cl">        <span class="nv">author</span>      <span class="o">=</span> <span class="s2">&#34;blog-demo&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">purpose</span>     <span class="o">=</span> <span class="s2">&#34;EDUCATIONAL TEST RULE ONLY - does not detect real Helldown ransomware&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">description</span> <span class="o">=</span> <span class="s2">&#34;Matches a synthetic marker string plus a hex pattern, for practising the YARA testing workflow&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    strings:
</span></span><span class="line"><span class="cl">        <span class="nv">$ascii_marker</span> <span class="o">=</span> <span class="s2">&#34;HelldownTest&#34;</span> ascii
</span></span><span class="line"><span class="cl">        <span class="nv">$hex_marker</span>   <span class="o">=</span> <span class="o">{</span> <span class="m">72</span> <span class="m">61</span> 6e <span class="m">73</span> 6f 6d ?? <span class="m">74</span> <span class="m">65</span> <span class="m">61</span> 6d <span class="o">}</span>  // <span class="s2">&#34; ransom&#34;</span> + any byte + <span class="s2">&#34;team&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    condition:
</span></span><span class="line"><span class="cl">        all of them
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>A few things worth noticing, since they mirror the design of the real rules:</p>
<ul>
<li><strong><code>all of them</code></strong> requires both the ASCII string <em>and</em> the hex pattern to be present — just like the real rules require multiple pattern groups to match simultaneously.</li>
<li><strong>The <code>??</code> wildcard</strong> in the hex pattern matches <em>any single byte</em> at that position, the same mechanism ReversingLabs uses to skip over compiler-generated bytes that vary between builds.</li>
<li><strong>The <code>meta</code> block</strong> clearly labels the rule as a demo so it&rsquo;s never mistaken for a real detection if it ends up in a shared rule set.</li>
</ul>
<p>Check the syntax compiles cleanly against something harmless before going further:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yara test_rules.yar /etc/hostname
</span></span></code></pre></td></tr></table>
</div>
</div><p>No output means no match — which is correct, since <code>/etc/hostname</code> contains neither marker.</p>
<h3 id="step-3--craft-test-files-that-trigger-the-rule">Step 3 — Craft test files that trigger the rule</h3>
<p>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.</p>
<p>A quick but important gotcha: on Ubuntu, <code>/bin/sh</code> is <strong>dash</strong>, not bash, and dash&rsquo;s built-in <code>echo</code> does not reliably expand <code>-e</code>/<code>\x</code> hex escapes the way bash&rsquo;s does. Run these either in a bash shell (<code>bash</code> or a script starting with <code>#!/bin/bash</code>) or use <code>printf</code> with the full path (<code>/usr/bin/printf</code>) — otherwise you&rsquo;ll end up with the literal characters <code>\x20</code> written into your file instead of an actual space byte.</p>
<h4 id="gwisinlocker-style-test-file">GwisinLocker-style test file</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> -n <span class="s2">&#34;GwisinLockerTest&#34;</span> <span class="p">|</span> sudo tee vm_agent.bin &gt; /dev/null
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> -ne <span class="s1">&#39;\x20\x72\x61\x6e\x73\x6f\x6d\x00\x6c\x6f\x63\x6b&#39;</span> <span class="p">|</span> sudo tee -a vm_agent.bin &gt; /dev/null
</span></span></code></pre></td></tr></table>
</div>
</div><p>Verify the bytes with <code>od</code> (or <code>xxd</code>/<code>hexdump -C</code> if installed):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ od -An -tx1 -c vm_agent.bin
</span></span><span class="line"><span class="cl"> <span class="m">47</span>  <span class="m">77</span>  <span class="m">69</span>  <span class="m">73</span>  <span class="m">69</span>  6e  4c  6f  <span class="m">63</span>  6b  <span class="m">65</span>  <span class="m">72</span>  <span class="m">54</span>  <span class="m">65</span>  <span class="m">73</span>  <span class="m">74</span>
</span></span><span class="line"><span class="cl">  G   w   i   s   i   n   L   o   c   k   e   r   T   e   s   t
</span></span><span class="line"><span class="cl"> <span class="m">20</span>  <span class="m">72</span>  <span class="m">61</span>  6e  <span class="m">73</span>  6f  6d  <span class="m">00</span>  6c  6f  <span class="m">63</span>  6b
</span></span><span class="line"><span class="cl">      r   a   n   s   o   m  <span class="se">\0</span>   l   o   c   k
</span></span></code></pre></td></tr></table>
</div>
</div><p>That&rsquo;s <code>GwisinLockerTest ransom\0lock</code> — 28 bytes total, matching exactly what the two <code>echo</code> commands wrote.</p>
<h4 id="helldown-style-test-file">Helldown-style test file</h4>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> -n <span class="s2">&#34;HelldownTest&#34;</span> <span class="p">|</span> sudo tee init_exec_lockdown.sh &gt; /dev/null
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> -ne <span class="s1">&#39;\x20\x72\x61\x6e\x73\x6f\x6d\x00\x74\x65\x61\x6d&#39;</span> <span class="p">|</span> sudo tee -a init_exec_lockdown.sh &gt; /dev/null
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">$ od -An -tx1 -c init_exec_lockdown.sh
</span></span><span class="line"><span class="cl"> <span class="m">48</span>  <span class="m">65</span>  6c  6c  <span class="m">64</span>  6f  <span class="m">77</span>  6e  <span class="m">54</span>  <span class="m">65</span>  <span class="m">73</span>  <span class="m">74</span>  <span class="m">20</span>  <span class="m">72</span>  <span class="m">61</span>  6e
</span></span><span class="line"><span class="cl">  H   e   l   l   d   o   w   n   T   e   s   t       r   a   n
</span></span><span class="line"><span class="cl"> <span class="m">73</span>  6f  6d  <span class="m">00</span>  <span class="m">74</span>  <span class="m">65</span>  <span class="m">61</span>  6d
</span></span><span class="line"><span class="cl">  s   o   m  <span class="se">\0</span>   t   e   a   m
</span></span></code></pre></td></tr></table>
</div>
</div><p>That&rsquo;s <code>HelldownTest ransom\0team</code> — 20 bytes, again matching the commands exactly.</p>
<h3 id="step-4--run-yara-against-the-test-files">Step 4 — Run YARA against the test files</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yara test_rules.yar vm_agent.bin
</span></span><span class="line"><span class="cl">yara test_rules.yar init_exec_lockdown.sh
</span></span></code></pre></td></tr></table>
</div>
</div><p>Expected output:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Test_Demo_GwisinLocker_Marker vm_agent.bin
</span></span><span class="line"><span class="cl">Test_Demo_Helldown_Marker init_exec_lockdown.sh
</span></span></code></pre></td></tr></table>
</div>
</div><p>And as a sanity check, confirm a clean file produces <strong>no</strong> output:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;just a normal file with no ransomware markers&#34;</span> &gt; clean.txt
</span></span><span class="line"><span class="cl">yara test_rules.yar clean.txt
</span></span></code></pre></td></tr></table>
</div>
</div><p>(No output is the correct, expected result — a false positive here would mean the rule logic is broken.)</p>
<h1 id="key-takeaways">Key takeaways</h1>
<ol>
<li><strong>Vendor YARA rules built from disassembled code can&rsquo;t be &ldquo;tested&rdquo; by editing plain strings.</strong> If a rule&rsquo;s <code>strings:</code> section is all hex bytes, only hex bytes (matching the wildcard positions) will trigger it.</li>
<li><strong>The <code>??</code> wildcard and compound <code>all of (...)</code> / <code>any of (...)</code> conditions are the mechanics to practice</strong>, not the specific opcodes of any one malware family. Build your own rule that uses the same mechanics against your own markers.</li>
<li><strong>Shell choice matters when crafting binary test data.</strong> <code>dash</code> and <code>bash</code> handle <code>echo -e</code>/<code>n</code> differently; use <code>printf</code> or explicitly invoke bash if your test bytes aren&rsquo;t showing up as expected.</li>
<li><strong>Always verify byte-for-byte with <code>od</code>/<code>xxd</code>/<code>hexdump -C</code></strong> before assuming a YARA miss is a rule problem rather than a file-creation problem — in practice, most &ldquo;the rule doesn&rsquo;t work&rdquo; issues turn out to be this.</li>
</ol>
<p>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&rsquo; when you need to evaluate what they detect and why.</p>
<hr>
]]></content:encoded>
    </item>
  </channel>
</rss>
