# encoding: ascii
# api: powershell
# title: Get-PEManifest
# description: Script is commented for explanation of each step
# version: 1.0
# type: function
# author: greg zakharov
# license: CC0
# function: Get-PEManifest
# x-poshcode-id: 5316
# x-archived: 2014-07-25T21:53:25
# x-published: 2014-07-20T14:00:00
#
#
function Get-PEManifest {
<#
.SYNOPSIS
Extract PE file manifest if it's possible.
.DESCRIPTION
This script is alternative for next way to get dump of PE manifest:
Add-Type -AssemblyName System.Deployment
try {
[Text.Encoding]::Default.GetString(
($SystemUtils = [Activator]::CreateInstance(
([AppDomain]::CurrentDomain.GetAssemblies() | ? {
$_.FullName.Contains(($asm = 'System.Deployment'))
}).GetType(
$asm + '.Application.Win32InterOp.SystemUtils'
)
)).GetType().InvokeMember(
'GetManifestFromPEResources',
[Reflection.BindingFlags]280,
$null,
$SystemUtils,
@($PE)
)
)
}
catch [Management.Automation.MethodInvocationException] {
$_.Exception.InnerException
}
.EXAMPLE
PS E:\> Get-PEManifest "E:\Program Files(x86)\Sysinternals\accesschk.exe"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="AccessChk"
processorArchitecture="x86"
version="1.0.0.0"
type="win32"/>
<description>File System Monitor</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
.LINK
http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v83.docx
.NOTES
Author: greg zakharov
#>
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
[ValidateScript({Test-Path $_})]
[String]$FileName
)
try {
$fs = [IO.File]::OpenRead($FileName)
$br = New-Object IO.BinaryReader($fs)
#get DOS signature
$buf = New-Object "Byte[]" 2
[void]$br.Read($buf, 0, $buf.Length)
$e_magic = [Text.Encoding]::Default.GetString($buf)
#get PE signature
$fs.Position = 0x3C
$e_lfanew = $br.ReadUInt16()
[void]$fs.Seek($e_lfanew, [IO.SeekOrigin]::Begin)
$buf = New-Object "Byte[]" 4
[void]$br.Read($buf, 0, $buf.Length)
$pe_sign = [Text.Encoding]::Default.GetString($buf)
if ($e_magic -ne 'MZ' -and $pe_sign -ne "PE`0`0") {
throw (New-Object ComponentModel.Win32Exception('Invalid file format.'))
}
#number of sections
$fs.Position += 0x02
$pe_sec = $br.ReadUInt16()
#size of optional header
$fs.Position += 0x0C
$pe_ioh = $br.ReadUInt16()
#jump to sections location and looking for resources directory
$fs.Position += $pe_ioh + 0x02
$buf = New-Object "Byte[]" 8 #length of section name (constant)
0..($pe_sec - 1) | % {
[void]$br.Read($buf, 0, $buf.Length)
if ([Text.Encoding]::Default.GetString($buf) -ne '.rsrc') {
$fs.Position += 0x20 #skip other data of section
}
else { #looking for virtual address and pointer to raw data
#virtual address
$fs.Position += 0x04
$vrt_addr = $br.ReadUInt32()
#file pointer to raw data
$fs.Position += 0x04
$ptr_data = $br.ReadUInt32()
}
} #foreach
if ($vrt_addr -eq $null -or $ptr_data -eq $null) {
throw (New-Object ComponentModel.Win32Exception('File does not contain resources or packed.'))
}
#jump to IMAGE_RESOURCE_DIRECTORY and skip its first two fields
$fs.Position = $ptr_data + 0x0C
#get length of IMAGE_RESOURCE_DIRECTORY_ENTRY[] and walk through it
0..($br.ReadUInt16() + $br.ReadUInt16() - 1) | % {
$Name = $br.ReadUInt32()
$OffsetToData = $br.ReadUInt32() -band 0xfffffff
if ($Name -eq 0x10) { #here lies manifest
$raw_addr = $OffsetToData
}
} #foreach
#walk through resource binary tree, get IMAGE_RESOURCE_DIRECTORY_ENTRY
$fs.Position = $ptr_data + 0x10 + $raw_addr
$fs.Position += 0x04
$raw_addr = $br.ReadUInt32() -band 0xfffffff
#go to the manifest directory
$fs.Position = $ptr_data + 0x10 + $raw_addr
$fs.Position += 0x04
$raw_addr = $br.ReadUInt32()
#get first two fields of IMAGE_RESOURCE_DATA_ENTRY
$fs.Position = $ptr_data + 0x10 + $raw_addr
$ofs_data = $br.ReadUInt32() #OffsetToData
$res_size = $br.ReadUInt32() #Size
#get address of resource and read
$fs.Position = $ptr_data + ($ofs_data - $vrt_addr)
$buf = New-Object "Byte[]" $res_size
[void]$br.Read($buf, 0, $buf.Length)
[Text.Encoding]::Default.GetString($buf)
}
catch {
if (($exp = $_.Exception.InnerException) -eq $null) {
Write-Host $_.Exception.Message`n
}
else { Write-Host $exp.Message`n }
}
finally {
if ($br -ne $null) { $br.Close() }
if ($fs -ne $null) { $fs.Close() }
}
}