├── Lib
├── Capstone
│ ├── lib
│ │ ├── place_capstone.dll_here
│ │ ├── x64
│ │ │ ├── place_64-bit_libcapstone.dll_here
│ │ │ └── libcapstone.dll
│ │ ├── x86
│ │ │ ├── place_32-bit_libcapstone.dll_here
│ │ │ └── libcapstone.dll
│ │ └── capstone.dll
│ ├── Capstone.psd1
│ ├── README
│ └── LICENSE.TXT
├── De4dot
│ ├── dnlib.dll
│ ├── AssemblyData.dll
│ ├── de4dot.code.dll
│ ├── de4dot.blocks.dll
│ └── de4dot.mdecrypt.dll
├── PSReflect
│ ├── README.md
│ ├── PSReflect.psd1
│ ├── LICENSE
│ ├── Examples
│ │ ├── Get-NetShare.ps1
│ │ └── SimplePEParser.ps1
│ └── PSReflect.psm1
└── Formatters
│ ├── ProcessModuleTrace.format.ps1xml
│ ├── MemoryTools.format.ps1xml
│ ├── Get-CSDisassembly.format.ps1xml
│ ├── Get-LibSymbols.format.ps1xml
│ ├── Get-ILDisassembly.format.ps1xml
│ └── Get-ObjDump.format.ps1xml
├── PowerShellArsenal.psm1
├── .gitattributes
├── WindowsInternals
├── Get-SystemInfo.ps1
└── ProcessModuleTrace.ps1
├── Misc
├── ConvertTo-String.ps1
├── Get-Strings.ps1
├── Get-Entropy.ps1
└── Get-Member.ps1
├── Disassembly
├── Get-ILDisassembly.ps1
└── Get-CSDisassembly.ps1
├── .gitignore
├── PowerShellArsenal.psd1
├── MalwareAnalysis
├── Hosts.ps1
├── loadlib.ps1
├── dotNetMalwareAnalysis.ps1
└── funcdelegate.ps1
├── README.md
├── Parsers
└── Get-LibSymbols.ps1
└── MemoryTools
└── MemoryTools.ps1
/Lib/Capstone/lib/place_capstone.dll_here:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Lib/Capstone/lib/x64/place_64-bit_libcapstone.dll_here:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Lib/Capstone/lib/x86/place_32-bit_libcapstone.dll_here:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Lib/De4dot/dnlib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/De4dot/dnlib.dll
--------------------------------------------------------------------------------
/Lib/De4dot/AssemblyData.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/De4dot/AssemblyData.dll
--------------------------------------------------------------------------------
/Lib/De4dot/de4dot.code.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/De4dot/de4dot.code.dll
--------------------------------------------------------------------------------
/Lib/Capstone/lib/capstone.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/Capstone/lib/capstone.dll
--------------------------------------------------------------------------------
/Lib/De4dot/de4dot.blocks.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/De4dot/de4dot.blocks.dll
--------------------------------------------------------------------------------
/Lib/De4dot/de4dot.mdecrypt.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/De4dot/de4dot.mdecrypt.dll
--------------------------------------------------------------------------------
/Lib/PSReflect/README.md:
--------------------------------------------------------------------------------
1 | PSReflect
2 | =========
3 |
4 | Easily define in-memory enums, structs, and Win32 functions in PowerShell
5 |
--------------------------------------------------------------------------------
/Lib/Capstone/lib/x64/libcapstone.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/Capstone/lib/x64/libcapstone.dll
--------------------------------------------------------------------------------
/Lib/Capstone/lib/x86/libcapstone.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattifestation/PowerShellArsenal/HEAD/Lib/Capstone/lib/x86/libcapstone.dll
--------------------------------------------------------------------------------
/PowerShellArsenal.psm1:
--------------------------------------------------------------------------------
1 | # Read in all ps1 files expect those in the Lib folder
2 | Get-ChildItem $PSScriptRoot |
3 | ? {$_.PSIsContainer -and ($_.Name -ne 'Lib')} |
4 | % {Get-ChildItem "$($_.FullName)\*" -Include '*.ps1'} |
5 | % {. $_.FullName}
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/Lib/Capstone/Capstone.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | # Version number of this module.
3 | ModuleVersion = '2.0.0.0'
4 |
5 | # ID used to uniquely identify this module
6 | GUID = 'bc335667-02fd-46c4-a3d9-0a5113c9c03b'
7 |
8 | # Author of this module
9 | Author = 'Matthew Graeber'
10 |
11 | # Copyright statement for this module
12 | Copyright = 'see LICENSE.TXT'
13 |
14 | # Description of the functionality provided by this module
15 | Description = 'Capstone Disassembly Framework Binding Module'
16 |
17 | # Minimum version of the Windows PowerShell engine required by this module
18 | PowerShellVersion = '3.0'
19 |
20 | # Minimum version of the common language runtime (CLR) required by this module
21 | CLRVersion = '4.0'
22 |
23 | # Assemblies that must be loaded prior to importing this module
24 | RequiredAssemblies = 'lib/capstone.dll'
25 | }
26 |
--------------------------------------------------------------------------------
/Lib/PSReflect/PSReflect.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | # Script module or binary module file associated with this manifest.
3 | ModuleToProcess = 'PSReflect.psm1'
4 |
5 | # Version number of this module.
6 | ModuleVersion = '1.1.1.0'
7 |
8 | # ID used to uniquely identify this module
9 | GUID = '32c3f36a-519f-4032-9090-053956ae85e1'
10 |
11 | # Author of this module
12 | Author = 'Matthew Graeber'
13 |
14 | # Copyright statement for this module
15 | Copyright = 'BSD 3-Clause'
16 |
17 | # Description of the functionality provided by this module
18 | Description = 'Easily define in-memory enums, structs, and Win32 functions'
19 |
20 | # Minimum version of the Windows PowerShell engine required by this module
21 | PowerShellVersion = '2.0'
22 |
23 | # Functions to export from this module
24 | FunctionsToExport = '*'
25 |
26 | # List of all files packaged with this module
27 | FileList = 'PSReflect.psm1', 'PSReflect.psd1'
28 | }
29 |
--------------------------------------------------------------------------------
/Lib/Capstone/README:
--------------------------------------------------------------------------------
1 | This module has three dependencies:
2 | * lib\x86\libcapstone.dll (the 32-bit unmanaged Capstone library)
3 | * lib\x64\libcapstone.dll (the 64-bit unmanaged Capstone library)
4 | * lib\capstone.dll (the managed C# bindings to the Capstone Framework)
5 |
6 | To install this module, drop the entire ScriptModification folder into one of your module directories. The default PowerShell module paths are listed in the $Env:PSModulePath environment variable.
7 |
8 | The default per-user module path is: "$Env:HomeDrive$Env:HOMEPATH\Documents\WindowsPowerShell\Modules"
9 | The default computer-level module path is: "$Env:windir\System32\WindowsPowerShell\v1.0\Modules"
10 |
11 | To use the module, type `Import-Module Capstone`
12 |
13 | To see the commands imported, type `Get-Command -Module Capstone`
14 |
15 | For help on each individual command, Get-Help is your friend.
16 |
17 | Note: The tools contained within this module were all designed such that they can be run individually. Including them in a module simply lends itself to increased portability.
--------------------------------------------------------------------------------
/Lib/PSReflect/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, Matt Graeber
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of PSReflect nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/Lib/Formatters/ProcessModuleTrace.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ProcessModuleTraceView
6 |
7 | LOADED_MODULE
8 |
9 |
10 |
11 |
12 |
13 |
14 | TimeCreated
15 |
16 |
17 | ProcessId
18 |
19 |
20 | FileName
21 |
22 |
23 |
24 | "0x$($_.ImageBase.ToString("X$([IntPtr]::Size * 2)"))"
25 |
26 |
27 | ImageSize
28 | 0x{0:X8}
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Lib/Formatters/MemoryTools.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MemoryStringView
6 |
7 | MEM.STRING
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | String
26 |
27 |
28 | Address
29 | 0x{0:X16}
30 |
31 |
32 | Encoding
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Lib/Capstone/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | This is the software license for Capstone disassembly framework.
2 | Capstone has been designed & implemented by Nguyen Anh Quynh
3 | See http://www.capstone-engine.org for further information.
4 |
5 | Copyright (c) 2013, COSEINC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 |
11 | * Redistributions of source code must retain the above copyright notice,
12 | this list of conditions and the following disclaimer.
13 | * Redistributions in binary form must reproduce the above copyright notice,
14 | this list of conditions and the following disclaimer in the documentation
15 | and/or other materials provided with the distribution.
16 | * Neither the name of the developer(s) nor the names of its
17 | contributors may be used to endorse or promote products derived from this
18 | software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 | POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/Lib/Formatters/Get-CSDisassembly.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | InstructionView
6 |
7 | Capstone.Instruction
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Address
27 | 0x{0:X8}
28 |
29 |
30 | Mnemonic
31 |
32 |
33 | Operands
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/WindowsInternals/Get-SystemInfo.ps1:
--------------------------------------------------------------------------------
1 | function Get-SystemInfo {
2 | <#
3 | .SYNOPSIS
4 |
5 | A wrapper for kernel32!GetSystemInfo
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: BSD 3-Clause
9 | Required Dependencies: PSReflect module
10 | Optional Dependencies: None
11 | #>
12 |
13 | $Mod = New-InMemoryModule -ModuleName SysInfo
14 |
15 | $ProcessorType = psenum $Mod SYSINFO.PROCESSOR_ARCH UInt16 @{
16 | PROCESSOR_ARCHITECTURE_INTEL = 0
17 | PROCESSOR_ARCHITECTURE_MIPS = 1
18 | PROCESSOR_ARCHITECTURE_ALPHA = 2
19 | PROCESSOR_ARCHITECTURE_PPC = 3
20 | PROCESSOR_ARCHITECTURE_SHX = 4
21 | PROCESSOR_ARCHITECTURE_ARM = 5
22 | PROCESSOR_ARCHITECTURE_IA64 = 6
23 | PROCESSOR_ARCHITECTURE_ALPHA64 = 7
24 | PROCESSOR_ARCHITECTURE_AMD64 = 9
25 | PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF
26 | }
27 |
28 | $SYSTEM_INFO = struct $Mod SYSINFO.SYSTEM_INFO @{
29 | ProcessorArchitecture = field 0 $ProcessorType
30 | Reserved = field 1 Int16
31 | PageSize = field 2 Int32
32 | MinimumApplicationAddress = field 3 IntPtr
33 | MaximumApplicationAddress = field 4 IntPtr
34 | ActiveProcessorMask = field 5 IntPtr
35 | NumberOfProcessors = field 6 Int32
36 | ProcessorType = field 7 Int32
37 | AllocationGranularity = field 8 Int32
38 | ProcessorLevel = field 9 Int16
39 | ProcessorRevision = field 10 Int16
40 | }
41 |
42 | $FunctionDefinitions = @(
43 | (func kernel32 GetSystemInfo ([Void]) @($SYSTEM_INFO.MakeByRefType()))
44 | )
45 |
46 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32SysInfo'
47 | $Kernel32 = $Types['kernel32']
48 |
49 | $SysInfo = [Activator]::CreateInstance($SYSTEM_INFO)
50 | $Kernel32::GetSystemInfo([Ref] $SysInfo)
51 |
52 | $SysInfo
53 | }
--------------------------------------------------------------------------------
/Misc/ConvertTo-String.ps1:
--------------------------------------------------------------------------------
1 | filter ConvertTo-String
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Converts the bytes of a file to a string.
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .DESCRIPTION
14 |
15 | ConvertTo-String converts the bytes of a file to a string that has a
16 | 1-to-1 mapping back to the file's original bytes. ConvertTo-String is
17 | useful for performing binary regular expressions.
18 |
19 | .PARAMETER Path
20 |
21 | Specifies the path to the file to convert.
22 |
23 | .EXAMPLE
24 |
25 | PS C:\>$BinaryString = ConvertTo-String C:\Windows\SysWow64\kernel32.dll
26 | PS C:\>$HotpatchableRegex = [Regex] '[\xCC\x90]{5}\x8B\xFF'
27 | PS C:\>$HotpatchableRegex.Matches($BinaryString)
28 |
29 | Description
30 | -----------
31 | Converts kernel32.dll into a string. A binary regular expression is
32 | then performed on the string searching for a hotpatchable code
33 | sequence - i.e. 5 nop/int3 followed by a mov edi, edi instruction.
34 |
35 | .NOTES
36 |
37 | The intent of ConvertTo-String is not to replicate the functionality
38 | of strings.exe, rather it is intended to be used when
39 | performing regular expressions on binary data.
40 | #>
41 |
42 | [OutputType([String])]
43 | Param (
44 | [Parameter( Mandatory = $True,
45 | Position = 0,
46 | ValueFromPipeline = $True )]
47 | [ValidateScript({-not (Test-Path $_ -PathType Container)})]
48 | [String]
49 | $Path
50 | )
51 |
52 | $FileStream = New-Object -TypeName IO.FileStream -ArgumentList (Resolve-Path $Path), 'Open', 'Read'
53 |
54 | # Note: Codepage 28591 returns a 1-to-1 char to byte mapping
55 | $Encoding = [Text.Encoding]::GetEncoding(28591)
56 |
57 | $StreamReader = New-Object IO.StreamReader($FileStream, $Encoding)
58 |
59 | $BinaryText = $StreamReader.ReadToEnd()
60 |
61 | $StreamReader.Close()
62 | $FileStream.Close()
63 |
64 | Write-Output $BinaryText
65 | }
66 |
--------------------------------------------------------------------------------
/Lib/Formatters/Get-LibSymbols.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SymbolTypeView
6 |
7 | COFF.SymbolInfo
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Module
30 |
31 |
32 | SymbolType
33 |
34 |
35 | UndecoratedName
36 |
37 |
38 | DecoratedName
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/WindowsInternals/ProcessModuleTrace.ps1:
--------------------------------------------------------------------------------
1 | function Register-ProcessModuleTrace
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Starts a trace of loaded process modules
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .OUTPUTS
14 |
15 | System.Management.Automation.PSEventJob
16 |
17 | If desired, you can manipulate the event returned with the *-Event cmdlets.
18 | #>
19 |
20 | [CmdletBinding()] Param ()
21 |
22 | if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator'))
23 | {
24 | throw 'You must run this cmdlet from an elevated PowerShell session.'
25 | }
26 |
27 | $ModuleLoadedAction = {
28 | $Event = $EventArgs.NewEvent
29 |
30 | $ModuleInfo = @{
31 | TimeCreated = [DateTime]::FromFileTime($Event.TIME_CREATED)
32 | ProcessId = $Event.ProcessId
33 | FileName = $Event.FileName
34 | ImageBase = $Event.ImageBase
35 | ImageSize = $Event.ImageSize
36 | }
37 |
38 | $ModuleObject = New-Object PSObject -Property $ModuleInfo
39 | $ModuleObject.PSObject.TypeNames[0] = 'LOADED_MODULE'
40 |
41 | $ModuleObject
42 | }
43 |
44 | Register-WmiEvent 'Win32_ModuleLoadTrace' -SourceIdentifier 'ModuleLoaded' -Action $ModuleLoadedAction
45 | }
46 |
47 | function Get-ProcessModuleTrace
48 | {
49 | <#
50 | .SYNOPSIS
51 |
52 | Displays the process modules that have been loaded since the call to Register-ProcessModuleTrace
53 |
54 | Author: Matthew Graeber (@mattifestation)
55 | License: BSD 3-Clause
56 | Required Dependencies: Register-ProcessModuleTrace
57 | Optional Dependencies: None
58 |
59 | .OUTPUTS
60 |
61 | PSObject
62 | #>
63 |
64 | $Events = Get-EventSubscriber -SourceIdentifier 'ModuleLoaded' -ErrorVariable NoEventRegistered -ErrorAction SilentlyContinue
65 |
66 | if ($NoEventRegistered)
67 | {
68 | throw 'You must execute Register-ProcessModuleTrace before you can retrieve a loaded module list'
69 | }
70 |
71 | $Events.Action.Output
72 | }
73 |
74 | function Unregister-ProcessModuleTrace
75 | {
76 | <#
77 | .SYNOPSIS
78 |
79 | Stops the running process module trace
80 |
81 | Author: Matthew Graeber (@mattifestation)
82 | License: BSD 3-Clause
83 | Required Dependencies: Register-ProcessModuleTrace
84 | Optional Dependencies: None
85 | #>
86 |
87 | Unregister-Event -SourceIdentifier 'ModuleLoaded'
88 | }
89 |
--------------------------------------------------------------------------------
/Misc/Get-Strings.ps1:
--------------------------------------------------------------------------------
1 | function Get-Strings
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Gets strings from a file.
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .DESCRIPTION
14 |
15 | The Get-Strings cmdlet returns strings (Unicode and/or Ascii) from a file. This cmdlet is useful for dumping strings from binary file and was designed to replicate the functionality of strings.exe from Sysinternals.
16 |
17 | .PARAMETER Path
18 |
19 | Specifies the path to an item.
20 |
21 | .PARAMETER Encoding
22 |
23 | Specifies the file encoding. The default value returns both Unicode and Ascii.
24 |
25 | .PARAMETER MinimumLength
26 |
27 | Specifies the minimum length string to return. The default string length is 3.
28 |
29 | .EXAMPLE
30 |
31 | Get-Strings C:\Windows\System32\calc.exe
32 |
33 | Description
34 | -----------
35 | Dump Unicode and Ascii strings of calc.exe.
36 |
37 | .EXAMPLE
38 |
39 | Get-ChildItem C:\Windows\System32\*.dll | Get-Strings -MinimumLength 12 -Encoding Ascii
40 |
41 | Description
42 | -----------
43 | Dumps Ascii strings of at least length 12 of every dll located in C:\Windows\System32.
44 | #>
45 |
46 | Param
47 | (
48 | [Parameter(Position = 1, Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
49 | [ValidateNotNullOrEmpty()]
50 | [ValidateScript({Test-Path $_ -PathType 'Leaf'})]
51 | [String[]]
52 | [Alias('PSPath')]
53 | $Path,
54 |
55 | [ValidateSet('Default','Ascii','Unicode')]
56 | [String]
57 | $Encoding = 'Default',
58 |
59 | [UInt32]
60 | $MinimumLength = 3
61 | )
62 |
63 | BEGIN
64 | {
65 | $FileContents = ''
66 | }
67 | PROCESS
68 | {
69 | foreach ($File in $Path)
70 | {
71 | if ($Encoding -eq 'Unicode' -or $Encoding -eq 'Default')
72 | {
73 | $UnicodeFileContents = Get-Content -Encoding 'Unicode' $File
74 | $UnicodeRegex = [Regex] "[\u0020-\u007E]{$MinimumLength,}"
75 | $Results += $UnicodeRegex.Matches($UnicodeFileContents)
76 | }
77 |
78 | if ($Encoding -eq 'Ascii' -or $Encoding -eq 'Default')
79 | {
80 | $AsciiFileContents = Get-Content -Encoding 'UTF7' $File
81 | $AsciiRegex = [Regex] "[\x20-\x7E]{$MinimumLength,}"
82 | $Results = $AsciiRegex.Matches($AsciiFileContents)
83 | }
84 |
85 | $Results | ForEach-Object { Write-Output $_.Value }
86 | }
87 | }
88 | END {}
89 | }
90 |
--------------------------------------------------------------------------------
/Misc/Get-Entropy.ps1:
--------------------------------------------------------------------------------
1 | function Get-Entropy
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Calculates the entropy of a file or byte array.
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .PARAMETER ByteArray
14 |
15 | Specifies the byte array containing the data from which entropy will be calculated.
16 |
17 | .PARAMETER FilePath
18 |
19 | Specifies the path to the input file from which entropy will be calculated.
20 |
21 | .EXAMPLE
22 |
23 | Get-Entropy -FilePath C:\Windows\System32\kernel32.dll
24 |
25 | .EXAMPLE
26 |
27 | ls C:\Windows\System32\*.dll | % { Get-Entropy -FilePath $_ }
28 |
29 | .EXAMPLE
30 |
31 | C:\PS>$RandArray = New-Object Byte[](10000)
32 | C:\PS>foreach ($Offset in 0..9999) { $RandArray[$Offset] = [Byte] (Get-Random -Min 0 -Max 256) }
33 | C:\PS>$RandArray | Get-Entropy
34 |
35 | Description
36 | -----------
37 | Calculates the entropy of a large array containing random bytes.
38 |
39 | .EXAMPLE
40 |
41 | 0..255 | Get-Entropy
42 |
43 | Description
44 | -----------
45 | Calculates the entropy of 0-255. This should equal exactly 8.
46 |
47 | .OUTPUTS
48 |
49 | System.Double
50 |
51 | Get-Entropy outputs a double representing the entropy of the byte array.
52 | #>
53 |
54 | [CmdletBinding()] Param (
55 | [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True, ParameterSetName = 'Bytes')]
56 | [ValidateNotNullOrEmpty()]
57 | [Byte[]]
58 | $ByteArray,
59 |
60 | [Parameter(Mandatory = $True, Position = 0, ParameterSetName = 'File')]
61 | [ValidateNotNullOrEmpty()]
62 | [IO.FileInfo]
63 | $FilePath
64 | )
65 |
66 | BEGIN
67 | {
68 | $FrequencyTable = @{}
69 | $ByteArrayLength = 0
70 | }
71 |
72 | PROCESS
73 | {
74 | if ($PsCmdlet.ParameterSetName -eq 'File')
75 | {
76 | $ByteArray = [IO.File]::ReadAllBytes($FilePath.FullName)
77 | }
78 |
79 | foreach ($Byte in $ByteArray)
80 | {
81 | $FrequencyTable[$Byte]++
82 | $ByteArrayLength++
83 | }
84 | }
85 |
86 | END
87 | {
88 | $Entropy = 0.0
89 |
90 | foreach ($Byte in 0..255)
91 | {
92 | $ByteProbability = ([Double] $FrequencyTable[[Byte]$Byte]) / $ByteArrayLength
93 | if ($ByteProbability -gt 0)
94 | {
95 | $Entropy += -$ByteProbability * [Math]::Log($ByteProbability, 2)
96 | }
97 | }
98 |
99 | Write-Output $Entropy
100 | }
101 | }
--------------------------------------------------------------------------------
/Disassembly/Get-ILDisassembly.ps1:
--------------------------------------------------------------------------------
1 | filter Get-ILDisassembly {
2 | <#
3 | .SYNOPSIS
4 |
5 | A MSIL (Microsoft Intermediate Language) disassembler.
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: GPLv3
9 | Required Dependencies: de4dot library dlls
10 | Optional Dependencies: Get-ILDisassembly.format.ps1xml
11 |
12 | .PARAMETER MethodInfo
13 |
14 | A MethodInfo object that describes the implementation of the method and contains the IL for the method.
15 |
16 | .EXAMPLE
17 |
18 | [Int].GetMethod('Parse', [String]) | Get-ILDisassembly
19 |
20 | .EXAMPLE
21 |
22 | [Array].GetMethod('BinarySearch', [Type[]]([Array], [Object])) | Get-ILDisassembly
23 |
24 | .EXAMPLE
25 |
26 | Get-ILDisassembly -AssemblyPath evil.exe -MetadataToken 0x06000001
27 |
28 | .OUTPUTS
29 |
30 | System.Object
31 |
32 | Returns a custom object consisting of the method name, metadata token, method signature, and instructions.
33 | #>
34 |
35 | Param (
36 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath')]
37 | [ValidateScript({Test-Path $_})]
38 | [Alias('Path')]
39 | [String]
40 | $AssemblyPath,
41 |
42 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath')]
43 | [ValidateScript({($_ -band 0x06000000) -eq 0x06000000})]
44 | [Int32]
45 | $MetadataToken,
46 |
47 | [Parameter(Mandatory = $True, ParameterSetName = 'MethodInfo', ValueFromPipeline = $True)]
48 | [Reflection.MethodBase]
49 | $MethodInfo,
50 |
51 | [Parameter(Mandatory = $True, ParameterSetName = 'MethodDef', ValueFromPipeline = $True)]
52 | [dnlib.DotNet.MethodDef]
53 | $MethodDef
54 | )
55 |
56 | switch ($PsCmdlet.ParameterSetName)
57 | {
58 | 'AssemblyPath' {
59 | $FullPath = Resolve-Path $AssemblyPath
60 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($FullPath.Path)
61 | $Method = $Module.ResolveMethod(($MetadataToken -band 0xFFFFFF))
62 | }
63 |
64 | 'MethodInfo' {
65 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($MethodInfo.Module)
66 | $Method = $Module.ResolveMethod(($MethodInfo.MetadataToken -band 0xFFFFFF))
67 | }
68 |
69 | 'MethodDef' {
70 | $Method = $MethodDef
71 | }
72 | }
73 |
74 | if ($Method.HasBody) {
75 | $Result = @{
76 | Name = $Method.Name.String
77 | MetadataToken = "0x$($Method.MDToken.Raw.ToString('X8'))"
78 | Signature = $Method.ToString()
79 | Instructions = $Method.MethodBody.Instructions
80 | }
81 |
82 | $Disasm = New-Object PSObject -Property $Result
83 | $Disasm.PSObject.TypeNames.Insert(0, 'IL_METAINFO')
84 |
85 | return $Disasm
86 | } else {
87 | Write-Warning "Method is not implemented. Name: $($Method.Name.String), MetadataToken: 0x$($Method.MDToken.Raw.ToString('X8'))"
88 | }
89 | }
--------------------------------------------------------------------------------
/Lib/Formatters/Get-ILDisassembly.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ILInstructionView
6 |
7 | dnlib.DotNet.Emit.Instruction
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Offset
27 | 0x{0:X4}
28 |
29 |
30 | OpCode
31 |
32 |
33 | Operand
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ILMetaInfoView
42 |
43 | IL_METAINFO
44 |
45 |
46 |
47 |
48 |
49 |
50 | Name
51 |
52 |
53 | MetadataToken
54 |
55 |
56 | Signature
57 |
58 |
59 | Instructions
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | build/
49 | [Bb]in/
50 | [Oo]bj/
51 |
52 | # MSTest test Results
53 | [Tt]est[Rr]esult*/
54 | [Bb]uild[Ll]og.*
55 |
56 | *_i.c
57 | *_p.c
58 | *.ilk
59 | *.meta
60 | *.obj
61 | *.pch
62 | *.pdb
63 | *.pgc
64 | *.pgd
65 | *.rsp
66 | *.sbr
67 | *.tlb
68 | *.tli
69 | *.tlh
70 | *.tmp
71 | *.tmp_proj
72 | *.log
73 | *.vspscc
74 | *.vssscc
75 | .builds
76 | *.pidb
77 | *.log
78 | *.scc
79 |
80 | # Visual C++ cache files
81 | ipch/
82 | *.aps
83 | *.ncb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 |
88 | # Visual Studio profiler
89 | *.psess
90 | *.vsp
91 | *.vspx
92 |
93 | # Guidance Automation Toolkit
94 | *.gpState
95 |
96 | # ReSharper is a .NET coding add-in
97 | _ReSharper*/
98 | *.[Rr]e[Ss]harper
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | *.ncrunch*
108 | .*crunch*.local.xml
109 |
110 | # Installshield output folder
111 | [Ee]xpress/
112 |
113 | # DocProject is a documentation generator add-in
114 | DocProject/buildhelp/
115 | DocProject/Help/*.HxT
116 | DocProject/Help/*.HxC
117 | DocProject/Help/*.hhc
118 | DocProject/Help/*.hhk
119 | DocProject/Help/*.hhp
120 | DocProject/Help/Html2
121 | DocProject/Help/html
122 |
123 | # Click-Once directory
124 | publish/
125 |
126 | # Publish Web Output
127 | *.Publish.xml
128 | *.pubxml
129 |
130 | # NuGet Packages Directory
131 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
132 | #packages/
133 |
134 | # Windows Azure Build Output
135 | csx
136 | *.build.csdef
137 |
138 | # Windows Store app package directory
139 | AppPackages/
140 |
141 | # Others
142 | sql/
143 | *.Cache
144 | ClientBin/
145 | [Ss]tyle[Cc]op.*
146 | ~$*
147 | *~
148 | *.dbmdl
149 | *.[Pp]ublish.xml
150 | *.pfx
151 | *.publishsettings
152 |
153 | # RIA/Silverlight projects
154 | Generated_Code/
155 |
156 | # Backup & report files from converting an old project file to a newer
157 | # Visual Studio version. Backup files are not needed, because we have git ;-)
158 | _UpgradeReport_Files/
159 | Backup*/
160 | UpgradeLog*.XML
161 | UpgradeLog*.htm
162 |
163 | # SQL Server files
164 | App_Data/*.mdf
165 | App_Data/*.ldf
166 |
167 | #############
168 | ## Windows detritus
169 | #############
170 |
171 | # Windows image file caches
172 | Thumbs.db
173 | ehthumbs.db
174 |
175 | # Folder config file
176 | Desktop.ini
177 |
178 | # Recycle Bin used on file shares
179 | $RECYCLE.BIN/
180 |
181 | # Mac crap
182 | .DS_Store
183 |
184 |
185 | #############
186 | ## Python
187 | #############
188 |
189 | *.py[co]
190 |
191 | # Packages
192 | *.egg
193 | *.egg-info
194 | dist/
195 | build/
196 | eggs/
197 | parts/
198 | var/
199 | sdist/
200 | develop-eggs/
201 | .installed.cfg
202 |
203 | # Installer logs
204 | pip-log.txt
205 |
206 | # Unit test / coverage reports
207 | .coverage
208 | .tox
209 |
210 | #Translations
211 | *.mo
212 |
213 | #Mr Developer
214 | .mr.developer.cfg
215 |
--------------------------------------------------------------------------------
/PowerShellArsenal.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | # Script module or binary module file associated with this manifest.
3 | ModuleToProcess = 'PowerShellArsenal.psm1'
4 |
5 | # Version number of this module.
6 | ModuleVersion = '1.0.1.0'
7 |
8 | # ID used to uniquely identify this module
9 | GUID = '55edc9c7-e790-4e78-88d6-0492cdcc4b3c'
10 |
11 | # Author of this module
12 | Author = 'Matthew Graeber'
13 |
14 | # Company or vendor of this module
15 | CompanyName = ''
16 |
17 | # Copyright statement for this module
18 | Copyright = 'BSD 3-Clause unless explicitly noted otherwise'
19 |
20 | # Description of the functionality provided by this module
21 | Description = 'Reverse Eningeering Module'
22 |
23 | # Minimum version of the Windows PowerShell engine required by this module
24 | PowerShellVersion = '2.0'
25 |
26 | # Assemblies that must be loaded prior to importing this module
27 | RequiredAssemblies = @('Lib\De4dot\dnlib.dll',
28 | 'Lib\De4dot\de4dot.blocks.dll',
29 | 'Lib\De4dot\de4dot.code.dll',
30 | 'Lib\De4dot\de4dot.mdecrypt.dll',
31 | 'Lib\De4dot\AssemblyData.dll')
32 |
33 | # Format files (.ps1xml) to be loaded when importing this module
34 | FormatsToProcess = @('Lib\Formatters\Get-CSDisassembly.format.ps1xml',
35 | 'Lib\Formatters\Get-ILDisassembly.format.ps1xml',
36 | 'Lib\Formatters\Get-LibSymbols.format.ps1xml',
37 | 'Lib\Formatters\Get-NtSystemInformation.format.ps1xml',
38 | 'Lib\Formatters\Get-ObjDump.format.ps1xml',
39 | 'Lib\Formatters\Get-PEB.format.ps1xml',
40 | 'Lib\Formatters\Get-PE.format.ps1xml',
41 | 'Lib\Formatters\ProcessModuleTrace.format.ps1xml',
42 | 'Lib\Formatters\MemoryTools.format.ps1xml')
43 |
44 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
45 | NestedModules = @('Lib\Capstone\Capstone.psd1',
46 | 'Lib\PSReflect\PSReflect.psd1')
47 |
48 | # Functions to export from this module
49 | # I've chosen to explicitly the functions I want to expose rather than exporting everything or calling Export-ModuleMember
50 | FunctionsToExport = @('Get-CSDisassembly',
51 | 'Get-ILDisassembly',
52 | 'Get-StructFromMemory',
53 | 'ConvertTo-String',
54 | 'Get-Strings',
55 | 'Get-Entropy',
56 | 'Get-Member',
57 | 'Get-PE',
58 | 'Get-PEB',
59 | 'Find-ProcessPEs',
60 | 'Get-LibSymbols',
61 | 'Get-ObjDump',
62 | 'Get-SystemInfo',
63 | 'Get-VirtualMemoryInfo',
64 | 'Get-ProcessMemoryInfo',
65 | 'Get-ProcessStrings',
66 | 'Get-AssemblyResources',
67 | 'Get-AssemblyStrings',
68 | 'Get-AssemblyImplementedMethods',
69 | 'Get-HostsFile',
70 | 'New-HostsFileEntry',
71 | 'Remove-HostsFileEntry',
72 | 'Remove-AssemblySuppressIldasmAttribute',
73 | 'New-FunctionDelegate',
74 | 'Get-NtSystemInformation',
75 | 'Register-ProcessModuleTrace',
76 | 'Get-ProcessModuleTrace',
77 | 'Unregister-ProcessModuleTrace',
78 | 'Invoke-LoadLibrary',
79 | 'New-DllExportFunction')
80 |
81 | # Cmdlets to export from this module
82 | CmdletsToExport = ''
83 |
84 | # Variables to export from this module
85 | VariablesToExport = ''
86 |
87 | # Aliases to export from this module
88 | AliasesToExport = ''
89 |
90 | # List of all modules packaged with this module.
91 | ModuleList = @(@{ModuleName = 'Capstone'; ModuleVersion = '1.0.0.0'; GUID = 'bc335667-02fd-46c4-a3d9-0a5113c9c03b'},
92 | @{ModuleName = 'PSReflect'; ModuleVersion = '1.1.1.0'; GUID = '32c3f36a-519f-4032-9090-053956ae85e1'})
93 | }
94 |
--------------------------------------------------------------------------------
/Lib/PSReflect/Examples/Get-NetShare.ps1:
--------------------------------------------------------------------------------
1 | #requires -version 2
2 |
3 |
4 | function Get-NetShare {
5 | <#
6 | .SYNOPSIS
7 | Gets share information for a specified server.
8 | By @harmj0y
9 |
10 | .DESCRIPTION
11 | This function will execute the NetShareEnum Win32API call to query
12 | a given host for open shares. This is a replacement for
13 | "net share \\hostname"
14 |
15 | .PARAMETER HostName
16 | The hostname to query for shares.
17 |
18 | .OUTPUTS
19 | SHARE_INFO_1 structure. A representation of the SHARE_INFO_1
20 | result structure which includes the name and note for each share.
21 |
22 | .EXAMPLE
23 | > Get-NetShare
24 | Returns active shares on the local host.
25 |
26 | .EXAMPLE
27 | > Get-NetShare -HostName sqlserver
28 | Returns active shares on the 'sqlserver' host
29 | #>
30 |
31 | [CmdletBinding()]
32 | param(
33 | [string]
34 | $HostName = 'localhost'
35 | )
36 |
37 | If ($PSBoundParameters['Debug']) {
38 | $DebugPreference = 'Continue'
39 | }
40 |
41 | # arguments for NetShareEnum
42 | $QueryLevel = 1
43 | $ptrInfo = [IntPtr]::Zero
44 | $EntriesRead = 0
45 | $TotalRead = 0
46 | $ResumeHandle = 0
47 |
48 | # get the share information
49 | $Result = $Netapi32::NetShareEnum($HostName, $QueryLevel,[ref]$ptrInfo,-1,[ref]$EntriesRead,[ref]$TotalRead,[ref]$ResumeHandle)
50 |
51 | # Locate the offset of the initial intPtr
52 | $offset = $ptrInfo.ToInt64()
53 |
54 | Write-Debug "Get-NetShare result: $Result"
55 |
56 | # 0 = success
57 | if (($Result -eq 0) -and ($offset -gt 0)) {
58 |
59 | # Work out how mutch to increment the pointer by finding out the size of the structure
60 | $Increment = $SHARE_INFO_1::GetSize()
61 |
62 | # parse all the result structures
63 | for ($i = 0; ($i -lt $EntriesRead); $i++){
64 | # create a new int ptr at the given offset and cast
65 | # the pointer as our result structure
66 | $newintptr = New-Object system.Intptr -ArgumentList $offset
67 | $Info = $newintptr -as $SHARE_INFO_1
68 | # return all the sections of the structure
69 | $Info | Select-Object *
70 | $offset = $newintptr.ToInt64()
71 | $offset += $increment
72 | }
73 | # free up the result buffer
74 | $Netapi32::NetApiBufferFree($ptrInfo) | Out-Null
75 | }
76 | else
77 | {
78 | switch ($Result) {
79 | (5) {Write-Debug 'The user does not have access to the requested information.'}
80 | (124) {Write-Debug 'The value specified for the level parameter is not valid.'}
81 | (87) {Write-Debug 'The specified parameter is not valid.'}
82 | (234) {Write-Debug 'More entries are available. Specify a large enough buffer to receive all entries.'}
83 | (8) {Write-Debug 'Insufficient memory is available.'}
84 | (2312) {Write-Debug 'A session does not exist with the computer name.'}
85 | (2351) {Write-Debug 'The computer name is not valid.'}
86 | (2221) {Write-Debug 'Username not found.'}
87 | (53) {Write-Debug 'Hostname could not be found'}
88 | }
89 | }
90 | }
91 |
92 | $Mod = New-InMemoryModule -ModuleName Win32
93 |
94 | # all of the Win32 API functions we need
95 | $FunctionDefinitions = @(
96 | (func netapi32 NetSessionEnum ([Int]) @([string], [string], [string], [Int], [IntPtr].MakeByRefType(), [Int], [Int32].MakeByRefType(), [Int32].MakeByRefType(), [Int32].MakeByRefType())),
97 | (func netapi32 NetApiBufferFree ([Int]) @([IntPtr]))
98 | )
99 |
100 | # the NetSessionEnum result structure
101 | $SESSION_INFO_10 = struct $Mod SESSION_INFO_10 @{
102 | sesi10_cname = field 0 String -MarshalAs @('LPWStr')
103 | sesi10_username = field 1 String -MarshalAs @('LPWStr')
104 | sesi10_time = field 2 UInt32
105 | sesi10_idle_time = field 3 UInt32
106 | }
107 |
108 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
109 | $Netapi32 = $Types['netapi32']
110 |
--------------------------------------------------------------------------------
/Disassembly/Get-CSDisassembly.ps1:
--------------------------------------------------------------------------------
1 | function Get-CSDisassembly
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Disassembles a byte array using the Capstone Engine disassembly framework.
7 |
8 | PowerSploit Function: Get-CSDisassembly
9 | Author: Matthew Graeber (@mattifestation)
10 | License: See LICENSE.TXT
11 | Required Dependencies: lib\capstone.dll, lib\[x86|x64]\libcapstone.dll
12 | Optional Dependencies: None
13 |
14 | .DESCRIPTION
15 |
16 | Get-CSDisassembly is compatible on 32 and 64-bit.
17 |
18 | .PARAMETER Architecture
19 |
20 | Specifies the architecture of the code to be disassembled.
21 |
22 | .PARAMETER Mode
23 |
24 | Specifies the mode in which to disassemble code. For example, to disassemble Amd64 code, architecture is set to 'X86' and Mode is set to 'MODE_64'.
25 |
26 | .PARAMETER Code
27 |
28 | A byte array consisting of the code to be disassembled.
29 |
30 | .PARAMETER Offset
31 |
32 | Specifies the starting address of the disassembly listing.
33 |
34 | .PARAMETER Count
35 |
36 | Specifies the maximum number of instructions to disassemble.
37 |
38 | .PARAMETER Syntax
39 |
40 | Specifies the syntax flavor to be used (INTEL vs. ATT).
41 |
42 | .PARAMETER DetailOn
43 |
44 | Specifies that detailed parsing should be performed - i.e. provide detailed information for each disassembled instruction.
45 |
46 | .PARAMETER Verstion
47 |
48 | Prints the running Capstone Framework version.
49 |
50 | .EXAMPLE
51 |
52 | $Bytes = [Byte[]] @( 0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00 )
53 | Get-CSDisassembly -Architecture X86 -Mode Mode16 -Code $Bytes -Offset 0x1000
54 |
55 | $Bytes = [Byte[]] @( 0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00 )
56 | Get-CSDisassembly -Architecture X86 -Mode Mode32 -Code $Bytes
57 |
58 | $Bytes = [Byte[]] @( 0x8D, 0x4C, 0x32, 0x08, 0x01, 0xD8, 0x81, 0xC6, 0x34, 0x12, 0x00, 0x00 )
59 | Get-CSDisassembly -Architecture X86 -Mode Mode32 -Code $Bytes -Syntax ATT
60 |
61 | $Bytes = [Byte[]] @( 0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00 )
62 | Get-CSDisassembly -Architecture X86 -Mode Mode64 -Code $Bytes -DetailOn
63 |
64 | $Bytes = [Byte[]] @( 0xED, 0xFF, 0xFF, 0xEB, 0x04, 0xe0, 0x2d, 0xe5, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x83, 0x22, 0xe5, 0xf1, 0x02, 0x03, 0x0e, 0x00, 0x00, 0xa0, 0xe3, 0x02, 0x30, 0xc1, 0xe7, 0x00, 0x00, 0x53, 0xe3 )
65 | Get-CSDisassembly -Architecture Arm -Mode Arm -Code $Bytes
66 |
67 | $Bytes = [Byte[]] @( 0x4f, 0xf0, 0x00, 0x01, 0xbd, 0xe8, 0x00, 0x88, 0xd1, 0xe8, 0x00, 0xf0 )
68 | Get-CSDisassembly -Architecture Arm -Mode Thumb -Code $Bytes
69 |
70 | $Bytes = [Byte[]] @( 0x10, 0xf1, 0x10, 0xe7, 0x11, 0xf2, 0x31, 0xe7, 0xdc, 0xa1, 0x2e, 0xf3, 0xe8, 0x4e, 0x62, 0xf3 )
71 | Get-CSDisassembly -Architecture Arm -Mode Arm -Code $Bytes
72 |
73 | $Bytes = [Byte[]] @( 0x70, 0x47, 0xeb, 0x46, 0x83, 0xb0, 0xc9, 0x68 )
74 | Get-CSDisassembly -Architecture Arm -Mode Thumb -Code $Bytes -DetailOn
75 |
76 | $Bytes = [Byte[]] @( 0x21, 0x7c, 0x02, 0x9b, 0x21, 0x7c, 0x00, 0x53, 0x00, 0x40, 0x21, 0x4b, 0xe1, 0x0b, 0x40, 0xb9 )
77 | Get-CSDisassembly -Architecture Arm64 -Mode Arm -Code $Bytes
78 |
79 | $Bytes = [Byte[]] @( 0x0C, 0x10, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0c, 0x8f, 0xa2, 0x00, 0x00, 0x34, 0x21, 0x34, 0x56 )
80 | Get-CSDisassembly -Architecture Mips -Mode 'Mode32, BigEndian' -Code $Bytes
81 |
82 | $Bytes = [Byte[]] @( 0x56, 0x34, 0x21, 0x34, 0xc2, 0x17, 0x01, 0x00 )
83 | Get-CSDisassembly -Architecture Mips -Mode 'Mode64, LittleEndian' -Code $Bytes
84 |
85 | $Bytes = [Byte[]] @( 0x80, 0x20, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x10, 0x43, 0x23, 0x0e, 0xd0, 0x44, 0x00, 0x80, 0x4c, 0x43, 0x22, 0x02, 0x2d, 0x03, 0x00, 0x80, 0x7c, 0x43, 0x20, 0x14, 0x7c, 0x43, 0x20, 0x93, 0x4f, 0x20, 0x00, 0x21, 0x4c, 0xc8, 0x00, 0x21 )
86 | Get-CSDisassembly -Architecture PPC -Mode BigEndian -Code $Bytes
87 |
88 | .INPUTS
89 |
90 | None
91 |
92 | You cannot pipe objects to Get-CSDisassembly.
93 |
94 | .OUTPUTS
95 |
96 | Capstone.Instruction[]
97 |
98 | Get-CSDisassembly returns an array of Instruction objects.
99 | #>
100 |
101 | [OutputType([Capstone.Instruction])]
102 | [CmdletBinding(DefaultParameterSetName = 'Disassemble')]
103 | Param (
104 | [Parameter(Mandatory, ParameterSetName = 'Disassemble')]
105 | [Capstone.Architecture]
106 | $Architecture,
107 |
108 | [Parameter(Mandatory, ParameterSetName = 'Disassemble')]
109 | [Capstone.Mode]
110 | $Mode,
111 |
112 | [Parameter(Mandatory, ParameterSetName = 'Disassemble')]
113 | [ValidateNotNullOrEmpty()]
114 | [Byte[]]
115 | $Code,
116 |
117 | [Parameter( ParameterSetName = 'Disassemble' )]
118 | [UInt64]
119 | $Offset = 0,
120 |
121 | [Parameter( ParameterSetName = 'Disassemble' )]
122 | [UInt32]
123 | $Count = 0,
124 |
125 | [Parameter( ParameterSetName = 'Disassemble' )]
126 | [ValidateSet('Intel', 'ATT')]
127 | [String]
128 | $Syntax,
129 |
130 | [Parameter( ParameterSetName = 'Disassemble' )]
131 | [Switch]
132 | $DetailOn,
133 |
134 | [Parameter( ParameterSetName = 'Version' )]
135 | [Switch]
136 | $Version
137 | )
138 |
139 | if ($PsCmdlet.ParameterSetName -eq 'Version')
140 | {
141 | $Disassembly = New-Object Capstone.Capstone([Capstone.Architecture]::X86, [Capstone.Mode]::Mode16)
142 | $Disassembly.Version
143 |
144 | return
145 | }
146 |
147 | $Disassembly = New-Object Capstone.Capstone($Architecture, $Mode)
148 |
149 | if ($Disassembly.Version -ne [Capstone.Capstone]::BindingVersion)
150 | {
151 | Write-Error "capstone.dll version ($([Capstone.Capstone]::BindingVersion.ToString())) should be the same as libcapstone.dll version. Otherwise, undefined behavior is likely."
152 | }
153 |
154 | if ($Syntax)
155 | {
156 | switch ($Syntax)
157 | {
158 | 'Intel' { $SyntaxMode = [Capstone.OptionValue]::SyntaxIntel }
159 | 'ATT' { $SyntaxMode = [Capstone.OptionValue]::SyntaxATT }
160 | }
161 |
162 | $Disassembly.SetSyntax($SyntaxMode)
163 | }
164 |
165 | if ($DetailOn)
166 | {
167 | $Disassembly.SetDetail($True)
168 | }
169 |
170 | $Disassembly.Disassemble($Code, $Offset, $Count)
171 | }
--------------------------------------------------------------------------------
/MalwareAnalysis/Hosts.ps1:
--------------------------------------------------------------------------------
1 | function Get-HostsFile {
2 | <#
3 | .SYNOPSIS
4 |
5 | Parses a HOSTS file.
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: BSD 3-Clause
9 | Required Dependencies: None
10 | Optional Dependencies: None
11 |
12 | .PARAMETER Path
13 |
14 | Specifies an alternate HOSTS path. Defaults to
15 | %SystemRoot%\System32\drivers\etc\hosts.
16 |
17 | .PARAMETER Show
18 |
19 | Opens the HOSTS file in notepad upon completion.
20 |
21 | .EXAMPLE
22 |
23 | Get-HostsFile
24 |
25 | .EXAMPLE
26 |
27 | Get-HostsFile -Path .\hosts
28 | #>
29 |
30 | Param (
31 | [ValidateScript({Test-Path $_})]
32 | [String]
33 | $Path = (Join-Path $Env:SystemRoot 'System32\drivers\etc\hosts'),
34 |
35 | [Switch]
36 | $Show
37 | )
38 |
39 | $Hosts = Get-Content $Path -ErrorAction Stop
40 |
41 | $CommentLine = '^\s*#'
42 | $HostLine = '^\s*(?\S+)\s+(?\S+)(\s*|\s+#(?.*))$'
43 |
44 | $TestIP = [Net.IPAddress] '127.0.0.1'
45 | $LineNum = 0
46 |
47 | for ($i = 0; $i -le $Hosts.Length; $i++) {
48 | if (!($Hosts[$i] -match $CommentLine) -and ($Hosts[$i] -match $HostLine)) {
49 | $IpAddress = $Matches['IPAddress']
50 | $Comment = ''
51 |
52 | if ($Matches['Comment']) {
53 | $Comment = $Matches['Comment']
54 | }
55 |
56 | $Result = New-Object PSObject -Property @{
57 | LineNumber = $LineNum
58 | IPAddress = $IpAddress
59 | IsValidIP = [Net.IPAddress]::TryParse($IPAddress, [Ref] $TestIP)
60 | Hostname = $Matches['Hostname']
61 | Comment = $Comment.Trim(' ')
62 | }
63 |
64 | $Result.PSObject.TypeNames.Insert(0, 'Hosts.Entry')
65 |
66 | Write-Output $Result
67 | }
68 |
69 | $LineNum++
70 | }
71 |
72 | if ($Show) {
73 | notepad $Path
74 | }
75 | }
76 |
77 | function New-HostsFileEntry {
78 | <#
79 | .SYNOPSIS
80 |
81 | Replace or append an entry to a HOSTS file.
82 |
83 | Author: Matthew Graeber (@mattifestation)
84 | License: BSD 3-Clause
85 | Required Dependencies: Get-HostsFile
86 | Optional Dependencies: None
87 |
88 | .PARAMETER IPAddress
89 |
90 | Specifies the IP address to which the specified hostname will resolve.
91 |
92 | .PARAMETER Hostname
93 |
94 | Specifies the hostname that should resolve to the specified IP address.
95 |
96 | .PARAMETER Comment
97 |
98 | Optionally, specify a comment to be added to the HOSTS entry.
99 |
100 | .PARAMETER Path
101 |
102 | Specifies an alternate HOSTS path. Defaults to
103 | %SystemRoot%\System32\drivers\etc\hosts.
104 |
105 | .PARAMETER PassThru
106 |
107 | Outputs a parsed HOSTS file upon completion.
108 |
109 | .PARAMETER Show
110 |
111 | Opens the HOSTS file in notepad upon completion.
112 |
113 | .EXAMPLE
114 |
115 | New-HostsFileEntry -IPAddress '127.0.0.1' -Hostname 'c2.evil.com'
116 |
117 | .EXAMPLE
118 |
119 | New-HostsFileEntry -IPAddress '127.0.0.1' -Hostname 'c2.evil.com' -Comment 'Malware C2'
120 | #>
121 |
122 | [CmdletBinding()] Param (
123 | [Parameter(Mandatory = $True, Position = 0)]
124 | [Net.IpAddress]
125 | $IPAddress,
126 |
127 | [Parameter(Mandatory = $True, Position = 1)]
128 | [ValidateNotNullOrEmpty()]
129 | [String]
130 | $Hostname,
131 |
132 | [Parameter(Position = 2)]
133 | [ValidateNotNull()]
134 | [String]
135 | $Comment,
136 |
137 | [ValidateScript({Test-Path $_})]
138 | [String]
139 | $Path = (Join-Path $Env:SystemRoot 'System32\drivers\etc\hosts'),
140 |
141 | [Switch]
142 | $PassThru,
143 |
144 | [Switch]
145 | $Show
146 | )
147 |
148 | $HostsRaw = Get-Content $Path
149 | $Hosts = Get-HostsFile -Path $Path
150 |
151 | $HostEntry = "$IpAddress $Hostname"
152 |
153 | if ($Comment) {
154 | $HostEntry += " # $Comment"
155 | }
156 |
157 | $HostEntryReplaced = $False
158 |
159 | for ($i = 0; $i -lt $Hosts.Length; $i++) {
160 | if ($Hosts[$i].Hostname -eq $Hostname) {
161 | if ($Hosts[$i].IpAddress -eq $IPAddress) {
162 | Write-Verbose "Hostname '$Hostname' and IP address '$IPAddress' already exist in $Path."
163 | } else {
164 | Write-Verbose "Replacing hostname '$Hostname' in $Path."
165 | $HostsRaw[$Hosts[$i].LineNumber] = $HostEntry
166 | }
167 |
168 | $HostEntryReplaced = $True
169 | }
170 | }
171 |
172 | if (!$HostEntryReplaced) {
173 | Write-Verbose "Appending hostname '$Hostname' and IP address '$IPAddress' to $Path."
174 | $HostsRaw += $HostEntry
175 | }
176 |
177 | $HostsRaw | Out-File -Encoding ascii -FilePath $Path -ErrorAction Stop
178 |
179 | if ($PassThru) { Get-HostsFile -Path $Path }
180 |
181 | if ($Show) {
182 | notepad $Path
183 | }
184 | }
185 |
186 | function Remove-HostsFileEntry {
187 | <#
188 | .SYNOPSIS
189 |
190 | Remove an entry or series of entries from a HOSTS file.
191 |
192 | Author: Matthew Graeber (@mattifestation)
193 | License: BSD 3-Clause
194 | Required Dependencies: Get-HostsFile
195 | Optional Dependencies: None
196 |
197 | .PARAMETER IPAddress
198 |
199 | Specifies the IP address. If multiple HOSTS entries exist containing
200 | the same IP address, they will all be removed.
201 |
202 | .PARAMETER Hostname
203 |
204 | Specifies the hostname that should be removed from the HOSTS file.
205 |
206 | .PARAMETER Path
207 |
208 | Specifies an alternate HOSTS path. Defaults to
209 | %SystemRoot%\System32\drivers\etc\hosts.
210 |
211 | .PARAMETER PassThru
212 |
213 | Outputs a parsed HOSTS file upon completion.
214 |
215 | .PARAMETER Show
216 |
217 | Opens the HOSTS file in notepad upon completion.
218 |
219 | .EXAMPLE
220 |
221 | Remove-HostsFileEntry -IPAddress '127.0.0.1'
222 |
223 | .EXAMPLE
224 |
225 | Remove-HostsFileEntry -IPAddress 'c2.evil.com'
226 |
227 | .EXAMPLE
228 |
229 | Get-HostsFile | Remove-HostsFileEntry
230 |
231 | Description
232 | -----------
233 | Removes all entries from the HOSTS file.
234 | #>
235 |
236 | Param (
237 | [Parameter(Mandatory = $True, ParameterSetName = 'IPAddress')]
238 | [Net.IpAddress]
239 | $IPAddress,
240 |
241 | [Parameter(Mandatory = $True, ParameterSetName = 'Hostname')]
242 | [ValidateNotNullOrEmpty()]
243 | [String]
244 | $Hostname,
245 |
246 | [ValidateScript({ Test-Path $_ })]
247 | [String]
248 | $Path = (Join-Path $Env:SystemRoot 'System32\drivers\etc\hosts'),
249 |
250 | [Switch]
251 | $PassThru,
252 |
253 | [Switch]
254 | $Show,
255 |
256 | [Parameter(ParameterSetName = 'PSObjectArray', ValueFromPipeline = $True)]
257 | [PSObject[]]
258 | $HostsEntry
259 | )
260 |
261 | BEGIN {
262 | $HostsRaw = Get-Content $Path
263 |
264 | if ($IPAddress -or $Hostname) {
265 | $HostsEntry = Get-HostsFile -Path $Path
266 | }
267 |
268 | $ExcludedLineNumbers = @()
269 |
270 | $StringBuilder = New-Object Text.StringBuilder
271 | }
272 |
273 | PROCESS {
274 | foreach ($Entry in $HostsEntry) {
275 | if ($Entry.PSObject.TypeNames[0] -eq 'Hosts.Entry') {
276 | if ($IPAddress) {
277 | if ($Entry.IPAddress -eq $IPAddress) {
278 | Write-Verbose "Removing line #$($Entry.LineNumber)."
279 | $ExcludedLineNumbers += $Entry.LineNumber
280 | }
281 | } elseif ($Hostname) {
282 | if ($Entry.Hostname -eq $Hostname) {
283 | Write-Verbose "Removing line #$($Entry.LineNumber)."
284 | $ExcludedLineNumbers += $Entry.LineNumber
285 | }
286 | } else {
287 | Write-Verbose "Removing line #$($Entry.LineNumber)."
288 | $ExcludedLineNumbers += $Entry.LineNumber
289 | }
290 | }
291 | }
292 | }
293 |
294 | END {
295 | for ($i = 0; $i -lt $HostsRaw.Length; $i++) {
296 | if (!$ExcludedLineNumbers.Contains($i)) {
297 | $null = $StringBuilder.AppendLine($HostsRaw[$i])
298 | }
299 | }
300 |
301 | $StringBuilder.ToString() | Out-File $Path
302 |
303 | if ($PassThru) { Get-HostsFile -Path $Path }
304 |
305 | if ($Show) {
306 | notepad $Path
307 | }
308 | }
309 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### PowerShellArsenal is a PowerShell module used to aid a reverse engineer. The module can be used to disassemble managed and unmanaged code, perform .NET malware analysis, analyze/scrape memory, parse file formats and memory structures, obtain internal system information, etc. PowerShellArsenal is comprised of the following tools:
2 |
3 | ## Disassembly
4 |
5 | **Disassemble native and managed code.**
6 |
7 | #### `Get-CSDisassembly`
8 |
9 | Disassembles a byte array using the Capstone Engine disassembly framework.
10 |
11 | #### `Get-ILDisassembly`
12 |
13 | Disassembles a raw MSIL byte array passed in from a MethodInfo object in a manner similar to that of Ildasm.
14 |
15 | ## MalwareAnalysis
16 |
17 | **Useful tools when performing malware analysis.**
18 |
19 | #### `New-FunctionDelegate`
20 |
21 | Provides an executable wrapper for an X86 or X86_64 function.
22 |
23 | #### `Invoke-LoadLibrary`
24 |
25 | Loads a DLL into the current PowerShell process.
26 |
27 | #### `New-DllExportFunction`
28 |
29 | Creates an executable wrapper delegate around an unmanaged, exported function.
30 |
31 | #### `Get-HostsFile`
32 |
33 | Parses a HOSTS file.
34 |
35 | #### `New-HostsFileEntry`
36 |
37 | Replace or append an entry to a HOSTS file.
38 |
39 | #### `Remove-HostsFileEntry`
40 |
41 | Remove an entry or series of entries from a HOSTS file.
42 |
43 | #### `Get-AssemblyStrings`
44 |
45 | Output all strings from a .NET executable.
46 |
47 | #### `Get-AssemblyResources`
48 |
49 | Extract managed resources from a .NET assembly
50 |
51 | #### `Remove-AssemblySuppressIldasmAttribute`
52 |
53 | Strips a SuppressIldasmAttribute attribute from a .NET assembly.
54 |
55 | #### `Get-AssemblyImplementedMethods`
56 |
57 | Returns all methods in an assembly that are implemented in MSIL.
58 |
59 | ## MemoryTools
60 |
61 | **Inspect and analyze process memory**
62 |
63 | #### `Get-ProcessStrings`
64 |
65 | Outputs all printable strings from the user-mode memory of a process.
66 |
67 | #### `Get-VirtualMemoryInfo`
68 |
69 | A wrapper for kernel32!VirtualQueryEx
70 |
71 | #### `Get-ProcessMemoryInfo`
72 |
73 | Retrieve virtual memory information for every unique set of pages in user memory. This function is similar to the !vadump WinDbg command.
74 |
75 | #### `Get-StructFromMemory`
76 |
77 | Marshals data from an unmanaged block of memory in an arbitrary process to a newly allocated managed object of the specified type.
78 |
79 | ## Parsers
80 |
81 | **Parse file formats and in-memory structures.**
82 |
83 | #### `Get-PE`
84 |
85 | An on-disk and in-memory PE parser and process dumper.
86 |
87 | #### `Find-ProcessPEs`
88 |
89 | Finds portable executables in memory regardless of whether or not they were loaded in a legitimate fashion.
90 |
91 | #### `Get-LibSymbols`
92 |
93 | Displays symbolic information from Windows LIB files.
94 |
95 | #### `Get-ObjDump`
96 |
97 | Displays information about Windows object (OBJ) files.
98 |
99 | ## WindowsInternals
100 |
101 | **Obtain and analyze low-level Windows OS information.**
102 |
103 | #### `Get-NtSystemInformation`
104 |
105 | A utility that calls and parses the output of the ntdll!NtQuerySystemInformation function. This utility can be used to query internal OS information that is typically not made visible to a user.
106 |
107 | #### `Get-PEB`
108 |
109 | Returns the process environment block (PEB) of a process.
110 |
111 | #### `Register-ProcessModuleTrace`
112 |
113 | Starts a trace of loaded process modules
114 |
115 | #### `Get-ProcessModuleTrace`
116 |
117 | Displays the process modules that have been loaded since the call to Register-ProcessModuleTrace
118 |
119 | #### `Unregister-ProcessModuleTrace`
120 |
121 | Stops the running process module trace
122 |
123 | #### `Get-SystemInfo`
124 |
125 | A wrapper for kernel32!GetSystemInfo
126 |
127 | ## Misc
128 |
129 | **Miscellaneous helper functions**
130 |
131 | #### `Get-Member`
132 |
133 | A proxy function used to extend the built-in Get-Member cmdlet. It adds the '-Private' parameter allowing you to display non-public .NET members
134 |
135 | #### `Get-Strings`
136 |
137 | Dumps strings from files in both Unicode and Ascii. This cmdlet replicates the functionality of strings.exe from Sysinternals.
138 |
139 | #### `ConvertTo-String`
140 |
141 | Converts the bytes of a file to a string that has a 1-to-1 mapping back to the file's original bytes. ConvertTo-String is useful for performing binary regular expressions.
142 |
143 | #### `Get-Entropy`
144 |
145 | Calculates the entropy of a file or byte array.
146 |
147 | ## Lib
148 |
149 | **Libraries required by some of the RE functions.**
150 |
151 | #### `Capstone`
152 |
153 | The Capstone disassembly engine C# binding.
154 |
155 | #### `De4dot`
156 |
157 | A powerful .NET deobfuscation and .NET PE parsing library.
158 |
159 | #### `PSReflect`
160 |
161 | A module used to easily define in-memory enums, structs, and Win32 functions.
162 |
163 | #### `Formatters`
164 |
165 | ps1xml files used to format the output of various PowerShellArsenal functions.
166 |
167 | ## License
168 |
169 | The PowerShellArsenal module and all individual scripts are under the [BSD 3-Clause license](https://raw.github.com/mattifestation/PowerSploit/master/LICENSE) unless explicitly noted otherwise.
170 |
171 | ## Usage
172 |
173 | Refer to the comment-based help in each individual script for detailed usage information.
174 |
175 | To install this module, drop the entire PowerShellArsenal folder into one of your module directories. The default PowerShell module paths are listed in the $Env:PSModulePath environment variable.
176 |
177 | The default per-user module path is: "$Env:HomeDrive$Env:HOMEPATH\Documents\WindowsPowerShell\Modules"
178 | The default computer-level module path is: "$Env:windir\System32\WindowsPowerShell\v1.0\Modules"
179 |
180 | To use the module, type `Import-Module PowerShellArsenal`
181 |
182 | To see the commands imported, type `Get-Command -Module PowerShellArsenal`
183 |
184 | If you're running PowerShell v3 and you want to remove the annoying 'Do you really want to run scripts downloaded from the Internet' warning, once you've placed PowerShellArsenal into your module path, run the following one-liner:
185 | `$Env:PSModulePath.Split(';') |
186 | % { if ( Test-Path (Join-Path $_ PowerShellArsenal) )
187 | {Get-ChildItem $_ -Recurse | Unblock-File} }`
188 |
189 | For help on each individual command, Get-Help is your friend.
190 |
191 | Note: The tools contained within this module were all designed such that they can be run individually. Including them in a module simply lends itself to increased portability.
192 |
193 | ## Script Style Guide
194 |
195 | **For all contributors and future contributors to PowerShellArsenal, I ask that you follow this style guide when writing your scripts/modules.**
196 |
197 | * Avoid Write-Host **at all costs**. PowerShell functions/cmdlets are not command-line utilities! Pull requests containing code that uses Write-Host will not be considered. You should output custom objects instead. For more information on creating custom objects, read these articles:
198 | *
199 | *
200 |
201 | * If you want to display relevant debugging information to the screen, use Write-Verbose. The user can always just tack on '-Verbose'.
202 |
203 | * Always provide descriptive, comment-based help for every script. Also, be sure to include your name and a BSD 3-Clause license (unless there are extenuating circumstances that prevent the application of the BSD license).
204 |
205 | * Make sure all functions follow the proper PowerShell verb-noun agreement. Use Get-Verb to list the default verbs used by PowerShell. Exceptions to supported verbs will be considered on a case-by-case basis.
206 |
207 | * I prefer that variable names be capitalized and be as descriptive as possible.
208 |
209 | * Provide logical spacing in between your code. Indent your code to make it more readable.
210 |
211 | * If you find yourself repeating code, write a function.
212 |
213 | * Catch all anticipated errors and provide meaningful output. If you have an error that should stop execution of the script, use 'Throw'. If you have an error that doesn't need to stop execution, use Write-Error.
214 |
215 | * If you are writing a script that interfaces with the Win32 API, try to avoid compiling C# inline with Add-Type. Try to use the PSReflect module, if possible.
216 |
217 | * Do not use hardcoded paths. A script should be useable right out of the box. No one should have to modify the code unless they want to.
218 |
219 | * PowerShell v2 compatibility is highly desired.
220 |
221 | * Use positional parameters and make parameters mandatory when it makes sense to do so. For example, I'm looking for something like the following:
222 | * `[Parameter(Position = 0, Mandatory = $True)]`
223 |
224 | * Don't use any aliases unless it makes sense for receiving pipeline input. They make code more difficult to read for people who are unfamiliar with a particular alias.
225 |
226 | * Try not to let commands run on for too long. For example, a pipeline is a natural place for a line break.
227 |
228 | * Don't go overboard with inline comments. Only use them when certain aspects of the code might be confusing to a reader.
229 |
230 | * Rather than using Out-Null to suppress unwanted/irrelevant output, save the unwanted output to $null. Doing so provides a slight performance enhancement.
231 |
232 | * Use default values for your parameters when it makes sense. Ideally, you want a script that will work without requiring any parameters.
233 |
234 | * Explicitly state all required and optional dependencies in the comment-based help for your function. All library dependencies should reside in the 'Lib' folder.
235 |
236 | * If a script creates complex custom objects, include a ps1xml file that will properly format the object's output. ps1xml files are stored in Lib\Formatters.
--------------------------------------------------------------------------------
/MalwareAnalysis/loadlib.ps1:
--------------------------------------------------------------------------------
1 | function Invoke-LoadLibrary {
2 | <#
3 | .SYNOPSIS
4 |
5 | Loads a DLL into the current PowerShell process.
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: BSD 3-Clause
9 | Required Dependencies: None
10 | Optional Dependencies: None
11 |
12 | .DESCRIPTION
13 |
14 | Invoke-LoadLibrary is a simple wrapper for kernel32!LoadLibrary
15 | designed primarily for malware analysis the output of which can be
16 | consumed by New-DllExportFunction.
17 |
18 | .PARAMETER FileName
19 |
20 | Specifies the name of the module to load. If the string specifies a
21 | relative path or a module name without a path, the function uses a
22 | standard search strategy to find the module. See the MSDN
23 | documentation on LoadLibrary for more information on DLL search
24 | paths.
25 |
26 | .EXAMPLE
27 |
28 | Invoke-LoadLibrary -FileName C:\temp\evil.dll
29 |
30 | .EXAMPLE
31 |
32 | 'kernel32', 'ntdll' | Invoke-LoadLibrary
33 |
34 | .INPUTS
35 |
36 | System.String
37 |
38 | Invoke-LoadLibrary accepts one or more module names to load over the
39 | pipeline.
40 |
41 | .OUTPUTS
42 |
43 | System.Diagnostics.ProcessModule
44 | #>
45 |
46 | [OutputType([Diagnostics.ProcessModule])]
47 | [CmdletBinding()]
48 | Param (
49 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipeline = $True)]
50 | [ValidateNotNullOrEmpty()]
51 | [String]
52 | $FileName
53 | )
54 |
55 | BEGIN {
56 | $SafeNativeMethods = $null
57 | $LoadLibrary = $null
58 |
59 | # System.Uri and Microsoft.Win32.SafeNativeMethods are both
60 | # contained within System.dll. [Uri] is public though.
61 | # Microsoft.Win32.SafeNativeMethods is a NonPublic class.
62 | $UnmanagedClass = 'Microsoft.Win32.SafeNativeMethods'
63 | $SafeNativeMethods = [Uri].Assembly.GetType($UnmanagedClass)
64 |
65 | # Perform additional error handling since we're borrowing LoadLibrary
66 | # from a NonPublic class. Technically, Microsoft could change this
67 | # interface at any time.
68 | if ($SafeNativeMethods -eq $null) {
69 | throw 'Unable to get a reference to the ' +
70 | 'Microsoft.Win32.SafeNativeMethods within System.dll.'
71 | }
72 |
73 | $LoadLibrary = $SafeNativeMethods.GetMethod('LoadLibrary')
74 |
75 | if ($LoadLibrary -eq $null) {
76 | throw 'Unable to get a reference to LoadLibrary within' +
77 | 'Microsoft.Win32.SafeNativeMethods.'
78 | }
79 | }
80 |
81 | PROCESS {
82 | $LoadedModuleInfo = $null
83 |
84 | $LibAddress = $LoadLibrary.Invoke($null, @($FileName))
85 | $Exception = [Runtime.InteropServices.Marshal]::GetLastWin32Error()
86 |
87 | if ($LibAddress -eq [IntPtr]::Zero) {
88 | $Exception = New-Object ComponentModel.Win32Exception($Exception)
89 | throw $Exception.Message
90 | }
91 |
92 | $IntPtrPrintWidth = "X$([IntPtr]::Size * 2)"
93 |
94 | Write-Verbose "$FileName loaded at 0x$(($LibAddress).ToString($IntPtrPrintWidth))"
95 |
96 | $CurrentProcess = Get-Process -Id $PID
97 |
98 | $LoadedModuleInfo = $CurrentProcess.Modules |
99 | Where-Object { $_.BaseAddress -eq $LibAddress }
100 |
101 | if ($LoadedModuleInfo -eq $null) {
102 | throw 'Unable to obtain loaded module information for ' +
103 | "$FileName. The module was likely already unloaded."
104 | }
105 |
106 | return $LoadedModuleInfo
107 | }
108 | }
109 |
110 | function New-DllExportFunction {
111 | <#
112 | .SYNOPSIS
113 |
114 | Creates an executable wrapper delegate around an unmanaged, exported
115 | function.
116 |
117 | Author: Matthew Graeber (@mattifestation)
118 | License: BSD 3-Clause
119 | Required Dependencies: None
120 | Optional Dependencies: Invoke-LoadLibrary
121 |
122 | .DESCRIPTION
123 |
124 | New-DllExportFunction accepts a module, exported procedure name, a
125 | return type, and parameter types, and creates a managed delegate that
126 | can be used to execute the unmanaged function.
127 |
128 | .PARAMETER Module
129 |
130 | Specifies the module that contains the desired exported procedure.
131 | The Module parameter accepts a System.Diagnostics.ProcessModule
132 | object which can be obtained by calling Get-Process and filtering out
133 | the 'Modules' property or by calling Invoke-LoadLibrary.
134 |
135 | .PARAMETER ProcedureName
136 |
137 | Specifies the exported procedure name. Note, for functions that
138 | accept wide or ascii strings, you must specify which variant you want
139 | to call - e.g. CreateFileA vs. CreateFileW.
140 |
141 | .PARAMETER Parameters
142 |
143 | Specifies the managed parameter types of the function. pinvoke.net is
144 | a good reference for mapping managed to unmanaged types. This
145 | argument may be left empty if the function doesn't accept any
146 | arguments.
147 |
148 | .PARAMETER ReturnType
149 |
150 | Specifies the managed return type of the function. pinvoke.net is
151 | a good reference for mapping managed to unmanaged types. This
152 | argument may be left empty if the function doesn't has a void return
153 | type.
154 |
155 | .EXAMPLE
156 |
157 | C:\PS>$Kernel32 = Invoke-LoadLibrary -FileName kernel32
158 | C:\PS>$MulDiv = New-DllExportFunction -Module $Kernel32 -ProcedureName MulDiv -Parameters ([Int], [Int], [Int]) -ReturnType ([Int])
159 | C:\PS>$MulDiv.Invoke(2, 3, 1)
160 |
161 | .EXAMPLE
162 |
163 | C:\PS>$Kernel32 = Invoke-LoadLibrary -FileName kernel32
164 | C:\PS>$IsWow64Process = New-DllExportFunction -Module $Kernel32 -ProcedureName IsWow64Process -Parameters ([IntPtr], [Bool].MakeByRefType()) -ReturnType ([Bool])
165 | C:\PS>$bIsWow64Process = $False
166 | C:\PS>$IsWow64Process.Invoke((Get-Process -Id $PID).Handle, [Ref] $bIsWow64Process)
167 |
168 | .EXAMPLE
169 |
170 | C:\PS>$Ntdll = Get-Process -Id $PID | Select-Object -ExpandProperty Modules | Where-Object { $_.ModuleName -eq 'ntdll.dll' }
171 | C:\PS>$RtlGetCurrentPeb = New-DllExportFunction -Module $Ntdll -ProcedureName RtlGetCurrentPeb -ReturnType ([IntPtr])
172 | C:\PS>$RtlGetCurrentPeb.Invoke()
173 |
174 | .OUTPUTS
175 |
176 | System.Delegate
177 | #>
178 |
179 | [OutputType([Delegate])]
180 | Param (
181 | [Parameter(Mandatory = $True)]
182 | [Diagnostics.ProcessModule]
183 | [ValidateNotNull()]
184 | $Module,
185 |
186 | [Parameter(Mandatory = $True)]
187 | [String]
188 | [ValidateNotNullOrEmpty()]
189 | $ProcedureName,
190 |
191 | [Type[]]
192 | $Parameters = (New-Object Type[](0)),
193 |
194 | [Type]
195 | $ReturnType = [Void]
196 | )
197 |
198 | function Local:Get-DelegateType
199 | {
200 | [OutputType([Type])]
201 | Param (
202 | [Parameter( Position = 0)]
203 | [Type[]]
204 | $Parameters = (New-Object Type[](0)),
205 |
206 | [Parameter( Position = 1 )]
207 | [Type]
208 | $ReturnType = [Void]
209 | )
210 |
211 | $Domain = [AppDomain]::CurrentDomain
212 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
213 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
214 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $False)
215 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
216 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
217 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
218 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
219 | $MethodBuilder.SetImplementationFlags('Runtime, Managed')
220 |
221 | return $TypeBuilder.CreateType()
222 | }
223 |
224 | function Local:Get-ProcAddress
225 | {
226 | [OutputType([IntPtr])]
227 | Param (
228 | [Parameter( Position = 0, Mandatory = $True )]
229 | [Diagnostics.ProcessModule]
230 | $Module,
231 |
232 | [Parameter( Position = 1, Mandatory = $True )]
233 | [String]
234 | $ProcedureName
235 | )
236 |
237 | $UnsafeNativeMethods = $null
238 | $GetProcAddress = $null
239 |
240 | # System.Uri and Microsoft.Win32.UnsafeNativeMethods are both
241 | # contained within System.dll. [Uri] is public though.
242 | # Microsoft.Win32.UnsafeNativeMethods is a NonPublic class.
243 | $UnmanagedClass = 'Microsoft.Win32.UnsafeNativeMethods'
244 | $UnsafeNativeMethods = [Uri].Assembly.GetType($UnmanagedClass)
245 |
246 | # Perform additional error handling since we're borrowing GetProcAddress
247 | # from a NonPublic class. Technically, Microsoft could change this
248 | # interface at any time.
249 | if ($UnsafeNativeMethods -eq $null) {
250 | throw 'Unable to get a reference to the ' +
251 | 'Microsoft.Win32.UnsafeNativeMethods within System.dll.'
252 | }
253 |
254 | $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
255 |
256 | if ($GetProcAddress -eq $null) {
257 | throw 'Unable to get a reference to GetProcAddress within' +
258 | 'Microsoft.Win32.UnsafeNativeMethods.'
259 | }
260 |
261 | $TempPtr = New-Object IntPtr
262 | $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($TempPtr, $Module.BaseAddress)
263 |
264 | $ProcAddr = $GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef] $HandleRef, $ProcedureName))
265 |
266 | if ($ProcAddr -eq [IntPtr]::Zero) {
267 | Write-Error "Unable to obtain the address of $($Module.ModuleName)!$ProcedureName. $ProcedureName is likely not exported."
268 |
269 | return [IntPtr]::Zero
270 | }
271 |
272 | return $ProcAddr
273 | }
274 |
275 | $ProcAddress = Get-ProcAddress -Module $Module -ProcedureName $ProcedureName
276 |
277 | if ($ProcAddress -ne [IntPtr]::Zero) {
278 | $IntPtrPrintWidth = "X$([IntPtr]::Size * 2)"
279 |
280 | Write-Verbose "$($Module.ModuleName)!$ProcedureName address: 0x$(($ProcAddress).ToString($IntPtrPrintWidth))"
281 |
282 | $DelegateType = Get-DelegateType -Parameters $Parameters -ReturnType $ReturnType
283 | $ProcedureDelegate = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($ProcAddress, $DelegateType)
284 |
285 | return $ProcedureDelegate
286 | }
287 | }
--------------------------------------------------------------------------------
/Parsers/Get-LibSymbols.ps1:
--------------------------------------------------------------------------------
1 | function Get-LibSymbols
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Displays symbolic information from Windows LIB files.
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .DESCRIPTION
14 |
15 | Get-LibSymbols parses and returns symbols in Windows .lib files
16 | in both decorated and undecorated form (for C++ functions).
17 |
18 | .PARAMETER Path
19 |
20 | Specifies a path to one or more lib file locations.
21 |
22 | .EXAMPLE
23 |
24 | Get-LibSymbols -Path msvcrt.lib
25 |
26 | .EXAMPLE
27 |
28 | ls *.lib | Get-LibSymbols
29 |
30 | .INPUTS
31 |
32 | System.String[]
33 |
34 | You can pipe a file system path (in quotation marks) to Get-LibSymbols.
35 |
36 | .OUTPUTS
37 |
38 | COFF.SymbolInfo
39 | #>
40 | [CmdletBinding()] Param (
41 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
42 | [ValidateScript({ Test-Path $_ })]
43 | [Alias('FullName')]
44 | [String[]]
45 | $Path
46 | )
47 |
48 | BEGIN
49 | {
50 | $Code = @'
51 | using System;
52 | using System.IO;
53 | using System.Text;
54 | using System.Runtime.InteropServices;
55 |
56 | namespace COFF2
57 | {
58 | public class HEADER
59 | {
60 | public ushort Machine;
61 | public ushort NumberOfSections;
62 | public DateTime TimeDateStamp;
63 | public uint PointerToSymbolTable;
64 | public uint NumberOfSymbols;
65 | public ushort SizeOfOptionalHeader;
66 | public ushort Characteristics;
67 |
68 | public HEADER(BinaryReader br)
69 | {
70 | this.Machine = br.ReadUInt16();
71 | this.NumberOfSections = br.ReadUInt16();
72 | this.TimeDateStamp = (new DateTime(1970, 1, 1, 0, 0, 0)).AddSeconds(br.ReadUInt32());
73 | this.PointerToSymbolTable = br.ReadUInt32();
74 | this.NumberOfSymbols = br.ReadUInt32();
75 | this.SizeOfOptionalHeader = br.ReadUInt16();
76 | this.Characteristics = br.ReadUInt16();
77 | }
78 | }
79 |
80 | public class IMAGE_ARCHIVE_MEMBER_HEADER
81 | {
82 | public string Name;
83 | public DateTime Date;
84 | public ulong Size;
85 | public string EndHeader;
86 |
87 | public IMAGE_ARCHIVE_MEMBER_HEADER(BinaryReader br)
88 | {
89 | string tempName = Encoding.UTF8.GetString(br.ReadBytes(16));
90 | DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
91 | this.Name = tempName.Substring(0, tempName.IndexOf((Char) 47));
92 | this.Date = dt.AddSeconds(Convert.ToDouble(Encoding.UTF8.GetString(br.ReadBytes(12)).Split((Char) 20)[0]));
93 | br.ReadBytes(20); // Skip over UserID, GroupID, and Mode. They are useless fields.
94 | this.Size = Convert.ToUInt64(Encoding.UTF8.GetString(br.ReadBytes(10)).Split((Char) 20)[0]);
95 | this.EndHeader = Encoding.UTF8.GetString(br.ReadBytes(2));
96 | }
97 | }
98 |
99 | public class Functions
100 | {
101 | [DllImport("dbghelp.dll", SetLastError=true, PreserveSig=true)]
102 | public static extern int UnDecorateSymbolName(
103 | [In] [MarshalAs(UnmanagedType.LPStr)] string DecoratedName,
104 | [Out] StringBuilder UnDecoratedName,
105 | [In] [MarshalAs(UnmanagedType.U4)] uint UndecoratedLength,
106 | [In] [MarshalAs(UnmanagedType.U4)] uint Flags);
107 | }
108 | }
109 | '@
110 |
111 | Add-Type -TypeDefinition $Code
112 |
113 | function Dispose-Objects
114 | {
115 | $BinaryReader.Close()
116 | $FileStream.Dispose()
117 | }
118 | }
119 |
120 | PROCESS
121 | {
122 | foreach ($File in $Path)
123 | {
124 | # Resolve the absolute path of the lib file. [IO.File]::OpenRead requires an absolute path.
125 | $LibFilePath = Resolve-Path $File
126 |
127 | # Pull out just the file name
128 | $LibFileName = Split-Path $LibFilePath -Leaf
129 |
130 | $IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR = 60
131 | $IMAGE_ARCHIVE_START = "!`n" # Magic used for lib files
132 | $IMAGE_SIZEOF_LIB_HDR = $IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR + $IMAGE_ARCHIVE_START.Length
133 | $IMAGE_ARCHIVE_END = "```n" # Footer of an archive header
134 | $SizeofCOFFFileHeader = 20
135 |
136 | # Open the object file for reading
137 | $FileStream = [IO.File]::OpenRead($LibFilePath)
138 |
139 | $FileLength = $FileStream.Length
140 |
141 | # Validate lib header size
142 | if ($FileLength -lt $IMAGE_SIZEOF_LIB_HDR)
143 | {
144 | # You cannot parse the lib header if the file is not big enough to contain a lib header.
145 | Write-Error "$($LibFileName) is too small to store a lib header."
146 | $FileStream.Dispose()
147 | return
148 | }
149 |
150 | # Open a BinaryReader object for the lib file
151 | $BinaryReader = New-Object IO.BinaryReader($FileStream)
152 |
153 | $ArchiveStart = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes(8))
154 |
155 | if ($ArchiveStart -ne $IMAGE_ARCHIVE_START)
156 | {
157 | Write-Error "$($LibFileName) does not contain a valid lib header."
158 | Dispose-Objects
159 | return
160 | }
161 |
162 | # Parse the first archive header
163 | $ArchiveHeader = New-Object COFF2.IMAGE_ARCHIVE_MEMBER_HEADER($BinaryReader)
164 |
165 | if ($ArchiveHeader.EndHeader -ne $IMAGE_ARCHIVE_END)
166 | {
167 | Write-Error "$($LibFileName) does not contain a valid lib header."
168 | Dispose-Objects
169 | return
170 | }
171 |
172 | # Check for the existence of symbols
173 | if ($ArchiveHeader.Size -eq 0)
174 | {
175 | Write-Warning "$($LibFileName) contains no symbols."
176 | Dispose-Objects
177 | return
178 | }
179 |
180 | $NumberOfSymbols = $BinaryReader.ReadBytes(4)
181 |
182 | # The offsets in the first archive header of a Microsoft lib file are stored in big-endian format
183 | if ([BitConverter]::IsLittleEndian)
184 | {
185 | [Array]::Reverse($NumberOfSymbols)
186 | }
187 |
188 | $NumberOfSymbols = [BitConverter]::ToUInt32($NumberOfSymbols, 0)
189 |
190 | $SymbolOffsets = New-Object UInt32[]($NumberOfSymbols)
191 |
192 | foreach ($Offset in 0..($SymbolOffsets.Length - 1))
193 | {
194 | $SymbolOffset = $BinaryReader.ReadBytes(4)
195 |
196 | if ([BitConverter]::IsLittleEndian)
197 | {
198 | [Array]::Reverse($SymbolOffset)
199 | }
200 |
201 | $SymbolOffsets[$Offset] = [BitConverter]::ToUInt32($SymbolOffset, 0)
202 | }
203 |
204 | $SymbolStringLength = $ArchiveHeader.Size + $IMAGE_SIZEOF_LIB_HDR - $FileStream.Position - 1
205 | # $SymbolStrings = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes($SymbolStringLength)).Split([Char] 0)
206 |
207 | # Write-Output $SymbolStrings
208 |
209 | # There will be many duplicate offset entries. Remove them.
210 | $SymbolOffsetsSorted = $SymbolOffsets | Sort-Object -Unique
211 |
212 | $SymbolOffsetsSorted | ForEach-Object {
213 | # Seek to the each repective offset in the file
214 | $FileStream.Seek($_, 'Begin') | Out-Null
215 |
216 | $ArchiveHeader = New-Object COFF2.IMAGE_ARCHIVE_MEMBER_HEADER($BinaryReader)
217 |
218 | # This is not a true COFF header. It's the same size and mostly resembles a standard COFF header
219 | # but Microsoft placed a marker (0xFFFF) in the first WORD to indicate that the 'object file'
220 | # consists solely of the module name and symbol.
221 | $CoffHeader = New-Object COFF2.HEADER($BinaryReader)
222 |
223 | # Check for 0xFFFF flag value
224 | if ($CoffHeader.NumberOfSections -eq [UInt16]::MaxValue)
225 | {
226 | # Get the total length of the module and symbol name
227 | $SymbolStringLength = $CoffHeader.NumberOfSymbols
228 | $Symbols = [Text.Encoding]::UTF8.GetString($BinaryReader.ReadBytes($SymbolStringLength)).Split([Char] 0)
229 |
230 | $DecoratedSymbol = $Symbols[0]
231 | $UndecoratedSymbol = ''
232 |
233 | # Default to a 'C' type symbol unless it starts with a '?'
234 | $SymbolType = 'C'
235 |
236 | # Is the symbol a C++ type?
237 | if ($DecoratedSymbol.StartsWith('?'))
238 | {
239 | $StrBuilder = New-Object Text.Stringbuilder(512)
240 | # Magically undecorated the convoluted C++ symbol into a proper C++ function definition
241 | [COFF.Functions]::UnDecorateSymbolName($DecoratedSymbol, $StrBuilder, $StrBuilder.Capacity, 0) | Out-Null
242 | $UndecoratedSymbol = $StrBuilder.ToString()
243 | $SymbolType = 'C++'
244 | }
245 | else
246 | {
247 | if ($DecoratedSymbol[0] -eq '_' -or $DecoratedSymbol[0] -eq '@')
248 | {
249 | $UndecoratedSymbol = $DecoratedSymbol.Substring(1).Split('@')[0]
250 | }
251 | else
252 | {
253 | $UndecoratedSymbol = $DecoratedSymbol.Split('@')[0]
254 | }
255 | }
256 |
257 | $SymInfo = @{
258 | DecoratedName = $DecoratedSymbol
259 | UndecoratedName = $UndecoratedSymbol
260 | Module = $Symbols[1]
261 | SymbolType = $SymbolType
262 | }
263 |
264 | $ParsedSymbol = New-Object PSObject -Property $SymInfo
265 | $ParsedSymbol.PSObject.TypeNames[0] = 'COFF.SymbolInfo'
266 |
267 | Write-Output $ParsedSymbol
268 | }
269 | }
270 |
271 | # Close file and binaryreader objects
272 | Dispose-Objects
273 | }
274 | }
275 |
276 | END {}
277 | }
278 |
--------------------------------------------------------------------------------
/Lib/PSReflect/Examples/SimplePEParser.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 2
2 |
3 | <#
4 | A very basic PE parser that demonstrates the usage of PSReflect
5 |
6 | Author: Matthew Graeber (@mattifestation)
7 | License: BSD 3-Clause
8 | #>
9 |
10 | $Mod = New-InMemoryModule -ModuleName Win32
11 |
12 | $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{
13 | DOS_SIGNATURE = 0x5A4D
14 | OS2_SIGNATURE = 0x454E
15 | OS2_SIGNATURE_LE = 0x454C
16 | VXD_SIGNATURE = 0x454C
17 | }
18 |
19 | $ImageFileMachine = psenum $Mod PE.IMAGE_FILE_MACHINE UInt16 @{
20 | UNKNOWN = 0x0000
21 | I386 = 0x014C # Intel 386.
22 | R3000 = 0x0162 # MIPS little-endian =0x160 big-endian
23 | R4000 = 0x0166 # MIPS little-endian
24 | R10000 = 0x0168 # MIPS little-endian
25 | WCEMIPSV2 = 0x0169 # MIPS little-endian WCE v2
26 | ALPHA = 0x0184 # Alpha_AXP
27 | SH3 = 0x01A2 # SH3 little-endian
28 | SH3DSP = 0x01A3
29 | SH3E = 0x01A4 # SH3E little-endian
30 | SH4 = 0x01A6 # SH4 little-endian
31 | SH5 = 0x01A8 # SH5
32 | ARM = 0x01C0 # ARM Little-Endian
33 | THUMB = 0x01C2
34 | ARMNT = 0x01C4 # ARM Thumb-2 Little-Endian
35 | AM33 = 0x01D3
36 | POWERPC = 0x01F0 # IBM PowerPC Little-Endian
37 | POWERPCFP = 0x01F1
38 | IA64 = 0x0200 # Intel 64
39 | MIPS16 = 0x0266 # MIPS
40 | ALPHA64 = 0x0284 # ALPHA64
41 | MIPSFPU = 0x0366 # MIPS
42 | MIPSFPU16 = 0x0466 # MIPS
43 | TRICORE = 0x0520 # Infineon
44 | CEF = 0x0CEF
45 | EBC = 0x0EBC # EFI public byte Code
46 | AMD64 = 0x8664 # AMD64 (K8)
47 | M32R = 0x9041 # M32R little-endian
48 | CEE = 0xC0EE
49 | }
50 |
51 | $ImageFileCharacteristics = psenum $Mod PE.IMAGE_FILE_CHARACTERISTICS UInt16 @{
52 | IMAGE_RELOCS_STRIPPED = 0x0001 # Relocation info stripped from file.
53 | IMAGE_EXECUTABLE_IMAGE = 0x0002 # File is executable (i.e. no unresolved external references).
54 | IMAGE_LINE_NUMS_STRIPPED = 0x0004 # Line numbers stripped from file.
55 | IMAGE_LOCAL_SYMS_STRIPPED = 0x0008 # Local symbols stripped from file.
56 | IMAGE_AGGRESIVE_WS_TRIM = 0x0010 # Agressively trim working set
57 | IMAGE_LARGE_ADDRESS_AWARE = 0x0020 # App can handle >2gb addresses
58 | IMAGE_REVERSED_LO = 0x0080 # public bytes of machine public ushort are reversed.
59 | IMAGE_32BIT_MACHINE = 0x0100 # 32 bit public ushort machine.
60 | IMAGE_DEBUG_STRIPPED = 0x0200 # Debugging info stripped from file in .DBG file
61 | IMAGE_REMOVABLE_RUN_FROM_SWAP = 0x0400 # If Image is on removable media copy and run from the swap file.
62 | IMAGE_NET_RUN_FROM_SWAP = 0x0800 # If Image is on Net copy and run from the swap file.
63 | IMAGE_SYSTEM = 0x1000 # System File.
64 | IMAGE_DLL = 0x2000 # File is a DLL.
65 | IMAGE_UP_SYSTEM_ONLY = 0x4000 # File should only be run on a UP machine
66 | IMAGE_REVERSED_HI = 0x8000 # public bytes of machine public ushort are reversed.
67 | } -Bitfield
68 |
69 | $ImageHdrMagic = psenum $Mod PE.IMAGE_NT_OPTIONAL_HDR_MAGIC UInt16 @{
70 | PE32 = 0x010B
71 | PE64 = 0x020B
72 | }
73 |
74 | $ImageNTSig = psenum $Mod PE.IMAGE_NT_SIGNATURE UInt32 @{
75 | VALID_PE_SIGNATURE = 0x00004550
76 | }
77 |
78 | $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{
79 | UNKNOWN = 0
80 | NATIVE = 1 # Image doesn't require a subsystem.
81 | WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem.
82 | WINDOWS_CUI = 3 # Image runs in the Windows character subsystem.
83 | OS2_CUI = 5 # Image runs in the OS/2 character subsystem.
84 | POSIX_CUI = 7 # Image runs in the Posix character subsystem.
85 | NATIVE_WINDOWS = 8 # Image is a native Win9x driver.
86 | WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem.
87 | EFI_APPLICATION = 10
88 | EFI_BOOT_SERVICE_DRIVER = 11
89 | EFI_RUNTIME_DRIVER = 12
90 | EFI_ROM = 13
91 | XBOX = 14
92 | WINDOWS_BOOT_APPLICATION = 16
93 | }
94 |
95 | $ImageDllCharacteristics = psenum $Mod PE.IMAGE_DLLCHARACTERISTICS UInt16 @{
96 | HIGH_ENTROPY_VA = 0x0020 # Opts in to high entropy ASLR
97 | DYNAMIC_BASE = 0x0040 # DLL can move.
98 | FORCE_INTEGRITY = 0x0080 # Code Integrity Image
99 | NX_COMPAT = 0x0100 # Image is NX compatible
100 | NO_ISOLATION = 0x0200 # Image understands isolation and doesn't want it
101 | NO_SEH = 0x0400 # Image does not use SEH. No SE handler may reside in this image
102 | NO_BIND = 0x0800 # Do not bind this image.
103 | WDM_DRIVER = 0x2000 # Driver uses WDM model
104 | TERMINAL_SERVER_AWARE = 0x8000
105 | } -Bitfield
106 |
107 | $ImageScn = psenum $Mod PE.IMAGE_SCN Int32 @{
108 | TYPE_NO_PAD = 0x00000008 # Reserved.
109 | CNT_CODE = 0x00000020 # Section contains code.
110 | CNT_INITIALIZED_DATA = 0x00000040 # Section contains initialized data.
111 | CNT_UNINITIALIZED_DATA = 0x00000080 # Section contains uninitialized data.
112 | LNK_INFO = 0x00000200 # Section contains comments or some other type of information.
113 | LNK_REMOVE = 0x00000800 # Section contents will not become part of image.
114 | LNK_COMDAT = 0x00001000 # Section contents comdat.
115 | NO_DEFER_SPEC_EXC = 0x00004000 # Reset speculative exceptions handling bits in the TLB entries for this section.
116 | GPREL = 0x00008000 # Section content can be accessed relative to GP
117 | MEM_FARDATA = 0x00008000
118 | MEM_PURGEABLE = 0x00020000
119 | MEM_16BIT = 0x00020000
120 | MEM_LOCKED = 0x00040000
121 | MEM_PRELOAD = 0x00080000
122 | ALIGN_1BYTES = 0x00100000
123 | ALIGN_2BYTES = 0x00200000
124 | ALIGN_4BYTES = 0x00300000
125 | ALIGN_8BYTES = 0x00400000
126 | ALIGN_16BYTES = 0x00500000 # Default alignment if no others are specified.
127 | ALIGN_32BYTES = 0x00600000
128 | ALIGN_64BYTES = 0x00700000
129 | ALIGN_128BYTES = 0x00800000
130 | ALIGN_256BYTES = 0x00900000
131 | ALIGN_512BYTES = 0x00A00000
132 | ALIGN_1024BYTES = 0x00B00000
133 | ALIGN_2048BYTES = 0x00C00000
134 | ALIGN_4096BYTES = 0x00D00000
135 | ALIGN_8192BYTES = 0x00E00000
136 | ALIGN_MASK = 0x00F00000
137 | LNK_NRELOC_OVFL = 0x01000000 # Section contains extended relocations.
138 | MEM_DISCARDABLE = 0x02000000 # Section can be discarded.
139 | MEM_NOT_CACHED = 0x04000000 # Section is not cachable.
140 | MEM_NOT_PAGED = 0x08000000 # Section is not pageable.
141 | MEM_SHARED = 0x10000000 # Section is shareable.
142 | MEM_EXECUTE = 0x20000000 # Section is executable.
143 | MEM_READ = 0x40000000 # Section is readable.
144 | MEM_WRITE = 0x80000000 # Section is writeable.
145 | } -Bitfield
146 |
147 | $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{
148 | e_magic = field 0 $ImageDosSignature
149 | e_cblp = field 1 UInt16
150 | e_cp = field 2 UInt16
151 | e_crlc = field 3 UInt16
152 | e_cparhdr = field 4 UInt16
153 | e_minalloc = field 5 UInt16
154 | e_maxalloc = field 6 UInt16
155 | e_ss = field 7 UInt16
156 | e_sp = field 8 UInt16
157 | e_csum = field 9 UInt16
158 | e_ip = field 10 UInt16
159 | e_cs = field 11 UInt16
160 | e_lfarlc = field 12 UInt16
161 | e_ovno = field 13 UInt16
162 | e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4)
163 | e_oemid = field 15 UInt16
164 | e_oeminfo = field 16 UInt16
165 | e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10)
166 | e_lfanew = field 18 Int32
167 | }
168 |
169 | $ImageFileHeader = struct $Mod PE.IMAGE_FILE_HEADER @{
170 | Machine = field 0 $ImageFileMachine
171 | NumberOfSections = field 1 UInt16
172 | TimeDateStamp = field 2 UInt32
173 | PointerToSymbolTable = field 3 UInt32
174 | NumberOfSymbols = field 4 UInt32
175 | SizeOfOptionalHeader = field 5 UInt16
176 | Characteristics = field 6 $ImageFileCharacteristics
177 | }
178 |
179 |
180 | $PeImageDataDir = struct $Mod PE.IMAGE_DATA_DIRECTORY @{
181 | VirtualAddress = field 0 UInt32
182 | Size = field 1 UInt32
183 | }
184 |
185 | $ImageOptionalHdr = struct $Mod PE.IMAGE_OPTIONAL_HEADER @{
186 | Magic = field 0 $ImageHdrMagic
187 | MajorLinkerVersion = field 1 Byte
188 | MinorLinkerVersion = field 2 Byte
189 | SizeOfCode = field 3 UInt32
190 | SizeOfInitializedData = field 4 UInt32
191 | SizeOfUninitializedData = field 5 UInt32
192 | AddressOfEntryPoint = field 6 UInt32
193 | BaseOfCode = field 7 UInt32
194 | BaseOfData = field 8 UInt32
195 | ImageBase = field 9 UInt32
196 | SectionAlignment = field 10 UInt32
197 | FileAlignment = field 11 UInt32
198 | MajorOperatingSystemVersion = field 12 UInt16
199 | MinorOperatingSystemVersion = field 13 UInt16
200 | MajorImageVersion = field 14 UInt16
201 | MinorImageVersion = field 15 UInt16
202 | MajorSubsystemVersion = field 16 UInt16
203 | MinorSubsystemVersion = field 17 UInt16
204 | Win32VersionValue = field 18 UInt32
205 | SizeOfImage = field 19 UInt32
206 | SizeOfHeaders = field 20 UInt32
207 | CheckSum = field 21 UInt32
208 | Subsystem = field 22 $ImageSubsystem
209 | DllCharacteristics = field 23 $ImageDllCharacteristics
210 | SizeOfStackReserve = field 24 UInt32
211 | SizeOfStackCommit = field 25 UInt32
212 | SizeOfHeapReserve = field 26 UInt32
213 | SizeOfHeapCommit = field 27 UInt32
214 | LoaderFlags = field 28 UInt32
215 | NumberOfRvaAndSizes = field 29 UInt32
216 | DataDirectory = field 30 $PeImageDataDir.MakeArrayType() -MarshalAs @('ByValArray', 16)
217 | }
218 |
219 | $ImageOptionalHdr64 = struct $Mod PE.IMAGE_OPTIONAL_HEADER64 @{
220 | Magic = field 0 $ImageHdrMagic
221 | MajorLinkerVersion = field 1 Byte
222 | MinorLinkerVersion = field 2 Byte
223 | SizeOfCode = field 3 UInt32
224 | SizeOfInitializedData = field 4 UInt32
225 | SizeOfUninitializedData = field 5 UInt32
226 | AddressOfEntryPoint = field 6 UInt32
227 | BaseOfCode = field 7 UInt32
228 | ImageBase = field 8 UInt64
229 | SectionAlignment = field 9 UInt32
230 | FileAlignment = field 10 UInt32
231 | MajorOperatingSystemVersion = field 11 UInt16
232 | MinorOperatingSystemVersion = field 12 UInt16
233 | MajorImageVersion = field 13 UInt16
234 | MinorImageVersion = field 14 UInt16
235 | MajorSubsystemVersion = field 15 UInt16
236 | MinorSubsystemVersion = field 16 UInt16
237 | Win32VersionValue = field 17 UInt32
238 | SizeOfImage = field 18 UInt32
239 | SizeOfHeaders = field 19 UInt32
240 | CheckSum = field 20 UInt32
241 | Subsystem = field 21 $ImageSubsystem
242 | DllCharacteristics = field 22 $ImageDllCharacteristics
243 | SizeOfStackReserve = field 23 UInt64
244 | SizeOfStackCommit = field 24 UInt64
245 | SizeOfHeapReserve = field 25 UInt64
246 | SizeOfHeapCommit = field 26 UInt64
247 | LoaderFlags = field 27 UInt32
248 | NumberOfRvaAndSizes = field 28 UInt32
249 | DataDirectory = field 29 $PeImageDataDir.MakeArrayType() -MarshalAs @('ByValArray', 16)
250 | }
251 |
252 | $ImageNTHdrs = struct $mod PE.IMAGE_NT_HEADERS @{
253 | Signature = field 0 $ImageNTSig
254 | FileHeader = field 1 $ImageFileHeader
255 | OptionalHeader = field 2 $ImageOptionalHdr
256 | }
257 |
258 | $ImageNTHdrs64 = struct $mod PE.IMAGE_NT_HEADERS64 @{
259 | Signature = field 0 $ImageNTSig
260 | FileHeader = field 1 $ImageFileHeader
261 | OptionalHeader = field 2 $ImageOptionalHdr64
262 | }
263 |
264 | $FunctionDefinitions = @(
265 | (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String])),
266 | (func kernel32 GetModuleHandle ([Intptr]) @([String])),
267 | (func ntdll RtlGetCurrentPeb ([IntPtr]) @())
268 | )
269 |
270 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
271 | $Kernel32 = $Types['kernel32']
272 | $Ntdll = $Types['ntdll']
273 |
274 | # Note: At this point, all the types defined are baked in
275 | # and cannot be changed until you restart PowerShell
276 |
277 | ################################
278 | # Example - A simple PE parser #
279 | ################################
280 |
281 | # Now that all the structs, enums, and function defs are
282 | # defined, working with them is easy!
283 |
284 | # Parse the PE header of ntdll in memory
285 | $ntdllbase = $Kernel32::GetModuleHandle('ntdll')
286 | $DosHeader = $ntdllbase -as $ImageDosHeader
287 | $NtHeaderOffset = [IntPtr] ($ntdllbase.ToInt64() + $DosHeader.e_lfanew)
288 | $NTHeader = $NtHeaderOffset -as $ImageNTHdrs
289 | if ($NtHeader.OptionalHeader.Magic -eq 'PE64')
290 | {
291 | $NTHeader = $NtHeaderOffset -as $ImageNTHdrs64
292 | }
293 |
294 | $NtHeader.FileHeader
295 | $NtHeader.OptionalHeader
296 | $NtHeader.OptionalHeader.DataDirectory
297 |
298 | # Parse the PE header of kernel32 on disk
299 | $Bytes = [IO.File]::ReadAllBytes('C:\Windows\System32\kernel32.dll')
300 | # Get the address of the byte array and tell the garbage collector
301 | # not to move it.
302 | $Handle = [Runtime.InteropServices.GCHandle]::Alloc($Bytes, 'Pinned')
303 | $PEBaseAddr = $Handle.AddrOfPinnedObject()
304 |
305 | $DosHeader = $PEBaseAddr -as $ImageDosHeader
306 | $NtHeaderOffset = [IntPtr] ($PEBaseAddr.ToInt64() + $DosHeader.e_lfanew)
307 | $NTHeader = $NtHeaderOffset -as $ImageNTHdrs
308 | if ($NtHeader.OptionalHeader.Magic -eq 'PE64')
309 | {
310 | $NTHeader = $NtHeaderOffset -as $ImageNTHdrs64
311 | }
312 |
313 | $NtHeader.FileHeader
314 | $NtHeader.OptionalHeader
315 | $NtHeader.OptionalHeader.DataDirectory
316 |
--------------------------------------------------------------------------------
/Lib/Formatters/Get-ObjDump.format.ps1xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ObjectFileView
6 |
7 | COFF.OBJECT_FILE
8 |
9 |
10 |
11 |
12 |
13 |
14 | COFFHeader
15 |
16 |
17 | SectionHeaders
18 |
19 |
20 | SymbolTable
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | COFFHeaderView
29 |
30 | COFF.HEADER
31 |
32 |
33 |
34 |
35 |
36 |
37 | Machine
38 |
39 |
40 | NumberOfSections
41 | 0x{0:X4}
42 |
43 |
44 | TimeDateStamp
45 |
46 |
47 | PointerToSymbolTable
48 | 0x{0:X8}
49 |
50 |
51 | NumberOfSymbols
52 | 0x{0:X8}
53 |
54 |
55 | SizeOfOptionalHeader
56 | 0x{0:X4}
57 |
58 |
59 | Characteristics
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | SectionHeaderView
68 |
69 | COFF.SECTION_HEADER
70 |
71 |
72 |
73 |
74 |
75 |
76 | Name
77 |
78 |
79 | PhysicalAddress
80 | 0x{0:X8}
81 |
82 |
83 | VirtualSize
84 | 0x{0:X8}
85 |
86 |
87 | VirtualAddress
88 | 0x{0:X8}
89 |
90 |
91 | SizeOfRawData
92 | 0x{0:X8}
93 |
94 |
95 | PointerToRawData
96 | 0x{0:X8}
97 |
98 |
99 | PointerToRelocations
100 | 0x{0:X8}
101 |
102 |
103 | PointerToLinenumbers
104 | 0x{0:X8}
105 |
106 |
107 | NumberOfRelocations
108 | 0x{0:X4}
109 |
110 |
111 | NumberOfLinenumbers
112 | 0x{0:X4}
113 |
114 |
115 | Characteristics
116 |
117 |
118 | RawData
119 |
120 |
121 | Relocations
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | SymbolTableView
130 |
131 | COFF.SYMBOL_TABLE
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | Name
163 |
164 |
165 | Value
166 | 0x{0:X8}
167 |
168 |
169 | SectionNumber
170 |
171 |
172 | Type
173 |
174 |
175 | StorageClass
176 |
177 |
178 | NumberOfAuxSymbols
179 | 0x{0:X2}
180 |
181 |
182 | AuxSymbols
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 | SectionDefinitionView
191 |
192 | COFF.SECTION_DEFINITION
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 | Length
221 | 0x{0:X8}
222 |
223 |
224 | NumberOfRelocations
225 | 0x{0:X4}
226 |
227 |
228 | NumberOfLinenumbers
229 | 0x{0:X4}
230 |
231 |
232 | CheckSum
233 | 0x{0:X8}
234 |
235 |
236 | Number
237 | 0x{0:X4}
238 |
239 |
240 | Selection
241 | 0x{0:X2}
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 | RelocationView
250 |
251 | COFF.RelocationEntry
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 | VirtualAddress
274 | 0x{0:X8}
275 |
276 |
277 | SymbolTableIndex
278 | 0x{0:X8}
279 |
280 |
281 | Type
282 |
283 |
284 | Name
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
--------------------------------------------------------------------------------
/MalwareAnalysis/dotNetMalwareAnalysis.ps1:
--------------------------------------------------------------------------------
1 | function Get-AssemblyResources
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Extract managed resources from a .NET assembly
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: GPLv3
10 | Required Dependencies: de4dot library dlls
11 | Optional Dependencies: None
12 |
13 | .DESCRIPTION
14 |
15 | Get-AssemblyResources outputs the name and content (as a byte array) of each
16 | managed resource present in a .NET assembly
17 |
18 | .PARAMETER AssemblyPath
19 |
20 | Specifies the path to the target .NET executable.
21 |
22 | .PARAMETER AssemblyBytes
23 |
24 | Specifies a .NET executable in the form of a byte array.
25 |
26 | .PARAMETER AssemblyInfo
27 |
28 | Specifies a System.Reflection.Assembly object.
29 |
30 | .EXAMPLE
31 |
32 | Get-AssemblyResources -Path .\MaliciousDotNet.exe
33 |
34 | .EXAMPLE
35 |
36 | Get-AssemblyResources -AssemblyBytes (Get-Contect -Encoding Bytes .\MaliciousDotNet.exe)
37 |
38 | .EXAMPLE
39 |
40 | [Int32].Assembly | Get-AssemblyResources
41 | #>
42 |
43 | Param (
44 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath', ValueFromPipeline = $True)]
45 | [ValidateScript({Test-Path $_})]
46 | [Alias('Path')]
47 | [String]
48 | $AssemblyPath,
49 |
50 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyByteArray')]
51 | [ValidateNotNullOrEmpty()]
52 | [Byte[]]
53 | $AssemblyBytes,
54 |
55 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyInfo', ValueFromPipeline = $True)]
56 | [ValidateNotNullOrEmpty()]
57 | [Reflection.Assembly]
58 | $AssemblyInfo
59 | )
60 |
61 | switch ($PsCmdlet.ParameterSetName)
62 | {
63 | 'AssemblyPath' {
64 | $FullPath = Resolve-Path $AssemblyPath
65 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($FullPath.Path)
66 | }
67 |
68 | 'AssemblyByteArray' {
69 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyBytes)
70 | }
71 |
72 | 'AssemblyInfo' {
73 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyInfo.GetModules()[0])
74 | }
75 | }
76 |
77 | foreach ($Resource in $Module.Resources)
78 | {
79 | $Type = $Resource.ResourceType.ToString()
80 |
81 | switch ($Type)
82 | {
83 | 'Embedded' {
84 | $Properties = @{
85 | Type = $Type
86 | Name = $Resource.Name
87 | Data = $Resource.GetResourceData()
88 | }
89 | }
90 |
91 | 'Linked' {
92 | $Properties = @{
93 | Type = $Type
94 | Name = $Resource.Name
95 | Data = $null
96 | }
97 | }
98 |
99 | 'AssemblyLinked' {
100 | $Properties = @{
101 | Type = $Type
102 | Name = $Resource.Assembly.FullName
103 | Data = $null
104 | }
105 | }
106 | }
107 |
108 | New-Object PSObject -Property $Properties
109 | }
110 | }
111 |
112 | function Get-AssemblyStrings
113 | {
114 | <#
115 | .SYNOPSIS
116 |
117 | Output all strings from a .NET executable.
118 |
119 | Author: Matthew Graeber (@mattifestation)
120 | License: GPLv3
121 | Required Dependencies: de4dot library dlls
122 | Optional Dependencies: None
123 |
124 | .DESCRIPTION
125 |
126 | Get-AssemblyStrings outputs all defined strings from a .NET executable. When
127 | performing analysis of a malicious .NET executable, Get-AssemblyStrings will
128 | provide more relevant output than strings.exe.
129 |
130 | .PARAMETER AssemblyPath
131 |
132 | Specifies the path to the target .NET executable.
133 |
134 | .PARAMETER AssemblyBytes
135 |
136 | Specifies a .NET executable in the form of a byte array.
137 |
138 | .PARAMETER AssemblyInfo
139 |
140 | Specifies a System.Reflection.Assembly object.
141 |
142 | .PARAMETER HeapType
143 |
144 | Specifies the assembly heap to dump - #US or #Strings. Defaults to both.
145 |
146 | .PARAMETER Raw
147 |
148 | Output only strings.
149 |
150 | .EXAMPLE
151 |
152 | Get-AssemblyStrings -Path .\MaliciousDotNet.exe -Raw
153 |
154 | .EXAMPLE
155 |
156 | Get-AssemblyStrings -AssemblyBytes (Get-Contect -Encoding Bytes .\MaliciousDotNet.exe)
157 |
158 | .EXAMPLE
159 |
160 | [Int32].Assembly | Get-AssemblyStrings
161 | #>
162 |
163 | Param (
164 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath', ValueFromPipeline = $True)]
165 | [ValidateScript({Test-Path $_})]
166 | [Alias('Path')]
167 | [String]
168 | $AssemblyPath,
169 |
170 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyByteArray')]
171 | [ValidateNotNullOrEmpty()]
172 | [Byte[]]
173 | $AssemblyBytes,
174 |
175 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyInfo', ValueFromPipeline = $True)]
176 | [ValidateNotNullOrEmpty()]
177 | [Reflection.Assembly]
178 | $AssemblyInfo,
179 |
180 | [ValidateSet('Strings', 'US', 'All')]
181 | [String]
182 | $HeapType = 'All',
183 |
184 | [Switch]
185 | $Raw
186 | )
187 |
188 | switch ($PsCmdlet.ParameterSetName)
189 | {
190 | 'AssemblyPath' {
191 | $FullPath = Resolve-Path $AssemblyPath
192 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($FullPath.Path)
193 | }
194 |
195 | 'AssemblyByteArray' {
196 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyBytes)
197 | }
198 |
199 | 'AssemblyInfo' {
200 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyInfo.GetModules()[0])
201 | }
202 | }
203 |
204 | $StringType = 0x70000000
205 | $StringsHeapName = $Module.StringsStream.Name
206 | $USHeapName = $Module.USStream.Name
207 |
208 | if (($HeapType -eq 'US') -or ($HeapType -eq 'All'))
209 | {
210 | $Stream = $Module.USStream.GetClonedImageStream()
211 |
212 | if ($Stream.Length -gt 3)
213 | {
214 | $Bytes = New-Object Byte[]($Stream.Length)
215 | $null = $Stream.Read($Bytes, 0, $Bytes.Length)
216 |
217 | $CurrentOffset = 1
218 |
219 | do
220 | {
221 | $MetadataToken = $CurrentOffset -bor $StringType
222 | $StringLength = $Bytes[$CurrentOffset]
223 |
224 | # Indicates a string of length 0x8000-0x3FFFFFFF
225 | if (($StringLength -band 0xC0) -eq 0xC0)
226 | {
227 | $LengthBytes = $Bytes[$CurrentOffset..($CurrentOffset+3)]
228 | [Array]::Reverse($LengthBytes)
229 | $LengthTemp = [BitConverter]::ToInt32($LengthBytes, 0)
230 | $StringLength = $LengthTemp -band 0x3FFFFFFF
231 | $CurrentOffset += 3
232 | } # Indicates a string of length 0x100-0x7FFF
233 | elseif (($StringLength -band 0x80) -eq 0x80)
234 | {
235 | $LengthBytes = $Bytes[$CurrentOffset..($CurrentOffset+1)]
236 | [Array]::Reverse($LengthBytes)
237 | $LengthTemp = [BitConverter]::ToInt16($LengthBytes, 0)
238 | $StringLength = $LengthTemp -band 0x7FFF
239 | $CurrentOffset += 1
240 | }
241 |
242 | $CurrentOffset++
243 |
244 | $Encoder = New-Object Text.UnicodeEncoding
245 | $String = $Encoder.GetString($Bytes, $CurrentOffset, $StringLength - 1)
246 |
247 | if ($Raw)
248 | {
249 | $String
250 | }
251 | else
252 | {
253 | $Properties = @{
254 | MetadataToken = "0x$($MetadataToken.ToString('X8'))"
255 | String = $String
256 | Heap = $USHeapName
257 | }
258 |
259 | New-Object PSObject -Property $Properties
260 | }
261 |
262 | $CurrentOffset = $CurrentOffset + $StringLength
263 | } while ($CurrentOffset -lt $Bytes.Length - 3)
264 | }
265 | }
266 |
267 | if (($HeapType -eq 'Strings') -or ($HeapType -eq 'All'))
268 | {
269 | $StreamLength = $Module.StringsStream.ImageStreamLength
270 |
271 | $CurrentPosition = 0
272 |
273 | while ($CurrentPosition -lt $StreamLength)
274 | {
275 | $StringInfo = $Module.StringsStream.Read($CurrentPosition)
276 |
277 | if ($StringInfo.Length -eq 0)
278 | {
279 | $CurrentPosition++
280 | }
281 | else
282 | {
283 | $String = $StringInfo.String
284 | $CurrentPosition += $StringInfo.Length
285 |
286 | if ($Raw)
287 | {
288 | $String
289 | }
290 | else
291 | {
292 | $Properties = @{
293 | MetadataToken = ''
294 | String = $String
295 | Heap = $StringsHeapName
296 | }
297 |
298 | New-Object PSObject -Property $Properties
299 | }
300 | }
301 | }
302 | }
303 | }
304 |
305 | function Get-AssemblyImplementedMethods {
306 | <#
307 | .SYNOPSIS
308 |
309 | Returns all methods in an assembly that are implemented in MSIL.
310 |
311 | Author: Matthew Graeber (@mattifestation)
312 | License: GPLv3
313 | Required Dependencies: de4dot library dlls
314 | Optional Dependencies: None
315 |
316 | .PARAMETER AssemblyPath
317 |
318 | Specifies the path to the target .NET executable.
319 |
320 | .PARAMETER AssemblyBytes
321 |
322 | Specifies a .NET executable in the form of a byte array.
323 |
324 | .PARAMETER AssemblyInfo
325 |
326 | Specifies a System.Reflection.Assembly object.
327 |
328 | .EXAMPLE
329 |
330 | Get-AssemblyImplementedMethods -AssemblyPath evil.exe
331 |
332 | .OUTPUTS
333 |
334 | dnlib.DotNet.MethodDef
335 |
336 | Returns a method definition for every method in an assembly that is backed by MSIL.
337 | #>
338 |
339 | [OutputType([dnlib.DotNet.MethodDef])]
340 | [CMdletBinding()]
341 | Param (
342 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath', ValueFromPipeline = $True)]
343 | [ValidateScript({Test-Path $_})]
344 | [Alias('Path')]
345 | [String]
346 | $AssemblyPath,
347 |
348 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyByteArray')]
349 | [ValidateNotNullOrEmpty()]
350 | [Byte[]]
351 | $AssemblyBytes,
352 |
353 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyInfo', ValueFromPipeline = $True)]
354 | [ValidateNotNullOrEmpty()]
355 | [Reflection.Assembly]
356 | $AssemblyInfo
357 | )
358 |
359 | switch ($PsCmdlet.ParameterSetName)
360 | {
361 | 'AssemblyPath' {
362 | $FullPath = Resolve-Path $AssemblyPath
363 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($FullPath.Path)
364 | }
365 |
366 | 'AssemblyByteArray' {
367 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyBytes)
368 | }
369 |
370 | 'AssemblyInfo' {
371 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyInfo.GetModules()[0])
372 | }
373 | }
374 |
375 | $ImplementedMethods = New-Object 'Collections.Generic.List`1[dnlib.DotNet.MethodDef]'
376 |
377 | foreach ($Type in $Module.GetTypes()) {
378 | if ($Type.HasMethods) {
379 | foreach ($Method in $Type.Methods) {
380 | if ($Method.HasBody -and $Method.MethodBody.Instructions.Count) {
381 | $ImplementedMethods.Add($Method)
382 | }
383 | }
384 | }
385 | }
386 |
387 | return $ImplementedMethods
388 | }
389 |
390 | function Remove-AssemblySuppressIldasmAttribute
391 | {
392 | <#
393 | .SYNOPSIS
394 |
395 | Strips a SuppressIldasmAttribute attribute from a .NET assembly.
396 |
397 | Author: Matthew Graeber (@mattifestation)
398 | License: GPLv3
399 | Required Dependencies: de4dot library dlls
400 | Optional Dependencies: None
401 |
402 | .DESCRIPTION
403 |
404 | Remove-AssemblySuppressIldasmAttribute strips the
405 | SuppressIldasmAttribute assembly attribute from an assembly so that
406 | it can be disassembled in Microsoft ILDasm.
407 |
408 | .PARAMETER AssemblyPath
409 |
410 | Specifies the path to the target .NET executable.
411 |
412 | .PARAMETER AssemblyBytes
413 |
414 | Specifies a .NET executable in the form of a byte array.
415 |
416 | .PARAMETER AssemblyInfo
417 |
418 | Specifies a System.Reflection.Assembly object.
419 |
420 | .PARAMETER FilePath
421 |
422 | Specifies the path to which the .NET assembly with the stripped
423 | SuppressIldasmAttribute attribute will be saved.
424 |
425 | .EXAMPLE
426 |
427 | Remove-AssemblySuppressIldasmAttribute -AssemblyPath evil.exe -FilePath evil_stripped.exe
428 |
429 | .OUTPUTS
430 |
431 | System.IO.FileInfo
432 |
433 | Remove-AssemblySuppressIldasmAttribute returns a FileInfo object if a
434 | SuppressIldasmAttribute is found a a stripped assembly is saved.
435 | #>
436 |
437 | [CmdletBinding()] Param (
438 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyPath', ValueFromPipeline = $True)]
439 | [ValidateScript({Test-Path $_})]
440 | [Alias('Path')]
441 | [String]
442 | $AssemblyPath,
443 |
444 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyByteArray')]
445 | [ValidateNotNullOrEmpty()]
446 | [Byte[]]
447 | $AssemblyBytes,
448 |
449 | [Parameter(Mandatory = $True, ParameterSetName = 'AssemblyInfo', ValueFromPipeline = $True)]
450 | [ValidateNotNullOrEmpty()]
451 | [Reflection.Assembly]
452 | $AssemblyInfo,
453 |
454 | [Parameter(Mandatory = $True)]
455 | [ValidateNotNullOrEmpty()]
456 | [String]
457 | $FilePath
458 | )
459 |
460 | switch ($PsCmdlet.ParameterSetName)
461 | {
462 | 'AssemblyPath' {
463 | $FullPath = Resolve-Path $AssemblyPath
464 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($FullPath.Path)
465 | }
466 |
467 | 'AssemblyByteArray' {
468 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyBytes)
469 | }
470 |
471 | 'AssemblyInfo' {
472 | $Module = [dnlib.DotNet.ModuleDefMD]::Load($AssemblyInfo.GetModules()[0])
473 | }
474 | }
475 |
476 | $Path = Split-Path $FilePath
477 | $FileName = Split-Path -Leaf $FilePath
478 |
479 | if (($Path -eq '') -or ($Path -eq '.')) {
480 | $Path = $PWD
481 | } else {
482 | $Path = Resolve-Path $Path -ErrorAction Stop
483 | }
484 |
485 | $FullPath = Join-Path $Path $FileName
486 |
487 | $Assembly = $Module.Assembly
488 |
489 | $CustomAttributes = $Assembly.CustomAttributes
490 |
491 | $AttributeFound = $False
492 |
493 | for ($i = 0; $i -lt $CustomAttributes.Count; $i++) {
494 | $AttributeName = $CustomAttributes[$i].TypeFullName
495 |
496 | if ($AttributeName -eq 'System.Runtime.CompilerServices.SuppressIldasmAttribute') {
497 | Write-Verbose 'Found SuppressIldasmAttribute attribute.'
498 |
499 | $CustomAttributes.RemoveAt($i)
500 | $Assembly.Write($FullPath)
501 | Get-ChildItem $FullPath
502 |
503 | $AttributeFound = $True
504 | }
505 | }
506 |
507 | if (!$AttributeFound) {
508 | Write-Verbose 'No SuppressIldasmAttribute is present.'
509 | }
510 | }
--------------------------------------------------------------------------------
/MalwareAnalysis/funcdelegate.ps1:
--------------------------------------------------------------------------------
1 | function New-FunctionDelegate {
2 | <#
3 | .SYNOPSIS
4 |
5 | Provides an executable wrapper for an X86 or X86_64 function.
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: BSD 3-Clause
9 | Required Dependencies: None
10 | Optional Dependencies: None
11 |
12 | .DESCRIPTION
13 |
14 | New-FunctionDelegate returns a delegate as a wrapper for an assembly
15 | language function. This, for example, enables a malware analyst to
16 | rip out and execute complicated compression or crypto leaf functions
17 | (functions that don't call other functions). This also allows you to
18 | marshal native parameters and return types to managed types.
19 |
20 | .PARAMETER Parameters
21 |
22 | Specifies an array of managed function parameters. For example, if
23 | the function accepts two DWORDs, you would provide the following
24 | array: @([UInt32], [UInt32]). 0-10 arguments may be provided. Note:
25 | If a native parameter is a pointer, some .NET types will
26 | automatically be marshalled as pointer types. For example, when
27 | passed to your native function, [String] and [Byte[]] are passed as
28 | pointers. Debugging may be required to validate how any arbitrary
29 | type may be marshalled as a native parameter.
30 |
31 | .PARAMETER ReturnType
32 |
33 | Specifies the managed return type of the functions. For example, if
34 | the function returns a FARPROC (i.e. function pointer), ReturnType
35 | would be [IntPtr]. If the function returned a USHORT, ReturnType
36 | would be [UInt16].
37 |
38 | .PARAMETER FunctionBytes
39 |
40 | Specifies the assembly language bytes of the function you want to
41 | execute. You must ensure that the calling convention of the function
42 | matches that of the native function.
43 |
44 | .PARAMETER FunctionAddress
45 |
46 | Specifies the virtual address of an internal function for which you
47 | would like to create a wrapper method. Do not use this for exported
48 | functions as that would be total overkill when you could just
49 | develop a P/Invoke signature for it. Just be mindul that this clearly
50 | won't work for all functions as internal functions may require some
51 | state to be set that would only be available through normal execution.
52 | If you're using this parameter though, it's a safe bet that you
53 | probably already know what you're doing. This parameter is currently
54 | only supported on x86 due to the fact that I haven't implemented a
55 | generic X86_64 call wrapper.
56 |
57 | .PARAMETER CallingConvention
58 |
59 | Specifies the calling convention - StdCall, Cdecl, FastCall,
60 | ThisCall. This only applies to X86. Currently, for X86_64,
61 | only FastCall is supported.
62 |
63 | .PARAMETER DebugBreak
64 |
65 | Inserts an INT3 (0xCC) prior to the function byte so that a debugger
66 | will break on your function.
67 |
68 | .EXAMPLE
69 |
70 | $AddStdcall = [Byte[]] @(
71 | 0x55, # push ebp
72 | 0x89,0xE5, # mov ebp, esp
73 | 0x8B,0x45,0x08, # mov eax, [ebp+0x08]
74 | 0x03,0x45,0x0C, # add eax, [ebp+0x0C]
75 | 0x89,0xEC, # mov esp, ebp
76 | 0x5D, # pop ebp
77 | 0xC2,0x08,0x00) # retn 8
78 |
79 | $AddStd = New-FunctionDelegate -ReturnType ([Int32]) -Parameters @([Int32], [Int32]) -FunctionBytes $AddStdcall -CallingConvention StdCall
80 | $AddStd.Invoke(1,2)
81 |
82 | .EXAMPLE
83 |
84 | $AddCdeclBytes = [Byte[]] @(
85 | 0x55, # push ebp
86 | 0x89,0xE5, # mov ebp, esp
87 | 0x8B,0x45,0x08, # mov eax, [ebp+0x08]
88 | 0x03,0x45,0x0C, # add eax, [ebp+0x0C]
89 | 0x89,0xEC, # mov esp, ebp
90 | 0x5D, # pop ebp
91 | 0xC3) # ret
92 |
93 | $AddCdecl = New-FunctionDelegate -ReturnType ([Int32]) -Parameters @([Int32], [Int32]) -FunctionBytes $AddCdeclBytes -CallingConvention Cdecl
94 | $AddCdecl.Invoke(1,2)
95 |
96 | .EXAMPLE
97 |
98 | $AddFastcall = [Byte[]] @(
99 | 0x89,0xC8, # mov eax, ecx
100 | 0x01,0xD0, # add eax, edx
101 | 0xC3) # ret
102 |
103 | $AddFast = New-FunctionDelegate -ReturnType ([Int32]) -Parameters @([Int32], [Int32]) -FunctionBytes $AddFastcall -CallingConvention FastCall
104 | $AddFast.Invoke(1,2)
105 |
106 | .EXAMPLE
107 |
108 | $AddThiscall = [Byte[]] @(
109 | 0x55, # push ebp
110 | 0x89,0xE5, # mov ebp, esp
111 | 0x89,0xC8, # mov eax, ecx
112 | 0x03,0x45,0x08, # add eax, [ebp+0x08]
113 | 0x89,0xEC, # mov esp, ebp
114 | 0x5D, # pop ebp
115 | 0xC2,0x04,0x00) # retn 4
116 |
117 | $AddThis = New-FunctionDelegate -ReturnType ([Int32]) -Parameters @([Int32], [Int32]) -FunctionBytes $AddThiscall -CallingConvention Thiscall
118 | $AddThis.Invoke(1,2)
119 |
120 | .EXAMPLE
121 |
122 | $X64AddBytes = [Byte[]] @(
123 | 0x48,0x89,0xC8, # mov rax, rcx
124 | 0x48,0x01,0xD0, # add rax, rdx
125 | 0xC3) # ret
126 |
127 | $X64Add = New-FunctionDelegate -ReturnType ([Int32]) -Parameters @([Int32], [Int32]) -FunctionBytes $X64AddBytes
128 | $X64Add.Invoke(1,2)
129 |
130 | .EXAMPLE
131 |
132 | $InternalFunctionRVA = 0x00187802
133 | $ModuleBaseAddr = [Uri].Assembly.GetType('Microsoft.Win32.SafeNativeMethods')::LoadLibrary('C:\Windows\System32\ReallyInteresting.dll')
134 | $InternalFunctionVA = [IntPtr]::Add($ModuleBaseAddr, $InternalFunctionRVA)
135 | $InternalFunctionWrapper = New-FunctionDelegate -Parameters @([UInt32]) -ReturnType ([IntPtr]) -FunctionAddress $InternalFunctionVA -CallingConvention ThisCall
136 | $InternalFunctionWrapper.Invoke(3)
137 |
138 | .OUTPUTS
139 |
140 | System.Delegate
141 | #>
142 |
143 | [OutputType([Delegate])]
144 | [CmdletBinding(DefaultParameterSetName = 'Bytes')]
145 | Param (
146 | [Parameter(Position = 0)]
147 | [ValidateCount(1, 10)]
148 | [Type[]]
149 | $Parameters = (New-Object Type[](0)),
150 |
151 | [Parameter(Position = 1)]
152 | [Type]
153 | $ReturnType = [Void],
154 |
155 | [Parameter(Position = 2, Mandatory = $True, ParameterSetName = 'Bytes')]
156 | [ValidateNotNullOrEmpty()]
157 | [Byte[]]
158 | $FunctionBytes,
159 |
160 | [Parameter(Position = 2, Mandatory = $True, ParameterSetName = 'Address')]
161 | [IntPtr]
162 | $FunctionAddress,
163 |
164 | [Parameter(Position = 3)]
165 | [Runtime.InteropServices.CallingConvention]
166 | $CallingConvention,
167 |
168 | [Switch]
169 | $DebugBreak
170 | )
171 |
172 | function local:Get-DelegateType {
173 |
174 | [OutputType([Type])]
175 | Param (
176 | [Parameter(Position = 0)]
177 | [Type[]]
178 | $Parameters = (New-Object Type[](0)),
179 |
180 | [Parameter(Position = 1)]
181 | [Type]
182 | $ReturnType = [Void]
183 | )
184 |
185 | $Domain = [AppDomain]::CurrentDomain
186 | $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
187 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
188 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
189 | $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
190 | $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
191 | $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
192 | $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
193 | $MethodBuilder.SetImplementationFlags('Runtime, Managed')
194 |
195 | Write-Output $TypeBuilder.CreateType()
196 | }
197 |
198 | # Define VirtualAlloc if it isn't already defined
199 | try { $Kernel32 = [FunctionDelegate.Kernel32] } catch [Management.Automation.RuntimeException] {
200 | $DynAssembly = New-Object System.Reflection.AssemblyName('FunctionDelegate_Win32_Assembly')
201 | $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
202 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('FunctionDelegate_Win32_Module', $False)
203 |
204 | $TypeBuilder = $ModuleBuilder.DefineType('FunctionDelegate.Kernel32', 'Public, Class')
205 |
206 | $PInvokeMethod = $TypeBuilder.DefineMethod(
207 | 'VirtualAlloc',
208 | 'Public, Static, HideBySig',
209 | [Reflection.CallingConventions]::Standard,
210 | [IntPtr],
211 | [Type[]]@([IntPtr], [IntPtr], [UInt32], [UInt32]))
212 |
213 | $PreserveSigConstructor = [Runtime.InteropServices.PreserveSigAttribute].GetConstructor(@())
214 | $PreserveSigCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($PreserveSigConstructor, @())
215 |
216 | $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
217 | $FieldArray = [Reflection.FieldInfo[]] @(
218 | [Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
219 | [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError'),
220 | [Runtime.InteropServices.DllImportAttribute].GetField('CallingConvention')
221 | )
222 |
223 | $FieldValueArray = [Object[]] @(
224 | 'VirtualAlloc',
225 | $True,
226 | [Runtime.InteropServices.CallingConvention]::Winapi
227 | )
228 |
229 | $DllImportCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor,
230 | @('kernel32.dll'),
231 | $FieldArray,
232 | $FieldValueArray)
233 |
234 | $PInvokeMethod.SetCustomAttribute($DllImportCustomAttribute)
235 | $null = $PInvokeMethod.DefineParameter(1, 'None', 'lpAddress')
236 | $null = $PInvokeMethod.DefineParameter(2, 'None', 'dwSize')
237 | $null = $PInvokeMethod.DefineParameter(3, 'None', 'flAllocationType')
238 | $null = $PInvokeMethod.DefineParameter(4, 'None', 'flProtect')
239 |
240 | $Kernel32 = $TypeBuilder.CreateType()
241 | }
242 |
243 | if ($DebugBreak) { $Int3 = [Byte[]] @(0xCC) } else { $Int3 = [Byte[]] @(0x90) }
244 |
245 | if ([IntPtr]::Size -eq 4) {
246 | if (-not $CallingConvention) {
247 | throw 'You must specify a calling convention for 32-bit code.'
248 | }
249 |
250 | # Prologue bytes that will remain consistent despite the calling convention used
251 | $CommonPrologueBytes = [Byte[]] @(
252 | 0x55, # push ebp ; Set up EBP-based frame
253 | 0x89,0xE5, # mov ebp, esp
254 | 0x57, # push edi ; Preserve all non-volatile registers
255 | 0x56, # push esi ; We can't trust our callee to preserve non-volatile register
256 | 0x53 # push ebx
257 | )
258 |
259 | # The arguments are the same for both stdcall and cdecl
260 | $StdcallArgs = @(
261 | [Byte[]] @(0xFF, 0x75, 0x08), # push dword [ebp+0x08]
262 | [Byte[]] @(0xFF, 0x75, 0x0C) # push dword [ebp+0x0C]
263 | )
264 |
265 | # In fastcall, arg0 is passed via ECX, arg1 is passed via EDX
266 | $FastcallArgs = @(
267 | [Byte[]] @(0x8B, 0x4D, 0x08), # mov ecx,[ebp+0x8]
268 | [Byte[]] @(0x8B, 0x55, 0x0C) # mov edx,[ebp+0xc]
269 | )
270 |
271 | # In thiscall, 'this' (or arg0) is passed via ECX
272 | $ThiscallArgs = @(
273 | [Byte[]] @(0x8B, 0x4D, 0x08), # mov ecx,[ebp+0x8]
274 | [Byte[]] @(0xFF, 0x75, 0x0C) # push dword [ebp+0x0C]
275 | )
276 |
277 | # Argument pushes common to all calling conventions
278 | $CommonArgs = @(
279 | [Byte[]] @(0xFF, 0x75, 0x10), # push dword [ebp+0x10]
280 | [Byte[]] @(0xFF, 0x75, 0x14), # push dword [ebp+0x14]
281 | [Byte[]] @(0xFF, 0x75, 0x18), # push dword [ebp+0x18]
282 | [Byte[]] @(0xFF, 0x75, 0x1C), # push dword [ebp+0x1C]
283 | [Byte[]] @(0xFF, 0x75, 0x20), # push dword [ebp+0x20]
284 | [Byte[]] @(0xFF, 0x75, 0x24), # push dword [ebp+0x24]
285 | [Byte[]] @(0xFF, 0x75, 0x28), # push dword [ebp+0x28]
286 | [Byte[]] @(0xFF, 0x75, 0x2C) # push dword [ebp+0x2C]
287 | )
288 |
289 | # Epilogue bytes that will remain consistent despite the calling convention used
290 | $CommonEpilogueBytes = [Byte[]] @(
291 | 0x5B, # pop ebx ; Restore all non-volatile registers
292 | 0x5E, # pop esi
293 | 0x5F, # pop edi
294 | 0x89,0xEC, # mov esp, ebp ; Restore frame of caller
295 | 0x5D, # pop ebp
296 | 0xC3) # ret
297 |
298 |
299 | # If the calling convention requires that we adjust the stack upon returning to the caller,
300 | # we will do so by this value.
301 | $Adjustment = [Byte[]] @([IntPtr]::Size * $Parameters.Length)
302 |
303 | $StackAdjustment = [Byte[]] @()
304 |
305 | # Choose the respective argument setup and stack adjustment
306 | # according to the calling convention specified
307 | switch ($CallingConvention) {
308 | 'StdCall' { $Arguments = $StdcallArgs }
309 |
310 | 'Winapi' { $Arguments = $StdcallArgs }
311 |
312 | 'FastCall' { $Arguments = $FastcallArgs }
313 |
314 | 'Cdecl' {
315 | $Arguments = $StdcallArgs
316 | $StackAdjustment = [Byte[]] @(0x83, 0xC4) + $Adjustment # add esp, STACK_ADJUSTMENT
317 | }
318 |
319 | 'ThisCall' { $Arguments = $ThiscallArgs }
320 | }
321 |
322 | # Append the push arguments that are common to all calling conventions
323 | $Arguments += $CommonArgs
324 |
325 | # THis will comprise the collection of push arguments
326 | $ArgumentBytes = [Byte[]] @()
327 |
328 | # Collect all of the relevant push arguments for the wrapper function
329 | for ($i = 0; $i -lt $Parameters.Length; $i++) { $ArgumentBytes += $Arguments[$i] }
330 |
331 | # Allocate RWX memory for the target function
332 | # Note: no, this function was not intended for stealth. Creation of arbitrary RWX and W->RX pages
333 | # is likely to get you caught - e.g. the Windows Defender Exploit Guard Arbitary Code Guard
334 | # mitigation (Microsoft-Windows-Security-Mitigations/KernelMode EID 1 and 2) is an example of something
335 | # that could detect/block this.
336 | if ($FunctionBytes) {
337 | $PBytes = $Kernel32::VirtualAlloc([IntPtr]::Zero, [IntPtr] $FunctionBytes.Length, 0x3000, 0x40)
338 | [Runtime.InteropServices.Marshal]::Copy($FunctionBytes, 0, $PBytes, $FunctionBytes.Length)
339 | } else {
340 | # -FunctionAddress was specified. They are mutually exclusive (via parametersets) and mandatory so I can get away with this logic.
341 | # It is assumed that the address you supplied point to actual, executable code.
342 | $PBytes = $FunctionAddress
343 | }
344 |
345 | $AddrBytes = [BitConverter]::GetBytes([Int32] $PBytes)
346 |
347 | # Note: this will need to change once I support passing of arguments via arbitrary registers (__usercall).
348 | $CallBytes = [Byte[]] @(
349 | 0xB8 ) + $AddrBytes + [Byte[]] @( # mov eax, CALL_TARGET
350 | 0xFF, 0xD0) + # call eax
351 | $StackAdjustment
352 |
353 | # Compose the entire calling convention converter wrapper function
354 | [Byte[]] $FunctionWrapperBytes = $Int3 +
355 | $CommonPrologueBytes +
356 | $ArgumentBytes +
357 | $CallBytes +
358 | $CommonEpilogueBytes
359 |
360 | # Allocate RWX memory for the wrapper function
361 | # Again, not intended for stealth.
362 | $PWrapper = $Kernel32::VirtualAlloc([IntPtr]::Zero, [IntPtr] $FunctionWrapperBytes.Length, 0x3000, 0x40)
363 | [Runtime.InteropServices.Marshal]::Copy($FunctionWrapperBytes, 0, $PWrapper, $FunctionWrapperBytes.Length)
364 |
365 | # Cast the wrapper function to a delegate so it can be invoked from within PowerShell
366 | $Prototype = Get-DelegateType $Parameters $ReturnType
367 | $Delegate = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($PWrapper, $Prototype)
368 | } else {
369 | if ($FunctionBytes) {
370 | if ($CallingConvention -eq 'FastCall') {
371 | # Only fastcall is currently supported for X86_64
372 |
373 | $X64Bytes = $Int3 + $FunctionBytes
374 |
375 | # Allocate RWX memory for the target function
376 | # Again, not intended for stealth.
377 | $PBytes = $Kernel32::VirtualAlloc([IntPtr]::Zero, [IntPtr] $X64Bytes.Length, 0x3000, 0x40)
378 | [Runtime.InteropServices.Marshal]::Copy($X64Bytes, 0, $PBytes, $X64Bytes.Length)
379 |
380 | # Cast the wrapper function to a delegate so it can be invoked from within PowerShell
381 | $Prototype = Get-DelegateType $Parameters $ReturnType
382 | $Delegate = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($PBytes, $Prototype)
383 | } else {
384 | Write-Error "The $CallingConvention calling convention is not supported on X86_64. Only FastCall is supported."
385 | }
386 | } else {
387 | Write-Error '-FunctionAddress is not currently supported on X86_64.'
388 | return
389 | }
390 | }
391 |
392 | return $Delegate
393 | }
--------------------------------------------------------------------------------
/Misc/Get-Member.ps1:
--------------------------------------------------------------------------------
1 | function Get-Member
2 | {
3 | <#
4 | .SYNOPSIS
5 |
6 | Gets the properties and methods of objects.
7 |
8 | Author: Matthew Graeber (@mattifestation)
9 | License: BSD 3-Clause (Except for the help documentation derived from the original Get-Member)
10 | Required Dependencies: None
11 | Optional Dependencies: None
12 |
13 | .DESCRIPTION
14 |
15 | The Get-Member cmdlet gets the "members" (properties and methods) of objects.
16 |
17 | To specify the object, use the InputObject parameter or pipe an object to Get-Member. To retrieve information about static members (members of the class, not of the instance), use the Static parameter. To get only certain types of members, such as NoteProperties, use the MemberType parameter.
18 |
19 | .PARAMETER Private
20 |
21 | Gets only the non-public members of the object.
22 |
23 | These members are typically not exposed and are extracted using reflection.
24 |
25 | .PARAMETER Static
26 |
27 | Gets only the static properties and methods of the object.
28 |
29 | Static properties and methods are defined on the class of objects, not on any particular instance of the class.
30 |
31 | If you use the Static parameter with the View parameter, the View parameter is ignored. If you use the Static parameter with the MemberType parameter, Get-Member gets only the members that belong to both sets.
32 |
33 | .PARAMETER Force
34 |
35 | Adds the intrinsic members (PSBase, PSAdapted, PSObject, PSTypeNames) and the compiler-generated get_, set_, op_, .ctor, and .cctor methods to the display. By default, Get-Member gets these properties in all views other than "Base" and "Adapted," but it does not display them.
36 |
37 | The following list describes the properties that are added when you use the Force parameter:
38 |
39 | -- PSBase: The original properties of the .NET Framework object without extension or adaptation. These are the properties defined for the object class and listed in MSDN.
40 | -- PSAdapted: The properties and methods defined in the Windows PowerShell extended type system.
41 | -- PSExtended: The properties and methods that were added in the Types.ps1xml files or by using the Add-Member cmdlet.
42 | -- PSObject: The adapter that converts the base object to a Windows PowerShell PSObject object.
43 | -- PSTypeNames: A list of object types that describe the object, in order of specificity. When formatting the object, Windows PowerShell searches for the types in the Format.ps1xml files in the Windows PowerShell installation directory ($pshome). It uses the formatting definition for the first type that it finds.
44 | -- get_*: The object's getter methods
45 | -- set_*: The object's setter methods
46 | -- op_*: The object's operator methods
47 | -- .ctor: The object's constructor
48 | -- .cctor: The object's copy constructor
49 |
50 | .PARAMETER InputObject
51 |
52 | Specifies the object whose members are retrieved.
53 |
54 | Using the InputObject parameter is not the same as piping an object to Get-Member. The differences are as follows:
55 |
56 | -- When you pipe a collection of objects to Get-Member, Get-Member gets the members of the individual objects in the collection, such as the properties of the integers in an array of integers.
57 |
58 | -- When you use InputObject to submit a collection of objects, Get-Member gets the members of the collection, such as the properties of the array in an array of integers.
59 |
60 | .PARAMETER PrivateMemberType
61 |
62 | When the 'Private' parameter is specified, only members with the specified member type. The default is All.
63 |
64 | The valid values for this parameter are:
65 |
66 | -- Constructor: A constructor method of the underlying .NET Framework object.
67 | -- Event: Indicates that the object sends a message to indicate an action or a change in state.
68 | -- Field: A private field of the underlying .NET Framework object.
69 | -- Method: A method of the underlying .NET Framework object.
70 | -- Property: A property of the underlying .NET Framework object.
71 | -- TypeInfo: A type of the underlying .NET Framework object.
72 | -- Custom: A custom member type
73 | -- NestedType: A nested type of the underlying .NET Framework object.
74 |
75 | -- All: Gets all member types.
76 |
77 | .PARAMETER MemberType
78 |
79 | Gets only members with the specified PowerShell member type. The default is All.
80 |
81 | The valid values for this parameter are:
82 |
83 | -- AliasProperty: A property that defines a new name for an existing property.
84 | -- CodeMethod: A method that references a static method of a .NET Framework class.
85 | -- CodeProperty: A property that references a static property of a .NET Framework class.
86 | -- Event: Indicates that the object sends a message to indicate an action or a change in state.
87 | -- MemberSet: A predefined collection of properties and methods, such as PSBase, PSObject, and PSTypeNames.
88 | -- Method: A method of the underlying .NET Framework object.
89 | -- NoteProperty: A property with a static value.
90 | -- ParameterizedProperty: A property that takes parameters and parameter values.
91 | -- Property: A property of the underlying .NET Framework object.
92 | -- PropertySet: A predefined collection of object properties.
93 | -- ScriptMethod: A method whose value is the output of a script.
94 | -- ScriptProperty: A property whose value is the output of a script.
95 |
96 | -- All: Gets all member types.
97 | -- Methods: Gets all types of methods of the object (for example, Method, CodeMethod, ScriptMethod).
98 | -- Properties: Gets all types of properties of the object (for example, Property, CodeProperty, AliasProperty, ScriptProperty).
99 |
100 | Not all objects have every type of member. If you specify a member type that the object does not have, Windows PowerShell returns a null value.
101 |
102 | To get related types of members, such as all extended members, use the View parameter. If you use the MemberType parameter with the Static or View parameters, Get-Member gets the members that belong to both sets.
103 |
104 | .PARAMETER Name
105 |
106 | Specifies the names of one or more properties or methods of the object. Get-Member gets only the specified properties and methods.
107 |
108 | If you use the Name parameter with the MemberType, View, or Static parameters, Get-Member gets only the members that satisfy the criteria of all parameters.
109 |
110 | To get a static member by name, use the Static parameter with the Name parameter.
111 |
112 | .PARAMETER View
113 |
114 | Gets only particular types of members (properties and methods). Specify one or more of the values. The default is "Adapted, Extended".
115 |
116 | Valid values are:
117 | -- Base: Gets only the original properties and methods of the .NET Framework object (without extension or adaptation).
118 | -- Adapted: Gets only the properties and methods defined in the Windows PowerShell extended type system.
119 | -- Extended: Gets only the properties and methods that were added in the Types.ps1xml files or by using the Add-Member cmdlet.
120 | -- All: Gets the members in the Base, Adapted, and Extended views.
121 |
122 | The View parameter determines the members retrieved, not just the display of those members.
123 |
124 | To get particular member types, such as script properties, use the MemberType parameter. If you use the MemberType and View parameters in the same command, Get-Member gets the members that belong to both sets. If you use the Static and View parameters in the same command, the View parameter is ignored.
125 |
126 | .EXAMPLE
127 |
128 | [String] | Get-Member -Static -Private
129 |
130 | Description
131 | -----------
132 | Returns all staic, non-public members of the String class.
133 |
134 | .EXAMPLE
135 |
136 | [Diagnostics.Process] | Get-Member -Private -PrivateMemberType Method
137 |
138 | Description
139 | -----------
140 | Returns all non-public instance methods of the Diagnostics.Process class
141 |
142 | .EXAMPLE
143 |
144 | 'Hello, World' | Get-Member -Private -Force
145 |
146 | Description
147 | -----------
148 | Returns all instance members including those with special names (like .ctor) of the string instance
149 | #>
150 | [CmdletBinding(DefaultParameterSetName = 'Default')]
151 | Param (
152 | [Parameter(ValueFromPipeline=$true, ParameterSetName = 'Default')]
153 | [Parameter(ValueFromPipeline=$true, ParameterSetName = 'Private')]
154 | [System.Management.Automation.PSObject]
155 | $InputObject,
156 |
157 | [Parameter(Position=0, ParameterSetName = 'Default')]
158 | [Parameter(Position=0, ParameterSetName = 'Private')]
159 | [ValidateNotNullOrEmpty()]
160 | [System.String[]]
161 | $Name,
162 |
163 | [Parameter(ParameterSetName = 'Default')]
164 | [Alias('Type')]
165 | [System.Management.Automation.PSMemberTypes]
166 | $MemberType,
167 |
168 | [Parameter(ParameterSetName = 'Private')]
169 | [System.Reflection.MemberTypes]
170 | $PrivateMemberType = [System.Reflection.MemberTypes]::All,
171 |
172 | [Parameter(ParameterSetName = 'Default')]
173 | [System.Management.Automation.PSMemberViewTypes]
174 | $View,
175 |
176 | [Parameter(ParameterSetName = 'Default')]
177 | [Parameter(ParameterSetName = 'Private')]
178 | [Switch]
179 | $Static,
180 |
181 | [Parameter(ParameterSetName = 'Default')]
182 | [Parameter(ParameterSetName = 'Private')]
183 | [Switch]
184 | $Force,
185 |
186 | [Parameter(ParameterSetName = 'Private')]
187 | [Switch]
188 | $Private
189 | )
190 |
191 | BEGIN
192 | {
193 | try {
194 | $outBuffer = $null
195 | if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
196 | {
197 | $PSBoundParameters['OutBuffer'] = 1
198 | }
199 | $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Get-Member', [System.Management.Automation.CommandTypes]::Cmdlet)
200 | # Redirect the output of the command to $out variable
201 | $null = $PSBoundParameters.Add('OutVariable', 'out')
202 | # Redirect original output to $null
203 | if ($PSBoundParameters['Private']) {
204 | $null = $PSBoundParameters.Remove('Private')
205 | $Private = $True
206 | }
207 | if ($PSBoundParameters['PrivateMemberType']) {
208 | $PrivateMemberType = $PSBoundParameters['PrivateMemberType']
209 | $null = $PSBoundParameters.Remove('PrivateMemberType')
210 | }
211 | $scriptCmd = {& $wrappedCmd @PSBoundParameters | Out-Null }
212 | $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
213 | $steppablePipeline.Begin($PSCmdlet)
214 | } catch {
215 | }
216 | }
217 |
218 | PROCESS
219 | {
220 | try {
221 | $steppablePipeline.Process($_)
222 | } catch {
223 | }
224 | }
225 |
226 | END
227 | {
228 | try {
229 | $steppablePipeline.End()
230 | if ($Private) {
231 |
232 | $Object = $PSBoundParameters['InputObject']
233 | if ($Object.GetType().FullName -ne 'System.RuntimeType') {
234 | # If InputObject is an instance of an object, get its type
235 | # Otherwise, it's assumed that what was passed in was already a type
236 | $Object = $Object.GetType()
237 | }
238 |
239 | if ($PSBoundParameters['Static']) {
240 | $Flags = 'Static, NonPublic'
241 |
242 | # Retrieve all static, nonpublic members except for constructors
243 | $Types = foreach ($Val in [Enum]::GetValues([System.Reflection.MemberTypes])) {
244 | $Object.GetMembers($Flags) | Where-Object { ($_.MemberType -eq ($Val.value__ -band $PrivateMemberType)) -and ($Val -ne [System.Reflection.MemberTypes]::All) -and ($_.MemberType -ne 'Constructor') }
245 | }
246 |
247 | # Retrieve all static constructors (both public and nonpublic)
248 | # Public constructors are retrieved because the original 'Get-Member -Force' does not retrieve constructors
249 | $Types += $Object.GetConstructors('Static, NonPublic, Public')
250 | } else {
251 | $Flags = 'Instance, NonPublic'
252 |
253 | # Retrieve all instance, nonpublic members except for constructors
254 | $Types = foreach ($Val in [Enum]::GetValues([System.Reflection.MemberTypes])) {
255 | $Object.GetMembers($Flags) | Where-Object { ($_.MemberType -eq ($Val.value__ -band $PrivateMemberType)) -and ($Val -ne [System.Reflection.MemberTypes]::All) -and ($_.MemberType -ne 'Constructor') }
256 | }
257 |
258 | # Retrieve all instance constructors (both public and nonpublic)
259 | # Public constructors are retrieved because the original 'Get-Member -Force' does not retrieve constructors
260 | $Types += $Object.GetConstructors('Instance, NonPublic, Public')
261 | }
262 |
263 | # Filter out types with special names if '-Force' is not specified
264 | if (!$Force) {
265 | $Types = $Types | Where-Object { !$_.IsSpecialName }
266 | }
267 |
268 | $TypeTable = @{}
269 |
270 | # For each type, build an array of object equivalent to an array of Microsoft.PowerShell.Commands.MemberDefinition objects.
271 | # An array of custom objects is required because the MemberDefinition object doesn't take System.Reflection.MemberTypes
272 | # objects in its constructor.
273 | $Results = $Types | ForEach-Object {
274 |
275 | $Type = $_
276 |
277 | switch ($Type.MemberType) {
278 | 'Constructor' {
279 | $Parameters = ($Type.GetParameters() | % {$_.ParameterType.FullName}) -join ', '
280 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.Name)($($Parameters))"
281 | }
282 | 'Field' {
283 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.FieldType)"
284 | }
285 | 'Method' {
286 | $Parameters = ($Type.GetParameters() | % {$_.ParameterType.FullName}) -join ', '
287 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.ReturnType) $($Type.Name)($($Parameters))"
288 | }
289 | 'Property' {
290 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.PropertyType) $($Type.Name) {$(if ($Type.CanRead){'get;'})$(if ($Type.CanWrite){'set;'})}"
291 | }
292 | 'NestedType' {
293 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.FullName) BaseType=$($Type.BaseType)"
294 | }
295 | 'Event' {
296 | $Parameters = ($Type.GetAddMethod().GetParameters() | % {$_.ParameterType.FullName}) -join ', '
297 | $Definition = "$(if ($Type.IsStatic){'static '})$($Type.EventHandlerType) $($Type.Name)(System.Object, $($Parameters))"
298 | }
299 | }
300 |
301 | # Identical properties as the Microsoft.PowerShell.Commands.MemberDefinition object
302 | $InternalMemberType = @{
303 | TypeName = $Type.DeclaringType.FullName
304 | Name = $Type.Name
305 | MemberType = $Type.MemberType
306 | Definition = $Definition
307 | }
308 |
309 | New-Object PSObject -Property $InternalMemberType
310 | }
311 |
312 | # For members with the same name, compress them into an array that will be stored in a hashtable
313 | $Results | ForEach-Object {
314 | $TypeTable["$($_.Name)"] += @($_)
315 | }
316 |
317 | $Results = foreach ($Type in $TypeTable.Keys) {
318 | $ReturnType = @{
319 | TypeName = $TypeTable[$Type][0].TypeName
320 | Name = $TypeTable[$Type][0].Name
321 | MemberType = $TypeTable[$Type][0].MemberType
322 | # Append each definition into a single definition.
323 | # This behavior is indentical to what the unmodified
324 | # Get-Member does.
325 | Definition = ($TypeTable[$Type] | ForEach-Object { $_.Definition }) -join ', '
326 | }
327 |
328 | $MemberDef = New-Object PSObject -Property $ReturnType
329 | <#
330 | Cool trick. Even though the custom object is actually a Microsoft.PowerShell.Commands.MemberDefinition
331 | object, you can trick it into thinking it is so that it will display the same way the result of the
332 | original Get-Member cmdlet would.
333 | #>
334 | $MemberDef.PSObject.TypeNames.Insert(0, 'Microsoft.PowerShell.Commands.MemberDefinition')
335 | $MemberDef
336 | }
337 |
338 | # If '-Name' parameter is specified, only return members matching the name specified
339 | if ($PSBoundParameters['Name']) {
340 | $MemberNames = [String[]] $PSBoundParameters['Name']
341 |
342 | $Tmp = New-Object PSObject[](0)
343 |
344 | foreach ($MemberName in $MemberNames) {
345 | $Tmp += $Results | Where-Object { $_.Name -eq $MemberName }
346 | }
347 |
348 | $Results = $Tmp
349 | }
350 |
351 | # Return the results if the results are non-null
352 | if ($Results.Count) {
353 | $Results | Sort-Object TypeName, MemberType, Name
354 | }
355 | } else {
356 | # If '-Private' is not set, return the results of the original Get-Member cmdlet
357 | $out | Sort-Object TypeName, MemberType, Name
358 | }
359 | } catch {
360 | }
361 | }
362 | }
363 |
364 |
--------------------------------------------------------------------------------
/MemoryTools/MemoryTools.ps1:
--------------------------------------------------------------------------------
1 | function Get-VirtualMemoryInfo {
2 | <#
3 | .SYNOPSIS
4 |
5 | A wrapper for kernel32!VirtualQueryEx
6 |
7 | Author: Matthew Graeber (@mattifestation)
8 | License: BSD 3-Clause
9 | Required Dependencies: PSReflect module
10 | Optional Dependencies: None
11 |
12 | .PARAMETER ProcessID
13 |
14 | Specifies the process ID.
15 |
16 | .PARAMETER ModuleBaseAddress
17 |
18 | Specifies the address of the memory to be queried.
19 |
20 | .PARAMETER PageSize
21 |
22 | Specifies the system page size. Defaults to 0x1000 if one is not
23 | specified.
24 |
25 | .EXAMPLE
26 |
27 | Get-VirtualMemoryInfo -ProcessID $PID -ModuleBaseAddress 0
28 | #>
29 |
30 | Param (
31 | [Parameter(Position = 0, Mandatory = $True)]
32 | [ValidateScript({Get-Process -Id $_})]
33 | [Int]
34 | $ProcessID,
35 |
36 | [Parameter(Position = 1, Mandatory = $True)]
37 | [IntPtr]
38 | $ModuleBaseAddress,
39 |
40 | [Int]
41 | $PageSize = 0x1000
42 | )
43 |
44 | $Mod = New-InMemoryModule -ModuleName MemUtils
45 |
46 | $MemProtection = psenum $Mod MEMUTIL.MEM_PROTECT Int32 @{
47 | PAGE_EXECUTE = 0x00000010
48 | PAGE_EXECUTE_READ = 0x00000020
49 | PAGE_EXECUTE_READWRITE = 0x00000040
50 | PAGE_EXECUTE_WRITECOPY = 0x00000080
51 | PAGE_NOACCESS = 0x00000001
52 | PAGE_READONLY = 0x00000002
53 | PAGE_READWRITE = 0x00000004
54 | PAGE_WRITECOPY = 0x00000008
55 | PAGE_GUARD = 0x00000100
56 | PAGE_NOCACHE = 0x00000200
57 | PAGE_WRITECOMBINE = 0x00000400
58 | } -Bitfield
59 |
60 | $MemState = psenum $Mod MEMUTIL.MEM_STATE Int32 @{
61 | MEM_COMMIT = 0x00001000
62 | MEM_FREE = 0x00010000
63 | MEM_RESERVE = 0x00002000
64 | } -Bitfield
65 |
66 | $MemType = psenum $Mod MEMUTIL.MEM_TYPE Int32 @{
67 | MEM_IMAGE = 0x01000000
68 | MEM_MAPPED = 0x00040000
69 | MEM_PRIVATE = 0x00020000
70 | } -Bitfield
71 |
72 | if ([IntPtr]::Size -eq 4) {
73 | $MEMORY_BASIC_INFORMATION = struct $Mod MEMUTIL.MEMORY_BASIC_INFORMATION @{
74 | BaseAddress = field 0 Int32
75 | AllocationBase = field 1 Int32
76 | AllocationProtect = field 2 $MemProtection
77 | RegionSize = field 3 Int32
78 | State = field 4 $MemState
79 | Protect = field 5 $MemProtection
80 | Type = field 6 $MemType
81 | }
82 | } else {
83 | $MEMORY_BASIC_INFORMATION = struct $Mod MEMUTIL.MEMORY_BASIC_INFORMATION @{
84 | BaseAddress = field 0 Int64
85 | AllocationBase = field 1 Int64
86 | AllocationProtect = field 2 $MemProtection
87 | Alignment1 = field 3 Int32
88 | RegionSize = field 4 Int64
89 | State = field 5 $MemState
90 | Protect = field 6 $MemProtection
91 | Type = field 7 $MemType
92 | Alignment2 = field 8 Int32
93 | }
94 | }
95 |
96 | $FunctionDefinitions = @(
97 | (func kernel32 VirtualQueryEx ([Int32]) @([IntPtr], [IntPtr], $MEMORY_BASIC_INFORMATION.MakeByRefType(), [Int]) -SetLastError),
98 | (func kernel32 OpenProcess ([IntPtr]) @([UInt32], [Bool], [UInt32]) -SetLastError),
99 | (func kernel32 CloseHandle ([Bool]) @([IntPtr]) -SetLastError)
100 | )
101 |
102 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32MemUtils'
103 | $Kernel32 = $Types['kernel32']
104 |
105 | # Get handle to the process
106 | $hProcess = $Kernel32::OpenProcess(0x400, $False, $ProcessID) # PROCESS_QUERY_INFORMATION (0x00000400)
107 |
108 | if (-not $hProcess) {
109 | throw "Unable to get a process handle for process ID: $ProcessID"
110 | }
111 |
112 | $MemoryInfo = New-Object $MEMORY_BASIC_INFORMATION
113 | $BytesRead = $Kernel32::VirtualQueryEx($hProcess, $ModuleBaseAddress, [Ref] $MemoryInfo, $PageSize)
114 |
115 | $null = $Kernel32::CloseHandle($hProcess)
116 |
117 | $Fields = @{
118 | BaseAddress = $MemoryInfo.BaseAddress
119 | AllocationBase = $MemoryInfo.AllocationBase
120 | AllocationProtect = $MemoryInfo.AllocationProtect
121 | RegionSize = $MemoryInfo.RegionSize
122 | State = $MemoryInfo.State
123 | Protect = $MemoryInfo.Protect
124 | Type = $MemoryInfo.Type
125 | }
126 |
127 | $Result = New-Object PSObject -Property $Fields
128 | $Result.PSObject.TypeNames.Insert(0, 'MEM.INFO')
129 |
130 | $Result
131 | }
132 |
133 | function Get-StructFromMemory {
134 | <#
135 | .SYNOPSIS
136 |
137 | Marshals data from an unmanaged block of memory in an arbitrary process to a newly allocated managed object of the specified type.
138 |
139 | Author: Matthew Graeber (@mattifestation)
140 | License: BSD 3-Clause
141 | Required Dependencies: None
142 | Optional Dependencies: None
143 |
144 | .DESCRIPTION
145 |
146 | Get-StructFromMemory is similar to the Marshal.PtrToStructure method but will parse and return a structure from any process.
147 |
148 | .PARAMETER Id
149 |
150 | Process ID of the process whose virtual memory space you want to access.
151 |
152 | .PARAMETER MemoryAddress
153 |
154 | The address containing the structure to be parsed.
155 |
156 | .PARAMETER StructType
157 |
158 | The type (System.Type) of the desired structure to be parsed.
159 |
160 | .EXAMPLE
161 |
162 | C:\PS> Get-Process | ForEach-Object { Get-StructFromMemory -Id $_.Id -MemoryAddress $_.MainModule.BaseAddress -StructType ([PE+_IMAGE_DOS_HEADER]) }
163 |
164 | Description
165 | -----------
166 | Parses the DOS headers of every loaded process. Note: In this example, this assumes that [PE+_IMAGE_DOS_HEADER] is defined. You can get the code to define [PE+_IMAGE_DOS_HEADER] here: http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html
167 |
168 | .NOTES
169 |
170 | Be sure to enclose the StructType parameter with parenthesis in order to force PowerShell to cast it as a Type object.
171 |
172 | Get-StructFromMemory does a good job with error handling however it will crash if the structure contains fields that attempt to marshal pointers. For example, if a field has a custom attribute of UnmanagedType.LPStr, when the structure is parsed, it will attempt to dererence a string pointer for virtual memory in another process and access violate.
173 | #>
174 |
175 | [CmdletBinding()] Param (
176 | [Parameter(Position = 0, Mandatory = $True)]
177 | [Alias('ProcessId')]
178 | [Alias('PID')]
179 | [UInt16]
180 | $Id,
181 |
182 | [Parameter(Position = 1, Mandatory = $True)]
183 | [IntPtr]
184 | $MemoryAddress,
185 |
186 | [Parameter(Position = 2, Mandatory = $True)]
187 | [Alias('Type')]
188 | [Type]
189 | $StructType
190 | )
191 |
192 | Set-StrictMode -Version 2
193 |
194 | $PROCESS_VM_READ = 0x0010 # The process permissions we'l ask for when getting a handle to the process
195 |
196 | # Get a reference to the private GetProcessHandle method is System.Diagnostics.Process
197 | $GetProcessHandle = [Diagnostics.Process].GetMethod('GetProcessHandle', [Reflection.BindingFlags] 'NonPublic, Instance', $null, @([Int]), $null)
198 |
199 | try
200 | {
201 | # Make sure user didn't pass in a non-existent PID
202 | $Process = Get-Process -Id $Id -ErrorVariable GetProcessError
203 | # Get the default process handle
204 | $Handle = $Process.Handle
205 | }
206 | catch [Exception]
207 | {
208 | throw $GetProcessError
209 | }
210 |
211 | if ($Handle -eq $null)
212 | {
213 | throw "Unable to obtain a handle for PID $Id. You will likely need to run this script elevated."
214 | }
215 |
216 | # Get a reference to MEMORY_BASIC_INFORMATION. I don't feel like making the structure myself
217 | $mscorlib = [AppDomain]::CurrentDomain.GetAssemblies() | ? { $_.FullName.Split(',')[0].ToLower() -eq 'mscorlib' }
218 | $Win32Native = $mscorlib.GetTypes() | ? { $_.FullName -eq 'Microsoft.Win32.Win32Native' }
219 | $MEMORY_BASIC_INFORMATION = $Win32Native.GetNestedType('MEMORY_BASIC_INFORMATION', [Reflection.BindingFlags] 'NonPublic')
220 |
221 | if ($MEMORY_BASIC_INFORMATION -eq $null)
222 | {
223 | throw 'Unable to get a reference to the MEMORY_BASIC_INFORMATION structure.'
224 | }
225 |
226 | # Get references to private fields in MEMORY_BASIC_INFORMATION
227 | $ProtectField = $MEMORY_BASIC_INFORMATION.GetField('Protect', [Reflection.BindingFlags] 'NonPublic, Instance')
228 | $AllocationBaseField = $MEMORY_BASIC_INFORMATION.GetField('BaseAddress', [Reflection.BindingFlags] 'NonPublic, Instance')
229 | $RegionSizeField = $MEMORY_BASIC_INFORMATION.GetField('RegionSize', [Reflection.BindingFlags] 'NonPublic, Instance')
230 |
231 | try { $NativeUtils = [NativeUtils] } catch [Management.Automation.RuntimeException] # Only build the assembly if it hasn't already been defined
232 | {
233 | # Build dynamic assembly in order to use P/Invoke for interacting with the following Win32 functions: ReadProcessMemory, VirtualQueryEx
234 | $DynAssembly = New-Object Reflection.AssemblyName('MemHacker')
235 | $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
236 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('MemHacker', $False)
237 | $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
238 | $TypeBuilder = $ModuleBuilder.DefineType('NativeUtils', $Attributes, [ValueType])
239 | $TypeBuilder.DefinePInvokeMethod('ReadProcessMemory', 'kernel32.dll', [Reflection.MethodAttributes] 'Public, Static', [Reflection.CallingConventions]::Standard, [Bool], @([IntPtr], [IntPtr], [IntPtr], [UInt32], [UInt32].MakeByRefType()), [Runtime.InteropServices.CallingConvention]::Winapi, 'Auto') | Out-Null
240 | $TypeBuilder.DefinePInvokeMethod('VirtualQueryEx', 'kernel32.dll', [Reflection.MethodAttributes] 'Public, Static', [Reflection.CallingConventions]::Standard, [UInt32], @([IntPtr], [IntPtr], $MEMORY_BASIC_INFORMATION.MakeByRefType(), [UInt32]), [Runtime.InteropServices.CallingConvention]::Winapi, 'Auto') | Out-Null
241 |
242 | $NativeUtils = $TypeBuilder.CreateType()
243 | }
244 |
245 | # Request a handle to the process in interest
246 | try
247 | {
248 | $SafeHandle = $GetProcessHandle.Invoke($Process, @($PROCESS_VM_READ))
249 | $Handle = $SafeHandle.DangerousGetHandle()
250 | }
251 | catch
252 | {
253 | throw $Error[0]
254 | }
255 |
256 | # Create an instance of MEMORY_BASIC_INFORMATION
257 | $MemoryBasicInformation = [Activator]::CreateInstance($MEMORY_BASIC_INFORMATION)
258 |
259 | # Confirm you can actually read the address you're interested in
260 | $NativeUtils::VirtualQueryEx($Handle, $MemoryAddress, [Ref] $MemoryBasicInformation, [Runtime.InteropServices.Marshal]::SizeOf([Type] $MEMORY_BASIC_INFORMATION)) | Out-Null
261 |
262 | $PAGE_EXECUTE_READ = 0x20
263 | $PAGE_EXECUTE_READWRITE = 0x40
264 | $PAGE_READONLY = 2
265 | $PAGE_READWRITE = 4
266 |
267 | $Protection = $ProtectField.GetValue($MemoryBasicInformation)
268 | $AllocationBaseOriginal = $AllocationBaseField.GetValue($MemoryBasicInformation)
269 | $GetPointerValue = $AllocationBaseOriginal.GetType().GetMethod('GetPointerValue', [Reflection.BindingFlags] 'NonPublic, Instance')
270 | $AllocationBase = $GetPointerValue.Invoke($AllocationBaseOriginal, $null).ToInt64()
271 | $RegionSize = $RegionSizeField.GetValue($MemoryBasicInformation).ToUInt64()
272 |
273 | Write-Verbose "Protection: $Protection"
274 | Write-Verbose "AllocationBase: $AllocationBase"
275 | Write-Verbose "RegionSize: $RegionSize"
276 |
277 | if (($Protection -ne $PAGE_READONLY) -and ($Protection -ne $PAGE_READWRITE) -and ($Protection -ne $PAGE_EXECUTE_READ) -and ($Protection -ne $PAGE_EXECUTE_READWRITE))
278 | {
279 | $SafeHandle.Close()
280 | throw 'The address specified does not have read access.'
281 | }
282 |
283 | $StructSize = [Runtime.InteropServices.Marshal]::SizeOf([Type] $StructType)
284 | $EndOfAllocation = $AllocationBase + $RegionSize
285 | $EndOfStruct = $MemoryAddress.ToInt64() + $StructSize
286 |
287 | if ($EndOfStruct -gt $EndOfAllocation)
288 | {
289 | $SafeHandle.Close()
290 | throw 'You are attempting to read beyond what was allocated.'
291 | }
292 |
293 | try
294 | {
295 | # Allocate unmanaged memory. This will be used to store the memory read from ReadProcessMemory
296 | $LocalStructPtr = [Runtime.InteropServices.Marshal]::AllocHGlobal($StructSize)
297 | }
298 | catch [OutOfMemoryException]
299 | {
300 | throw Error[0]
301 | }
302 |
303 | Write-Verbose "Memory allocated at 0x$($LocalStructPtr.ToString("X$([IntPtr]::Size * 2)"))"
304 |
305 | # Zero out the memory that was just allocated. According to MSDN documentation:
306 | # "When AllocHGlobal calls LocalAlloc, it passes a LMEM_FIXED flag, which causes the allocated memory to be locked in place. Also, the allocated memory is not zero-filled."
307 | # http://msdn.microsoft.com/en-us/library/s69bkh17.aspx
308 | $ZeroBytes = New-Object Byte[]($StructSize)
309 | [Runtime.InteropServices.Marshal]::Copy($ZeroBytes, 0, $LocalStructPtr, $StructSize)
310 |
311 | $BytesRead = [UInt32] 0
312 |
313 | if ($NativeUtils::ReadProcessMemory($Handle, $MemoryAddress, $LocalStructPtr, $StructSize, [Ref] $BytesRead))
314 | {
315 | $SafeHandle.Close()
316 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LocalStructPtr)
317 | throw ([ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error())
318 | }
319 |
320 | Write-Verbose "Struct Size: $StructSize"
321 | Write-Verbose "Bytes read: $BytesRead"
322 |
323 | $ParsedStruct = [Runtime.InteropServices.Marshal]::PtrToStructure($LocalStructPtr, [Type] $StructType)
324 |
325 | [Runtime.InteropServices.Marshal]::FreeHGlobal($LocalStructPtr)
326 | $SafeHandle.Close()
327 |
328 | Write-Output $ParsedStruct
329 | }
330 |
331 | filter Get-ProcessMemoryInfo {
332 | <#
333 | .SYNOPSIS
334 |
335 | Retrieve virtual memory information for every unique set of pages in
336 | user memory. This function is similar to the !vadump WinDbg command.
337 |
338 | Author: Matthew Graeber (@mattifestation)
339 | License: BSD 3-Clause
340 | Required Dependencies: PSReflect module
341 | Get-SystemInfo
342 | Get-VirtualMemoryInfo
343 | Optional Dependencies: None
344 |
345 | .PARAMETER ProcessID
346 |
347 | Specifies the process ID.
348 |
349 | .EXAMPLE
350 |
351 | Get-ProcessMemoryInfo -ProcessID $PID
352 | #>
353 |
354 | Param (
355 | [Parameter(ParameterSetName = 'InMemory', Position = 0, Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
356 | [Alias('Id')]
357 | [ValidateScript({Get-Process -Id $_})]
358 | [Int]
359 | $ProcessID
360 | )
361 |
362 | $SysInfo = Get-SystemInfo
363 |
364 | $MemoryInfo = Get-VirtualMemoryInfo -ProcessID $ProcessID -ModuleBaseAddress ([IntPtr]::Zero) -PageSize $SysInfo.PageSize
365 |
366 | $MemoryInfo
367 |
368 | while (($MemoryInfo.BaseAddress + $MemoryInfo.RegionSize) -lt $SysInfo.MaximumApplicationAddress) {
369 | $BaseAllocation = [IntPtr] ($MemoryInfo.BaseAddress + $MemoryInfo.RegionSize)
370 | $MemoryInfo = Get-VirtualMemoryInfo -ProcessID $ProcessID -ModuleBaseAddress $BaseAllocation -PageSize $SysInfo.PageSize
371 |
372 | if ($MemoryInfo.State -eq 0) { break }
373 | $MemoryInfo
374 | }
375 | }
376 |
377 | function Get-ProcessStrings
378 | {
379 | <#
380 | .SYNOPSIS
381 |
382 | Outputs all printable strings from the user-mode memory of a process.
383 |
384 | Author: Matthew Graeber (@mattifestation)
385 | License: BSD 3-Clause
386 | Required Dependencies: PSReflect module
387 | Get-ProcessMemoryInfo
388 | Optional Dependencies: MemoryTools.format.ps1xml
389 |
390 | .DESCRIPTION
391 |
392 | Get-ProcessStrings reads every committed memory allocation that is
393 | not a guard page and returns all printable strings. By default,
394 | Get-ProcessStrings ignores MEM_IMAGE allocations (most commonly
395 | allocated when modules are loaded) but they can be included with the
396 | -IncludeImages switch.
397 |
398 | .PARAMETER ProcessID
399 |
400 | Specifies the process ID.
401 |
402 | .PARAMETER MinimumLength
403 |
404 | Specifies the minimum length string to return. The default length is 3.
405 |
406 | .PARAMETER Encoding
407 |
408 | Specifies the string encoding to use. The default option is 'Default'
409 | which will return both Ascii and Unicode strings.
410 |
411 | .PARAMETER IncludeImages
412 |
413 | Specifies that memory allocations marked MEM_IMAGE should be
414 | included. These allocations typically consist of loaded PE images.
415 |
416 | .EXAMPLE
417 |
418 | Get-Process cmd | Get-ProcessStrings
419 |
420 | .EXAMPLE
421 |
422 | Get-Process cmd | Get-ProcessStrings -MinimumLength 40 -Encoding Ascii
423 | #>
424 |
425 | [CmdletBinding()] Param (
426 | [Parameter(Position = 0, Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
427 | [Alias('Id')]
428 | [ValidateScript({Get-Process -Id $_})]
429 | [Int32]
430 | $ProcessID,
431 |
432 | [UInt16]
433 | $MinimumLength = 3,
434 |
435 | [ValidateSet('Default','Ascii','Unicode')]
436 | [String]
437 | $Encoding = 'Default',
438 |
439 | [Switch]
440 | $IncludeImages
441 | )
442 |
443 | BEGIN {
444 | $Mod = New-InMemoryModule -ModuleName ProcessStrings
445 |
446 | $FunctionDefinitions = @(
447 | (func kernel32 OpenProcess ([IntPtr]) @([UInt32], [Bool], [UInt32]) -SetLastError),
448 | (func kernel32 ReadProcessMemory ([Bool]) @([IntPtr], [IntPtr], [Byte[]], [Int], [Int].MakeByRefType()) -SetLastError),
449 | (func kernel32 CloseHandle ([Bool]) @([IntPtr]) -SetLastError)
450 | )
451 |
452 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32ProcessStrings'
453 | $Kernel32 = $Types['kernel32']
454 | }
455 |
456 | PROCESS {
457 | $hProcess = $Kernel32::OpenProcess(0x10, $False, $ProcessID) # PROCESS_VM_READ (0x00000010)
458 |
459 | Get-ProcessMemoryInfo -ProcessID $ProcessID | ? { $_.State -eq 'MEM_COMMIT' } | % {
460 | $Allocation = $_
461 | $ReadAllocation = $True
462 | if (($Allocation.Type -eq 'MEM_IMAGE') -and (-not $IncludeImages)) { $ReadAllocation = $False }
463 | # Do not attempt to read guard pages
464 | if ($Allocation.Protect.ToString().Contains('PAGE_GUARD')) { $ReadAllocation = $False }
465 |
466 | if ($ReadAllocation) {
467 | $Bytes = New-Object Byte[]($Allocation.RegionSize)
468 |
469 | $BytesRead = 0
470 | $Result = $Kernel32::ReadProcessMemory($hProcess, $Allocation.BaseAddress, $Bytes, $Allocation.RegionSize, [Ref] $BytesRead)
471 |
472 | if ((-not $Result) -or ($BytesRead -ne $Allocation.RegionSize)) {
473 | Write-Warning "Unable to read 0x$($Allocation.BaseAddress.ToString('X16')) from PID $ProcessID. Size: 0x$($Allocation.RegionSize.ToString('X8'))"
474 | } else {
475 | if (($Encoding -eq 'Ascii') -or ($Encoding -eq 'Default')) {
476 | # This hack will get the raw ascii chars. The System.Text.UnicodeEncoding object will replace some unprintable chars with question marks.
477 | $ArrayPtr = [Runtime.InteropServices.Marshal]::UnsafeAddrOfPinnedArrayElement($Bytes, 0)
478 | $RawString = [Runtime.InteropServices.Marshal]::PtrToStringAnsi($ArrayPtr, $Bytes.Length)
479 | $Regex = [Regex] "[\x20-\x7E]{$MinimumLength,}"
480 | $Regex.Matches($RawString) | % {
481 | $Properties = @{
482 | Address = [IntPtr] ($Allocation.BaseAddress + $_.Index)
483 | Encoding = 'Ascii'
484 | String = $_.Value
485 | }
486 |
487 | $String = New-Object PSObject -Property $Properties
488 | $String.PSObject.TypeNames.Insert(0, 'MEM.STRING')
489 |
490 | Write-Output $String
491 | }
492 |
493 |
494 | }
495 |
496 | if (($Encoding -eq 'Unicode') -or ($Encoding -eq 'Default')) {
497 | $Encoder = New-Object System.Text.UnicodeEncoding
498 | $RawString = $Encoder.GetString($Bytes, 0, $Bytes.Length)
499 | $Regex = [Regex] "[\u0020-\u007E]{$MinimumLength,}"
500 | $Regex.Matches($RawString) | % {
501 | $Properties = @{
502 | Address = [IntPtr] ($Allocation.BaseAddress + ($_.Index * 2))
503 | Encoding = 'Unicode'
504 | String = $_.Value
505 | }
506 |
507 | $String = New-Object PSObject -Property $Properties
508 | $String.PSObject.TypeNames.Insert(0, 'MEM.STRING')
509 |
510 | Write-Output $String
511 | }
512 | }
513 | }
514 |
515 | $Bytes = $null
516 | }
517 | }
518 |
519 | $null = $Kernel32::CloseHandle($hProcess)
520 | }
521 |
522 | END {}
523 | }
--------------------------------------------------------------------------------
/Lib/PSReflect/PSReflect.psm1:
--------------------------------------------------------------------------------
1 | #Requires -Version 2
2 |
3 | function New-InMemoryModule
4 | {
5 | <#
6 | .SYNOPSIS
7 |
8 | Creates an in-memory assembly and module
9 |
10 | Author: Matthew Graeber (@mattifestation)
11 | License: BSD 3-Clause
12 | Required Dependencies: None
13 | Optional Dependencies: None
14 |
15 | .DESCRIPTION
16 |
17 | When defining custom enums, structs, and unmanaged functions, it is
18 | necessary to associate to an assembly module. This helper function
19 | creates an in-memory module that can be passed to the 'enum',
20 | 'struct', and Add-Win32Type functions.
21 |
22 | .PARAMETER ModuleName
23 |
24 | Specifies the desired name for the in-memory assembly and module. If
25 | ModuleName is not provided, it will default to a GUID.
26 |
27 | .EXAMPLE
28 |
29 | $Module = New-InMemoryModule -ModuleName Win32
30 | #>
31 |
32 | Param
33 | (
34 | [Parameter(Position = 0)]
35 | [ValidateNotNullOrEmpty()]
36 | [String]
37 | $ModuleName = [Guid]::NewGuid().ToString()
38 | )
39 |
40 | $LoadedAssemblies = [AppDomain]::CurrentDomain.GetAssemblies()
41 |
42 | foreach ($Assembly in $LoadedAssemblies) {
43 | if ($Assembly.FullName -and ($Assembly.FullName.Split(',')[0] -eq $ModuleName)) {
44 | return $Assembly
45 | }
46 | }
47 |
48 | $DynAssembly = New-Object Reflection.AssemblyName($ModuleName)
49 | $Domain = [AppDomain]::CurrentDomain
50 | $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, 'Run')
51 | $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule($ModuleName, $False)
52 |
53 | return $ModuleBuilder
54 | }
55 |
56 |
57 | # A helper function used to reduce typing while defining function
58 | # prototypes for Add-Win32Type.
59 | function func
60 | {
61 | Param
62 | (
63 | [Parameter(Position = 0, Mandatory = $True)]
64 | [String]
65 | $DllName,
66 |
67 | [Parameter(Position = 1, Mandatory = $True)]
68 | [string]
69 | $FunctionName,
70 |
71 | [Parameter(Position = 2, Mandatory = $True)]
72 | [Type]
73 | $ReturnType,
74 |
75 | [Parameter(Position = 3)]
76 | [Type[]]
77 | $ParameterTypes,
78 |
79 | [Parameter(Position = 4)]
80 | [Runtime.InteropServices.CallingConvention]
81 | $NativeCallingConvention,
82 |
83 | [Parameter(Position = 5)]
84 | [Runtime.InteropServices.CharSet]
85 | $Charset,
86 |
87 | [Switch]
88 | $SetLastError
89 | )
90 |
91 | $Properties = @{
92 | DllName = $DllName
93 | FunctionName = $FunctionName
94 | ReturnType = $ReturnType
95 | }
96 |
97 | if ($ParameterTypes) { $Properties['ParameterTypes'] = $ParameterTypes }
98 | if ($NativeCallingConvention) { $Properties['NativeCallingConvention'] = $NativeCallingConvention }
99 | if ($Charset) { $Properties['Charset'] = $Charset }
100 | if ($SetLastError) { $Properties['SetLastError'] = $SetLastError }
101 |
102 | New-Object PSObject -Property $Properties
103 | }
104 |
105 |
106 | function Add-Win32Type
107 | {
108 | <#
109 | .SYNOPSIS
110 |
111 | Creates a .NET type for an unmanaged Win32 function.
112 |
113 | Author: Matthew Graeber (@mattifestation)
114 | License: BSD 3-Clause
115 | Required Dependencies: None
116 | Optional Dependencies: func
117 |
118 | .DESCRIPTION
119 |
120 | Add-Win32Type enables you to easily interact with unmanaged (i.e.
121 | Win32 unmanaged) functions in PowerShell. After providing
122 | Add-Win32Type with a function signature, a .NET type is created
123 | using reflection (i.e. csc.exe is never called like with Add-Type).
124 |
125 | The 'func' helper function can be used to reduce typing when defining
126 | multiple function definitions.
127 |
128 | .PARAMETER DllName
129 |
130 | The name of the DLL.
131 |
132 | .PARAMETER FunctionName
133 |
134 | The name of the target function.
135 |
136 | .PARAMETER ReturnType
137 |
138 | The return type of the function.
139 |
140 | .PARAMETER ParameterTypes
141 |
142 | The function parameters.
143 |
144 | .PARAMETER NativeCallingConvention
145 |
146 | Specifies the native calling convention of the function. Defaults to
147 | stdcall.
148 |
149 | .PARAMETER Charset
150 |
151 | If you need to explicitly call an 'A' or 'W' Win32 function, you can
152 | specify the character set.
153 |
154 | .PARAMETER SetLastError
155 |
156 | Indicates whether the callee calls the SetLastError Win32 API
157 | function before returning from the attributed method.
158 |
159 | .PARAMETER Module
160 |
161 | The in-memory module that will host the functions. Use
162 | New-InMemoryModule to define an in-memory module.
163 |
164 | .PARAMETER Namespace
165 |
166 | An optional namespace to prepend to the type. Add-Win32Type defaults
167 | to a namespace consisting only of the name of the DLL.
168 |
169 | .EXAMPLE
170 |
171 | $Mod = New-InMemoryModule -ModuleName Win32
172 |
173 | $FunctionDefinitions = @(
174 | (func kernel32 GetProcAddress ([IntPtr]) @([IntPtr], [String]) -Charset Ansi -SetLastError),
175 | (func kernel32 GetModuleHandle ([Intptr]) @([String]) -SetLastError),
176 | (func ntdll RtlGetCurrentPeb ([IntPtr]) @())
177 | )
178 |
179 | $Types = $FunctionDefinitions | Add-Win32Type -Module $Mod -Namespace 'Win32'
180 | $Kernel32 = $Types['kernel32']
181 | $Ntdll = $Types['ntdll']
182 | $Ntdll::RtlGetCurrentPeb()
183 | $ntdllbase = $Kernel32::GetModuleHandle('ntdll')
184 | $Kernel32::GetProcAddress($ntdllbase, 'RtlGetCurrentPeb')
185 |
186 | .NOTES
187 |
188 | Inspired by Lee Holmes' Invoke-WindowsApi http://poshcode.org/2189
189 |
190 | When defining multiple function prototypes, it is ideal to provide
191 | Add-Win32Type with an array of function signatures. That way, they
192 | are all incorporated into the same in-memory module.
193 | #>
194 |
195 | [OutputType([Hashtable])]
196 | Param(
197 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
198 | [String]
199 | $DllName,
200 |
201 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
202 | [String]
203 | $FunctionName,
204 |
205 | [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
206 | [Type]
207 | $ReturnType,
208 |
209 | [Parameter(ValueFromPipelineByPropertyName = $True)]
210 | [Type[]]
211 | $ParameterTypes,
212 |
213 | [Parameter(ValueFromPipelineByPropertyName = $True)]
214 | [Runtime.InteropServices.CallingConvention]
215 | $NativeCallingConvention = [Runtime.InteropServices.CallingConvention]::StdCall,
216 |
217 | [Parameter(ValueFromPipelineByPropertyName = $True)]
218 | [Runtime.InteropServices.CharSet]
219 | $Charset = [Runtime.InteropServices.CharSet]::Auto,
220 |
221 | [Parameter(ValueFromPipelineByPropertyName = $True)]
222 | [Switch]
223 | $SetLastError,
224 |
225 | [Parameter(Mandatory = $True)]
226 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
227 | $Module,
228 |
229 | [ValidateNotNull()]
230 | [String]
231 | $Namespace = ''
232 | )
233 |
234 | BEGIN
235 | {
236 | $TypeHash = @{}
237 | }
238 |
239 | PROCESS
240 | {
241 | if ($Module -is [Reflection.Assembly])
242 | {
243 | if ($Namespace)
244 | {
245 | $TypeHash[$DllName] = $Module.GetType("$Namespace.$DllName")
246 | }
247 | else
248 | {
249 | $TypeHash[$DllName] = $Module.GetType($DllName)
250 | }
251 | }
252 | else
253 | {
254 | # Define one type for each DLL
255 | if (!$TypeHash.ContainsKey($DllName))
256 | {
257 | if ($Namespace)
258 | {
259 | $TypeHash[$DllName] = $Module.DefineType("$Namespace.$DllName", 'Public,BeforeFieldInit')
260 | }
261 | else
262 | {
263 | $TypeHash[$DllName] = $Module.DefineType($DllName, 'Public,BeforeFieldInit')
264 | }
265 | }
266 |
267 | $Method = $TypeHash[$DllName].DefineMethod(
268 | $FunctionName,
269 | 'Public,Static,PinvokeImpl',
270 | $ReturnType,
271 | $ParameterTypes)
272 |
273 | # Make each ByRef parameter an Out parameter
274 | $i = 1
275 | foreach($Parameter in $ParameterTypes)
276 | {
277 | if ($Parameter.IsByRef)
278 | {
279 | [void] $Method.DefineParameter($i, 'Out', $null)
280 | }
281 |
282 | $i++
283 | }
284 |
285 | $DllImport = [Runtime.InteropServices.DllImportAttribute]
286 | $SetLastErrorField = $DllImport.GetField('SetLastError')
287 | $CallingConventionField = $DllImport.GetField('CallingConvention')
288 | $CharsetField = $DllImport.GetField('CharSet')
289 | if ($SetLastError) { $SLEValue = $True } else { $SLEValue = $False }
290 |
291 | # Equivalent to C# version of [DllImport(DllName)]
292 | $Constructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([String])
293 | $DllImportAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($Constructor,
294 | $DllName, [Reflection.PropertyInfo[]] @(), [Object[]] @(),
295 | [Reflection.FieldInfo[]] @($SetLastErrorField, $CallingConventionField, $CharsetField),
296 | [Object[]] @($SLEValue, ([Runtime.InteropServices.CallingConvention] $NativeCallingConvention), ([Runtime.InteropServices.CharSet] $Charset)))
297 |
298 | $Method.SetCustomAttribute($DllImportAttribute)
299 | }
300 | }
301 |
302 | END
303 | {
304 | if ($Module -is [Reflection.Assembly])
305 | {
306 | return $TypeHash
307 | }
308 |
309 | $ReturnTypes = @{}
310 |
311 | foreach ($Key in $TypeHash.Keys)
312 | {
313 | $Type = $TypeHash[$Key].CreateType()
314 |
315 | $ReturnTypes[$Key] = $Type
316 | }
317 |
318 | return $ReturnTypes
319 | }
320 | }
321 |
322 |
323 | function psenum
324 | {
325 | <#
326 | .SYNOPSIS
327 |
328 | Creates an in-memory enumeration for use in your PowerShell session.
329 |
330 | Author: Matthew Graeber (@mattifestation)
331 | License: BSD 3-Clause
332 | Required Dependencies: None
333 | Optional Dependencies: None
334 |
335 | .DESCRIPTION
336 |
337 | The 'psenum' function facilitates the creation of enums entirely in
338 | memory using as close to a "C style" as PowerShell will allow.
339 |
340 | .PARAMETER Module
341 |
342 | The in-memory module that will host the enum. Use
343 | New-InMemoryModule to define an in-memory module.
344 |
345 | .PARAMETER FullName
346 |
347 | The fully-qualified name of the enum.
348 |
349 | .PARAMETER Type
350 |
351 | The type of each enum element.
352 |
353 | .PARAMETER EnumElements
354 |
355 | A hashtable of enum elements.
356 |
357 | .PARAMETER Bitfield
358 |
359 | Specifies that the enum should be treated as a bitfield.
360 |
361 | .EXAMPLE
362 |
363 | $Mod = New-InMemoryModule -ModuleName Win32
364 |
365 | $ImageSubsystem = psenum $Mod PE.IMAGE_SUBSYSTEM UInt16 @{
366 | UNKNOWN = 0
367 | NATIVE = 1 # Image doesn't require a subsystem.
368 | WINDOWS_GUI = 2 # Image runs in the Windows GUI subsystem.
369 | WINDOWS_CUI = 3 # Image runs in the Windows character subsystem.
370 | OS2_CUI = 5 # Image runs in the OS/2 character subsystem.
371 | POSIX_CUI = 7 # Image runs in the Posix character subsystem.
372 | NATIVE_WINDOWS = 8 # Image is a native Win9x driver.
373 | WINDOWS_CE_GUI = 9 # Image runs in the Windows CE subsystem.
374 | EFI_APPLICATION = 10
375 | EFI_BOOT_SERVICE_DRIVER = 11
376 | EFI_RUNTIME_DRIVER = 12
377 | EFI_ROM = 13
378 | XBOX = 14
379 | WINDOWS_BOOT_APPLICATION = 16
380 | }
381 |
382 | .NOTES
383 |
384 | PowerShell purists may disagree with the naming of this function but
385 | again, this was developed in such a way so as to emulate a "C style"
386 | definition as closely as possible. Sorry, I'm not going to name it
387 | New-Enum. :P
388 | #>
389 |
390 | [OutputType([Type])]
391 | Param
392 | (
393 | [Parameter(Position = 0, Mandatory = $True)]
394 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
395 | $Module,
396 |
397 | [Parameter(Position = 1, Mandatory = $True)]
398 | [ValidateNotNullOrEmpty()]
399 | [String]
400 | $FullName,
401 |
402 | [Parameter(Position = 2, Mandatory = $True)]
403 | [Type]
404 | $Type,
405 |
406 | [Parameter(Position = 3, Mandatory = $True)]
407 | [ValidateNotNullOrEmpty()]
408 | [Hashtable]
409 | $EnumElements,
410 |
411 | [Switch]
412 | $Bitfield
413 | )
414 |
415 | if ($Module -is [Reflection.Assembly])
416 | {
417 | return ($Module.GetType($FullName))
418 | }
419 |
420 | $EnumType = $Type -as [Type]
421 |
422 | $EnumBuilder = $Module.DefineEnum($FullName, 'Public', $EnumType)
423 |
424 | if ($Bitfield)
425 | {
426 | $FlagsConstructor = [FlagsAttribute].GetConstructor(@())
427 | $FlagsCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($FlagsConstructor, @())
428 | $EnumBuilder.SetCustomAttribute($FlagsCustomAttribute)
429 | }
430 |
431 | foreach ($Key in $EnumElements.Keys)
432 | {
433 | # Apply the specified enum type to each element
434 | $null = $EnumBuilder.DefineLiteral($Key, $EnumElements[$Key] -as $EnumType)
435 | }
436 |
437 | $EnumBuilder.CreateType()
438 | }
439 |
440 |
441 | # A helper function used to reduce typing while defining struct
442 | # fields.
443 | function field
444 | {
445 | Param
446 | (
447 | [Parameter(Position = 0, Mandatory = $True)]
448 | [UInt16]
449 | $Position,
450 |
451 | [Parameter(Position = 1, Mandatory = $True)]
452 | [Type]
453 | $Type,
454 |
455 | [Parameter(Position = 2)]
456 | [UInt16]
457 | $Offset,
458 |
459 | [Object[]]
460 | $MarshalAs
461 | )
462 |
463 | @{
464 | Position = $Position
465 | Type = $Type -as [Type]
466 | Offset = $Offset
467 | MarshalAs = $MarshalAs
468 | }
469 | }
470 |
471 |
472 | function struct
473 | {
474 | <#
475 | .SYNOPSIS
476 |
477 | Creates an in-memory struct for use in your PowerShell session.
478 |
479 | Author: Matthew Graeber (@mattifestation)
480 | License: BSD 3-Clause
481 | Required Dependencies: None
482 | Optional Dependencies: field
483 |
484 | .DESCRIPTION
485 |
486 | The 'struct' function facilitates the creation of structs entirely in
487 | memory using as close to a "C style" as PowerShell will allow. Struct
488 | fields are specified using a hashtable where each field of the struct
489 | is comprosed of the order in which it should be defined, its .NET
490 | type, and optionally, its offset and special marshaling attributes.
491 |
492 | One of the features of 'struct' is that after your struct is defined,
493 | it will come with a built-in GetSize method as well as an explicit
494 | converter so that you can easily cast an IntPtr to the struct without
495 | relying upon calling SizeOf and/or PtrToStructure in the Marshal
496 | class.
497 |
498 | .PARAMETER Module
499 |
500 | The in-memory module that will host the struct. Use
501 | New-InMemoryModule to define an in-memory module.
502 |
503 | .PARAMETER FullName
504 |
505 | The fully-qualified name of the struct.
506 |
507 | .PARAMETER StructFields
508 |
509 | A hashtable of fields. Use the 'field' helper function to ease
510 | defining each field.
511 |
512 | .PARAMETER PackingSize
513 |
514 | Specifies the memory alignment of fields.
515 |
516 | .PARAMETER ExplicitLayout
517 |
518 | Indicates that an explicit offset for each field will be specified.
519 |
520 | .EXAMPLE
521 |
522 | $Mod = New-InMemoryModule -ModuleName Win32
523 |
524 | $ImageDosSignature = psenum $Mod PE.IMAGE_DOS_SIGNATURE UInt16 @{
525 | DOS_SIGNATURE = 0x5A4D
526 | OS2_SIGNATURE = 0x454E
527 | OS2_SIGNATURE_LE = 0x454C
528 | VXD_SIGNATURE = 0x454C
529 | }
530 |
531 | $ImageDosHeader = struct $Mod PE.IMAGE_DOS_HEADER @{
532 | e_magic = field 0 $ImageDosSignature
533 | e_cblp = field 1 UInt16
534 | e_cp = field 2 UInt16
535 | e_crlc = field 3 UInt16
536 | e_cparhdr = field 4 UInt16
537 | e_minalloc = field 5 UInt16
538 | e_maxalloc = field 6 UInt16
539 | e_ss = field 7 UInt16
540 | e_sp = field 8 UInt16
541 | e_csum = field 9 UInt16
542 | e_ip = field 10 UInt16
543 | e_cs = field 11 UInt16
544 | e_lfarlc = field 12 UInt16
545 | e_ovno = field 13 UInt16
546 | e_res = field 14 UInt16[] -MarshalAs @('ByValArray', 4)
547 | e_oemid = field 15 UInt16
548 | e_oeminfo = field 16 UInt16
549 | e_res2 = field 17 UInt16[] -MarshalAs @('ByValArray', 10)
550 | e_lfanew = field 18 Int32
551 | }
552 |
553 | # Example of using an explicit layout in order to create a union.
554 | $TestUnion = struct $Mod TestUnion @{
555 | field1 = field 0 UInt32 0
556 | field2 = field 1 IntPtr 0
557 | } -ExplicitLayout
558 |
559 | .NOTES
560 |
561 | PowerShell purists may disagree with the naming of this function but
562 | again, this was developed in such a way so as to emulate a "C style"
563 | definition as closely as possible. Sorry, I'm not going to name it
564 | New-Struct. :P
565 | #>
566 |
567 | [OutputType([Type])]
568 | Param
569 | (
570 | [Parameter(Position = 1, Mandatory = $True)]
571 | [ValidateScript({($_ -is [Reflection.Emit.ModuleBuilder]) -or ($_ -is [Reflection.Assembly])})]
572 | $Module,
573 |
574 | [Parameter(Position = 2, Mandatory = $True)]
575 | [ValidateNotNullOrEmpty()]
576 | [String]
577 | $FullName,
578 |
579 | [Parameter(Position = 3, Mandatory = $True)]
580 | [ValidateNotNullOrEmpty()]
581 | [Hashtable]
582 | $StructFields,
583 |
584 | [Reflection.Emit.PackingSize]
585 | $PackingSize = [Reflection.Emit.PackingSize]::Unspecified,
586 |
587 | [Switch]
588 | $ExplicitLayout
589 | )
590 |
591 | if ($Module -is [Reflection.Assembly])
592 | {
593 | return ($Module.GetType($FullName))
594 | }
595 |
596 | [Reflection.TypeAttributes] $StructAttributes = 'AnsiClass,
597 | Class,
598 | Public,
599 | Sealed,
600 | BeforeFieldInit'
601 |
602 | if ($ExplicitLayout)
603 | {
604 | $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::ExplicitLayout
605 | }
606 | else
607 | {
608 | $StructAttributes = $StructAttributes -bor [Reflection.TypeAttributes]::SequentialLayout
609 | }
610 |
611 | $StructBuilder = $Module.DefineType($FullName, $StructAttributes, [ValueType], $PackingSize)
612 | $ConstructorInfo = [Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
613 | $SizeConst = @([Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst'))
614 |
615 | $Fields = New-Object Hashtable[]($StructFields.Count)
616 |
617 | # Sort each field according to the orders specified
618 | # Unfortunately, PSv2 doesn't have the luxury of the
619 | # hashtable [Ordered] accelerator.
620 | foreach ($Field in $StructFields.Keys)
621 | {
622 | $Index = $StructFields[$Field]['Position']
623 | $Fields[$Index] = @{FieldName = $Field; Properties = $StructFields[$Field]}
624 | }
625 |
626 | foreach ($Field in $Fields)
627 | {
628 | $FieldName = $Field['FieldName']
629 | $FieldProp = $Field['Properties']
630 |
631 | $Offset = $FieldProp['Offset']
632 | $Type = $FieldProp['Type']
633 | $MarshalAs = $FieldProp['MarshalAs']
634 |
635 | $NewField = $StructBuilder.DefineField($FieldName, $Type, 'Public')
636 |
637 | if ($MarshalAs)
638 | {
639 | $UnmanagedType = $MarshalAs[0] -as ([Runtime.InteropServices.UnmanagedType])
640 | if ($MarshalAs[1])
641 | {
642 | $Size = $MarshalAs[1]
643 | $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo,
644 | $UnmanagedType, $SizeConst, @($Size))
645 | }
646 | else
647 | {
648 | $AttribBuilder = New-Object Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, [Object[]] @($UnmanagedType))
649 | }
650 |
651 | $NewField.SetCustomAttribute($AttribBuilder)
652 | }
653 |
654 | if ($ExplicitLayout) { $NewField.SetOffset($Offset) }
655 | }
656 |
657 | # Make the struct aware of its own size.
658 | # No more having to call [Runtime.InteropServices.Marshal]::SizeOf!
659 | $SizeMethod = $StructBuilder.DefineMethod('GetSize',
660 | 'Public, Static',
661 | [Int],
662 | [Type[]] @())
663 | $ILGenerator = $SizeMethod.GetILGenerator()
664 | # Thanks for the help, Jason Shirk!
665 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
666 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
667 | [Type].GetMethod('GetTypeFromHandle'))
668 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Call,
669 | [Runtime.InteropServices.Marshal].GetMethod('SizeOf', [Type[]] @([Type])))
670 | $ILGenerator.Emit([Reflection.Emit.OpCodes]::Ret)
671 |
672 | # Allow for explicit casting from an IntPtr
673 | # No more having to call [Runtime.InteropServices.Marshal]::PtrToStructure!
674 | $ImplicitConverter = $StructBuilder.DefineMethod('op_Implicit',
675 | 'PrivateScope, Public, Static, HideBySig, SpecialName',
676 | $StructBuilder,
677 | [Type[]] @([IntPtr]))
678 | $ILGenerator2 = $ImplicitConverter.GetILGenerator()
679 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Nop)
680 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldarg_0)
681 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ldtoken, $StructBuilder)
682 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
683 | [Type].GetMethod('GetTypeFromHandle'))
684 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Call,
685 | [Runtime.InteropServices.Marshal].GetMethod('PtrToStructure', [Type[]] @([IntPtr], [Type])))
686 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Unbox_Any, $StructBuilder)
687 | $ILGenerator2.Emit([Reflection.Emit.OpCodes]::Ret)
688 |
689 | $StructBuilder.CreateType()
690 | }
691 |
--------------------------------------------------------------------------------