Skip to content

Instantly share code, notes, and snippets.

@franklesniak
Created November 2, 2015 04:44
Show Gist options
  • Save franklesniak/3fe7c80f93193521c5d5 to your computer and use it in GitHub Desktop.
Save franklesniak/3fe7c80f93193521c5d5 to your computer and use it in GitHub Desktop.
I was hoping to use reflection to invoke the native DhcpRequestParams function, but I am getting an error: Exception calling "LoadFile" with "1" argument(s): "The module was expected to contain an assembly manifest.
##############################################################################
##
## Invoke-WindowsApi.ps1
##
## Invoke a native Windows API call that takes and returns simple data types.
##
## ie:
##
##
## Prepare the parameter types and parameters for the
## CreateHardLink function
## $parameterTypes = [string], [string], [IntPtr]
## $parameters = [string] $filename, [string] $existingFilename, $null
##
##
## Call the CreateHardLink method in the Kernel32 DLL
## $result = Invoke-WindowsApi "kernel32" ([bool]) "CreateHardLink" `
## $parameterTypes $parameters
##
##############################################################################
function Invoke-WindowsAPI
{
param
(
[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)
{
[void] $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]
}
}
# See http://www.exploit-monday.com/2012/07/structs-and-enums-using-reflection.html
# See http://poshcode.org/2189
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('DHCPClientAPI')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('DHCPClientAPIModule', $False)
####################################################################################
# Create DhcpRequestFlags enum
$EnumBuilder = $ModuleBuilder.DefineEnum('DhcpRequestFlags', 'Public', [UInt32])
# Define values of the enum
$EnumBuilder.DefineLiteral('DHCPCAPI_REQUEST_PERSISTENT', [UInt32] 0x01) | Out-Null
$EnumBuilder.DefineLiteral('DHCPCAPI_REQUEST_SYNCHRONOUS', [UInt32] 0x02) | Out-Null
$EnumBuilder.DefineLiteral('DHCPCAPI_REQUEST_ASYNCHRONOUS', [UInt32] 0x04) | Out-Null
$EnumBuilder.DefineLiteral('DHCPCAPI_REQUEST_CANCEL', [UInt32] 0x08) | Out-Null
$EnumBuilder.DefineLiteral('DHCPCAPI_REQUEST_MASK', [UInt32] 0x0F) | Out-Null
$DhcpRequestFlagsType = $EnumBuilder.CreateType()
####################################################################################
# Create DHCPCAPI_PARAMS struct
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
# There is no such thing as a DefineStruct type. So define a type with the attributes of a struct.
# A struct is essentially a class with no methods.
$TypeBuilder = $ModuleBuilder.DefineType('DHCPCAPI_PARAMS', $Attributes, [System.ValueType], 1, 0x40)
$TypeBuilder.DefineField('Flags', [UInt32], 'Public') | Out-Null
$TypeBuilder.DefineField('OptionId', [UInt32], 'Public') | Out-Null
$IsVendorField = $TypeBuilder.DefineField('IsVendor', [Bool], 'Public, HasFieldMarshal')
$ConstructorInfo = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructors()[0]
$ConstructorValue = [System.Runtime.InteropServices.UnmanagedType]::Bool
$AttribBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder($ConstructorInfo, $ConstructorValue)
$IsVendorField.SetCustomAttribute($AttribBuilder)
#$TypeBuilder.DefineField('Data', [IntPtr], 'Public') | Out-Null
$TypeBuilder.DefineField('Data', [Byte], 'Public') | Out-Null
$TypeBuilder.DefineField('nBytesData', [UInt32], 'Public') | Out-Null
$DHCPCAPI_PARAMSType = $TypeBuilder.CreateType()
####################################################################################
# Create DHCPCAPI_PARAMS_ARRAY struct
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
# There is no such thing as a DefineStruct type. So define a type with the attributes of a struct.
# A struct is essentially a class with no methods.
$TypeBuilder = $ModuleBuilder.DefineType('DHCPCAPI_PARAMS_ARRAY', $Attributes, [System.ValueType], 1, 0x40)
$TypeBuilder.DefineField('nParams', [UInt32], 'Public') | Out-Null
$TypeBuilder.DefineField('Params', [DHCPCAPI_PARAMS], 'Public') | Out-Null
$DHCPCAPI_PARAMS_ARRAYType = $TypeBuilder.CreateType()
####################################################################################
$sendParams = New-Object DHCPCAPI_PARAMS_ARRAY
$sendParams.nParams = 0
$recv = New-Object DHCPCAPI_PARAMS
$recv.Flags = 0x0
$recv.OptionId = 245
$recv.IsVendor = $false
$recv.nBytesData = 0
$recdParams = New-Object DHCPCAPI_PARAMS_ARRAY
$recdParams.nParams = 1
$recdParams.Params = $recv
[UInt32]$flags = $DhcpRequestFlagsType::DHCPCAPI_REQUEST_SYNCHRONOUS.value__
$buffer = New-Object byte[] 1024
$types = @([UInt32], [IntPtr], [string], [IntPtr], [DHCPCAPI_PARAMS_ARRAY], [DHCPCAPI_PARAMS_ARRAY], [Byte[]], [uint32], [IntPtr])
$params = @($flags, [IntPtr]::Zero, "{6362DADD-53D1-48DB-83B8-F1C79B3D1036}", [IntPtr]::Zero, $sendParams, $recdParams, $buffer, 1024, [IntPtr]::Zero)
$result = Invoke-WindowsAPI "dhcpcsvc" ([int32]) "DhcpRequestParams" $types $params
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment