diff options
author | mattifestation <mattgraeber@gmail.com> | 2013-09-29 17:12:03 -0400 |
---|---|---|
committer | mattifestation <mattgraeber@gmail.com> | 2013-09-29 17:12:16 -0400 |
commit | e62121ea27d01f4cfa2be180353cc3bc34bdb677 (patch) | |
tree | 21d34d61aea11cd9aa3ae0031c7a1ef12665f85e | |
parent | 65cd074eaff338ba4091eb934c442cda86cc88dc (diff) | |
download | PowerSploit-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.ps1xml | 31 | ||||
-rw-r--r-- | PETools/Get-LibSymbols.ps1 | 275 | ||||
-rw-r--r-- | PETools/PETools.psd1 | 5 | ||||
-rw-r--r-- | README.md | 4 |
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 = ''
@@ -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. |