# encoding: ascii
# api: powershell
# title: Test-Packer
# description: Checking file if it has been packed with something like UPX.
# version: 0.1
# type: function
# author: greg zakharov
# license: CC0
# function: Test-Packer
# x-poshcode-id: 4992
# x-archived: 2014-03-22T00:34:13
# x-published: 2014-03-17T08:37:00
#
#
#requires -version 2.0
function Test-Packer {
  <#
    .EXAMPLE
        PS C:\>Test-Packer E:\bin\whois.exe
        File has not been packed.
    .EXAMPLE
        PS C:\>Test-Packer E:\bin\delprof.exe
        File has been packed with: UPX
    .NOTES
        Author: greg zakharov
  #>
  param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
    [ValidateScript({Test-Path $_})]
    [String]$FileName
  )
  
  begin {
    $FileName = cvpa $FileName
  }
  process {
    try {
      $fs = [IO.File]::OpenRead($FileName)
      $buf = New-Object "Byte[]" 1024
      [void]$fs.Read($buf, 0, $buf.Length)
      #e_lfanew
      $e_lfanew = 256 * $buf[0x3D] + $buf[0x3C]
      #wrong signature
      if ([String]::Join('', [Char[]]$buf[0..1]) -ne 'MZ' -and
        [String]::Join('', [Char[]]$buf[$e_lfanew..($e_lfanew + 3)]) -ne "PE`0`0") {
        throw (New-Object FormatException('Invalid file format.'))
      }
      #offset macro
      function private:get([Int32]$offset, [Switch]$band) {
        return $([BitConverter]::ToUInt32($buf, ($e_lfanew + $offset)) -band 0xffff)
      }
      #sections block pointer
      $ptr = $e_lfanew + (get 0x14) + 24
      $chr = [BitConverter]::ToUInt32($buf, ($ptr + 0x24))
      #looking for sections with Code or MemeoryExecute characteristics
      $Sections = for ($i = 0; $i -lt (get 0x6); ++$i) {
        if ($chr -band 0x20 -or $chr -band 0x20000000) {
          [String]::Join('', [Char[]]$buf[$ptr..($ptr + 0x7)])
        }
        $ptr += 40
      }
    }
    catch {
      $_.Exception.Message
    }
    finally {
      if ($fs -ne $null) { $fs.Close() }
    }
  }
  end {
    if ($Sections -eq '.text') {
      "File has not been packed.`n"
    }
    elseif ($Sections -is [Array]) {
      "File has been packed with: $($Sections[0] -replace '\d+|\.', '')`n"
    }
    else {
      $Sections
    }
  }
}
