├── .gitattributes ├── .gitignore ├── Disassembly ├── Get-CSDisassembly.ps1 └── Get-ILDisassembly.ps1 ├── Lib ├── Capstone │ ├── Capstone.psd1 │ ├── LICENSE.TXT │ ├── README │ └── lib │ │ ├── capstone.dll │ │ ├── place_capstone.dll_here │ │ ├── x64 │ │ ├── libcapstone.dll │ │ └── place_64-bit_libcapstone.dll_here │ │ └── x86 │ │ ├── libcapstone.dll │ │ └── place_32-bit_libcapstone.dll_here ├── De4dot │ ├── AssemblyData.dll │ ├── de4dot.blocks.dll │ ├── de4dot.code.dll │ ├── de4dot.mdecrypt.dll │ └── dnlib.dll ├── Formatters │ ├── Get-CSDisassembly.format.ps1xml │ ├── Get-ILDisassembly.format.ps1xml │ ├── Get-LibSymbols.format.ps1xml │ ├── Get-NtSystemInformation.format.ps1xml │ ├── Get-ObjDump.format.ps1xml │ ├── Get-PE.format.ps1xml │ ├── Get-PEB.format.ps1xml │ ├── MemoryTools.format.ps1xml │ └── ProcessModuleTrace.format.ps1xml └── PSReflect │ ├── Examples │ ├── Get-NetShare.ps1 │ └── SimplePEParser.ps1 │ ├── LICENSE │ ├── PSReflect.psd1 │ ├── PSReflect.psm1 │ └── README.md ├── MalwareAnalysis ├── Hosts.ps1 ├── dotNetMalwareAnalysis.ps1 ├── funcdelegate.ps1 └── loadlib.ps1 ├── MemoryTools └── MemoryTools.ps1 ├── Misc ├── ConvertTo-String.ps1 ├── Get-Entropy.ps1 ├── Get-Member.ps1 └── Get-Strings.ps1 ├── Parsers ├── Get-LibSymbols.ps1 ├── Get-ObjDump.ps1 └── Get-PE.ps1 ├── PowerShellArsenal.psd1 ├── PowerShellArsenal.psm1 ├── README.md └── WindowsInternals ├── Get-NtSystemInformation.ps1 ├── Get-PEB.ps1 ├── Get-SystemInfo.ps1 └── ProcessModuleTrace.ps1 /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/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/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/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/Capstone/lib/capstone.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/capstone.dll -------------------------------------------------------------------------------- /Lib/Capstone/lib/place_capstone.dll_here: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/place_capstone.dll_here -------------------------------------------------------------------------------- /Lib/Capstone/lib/x64/libcapstone.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/x64/libcapstone.dll -------------------------------------------------------------------------------- /Lib/Capstone/lib/x64/place_64-bit_libcapstone.dll_here: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/x64/place_64-bit_libcapstone.dll_here -------------------------------------------------------------------------------- /Lib/Capstone/lib/x86/libcapstone.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/x86/libcapstone.dll -------------------------------------------------------------------------------- /Lib/Capstone/lib/x86/place_32-bit_libcapstone.dll_here: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/Capstone/lib/x86/place_32-bit_libcapstone.dll_here -------------------------------------------------------------------------------- /Lib/De4dot/AssemblyData.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/De4dot/AssemblyData.dll -------------------------------------------------------------------------------- /Lib/De4dot/de4dot.blocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/De4dot/de4dot.blocks.dll -------------------------------------------------------------------------------- /Lib/De4dot/de4dot.code.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/De4dot/de4dot.code.dll -------------------------------------------------------------------------------- /Lib/De4dot/de4dot.mdecrypt.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/De4dot/de4dot.mdecrypt.dll -------------------------------------------------------------------------------- /Lib/De4dot/dnlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HarmJ0y/PowerShellArsenal/56c895696dd1e97cd6bd8e9a80cf2c6f31f45cb1/Lib/De4dot/dnlib.dll -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 nunbers 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/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/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/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 | -------------------------------------------------------------------------------- /Lib/PSReflect/README.md: -------------------------------------------------------------------------------- 1 | PSReflect 2 | ========= 3 | 4 | Easily define in-memory enums, structs, and Win32 functions in PowerShell 5 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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} -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------