This document walks each obfuscation technique in malware.bat. Read this with
detection-and-defense.md open — every technique
here is judged with a "What this actually defeats" / "What it doesn't" line so
you don't walk away thinking batch tricks beat AMSI.
TL;DR: Every layer here operates on the batch / dropper stage. The moment PowerShell decodes the base64
-EncodedCommand, AMSI and ScriptBlock Logging see the plaintext payload regardless of what the batch did.
if "%~1"=="" set "LEVEL=0" & goto :init
if "%LEVEL%"=="1" goto :real_start
goto :confuse_trace
:init
set "LEVEL=1"
call "%~f0" dummy_param
exit /bThe script re-invokes itself with a sentinel argument so the "real" entry point
is reached on the second pass. Naive static analyzers that only follow the
first label sequence see a benign confuse_trace exit and stop.
- Defeats: Trivial line-by-line reading; some signature scanners that fingerprint the first few labels.
- Doesn't defeat: Anything that actually executes the script (cmd.exe-instrumented sandboxes), Sysmon EID 1 (records both invocations), AMSI on the downstream PowerShell child.
set "PATH_ORIG=%PATH%"
set "PATH=%TEMP%;%PATH%"Temporarily prepends %TEMP% to PATH. The intent is to confuse tools that
resolve binary paths during analysis.
- Defeats: Almost nothing in 2026. Defenders resolve binaries by image path
via ETW / Sysmon, not by
PATHlookup at analysis time. - Doesn't defeat: Anything monitoring
ImageLoadedorProcessCreateevents.
set "str_pool=powershell-encodedCommandNonInteractive"
set "_cmd1=!str_pool:~0,5!"
set "_cmd2=!str_pool:~5,6!"
..."powershell" and the flag names never appear as contiguous strings in the
file. Pieces are spliced out of a pool and reassembled at runtime.
- Defeats:
grep-based hunting and very old AV signatures that look for the literal tokenpowershell -EncodedCommand. - Doesn't defeat: Yara rules with
nocaseor wide patterns, behavioural rules that flagcmd.exespawningpowershell.exe(str_poolitself contains the giveaway).
Note: in this script, exec_cmd is decoy output — the real execution uses
the hardcoded c_1 / c_2 strings. The substring layer exists to draw the
analyst's eye away.
set "g1=%RANDOM%%RANDOM%"
set "g2=%RANDOM%%RANDOM%"
if %g1% NEQ %g2% ( ...real path... ) else ( exit /b )Two consecutive %RANDOM%%RANDOM% reads should virtually never match. Some
naive emulators stub %RANDOM% to a constant — those exit the script
immediately and never see the payload.
- Defeats: Emulators that constant-stub
%RANDOM%. - Doesn't defeat: Real cmd.exe execution, modern sandbox emulators (which use proper RNG), AMSI on the downstream PowerShell.
if %time:~7,1% LSS 5 ( ...path A... ) else ( ...path B... )Two execution paths that produce identical #part1/#part2/#part3 values but
exercise different variables. Pure control-flow obfuscation.
- Defeats: Coverage-based fuzzers that expect one branch.
- Doesn't defeat: Anything looking at the final result.
These functions are defined and called in :init_char_map / :init_math_funcs
but their outputs are never used in the real payload-assembly path. Their job
is to make :strrev, :StrLen, and the math aliases look like load-bearing
machinery to a static reader.
- Defeats: Analysts who follow every function definition expecting it to matter.
- Doesn't defeat: Anyone who traces from
:execute_payloadbackwards.
The honest lesson here: real-world droppers also pad heavily with decoy routines. Time spent in dead code is the analyst-economics goal.
set "p1=cABvAHcAZQByAHMAaABlAGwAbAAgAC0ATgBvAFAAIAAtAE"
...
set "layer1_A=p1" :: slot key -> variable name
...
for /L %%i in (0,1,7) do (
set "current=!seq:~%%i,1!"
for /f "tokens=1,2 delims==" %%a in ('set layer1_!current!') do (
set "part_value=!%%b!"
set "final_payload=!final_payload!!part_value!"
)
)Each base64 fragment is named p1..p8. A second variable layer maps slot keys
A..H to the part names. The reassembly loop walks seq=ABCDEFGH, resolves
layer1_<key> to a name, then dereferences the name to its value.
- Defeats: Yara rules that hunt for contiguous base64 of a known PowerShell-encoded download cradle.
- Doesn't defeat: Process-tree rules (the resulting
powershell.exestill has the long base64 on its command line), AMSI (sees decoded plaintext), Event ID 4104.
Bug history: Earlier versions of this script used random single-digit slot keys (e.g.
set "s1=%random:~0,1%") with 8 keys drawn from {0..9}. That caused near-guaranteed collisions and silent payload truncation. Fixed to fixed unique single-character keys A..H. Same idea, no collisions.
:shuffle_data :: circular-rotate #part1/#part2/#part3 sometimes
:verify_checksum :: trivial sum, always passes#part1/#part2/#part3 are decoy values; verify_checksum always returns 0.
Both functions are pure analyst-bait.
set "wrapper1=c_1"
set "wrapper2=c_2"
set "x=!%wrapper1%!"
set "y=!%wrapper2%!"
...
%x% %y% "%payload%"Even the executable name (powershell) and flags are one variable-dereference
removed from the literal text. The final %x% %y% "%payload%" line is the
only real load-bearing line in the script.
- Defeats: Read-the-last-line analysts who expect to see
powershell ...written directly. - Doesn't defeat: Process Monitor, Sysmon EID 1,
Get-CimInstance Win32_Process— all see the final fully-resolved command line.
- Start at
:real_start, scroll to the bottom (:execute_payload) and read backwards viaprepare_execution → assemble_payload → generate_payload_parts. - Everything between
:init_char_mapand:shuffle_datais decoy. - The whole script collapses to:
powershell -NoProfile -NonInteractive -EncodedCommand <base64 of cradle>Knowing that, every other technique in the file is a delay tactic measured in analyst-minutes, not detection events.
Forget signature evasion. To actually disrupt this chain in production you want:
- PowerShell Constrained Language Mode via AppLocker / WDAC — breaks
New-Object Net.WebClientand[ScriptBlock]::Create. - ScriptBlock Logging (EID 4104) + central collection — gives you the decoded payload regardless of obfuscation.
- AMSI + a modern AV — catches the post-decode PowerShell instantly.
- Behavioral rule:
cmd.exe→mshta.exe→powershell.exe -EncodedCommandparent chain. Sysmon EID 1 + a Sigma rule, deployed once, ends this entire class of dropper. - Network egress controls on
127.0.0.1is N/A but in the real-world variant, blocking outbound on PowerShell host (via WFP / EDR) defeats theDownloadStringcradle outright.
The obfuscation in this file teaches you what attackers spend time on. The list above is where defenders should spend theirs.