mirror of
https://github.com/PowerShellMafia/PowerSploit
synced 2026-06-08 12:13:33 +00:00
Added Get-LibSymbols
Get-LibSymbols parses Microsoft .lib files and displays decorated and undecorated symbols.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Configuration>
|
||||
<ViewDefinitions>
|
||||
<View>
|
||||
<Name>SymbolTypeView</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>COFF.SymbolInfo</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<ListControl>
|
||||
<ListEntries>
|
||||
<ListEntry>
|
||||
<ListItems>
|
||||
<ListItem>
|
||||
<PropertyName>SymbolType</PropertyName>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<PropertyName>Module</PropertyName>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<PropertyName>DecoratedName</PropertyName>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<PropertyName>UndecoratedName</PropertyName>
|
||||
</ListItem>
|
||||
</ListItems>
|
||||
</ListEntry>
|
||||
</ListEntries>
|
||||
</ListControl>
|
||||
</View>
|
||||
</ViewDefinitions>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,275 @@
|
||||
function Get-LibSymbols
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Displays symbolic information from Windows lib files.
|
||||
|
||||
PowerSploit Function: Get-LibSymbols
|
||||
Author: Matthew Graeber (@mattifestation)
|
||||
License: BSD 3-Clause
|
||||
Required Dependencies: None
|
||||
Optional Dependencies: None
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Get-LibSymbols parses and returns symbols in Windows .lib files
|
||||
in both decorated and undecorated form (for C++ functions).
|
||||
|
||||
.PARAMETER Path
|
||||
|
||||
Specifies a path to one or more lib file locations.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
C:\PS>Get-LibSymbols -Path msvcrt.lib
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
C:\PS>ls *.lib | Get-LibSymbols
|
||||
|
||||
.INPUTS
|
||||
|
||||
System.String[]
|
||||
|
||||
You can pipe a file system path (in quotation marks) to Get-LibSymbols.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
COFF.SymbolInfo
|
||||
|
||||
.LINK
|
||||
|
||||
http://www.exploit-monday.com/
|
||||
#>
|
||||
[CmdletBinding()] Param (
|
||||
[Parameter(Position = 0, Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
|
||||
[ValidateScript({ Test-Path $_ })]
|
||||
[Alias('FullName')]
|
||||
[String[]]
|
||||
$Path
|
||||
)
|
||||
|
||||
BEGIN
|
||||
{
|
||||
$Code = @'
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace COFF
|
||||
{
|
||||
public class HEADER
|
||||
{
|
||||
public ushort Machine;
|
||||
public ushort NumberOfSections;
|
||||
public DateTime TimeDateStamp;
|
||||
public uint PointerToSymbolTable;
|
||||
public uint NumberOfSymbols;
|
||||
public ushort SizeOfOptionalHeader;
|
||||
public ushort Characteristics;
|
||||
|
||||
public HEADER(BinaryReader br)
|
||||
{
|
||||
this.Machine = br.ReadUInt16();
|
||||
this.NumberOfSections = br.ReadUInt16();
|
||||
this.TimeDateStamp = (new DateTime(1970, 1, 1, 0, 0, 0)).AddSeconds(br.ReadUInt32());
|
||||
this.PointerToSymbolTable = br.ReadUInt32();
|
||||
this.NumberOfSymbols = br.ReadUInt32();
|
||||
this.SizeOfOptionalHeader = br.ReadUInt16();
|
||||
this.Characteristics = br.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public class IMAGE_ARCHIVE_MEMBER_HEADER
|
||||
{
|
||||
public string Name;
|
||||
public DateTime Date;
|
||||
public ulong Size;
|
||||
public string EndHeader;
|
||||
|
||||
public IMAGE_ARCHIVE_MEMBER_HEADER(BinaryReader br)
|
||||
{
|
||||
string tempName = Encoding.UTF8.GetString(br.ReadBytes(16));
|
||||
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
this.Name = tempName.Substring(0, tempName.IndexOf((Char) 47));
|
||||
this.Date = dt.AddSeconds(Convert.ToDouble(Encoding.UTF8.GetString(br.ReadBytes(12)).Split((Char) 20)[0]));
|
||||
br.ReadBytes(20); // Skip over UserID, GroupID, and Mode. They are useless fields.
|
||||
this.Size = Convert.ToUInt64(Encoding.UTF8.GetString(br.ReadBytes(10)).Split((Char) 20)[0]);
|
||||
this.EndHeader = Encoding.UTF8.GetString(br.ReadBytes(2));
|
||||
}
|
||||
}
|
||||
|
||||
public class Functions
|
||||
{
|
||||
[DllImport("dbghelp.dll", SetLastError=true, PreserveSig=true)]
|
||||
public static extern int UnDecorateSymbolName(
|
||||
[In] [MarshalAs(UnmanagedType.LPStr)] string DecoratedName,
|
||||
[Out] StringBuilder UnDecoratedName,
|
||||
[In] [MarshalAs(UnmanagedType.U4)] uint UndecoratedLength,
|
||||
[In] [MarshalAs(UnmanagedType.U4)] uint Flags);
|
||||
}
|
||||
}
|
||||
'@
|
||||
|
||||
Add-Type -TypeDefinition $Code
|
||||
|
||||
function Dispose-Objects
|
||||
{
|
||||
$BinaryReader.Close()
|
||||
$FileStream.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS
|
||||
{
|
||||
foreach ($File in $Path)
|
||||
{
|
||||
# Resolve the absolute path of the lib file. [IO.File]::OpenRead requires an absolute path.
|
||||
$LibFilePath = Resolve-Path $File
|
||||
|
||||
# Pull out just the file name
|
||||
$LibFileName = Split-Path $LibFilePath -Leaf
|
||||
|
||||
$IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60
|
||||
$IMAGE_ARCHIVE_START = "!<arch>`n" # Magic used for lib files
|
||||
$IMAGE_SIZEOF_LIB_HDR = $IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR + $IMAGE_ARCHIVE_START.Length
|
||||
$IMAGE_ARCHIVE_END = "```n" # Footer of an archive header
|
||||
$SizeofCOFFFileHeader = 20
|
||||
|
||||
# Open the object file for reading
|
||||
$FileStream = [IO.File]::OpenRead($LibFilePath)
|
||||
|
||||
$FileLength = $FileStream.Length
|
||||
|
||||
# Validate lib header size
|
||||
if ($FileLength -lt $IMAGE_SIZEOF_LIB_HDR)
|
||||
{
|
||||
# You cannot parse the lib header if the file is not big enough to contain a lib header.
|
||||
Write-Error "$($LibFileName) is too small to store a lib header."
|
||||
$FileStream.Dispose()
|
||||
return
|
||||
}
|
||||
|
||||
# Open a BinaryReader object for the lib file
|
||||
$BinaryReader = New-Object IO.BinaryReader($FileStream)
|
||||
|
||||
$ArchiveStart = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes(8))
|
||||
|
||||
if ($ArchiveStart -ne $IMAGE_ARCHIVE_START)
|
||||
{
|
||||
Write-Error "$($LibFileName) does not contain a valid lib header."
|
||||
Dispose-Objects
|
||||
return
|
||||
}
|
||||
|
||||
# Parse the first archive header
|
||||
$ArchiveHeader = New-Object COFF.IMAGE_ARCHIVE_MEMBER_HEADER($BinaryReader)
|
||||
|
||||
if ($ArchiveHeader.EndHeader -ne $IMAGE_ARCHIVE_END)
|
||||
{
|
||||
Write-Error "$($LibFileName) does not contain a valid lib header."
|
||||
Dispose-Objects
|
||||
return
|
||||
}
|
||||
|
||||
# Check for the existence of symbols
|
||||
if ($ArchiveHeader.Size -eq 0)
|
||||
{
|
||||
Write-Warning "$($LibFileName) contains no symbols."
|
||||
Dispose-Objects
|
||||
return
|
||||
}
|
||||
|
||||
$NumberOfSymbols = $BinaryReader.ReadBytes(4)
|
||||
|
||||
# The offsets in the first archive header of a Microsoft lib file are stored in big-endian format
|
||||
if ([BitConverter]::IsLittleEndian)
|
||||
{
|
||||
[Array]::Reverse($NumberOfSymbols)
|
||||
}
|
||||
|
||||
$NumberOfSymbols = [BitConverter]::ToUInt32($NumberOfSymbols, 0)
|
||||
|
||||
$SymbolOffsets = New-Object UInt32[]($NumberOfSymbols)
|
||||
|
||||
foreach ($Offset in 0..($SymbolOffsets.Length - 1))
|
||||
{
|
||||
$SymbolOffset = $BinaryReader.ReadBytes(4)
|
||||
|
||||
if ([BitConverter]::IsLittleEndian)
|
||||
{
|
||||
[Array]::Reverse($SymbolOffset)
|
||||
}
|
||||
|
||||
$SymbolOffsets[$Offset] = [BitConverter]::ToUInt32($SymbolOffset, 0)
|
||||
}
|
||||
|
||||
$SymbolStringLength = $ArchiveHeader.Size + $IMAGE_SIZEOF_LIB_HDR - $FileStream.Position - 1
|
||||
# $SymbolStrings = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes($SymbolStringLength)).Split([Char] 0)
|
||||
|
||||
# Write-Output $SymbolStrings
|
||||
|
||||
# There will be many duplicate offset entries. Remove them.
|
||||
$SymbolOffsetsSorted = $SymbolOffsets | Sort-Object -Unique
|
||||
|
||||
$SymbolOffsetsSorted | ForEach-Object {
|
||||
# Seek to the each repective offset in the file
|
||||
$FileStream.Seek($_, 'Begin') | Out-Null
|
||||
|
||||
$ArchiveHeader = New-Object COFF.IMAGE_ARCHIVE_MEMBER_HEADER($BinaryReader)
|
||||
|
||||
# This is not a true COFF header. It's the same size and mostly resembles a standard COFF header
|
||||
# but Microsoft placed a marker (0xFFFF) in the first WORD to indicate that the 'object file'
|
||||
# consists solely of the module name and symbol.
|
||||
$CoffHeader = New-Object COFF.HEADER($BinaryReader)
|
||||
|
||||
# Check for 0xFFFF flag value
|
||||
if ($CoffHeader.NumberOfSections -eq [UInt16]::MaxValue)
|
||||
{
|
||||
# Get the total length of the module and symbol name
|
||||
$SymbolStringLength = $CoffHeader.NumberOfSymbols
|
||||
$Symbols = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes($SymbolStringLength)).Split([Char] 0)
|
||||
|
||||
$DecoratedSymbol = $Symbols[0]
|
||||
$UndecoratedSymbol = ''
|
||||
|
||||
# Default to a 'C' type symbol unless it starts with a '?'
|
||||
$SymbolType = 'C'
|
||||
|
||||
# Is the symbol a C++ type?
|
||||
if ($DecoratedSymbol.StartsWith('?'))
|
||||
{
|
||||
$StrBuilder = New-Object Text.Stringbuilder(512)
|
||||
# Magically undecorated the convoluted C++ symbol into a proper C++ function definition
|
||||
[COFF.Functions]::UnDecorateSymbolName($DecoratedSymbol, $StrBuilder, $StrBuilder.Capacity, 0) | Out-Null
|
||||
$UndecoratedSymbol = $StrBuilder.ToString()
|
||||
$SymbolType = 'C++'
|
||||
}
|
||||
else
|
||||
{
|
||||
$UndecoratedSymbol = $DecoratedSymbol.Substring(1).Split('@')[0]
|
||||
}
|
||||
|
||||
$SymInfo = @{
|
||||
DecoratedName = $DecoratedSymbol
|
||||
UndecoratedName = $UndecoratedSymbol
|
||||
Module = $Symbols[1]
|
||||
SymbolType = $SymbolType
|
||||
}
|
||||
|
||||
$ParsedSymbol = New-Object PSObject -Property $SymInfo
|
||||
$ParsedSymbol.PSObject.TypeNames[0] = 'COFF.SymbolInfo'
|
||||
|
||||
Write-Output $ParsedSymbol
|
||||
}
|
||||
}
|
||||
|
||||
# Close file and binaryreader objects
|
||||
Dispose-Objects
|
||||
}
|
||||
}
|
||||
|
||||
END {}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ PowerShellVersion = '2.0'
|
||||
# TypesToProcess = @()
|
||||
|
||||
# Format files (.ps1xml) to be loaded when importing this module
|
||||
FormatsToProcess = 'PETools.format.ps1xml', 'Get-ObjDump.format.ps1xml'
|
||||
FormatsToProcess = 'PETools.format.ps1xml', 'Get-ObjDump.format.ps1xml', 'Get-LibSymbols.format.ps1xml'
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
# NestedModules = @()
|
||||
@@ -74,7 +74,8 @@ ModuleList = @(@{ModuleName = 'PETools'; ModuleVersion = '1.0.0.0'; GUID = 'd150
|
||||
|
||||
# List of all files packaged with this module
|
||||
FileList = 'PETools.psm1', 'PETools.psd1', 'PETools.format.ps1xml', 'Get-DllLoadPath.ps1',
|
||||
'Get-PEHeader.ps1', 'Get-ObjDump.ps1', 'Get-ObjDump.format.ps1xml', 'Usage.md'
|
||||
'Get-PEHeader.ps1', 'Get-ObjDump.ps1', 'Get-ObjDump.format.ps1xml', 'Get-LibSymbols.ps1',
|
||||
'Usage.md'
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess
|
||||
# PrivateData = ''
|
||||
|
||||
@@ -72,6 +72,10 @@ An in-memory and on-disk PE parsing utility.
|
||||
|
||||
Displays information about one or more Windows object files.
|
||||
|
||||
#### `Get-LibSymbols`
|
||||
|
||||
Displays symbolic information from Windows lib files.
|
||||
|
||||
#### `Get-DllLoadPath`
|
||||
|
||||
Returns the path from which Windows will load a Dll for the given executable.
|
||||
|
||||
Reference in New Issue
Block a user