Fixed x86 bug in Get-MethodAddress

Get-MethodAddress was not working correctly in 32-bit PowerShell because
it was returning a [UInt64] value when it should have been a [UInt32].
This fix will detect if PowerShell is running as 32 or 64-bit and define
its return type accordingly.
This commit is contained in:
Matt Graeber 2013-04-05 11:04:48 -04:00
parent 577be2fea5
commit 1e79c0f793
1 changed files with 119 additions and 110 deletions

View File

@ -1,111 +1,120 @@
function Get-MethodAddress function Get-MethodAddress
{ {
<# <#
.SYNOPSIS .SYNOPSIS
Get the unmanaged function address of a .NET method. Get the unmanaged function address of a .NET method.
PowerSploit Function: Get-MethodAddress PowerSploit Function: Get-MethodAddress
Author: Matthew Graeber (@mattifestation) Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause License: BSD 3-Clause
Required Dependencies: None Required Dependencies: None
Optional Dependencies: None Optional Dependencies: None
.DESCRIPTION .DESCRIPTION
Get-MethodAddress aids in the process of reverse engineering and exploitation by returning an unmanaged function pointer to any .NET method. This method is useful for those interested in seeing what JITed MSIL opcodes look like in their assembly language representation. Get-MethodAddress aids in the process of reverse engineering and exploitation by returning an unmanaged function pointer to any .NET method. This method is useful for those interested in seeing what JITed MSIL opcodes look like in their assembly language representation.
For example, here is the MSIL representation of [System.IntPtr].ToPointer: For example, here is the MSIL representation of [System.IntPtr].ToPointer:
0x02 ldarg.0 0x02 ldarg.0
0x7B,0x53,0x04,0x00,0x04 ldfld void* System.IntPtr::m_value 0x7B,0x53,0x04,0x00,0x04 ldfld void* System.IntPtr::m_value
0x2A ret 0x2A ret
After calling Get-MethodAddress and inspecting it in WinDbg, here is the x86_64 ASM representation: After calling Get-MethodAddress and inspecting it in WinDbg, here is the x86_64 ASM representation:
C:\PS> Get-MethodAddress ([IntPtr].GetMethod('ToPointer')) C:\PS> Get-MethodAddress ([IntPtr].GetMethod('ToPointer'))
0x000007FF35544CC0 0x000007FF35544CC0
mscorlib_ni+0xd04cc0: mscorlib_ni+0xd04cc0:
000007ff`35544cc0 488b01 mov rax,qword ptr [rcx] 000007ff`35544cc0 488b01 mov rax,qword ptr [rcx]
000007ff`35544cc3 c3 ret 000007ff`35544cc3 c3 ret
000007ff`35544cc4 cc int 3 000007ff`35544cc4 cc int 3
This MSIL to ASM translation makes sense because all the assembly instructions are doing is dereferencing the pointer in rcx. This MSIL to ASM translation makes sense because all the assembly instructions are doing is dereferencing the pointer in rcx.
.PARAMETER MethodInfo .PARAMETER MethodInfo
The method whose unmanaged address will be returned. The method whose unmanaged address will be returned.
.EXAMPLE .EXAMPLE
C:\PS> Get-MethodAddress ([String].GetMethod('Trim', [Type[]]@())) C:\PS> Get-MethodAddress ([String].GetMethod('Trim', [Type[]]@()))
Description Description
----------- -----------
Returns the unmanaged address of [System.Object].Trim() method. Returns the unmanaged address of [System.Object].Trim() method.
.EXAMPLE .EXAMPLE
C:\PS> [Int].Module.GetTypes().GetMethods() | ForEach-Object {Get-MethodAddress $_ -ErrorAction SilentlyContinue -WarningAction SilentlyContinue} C:\PS> [Int].Module.GetTypes().GetMethods() | ForEach-Object {Get-MethodAddress $_ -ErrorAction SilentlyContinue -WarningAction SilentlyContinue}
Description Description
----------- -----------
Returns an unmanaged address for every method (in which an address can be returned) in mscorlib. Returns an unmanaged address for every method (in which an address can be returned) in mscorlib.
.OUTPUTS .OUTPUTS
System.String System.String
A hexadecimal representation of the method address. A hexadecimal representation of the method address.
.NOTES .NOTES
Not all methods will be able to return an address. For example, methods with implementation flags of AggressiveInlining, Synchronized, or CodeTypeMask will not return an address. Also note that any InternalCall method will return the same pointer every time because the CLR determines its address at runtime. Not all methods will be able to return an address. For example, methods with implementation flags of AggressiveInlining, Synchronized, or CodeTypeMask will not return an address. Also note that any InternalCall method will return the same pointer every time because the CLR determines its address at runtime.
Lastly, note that the MSIL opcodes used to implement this cmdlet are unverifiable. This means for example, that this technique won't aid exploiting Silverlight applications. :'( Lastly, note that the MSIL opcodes used to implement this cmdlet are unverifiable. This means for example, that this technique won't aid exploiting Silverlight applications. :'(
.LINK .LINK
http://www.exploit-monday.com/2012/11/Get-MethodAddress.html http://www.exploit-monday.com/2012/11/Get-MethodAddress.html
#> #>
[CmdletBinding()] Param ( [CmdletBinding()] Param (
[Parameter(Mandatory = $True, ValueFromPipeline = $True)] [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
[System.Reflection.MethodInfo] [System.Reflection.MethodInfo]
$MethodInfo $MethodInfo
) )
if ($MethodInfo.MethodImplementationFlags -eq 'InternalCall') if ($MethodInfo.MethodImplementationFlags -eq 'InternalCall')
{ {
Write-Warning "$($MethodInfo.Name) is an InternalCall method. These methods always point to the same address." Write-Warning "$($MethodInfo.Name) is an InternalCall method. These methods always point to the same address."
} }
$Domain = [AppDomain]::CurrentDomain if ([IntPtr]::Size -eq 4)
$DynAssembly = New-Object System.Reflection.AssemblyName('MethodLeakAssembly') {
# Assemble in memory $ReturnType = [UInt32]
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) }
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('MethodLeakModule') else
$TypeBuilder = $ModuleBuilder.DefineType('MethodLeaker', [System.Reflection.TypeAttributes]::Public) {
# Declaration of the LeakMethod method $ReturnType = [UInt64]
$MethodBuilder = $TypeBuilder.DefineMethod('LeakMethod', [System.Reflection.MethodAttributes]::Public -bOr [System.Reflection.MethodAttributes]::Static, [UInt64], $null) }
$Generator = $MethodBuilder.GetILGenerator()
$Domain = [AppDomain]::CurrentDomain
# Push unmanaged pointer to MethodInfo onto the evaluation stack $DynAssembly = New-Object System.Reflection.AssemblyName('MethodLeakAssembly')
$Generator.Emit([System.Reflection.Emit.OpCodes]::Ldftn, $MethodInfo) # Assemble in memory
$Generator.Emit([System.Reflection.Emit.OpCodes]::Ret) $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('MethodLeakModule')
# Assemble everything $TypeBuilder = $ModuleBuilder.DefineType('MethodLeaker', [System.Reflection.TypeAttributes]::Public)
$Type = $TypeBuilder.CreateType() # Declaration of the LeakMethod method
$Method = $Type.GetMethod('LeakMethod') $MethodBuilder = $TypeBuilder.DefineMethod('LeakMethod', [System.Reflection.MethodAttributes]::Public -bOr [System.Reflection.MethodAttributes]::Static, $ReturnType, $null)
$Generator = $MethodBuilder.GetILGenerator()
try
{ # Push unmanaged pointer to MethodInfo onto the evaluation stack
# Call the method and return its JITed address $Generator.Emit([System.Reflection.Emit.OpCodes]::Ldftn, $MethodInfo)
$Address = $Method.Invoke($null, @()) $Generator.Emit([System.Reflection.Emit.OpCodes]::Ret)
Write-Output (New-Object IntPtr -ArgumentList $Address) # Assemble everything
} $Type = $TypeBuilder.CreateType()
catch [System.Management.Automation.MethodInvocationException] $Method = $Type.GetMethod('LeakMethod')
{
Write-Error "$($MethodInfo.Name) cannot return an unmanaged address." try
} {
# Call the method and return its JITed address
$Address = $Method.Invoke($null, @())
Write-Output (New-Object IntPtr -ArgumentList $Address)
}
catch [System.Management.Automation.MethodInvocationException]
{
Write-Error "$($MethodInfo.Name) cannot return an unmanaged address."
}
} }