typetechniqueconfidencehighcreated2026-06-03updated2026-06-03obfuscationscriptdefense-evasionanti-debug

Batch PowerShell Variable Expansion Obfuscation

What It Does

A DOS batch-script anti-static technique in which a PowerShell payload is fragmented across tens of SET variable assignments, then reassembled in a single line via %VARNAME% expansion and passed as an -ArgumentList to a nested powershell.exe -WindowStyle Hidden invocation. The goal is to defeat naive string extraction and signature matching, because no single line contains a complete keyword like powershell or FromBase64String.

Detection / Fingerprint

Look for these indicators in a .bat or .cmd file:

  • 30 SET VARNAME= lines with >60 character values.

  • A single line containing 50+ %VARNAME% concatenations (no spaces between expansions).
  • That same line contains powershell.exe, Start-Process, or -WindowStyle Hidden.
  • Labels (:LABELNAME) and GOTO jumps interleaved between SETs, forming a chain.
  • The file is ASCII text, 5–15 KB, with very long lines (500–800 chars) but no complex control flow (loops, IF blocks).

Implementation Patterns Observed

In sample cae0056ac (8.4 KB batch), the script uses 63 variables, each holding a slice of raw UTF-16LE characters, assembled on one line into a full powershell.exe -Command "Start-Process … -ArgumentList …" call. ^[/intel/analyses/cae0056acc2f1b6285544c96e33a4e4c49b964f309b8e4df08b9bf55695389b8.html]

Obfuscation refinements observed:

  • f@ insertion — The assembled string embeds the sequence f@ inside valid base64; PowerShell regex-replaces it before decoding. ^[decoded_payload.txt]
  • Method-name splitting'run' + 'ss' instead of 'runss', evading exact-string YARA. ^[decoded_payload.txt]
  • Tag splitting<<BASE64_START>> built from 'base64' concatenated with literal prefix and suffix. ^[decoded_payload.txt]
  • URL reversal — The final C2 URL is stored reversed (txt.sabeurp/niam/war/-/...) and cleaned with a trailing substring strip before use. ^[decoded_payload.txt]

Reproduce on Your Own VMs

  1. Write a PowerShell one-liner, e.g.:
    $a = [System.Text.Encoding]::UTF8.GetBytes('Hello'); [Convert]::ToBase64String($a)
    
  2. Encode it as UTF-16LE raw bytes (not base64) and split into 60-character chunks.
  3. Create a .bat:
    @echo off
    GOTO START
    :A1
    SET V01=ABC...
    GOTO A2
    :A2
    SET V02=DEF...
    ...
    :START
    %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "%V01%%V02%..."
    
  4. Test against your EDR / sandbox — does it surface the full PowerShell string in process arguments? A basic cmd.exe logger usually captures the final expanded line, but static YARA against the .bat file will be blind to the payload unless it looks for concatenation patterns.

Defensive Countermeasures

  • EDR: Log parent cmd.exe command lines with >50 %VAR% tokens; these are abnormal for legitimate batch files.
  • YARA: See the rule in unclassified-batch-powershell-dropper analysis.
  • Behavioral: flag any cmd.exe spawning powershell.exe where the command-line length exceeds 4000 characters and the parent is a .bat file.

Pages Where Observed

References

  • cae0056ac batch reconstruction: ^[/intel/analyses/cae0056acc2f1b6285544c96e33a4e4c49b964f309b8e4df08b9bf55695389b8.html]