Skip to content

Instantly share code, notes, and snippets.

@yak1ex
Created August 18, 2023 13:55
Show Gist options
  • Save yak1ex/d00046344ce043db922285f9ac7ddb5a to your computer and use it in GitHub Desktop.
Save yak1ex/d00046344ce043db922285f9ac7ddb5a to your computer and use it in GitHub Desktop.
R.I.P. needless PowerShell script to extract a resource from Windows EXE
function SeekPos
{
param([System.IO.BinaryReader]$br, $offset)
$br.BaseStream.Seek($offset, [System.IO.SeekOrigin]::Begin)
}
function SeekDiff
{
param([System.IO.BinaryReader]$br, $offset)
$br.BaseStream.Seek($offset, [System.IO.SeekOrigin]::Current)
}
$br = [System.IO.BinaryReader]::new(
[System.IO.FileStream]::new(
"$(Get-Location)\calibre-portable-installer-6.24.0.exe",
[System.IO.FileMode]::Open,
[System.IO.FileAccess]::Read)
)
SeekPos $br 0x3c
$peOffset = $br.ReadInt16()
SeekPos $br $peOffset
if ($br.ReadUInt32() -eq 0x00004550) { # PE\x00\x00
SeekDiff $br 2
$sections = $br.ReadUInt16()
Write-Host Sections $sections
SeekDiff $br 16
$peOpt = $br.ReadUInt16()
if ($peOpt -eq 0x20b) {
SeekPos $br ($peOffset + 4 + 20 + 108)
$rvas = $br.ReadUInt32()
Write-Host $rvas
SeekDiff $br ($rvas * 8)
$sectionHeader = $br.BaseStream.Position
foreach ($_ in 1..$sections) {
SeekPos $br ($sectionHeader + ($_ - 1) * 40)
$name1 = $br.ReadUInt32()
$name2 = $br.ReadUInt32()
if (($name1 -eq 0x7273722e) -and ($name2 -eq 0x00000063)) { # .rsrc
SeekDiff $br 4
$rsrcRva = $br.ReadUInt32()
$rsrcSize = $br.ReadUInt32()
$rsrcOffset = $br.ReadUInt32()
Write-Host $rsrcRva $rsrcSize $rsrcOffset
SeekPos $br ($rsrcOffset + 12)
$numName = $br.ReadUInt16()
if ($numName -eq 1) {
SeekDiff $br 2
$nameOffset = $br.ReadUInt32()
$sdOffset = $br.ReadUInt32()
Write-Host $nameOffset $sdOffset
SeekPos $br ($rsrcOffset + ($sdOffset -band 0x7fffffff) + 12)
$numName = $br.ReadUInt16()
if ($numName -eq 1) {
SeekDiff $br 2
$nameOffset = $br.ReadUInt32()
$sdOffset = $br.ReadUInt32()
SeekPos $br ($rsrcOffset + ($sdOffset -band 0x7fffffff) + 12)
$numName = $br.ReadUInt16()
$numId = $br.ReadUInt16()
if ($numName -eq 0 -and $numId -eq 1) {
$id = $br.ReadUInt32()
$entryOffset = $br.ReadUInt32()
SeekPos $br ($rsrcOffset + $entryOffset)
$rvaOffset = $br.ReadUInt32()
$actualSize = $br.ReadUInt32()
$actualOffset = $rvaOffset + $rsrcOffset - $rsrcRva
Write-Host $actualOffset $actualSize
}
}
}
}
}
}
if(-not($null -eq $actualOffset)) {
# 18 = lzip header(6) + lzip footer(12), 13 = lzma header
$buffer = [System.Array]::CreateInstance([byte], $actualSize - 18 + 13)
SeekPos $br ($actualOffset + 4) # skip lzip signature (4bytes)
if(-not ($br.ReadByte() -eq 0)) { throw "lzip version is not 0" }
$dictBits = $br.ReadByte()
$bytesToRead = $actualSize - 18
$bytesRead = 13
$bufSize = 4*1024*1024
while ($bytesToRead -gt 0) {
if ($bytesToRead -gt $bufSize) {
$readLength = $bufSize
} else {
$readLength = $bytesToRead
}
$ret = $br.BaseStream.Read($buffer, $bytesRead, $readLength)
if($ret -eq 0) { break }
$bytesRead += $ret
$bytesToRead -= $ret
}
$crc = $br.ReadUInt32()
$length = $br.ReadUInt64()
$buffer[0] = 0x5d # =93=(pb*5+lp)*9+lc (pb=2,lp=0,lc=3)
$dictSize = [Math]::pow(2, $dictBits)
foreach ($_ in 0..3) {
$buffer[1+$_] = ($dictSize -shr (8 * $_)) -band 0xFF
}
foreach ($_ in 0..7) {
$buffer[5+$_] = ($length -shr (8 * $_)) -band 0xFF
}
[System.IO.File]::WriteAllBytes("$(Get-Location)\temp.zip.lzma", $buffer);
}
}
$br.Dispose()
$br.Close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment