<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Malware-Development on</title><link>https://mcculley.tech/tags/malware-development/</link><description>Recent content in Malware-Development on</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 20 May 2026 00:00:00 -0500</lastBuildDate><atom:link href="https://mcculley.tech/tags/malware-development/index.xml" rel="self" type="application/rss+xml"/><item><title>malware development studies (pt. 1)</title><link>https://mcculley.tech/posts/malware-development-studies-pt-1/</link><pubDate>Wed, 20 May 2026 00:00:00 -0500</pubDate><guid>https://mcculley.tech/posts/malware-development-studies-pt-1/</guid><description>&lt;p&gt;I&amp;rsquo;ve been studying malware development recently in an effort to understand Windows at a low level and begin working more on that side of offensive operations. It&amp;rsquo;s a shift from my typical world of network penetration testing that I&amp;rsquo;ve been living in, and has necessitated me using 100% of my brain. As a way of keeping myself motivated and solidifying my understanding I wanted to write up some blog posts as I&amp;rsquo;ve moved along in my coursework.&lt;/p&gt;</description><content>&lt;p&gt;I&amp;rsquo;ve been studying malware development recently in an effort to understand Windows at a low level and begin working more on that side of offensive operations. It&amp;rsquo;s a shift from my typical world of network penetration testing that I&amp;rsquo;ve been living in, and has necessitated me using 100% of my brain. As a way of keeping myself motivated and solidifying my understanding I wanted to write up some blog posts as I&amp;rsquo;ve moved along in my coursework.&lt;/p&gt;
&lt;h2 id="pe-structure"&gt;pe structure&lt;/h2&gt;
&lt;p&gt;The Portable Executable (PE) file format is crucial to understand for this work. PE files are native executables for Windows (think EXEs and DLLs). Breaking down the PE structure allows us to start talking about payload placement and permissions on sections of the PE where data is stored (more on that later). Here&amp;rsquo;s a few of the parts of a PE structure worth noting (non exhaustive for brevity):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DOS Header - first part of a PE. It&amp;rsquo;s a struct that first contains the magic bytes &amp;lsquo;MZ&amp;rsquo; letting the system know we&amp;rsquo;re working with a PE file.&lt;/li&gt;
&lt;li&gt;Data Directories - An array of structs that each contain a &lt;code&gt;Size&lt;/code&gt; and &lt;code&gt;VirtualAddress&lt;/code&gt; that point to tables.&lt;/li&gt;
&lt;li&gt;Sections - PE content that I&amp;rsquo;ve worked the most with so far. This contains things like the &lt;code&gt;.text&lt;/code&gt;, &lt;code&gt;.rsrc&lt;/code&gt;, &lt;code&gt;.data&lt;/code&gt;, and &lt;code&gt;.rdata&lt;/code&gt; sections. Each has its own permissions which has interesting implications for payload placement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One way that I&amp;rsquo;ve thought about PEs is that it&amp;rsquo;s like a low level database where headers are like metadata and schema, data directories act as an index/lookup table, with each entry pointing to specific &amp;ldquo;tables&amp;rdquo; of information scattered throughout the sections. The sections themselves are the actual data storage.&lt;/p&gt;
&lt;p&gt;The windows loader doesn&amp;rsquo;t read the file linearly but instead follows pointers and offsets to data that gets placed into memory.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://mcculley.tech/posts/malware-development-studies-pt-1/pe-structure.png" alt="PE file layout diagram showing DOS Header, DOS Stub, NT Headers (PE signature, File Header, Optional Header), Section Table, and Section 1 through Section n stacked vertically"&gt;&lt;/p&gt;
&lt;h2 id="win32api"&gt;win32api&lt;/h2&gt;
&lt;p&gt;Inside the PE are calls to the Win32API. This is what lets programs interact with Windows as an operating system both in userland and - through layers of DLLs - in the kernel space. Win32API is one of those &amp;lsquo;I&amp;rsquo;m always going to be learning&amp;rsquo; type things. There are a ton of data types defined by the windows api and to add to the complexity some of the windows API calls are undocumented (because proprietary software).&lt;/p&gt;
&lt;p&gt;Something I&amp;rsquo;ve learned poking at the windows api and reading older malware development docs is that it&amp;rsquo;s much tougher to successfully bypass the windows api and make direct syscalls than it used to be. EDR vendors have hooks into &lt;code&gt;ntdll.dll&lt;/code&gt;, meaning they have a &lt;code&gt;jmp&lt;/code&gt; instruction to intercept syscalls made through legitimate means. Direct syscalls are checked to see if they come from legitimate sources like &lt;code&gt;ntdll.dll&lt;/code&gt;. When the return address isn&amp;rsquo;t within &lt;code&gt;ntdll.dll&lt;/code&gt; it raises suspicion.&lt;/p&gt;
&lt;p&gt;As an example, I can walkthrough a simple win32api call - MessageBoxA. Per the &lt;a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa"&gt;MSDN&lt;/a&gt; here&amp;rsquo;s the call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MessageBoxA&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [in, optional] HWND hWnd,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [in, optional] LPCSTR lpText,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [in, optional] LPCSTR lpCaption,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [in] UINT uType
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first thing I do when I see a win32api call is make sure I understand the datatypes fed into the call. In this example we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HWND&lt;/code&gt; - Handle (like opening a door to an object) to an &amp;lsquo;owner window&amp;rsquo; in the graphical sense. In this instance it&amp;rsquo;s like a parent process but for graphical windows.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LPCSTR&lt;/code&gt; - Stands for Long Pointer to Const String. an immutable character string that will display the message in the window (&lt;code&gt;lpText&lt;/code&gt;) and the title (&lt;code&gt;lpCaption&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UINT&lt;/code&gt; - Unsigned int that will display the user&amp;rsquo;s options they can click.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With all that in mind we can use the following code to display a simple text box to the user:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#include&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LPCSTR lpText &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;trashpanda was here&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LPCSTR lpCaption &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;trashpanda&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;MessageBoxA&lt;/span&gt;(NULL, lpText, lpCaption, MB_OK);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;NULL&lt;/code&gt; means that there&amp;rsquo;s no parent window. &lt;code&gt;MB_OK&lt;/code&gt; displays only an &lt;code&gt;OK&lt;/code&gt; option for the user to click. It&amp;rsquo;ll display the following when run:&lt;/p&gt;
&lt;div style="display:flex; justify-content:center;"&gt;
&lt;img src="messageboxa.png" alt='Windows message box titled trashpanda with body text "trashpanda was here" and an OK button' /&gt;
&lt;/div&gt;
&lt;p&gt;Neat! Most win32api calls are not this simple. Sometimes they contain structs within structs or additional data types that are oddly named or a type that I&amp;rsquo;ve never seen before. It&amp;rsquo;s a constant learning process. One of the neat things that we could do with the message box is create trollware - where things like &lt;code&gt;OK&lt;/code&gt; don&amp;rsquo;t close the window. Funny to think about - haven&amp;rsquo;t done it yet.&lt;/p&gt;
&lt;h2 id="payload-placement"&gt;payload placement&lt;/h2&gt;
&lt;p&gt;In the context of the PE structure so far I&amp;rsquo;ve examined the following locations for payload placement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.text&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.rdata&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.rsrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;.text&lt;/code&gt; has executable permissions for shellcode stored in it. &lt;code&gt;.rsrc&lt;/code&gt; can store larger payloads since it&amp;rsquo;s technically stored by reference inside the PE. &lt;code&gt;.data&lt;/code&gt; and &lt;code&gt;.rdata&lt;/code&gt; allow for storing the shellcode in the PE although you&amp;rsquo;ll need to set executable permission in &lt;code&gt;.data&lt;/code&gt; specifically. The downside to &lt;code&gt;.text&lt;/code&gt;, &lt;code&gt;.data&lt;/code&gt;, and &lt;code&gt;.rdata&lt;/code&gt; is a storage constraint. Larger payloads aren&amp;rsquo;t going to fit into these sections, making it a good landing place for loaders or stagers (Although you could also just write a full fat exe to do the same work). Another consideration is detection noise. Storing payloads in the &lt;code&gt;.data&lt;/code&gt; or &lt;code&gt;.rdata&lt;/code&gt; is the noisiest. Since &lt;code&gt;.text&lt;/code&gt; contains executable code it&amp;rsquo;s less suspicious but also we&amp;rsquo;re talking about malware so the normal opsec considerations apply there.&lt;/p&gt;
&lt;h2 id="payload-encryption"&gt;payload encryption&lt;/h2&gt;
&lt;p&gt;Encrypting payloads requires walking a fine line. Encryption helps mask your payload from static detection but can increase entropy which is also a detection risk. In my studies I&amp;rsquo;ve looked at encrypting via &lt;code&gt;XOR&lt;/code&gt;, &lt;code&gt;RC4&lt;/code&gt;, and &lt;code&gt;AES&lt;/code&gt;. &lt;code&gt;XOR&lt;/code&gt; is the simplest route. While not an encryption algorithm technically (it&amp;rsquo;s an operation that stream ciphers use) the main idea is that it flips bits according to a key. Performing the XOR operation with the same key against the encrypted payload will decrypt it (much like &lt;code&gt;RC4&lt;/code&gt;, except you have to reinitialize the context in &lt;code&gt;RC4&lt;/code&gt;). Playing around with simple &lt;code&gt;XOR&lt;/code&gt; encryption (re &lt;code&gt;msfvenom&lt;/code&gt; payloads) - it got blown away by defender. The same cannot be said for &lt;code&gt;RC4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://mcculley.tech/posts/malware-development-studies-pt-1/xor-fail.png" alt="Windows Defender “Threats found” toast notification after running an XOR-encrypted msfvenom payload"&gt;
Unsuccessful simple XOR attempt&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RC4&lt;/code&gt; is also a symmetric stream cipher and unlike &lt;code&gt;XOR&lt;/code&gt; I actually had some success with &lt;code&gt;RC4&lt;/code&gt; and not just having the encrypted payload sitting on disk but also printing the shellcode to stdout! That confirms that the decryption works and evades detection which is a precursor to execution. Both a more manual RC4 method as well as using the WinAPI call &lt;code&gt;SystemFunction032&lt;/code&gt; allowed for the payload to sit on disk and print to stdout.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://mcculley.tech/posts/malware-development-studies-pt-1/rc4-success.png" alt="Terminal showing RC4-decrypted shellcode hex bytes printed to stdout with Windows Defender still enabled in the background"&gt;
Success with RC4!&lt;/p&gt;
&lt;p&gt;AES is a block cipher and because of that the data to be encrypted needs to be in blocks of 16 bytes. If it&amp;rsquo;s not, then padding is required to make it work. AES also involves modes like CBC, ECB, etc. I don&amp;rsquo;t want to go too deep into the weeds on specifics. What I learned is that the easiest way to perform AES encryption is through the bcrypt library in windows. The code to perform it followed a few steps and was significantly more complex than RC4 or XOR. AES also succeeded in surviving on disk and printing to stdout:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://mcculley.tech/posts/malware-development-studies-pt-1/aes-success.png" alt="Terminal showing AES-decrypted shellcode hex bytes printed to stdout with Windows Defender still enabled in the background"&gt;&lt;/p&gt;
&lt;h2 id="payload-obfuscation"&gt;payload obfuscation&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a lot of different ways to obfuscate a payload and they all follow a similar path. First you write a function that converts your shellcode into chunks of whatever format you want (ie IPv4) and store it in an array. You then take your fully obfuscated shellcode and place it into a loader to be deobfuscated in a separate program. Some EDRs may see storage of a large amount of IPv4 addresses or whatever else in a PE as suspicious. With your shellcode stored in an obfuscated manner, you need to include a way to deobfuscate that shellcode in your malware. The upside is that Windows ships ways to deobfuscate some formats into bytes (ie &lt;code&gt;RtlIpv4StringToAddressA&lt;/code&gt;). This means that because it&amp;rsquo;s a legitimate windows call performing the deobfuscation, your shellcode has a higher chance of survival. But even with that in mind, if the shellcode is well signatured EDRs may blow up your process. This also can burn you since certain EDRs will run your PE in a sandbox and quarantine/ delete it if they see raw shellcode.&lt;/p&gt;
&lt;p&gt;Although obfuscation is weak by itself, it can actually help to &lt;em&gt;lower&lt;/em&gt; entropy created by encryption. Encrypting a payload and then obfuscating it gives the payload a good chance of survival on disk. Note that it&amp;rsquo;s not a catch all. There&amp;rsquo;s a good chance it blows up even with encryption and obfuscation due to sandbox analysis.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;conclusion&lt;/h2&gt;
&lt;p&gt;Working with C is something that I&amp;rsquo;m still getting used to, but I&amp;rsquo;m starting to grasp some of the ideas about using it in conjunction with the Win32API. I just have to keep telling myself that C treats everything like numbers and data types are contracts with the compiler about how to treat those numbers. An &lt;code&gt;int&lt;/code&gt; is a number that&amp;rsquo;s an integer. A &lt;code&gt;char&lt;/code&gt; is a number that&amp;rsquo;s a character. A pointer is a number that has a job to point to an address in memory. It&amp;rsquo;s different than the Fischer-Price Python world I&amp;rsquo;m used to, but the control is worth the effort. Everything to this point has been malware fundamentals. Shellcode that lives in a PE and needs to avoid detection. After I finish local payload execution (which may or may not survive stock Windows Defender - we&amp;rsquo;ll see) I&amp;rsquo;ll move onto the more advanced techniques like network loaders and living in memory. That&amp;rsquo;s where the real wizardry begins.&lt;/p&gt;</content></item></channel></rss>