Method A (two-step): extract unpacker first, then run it. Method B (direct): extract file with single one-liner using rfind/LastIndexOf — bypasses Windows Execution Policy.
4.7 KiB
png-zip: PowerShell версия
Упаковка и распаковка файлов внутри PNG без Python. Только PowerShell 5.1+ (встроен в Windows 10/11).
Упаковка
powershell -File pack.ps1 cover.png secret.txt -Output packed.png
Self-extract
Встраивает unpack.ps1 внутрь PNG — на целевой машине не нужны никакие скрипты:
powershell -File pack.ps1 cover.png secret.txt -Output bootstrap.png -SelfExtract
Внутри bootstrap.png: unpack.ps1 + secret.txt. Извлечение на целевой машине — см. раздел «Bootstrap».
При -SelfExtract все bootstrap-однострочники (Python, Python CMD, PowerShell, PowerShell CMD) автоматически сохраняются в метаданных PNG — eXIf (EXIF UserComment) и tEXt (Comment). Их видно в свойствах файла:
- Windows: правый клик → Свойства → Details → Comments
- PowerShell:
exiftool bootstrap.png
Base64/EncodedCommand варианты генерируются динамически с реальным именем выходного файла.
Распаковка
powershell -File unpack.ps1 packed.png
powershell -File unpack.ps1 packed.png -OutDir .\out
powershell -File unpack.ps1 packed.png -List
powershell -File unpack.ps1 packed.png -All
Bootstrap: доставка без ничего
На целевой машине есть только bootstrap.png (созданный с -SelfExtract) и PowerShell.
Два способа извлечения. Замените IMG на имя вашего файла.
Способ A: двухшаговый (распаковщик → файл)
Шаг 1. Извлечь unpack.ps1 — ищет первый payload:
$d=[IO.File]::ReadAllBytes('IMG');$t=[Text.Encoding]::GetEncoding(28591).GetString($d);$s='PNGZIP';$i=-1;do{$i=$t.IndexOf($s,$i+1,[StringComparison]::Ordinal)}while($i-ge0-and($d[$i+6]-ne0-or$d[$i+7]-ne1));$p=$i+8;$nl=$d[$p]*256+$d[$p+1];$p+=2;$n=[Text.Encoding]::UTF8.GetString($d,$p,$nl);$p+=$nl;$pl=[uint64]0;for($k=0;$k-lt8;$k++){$pl=$pl*256+$d[$p+$k]};$p+=8;$ms=New-Object IO.MemoryStream;$ms.Write($d,$p+2,$pl-6);[void]$ms.Seek(0,0);$ds=New-Object IO.Compression.DeflateStream($ms,[IO.Compression.CompressionMode]::Decompress);$os=New-Object IO.MemoryStream;$ds.CopyTo($os);[IO.File]::WriteAllBytes($n,$os.ToArray());Write-Host "Extracted: $n"
Шаг 2. Извлечь основной файл:
powershell -File unpack.ps1 bootstrap.png
Способ B: прямое извлечение файла (без распаковщика)
Ищет последний payload — это сам файл. Не нужен unpack.ps1, обходит Execution Policy:
$d=[IO.File]::ReadAllBytes('IMG');$t=[Text.Encoding]::GetEncoding(28591).GetString($d);$s='PNGZIP';$i=$d.Length;do{$i=$t.LastIndexOf($s,$i-1,[StringComparison]::Ordinal)}while($i-ge0-and($d[$i+6]-ne0-or$d[$i+7]-ne1));$p=$i+8;$nl=$d[$p]*256+$d[$p+1];$p+=2;$n=[Text.Encoding]::UTF8.GetString($d,$p,$nl);$p+=$nl;$pl=[uint64]0;for($k=0;$k-lt8;$k++){$pl=$pl*256+$d[$p+$k]};$p+=8;$ms=New-Object IO.MemoryStream;$ms.Write($d,$p+2,$pl-6);[void]$ms.Seek(0,0);$ds=New-Object IO.Compression.DeflateStream($ms,[IO.Compression.CompressionMode]::Decompress);$os=New-Object IO.MemoryStream;$ds.CopyTo($os);[IO.File]::WriteAllBytes($n,$os.ToArray());Write-Host "Extracted: $n"
Работает и для обычных packed-образов (без self-extract).
Windows CMD — готовые EncodedCommand-однострочники для обоих способов выводятся при паковке и сохраняются в метаданных PNG. Скопируйте из консоли или из свойств файла (Details → Comments).
Очистка PNG
Удалить все встроенные данные (payload, bootstrap-метаданные eXIf/tEXt):
powershell -File pack.ps1 packed.png -Clean -Output clean.png
Ограничения
- Только append-режим. Для chunk и lsb используйте Python-версию (
pack.py/unpack.py). - CRC32 и Adler32 реализованы через inline C# (
Add-Type), первый запуск чуть медленнее из-за компиляции. - Для файлов > 100 MB может быть медленнее Python-версии.
- Формат payload полностью совместим с Python-версией — можно паковать на одной ОС, распаковывать на другой.