aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormattifestation <mattgraeber@gmail.com>2013-09-29 17:12:03 -0400
committermattifestation <mattgraeber@gmail.com>2013-09-29 17:12:16 -0400
commite62121ea27d01f4cfa2be180353cc3bc34bdb677 (patch)
tree21d34d61aea11cd9aa3ae0031c7a1ef12665f85e
parent65cd074eaff338ba4091eb934c442cda86cc88dc (diff)
downloadPowerSploit-e62121ea27d01f4cfa2be180353cc3bc34bdb677.tar.gz
PowerSploit-e62121ea27d01f4cfa2be180353cc3bc34bdb677.zip
Added Get-LibSymbols
Get-LibSymbols parses Microsoft .lib files and displays decorated and undecorated symbols.
-rw-r--r--PETools/Get-LibSymbols.format.ps1xml31
-rw-r--r--PETools/Get-LibSymbols.ps1275
-rw-r--r--PETools/PETools.psd15
-rw-r--r--README.md4
4 files changed, 313 insertions, 2 deletions
diff --git a/PETools/Get-LibSymbols.format.ps1xml b/PETools/Get-LibSymbols.format.ps1xml
new file mode 100644
index 0000000..41747cb
--- /dev/null
+++ b/PETools/Get-LibSymbols.format.ps1xml
@@ -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> \ No newline at end of file
diff --git a/PETools/Get-LibSymbols.ps1 b/PETools/Get-LibSymbols.ps1
new file mode 100644
index 0000000..79dede5
--- /dev/null
+++ b/PETools/Get-LibSymbols.ps1
@@ -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 {}
+} \ No newline at end of file
diff --git a/PETools/PETools.psd1 b/PETools/PETools.psd1
index d414365..28a60b9 100644
--- a/PETools/PETools.psd1
+++ b/PETools/PETools.psd1
@@ -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 = ''
diff --git a/README.md b/README.md
index 5141808..e326519 100644
--- a/README.md
+++ b/README.md
@@ -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.