diff --git a/data/templates/to_mem_dotnet.ps1.template b/data/templates/to_mem_dotnet.ps1.template index c17496e..16bff61 100644 --- a/data/templates/to_mem_dotnet.ps1.template +++ b/data/templates/to_mem_dotnet.ps1.template @@ -9,6 +9,7 @@ $%{var_syscode} = @" [Flags] public enum Time : uint { Infinite = 0xFFFFFFFF } [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] public static extern bool VirtualProtect(IntPtr lpAddress, int dwSize, int flNewProtect,out int lpflOldProtect); + [DllImport("kernel32.dll")] public static extern bool FlushInstructionCache(IntPtr hProcess, IntPtr lpBaseAddress, UIntPtr dwSize); [DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); [DllImport("kernel32.dll")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds); } @@ -29,6 +30,7 @@ if ([Bool]!$%{var_baseaddr}) { $global:result = 3; return } [System.Runtime.InteropServices.Marshal]::Copy($%{var_code}, 0, $%{var_baseaddr}, $%{var_code}.Length) if ([%{var_kernel32}.func]::VirtualProtect($%{var_baseaddr},[Uint32]$%{var_code}.Length + 1, [%{var_kernel32}.func+MemoryProtection]::Execute, [Ref]$%{var_opf}) -eq $true ) { + [%{var_kernel32}.func]::FlushInstructionCache([IntPtr](-1), $%{var_baseaddr}, [UIntPtr]($%{var_code}.Length + 1)) | Out-Null [IntPtr] $%{var_threadHandle} = [%{var_kernel32}.func]::CreateThread(0,0,$%{var_baseaddr},0,0,0) if ([Bool]!$%{var_threadHandle}) { $global:result = 7; return } $%{var_temp} = [%{var_kernel32}.func]::WaitForSingleObject($%{var_threadHandle}, [%{var_kernel32}.func+Time]::Infinite) diff --git a/data/templates/to_mem_msil.ps1.template b/data/templates/to_mem_msil.ps1.template index 45ce487..77260e0 100644 --- a/data/templates/to_mem_msil.ps1.template +++ b/data/templates/to_mem_msil.ps1.template @@ -46,9 +46,18 @@ $%{var_dyn_meth}.Emit([System.Reflection.Emit.OpCodes]::Xor) $%{var_dyn_meth}.Emit([System.Reflection.Emit.OpCodes]::Ret) $%{var_tgt_meth} = ($%{var_dyn_type}.CreateType()).GetMethod('%{str_tgt_meth}') +if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { + $%{var_flush_type} = %{func_build_dyn_type}('%{str_flush_type}') + $%{var_flush_method} = $%{var_flush_type}.DefinePInvokeMethod('%{str_flush_method}', 'kernel32.dll', 'FlushInstructionCache', [System.Reflection.MethodAttributes]::Public -bOr [System.Reflection.MethodAttributes]::Static -bOr [System.Reflection.MethodAttributes]::PinvokeImpl, [System.Reflection.CallingConventions]::Standard, [Bool], [Type[]]@([IntPtr], [IntPtr], [UIntPtr]), [System.Runtime.InteropServices.CallingConvention]::Winapi, [System.Runtime.InteropServices.CharSet]::Auto) + $%{var_flush_method}.SetImplementationFlags($%{var_flush_method}.GetMethodImplementationFlags() -bOr [System.Reflection.MethodImplAttributes]::PreserveSig) + $%{var_flush_method} = ($%{var_flush_type}.CreateType()).GetMethod('%{str_flush_method}') +} + foreach ($Exec in 1..20) { $%{var_tgt_meth}.Invoke($null, @(0x11112222)) | Out-Null } -if ( [IntPtr]::Size -eq 4 ) { +if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { + $%{var_sc} = [Byte[]] @(0xF3,0x53,0xBA,0xA9,0xF5,0x5B,0x01,0xA9,0xF7,0x63,0x02,0xA9,0xF9,0x6B,0x03,0xA9,0xFB,0x73,0x04,0xA9,0xFD,0x7B,0x05,0xA9,0x09,0x00,0x00,0x94,0xFD,0x7B,0x45,0xA9,0xFB,0x73,0x44,0xA9,0xF9,0x6B,0x43,0xA9,0xF7,0x63,0x42,0xA9,0xF5,0x5B,0x41,0xA9,0xF3,0x53,0xC6,0xA8,0x00,0x00,0x80,0xD2,0xC0,0x03,0x5F,0xD6) +} elseif ( [IntPtr]::Size -eq 4 ) { $%{var_sc} = [Byte[]] @(0x60,0xE8,0x04,0,0,0,0x61,0x31,0xC0,0xC3) } else { $%{var_sc} = [Byte[]] @(0x41,0x54,0x41,0x55,0x41,0x56,0x41,0x57,0x55,0xE8,0x0D,0x00,0x00,0x00,0x5D,0x41,0x5F,0x41,0x5E,0x41,0x5D,0x41,0x5C,0x48,0x31,0xC0,0xC3) @@ -58,10 +67,14 @@ $%{var_sc_addr} = [Runtime.InteropServices.Marshal]::AllocHGlobal($%{var_sc}.Len [Runtime.InteropServices.Marshal]::Copy($%{var_sc}, 0, $%{var_sc_addr}, $%{var_sc}.Length) $%{var_args} = New-Object Object[](3) -$%{var_args}[0] = [IntPtr]$(%{func_get_meth_addr} $%{var_tgt_meth}) +$%{var_tgt_addr} = [IntPtr]$(%{func_get_meth_addr} $%{var_tgt_meth}) +$%{var_args}[0] = $%{var_tgt_addr} $%{var_args}[1] = $%{var_sc_addr} $%{var_args}[2] = $%{var_sc}.Length $%{var_src_meth}.Invoke($null, $%{var_args}) +if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { + $%{var_flush_method}.Invoke($null, @([IntPtr](-1), $%{var_tgt_addr}, [UIntPtr]$%{var_sc}.Length)) | Out-Null +} $%{var_tgt_meth}.Invoke($null, @(0x11112222)) diff --git a/data/templates/to_mem_old.ps1.template b/data/templates/to_mem_old.ps1.template index 9d524f5..65a75b6 100644 --- a/data/templates/to_mem_old.ps1.template +++ b/data/templates/to_mem_old.ps1.template @@ -2,6 +2,8 @@ $%{var_syscode} = @" [DllImport("kernel32.dll")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")] +public static extern bool FlushInstructionCache(IntPtr hProcess, IntPtr lpBaseAddress, UIntPtr dwSize); +[DllImport("kernel32.dll")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); "@ @@ -13,4 +15,6 @@ $%{var_rwx} = $%{var_win32_func}::VirtualAlloc(0,[Math]::Max($%{var_code}.Length [System.Runtime.InteropServices.Marshal]::Copy($%{var_code},0,$%{var_rwx},$%{var_code}.Length) +$%{var_win32_func}::FlushInstructionCache([IntPtr](-1),$%{var_rwx},[UIntPtr]$%{var_code}.Length) | Out-Null + $%{var_win32_func}::CreateThread(0,0,$%{var_rwx},0,0,0) diff --git a/data/templates/to_mem_pshreflection.ps1.template b/data/templates/to_mem_pshreflection.ps1.template index 749a254..e8c2ce7 100644 --- a/data/templates/to_mem_pshreflection.ps1.template +++ b/data/templates/to_mem_pshreflection.ps1.template @@ -24,6 +24,7 @@ $%{var_buffer} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctio [System.Runtime.InteropServices.Marshal]::Copy($%{var_code}, 0, $%{var_buffer}, $%{var_code}.length) if (([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll VirtualProtect), (%{func_get_delegate_type} @([IntPtr], [UIntPtr], [UInt32], [UInt32].MakeByRefType()) ([Bool]))).Invoke($%{var_buffer}, [Uint32]$%{var_code}.Length, 0x10, [Ref]$%{var_opf})) -eq $true) { - $%{var_hthread} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll CreateThread), (%{func_get_delegate_type} @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$%{var_buffer},[IntPtr]::Zero,0,[IntPtr]::Zero) + [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll FlushInstructionCache), (%{func_get_delegate_type} @([IntPtr], [IntPtr], [UIntPtr]) ([Bool]))).Invoke([IntPtr](-1), $%{var_buffer}, [UIntPtr]$%{var_code}.Length) | Out-Null + $%{var_hthread} = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll CreateThread), (%{func_get_delegate_type} @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$%{var_buffer},[IntPtr]::Zero,0,[IntPtr]::Zero) [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((%{func_get_proc_address} kernel32.dll WaitForSingleObject), (%{func_get_delegate_type} @([IntPtr], [Int32]))).Invoke($%{var_hthread},0xffffffff) | Out-Null } diff --git a/lib/rex/powershell/command.rb b/lib/rex/powershell/command.rb index 0e9bffa..7e23fd9 100644 --- a/lib/rex/powershell/command.rb +++ b/lib/rex/powershell/command.rb @@ -208,8 +208,14 @@ def self.generate_psh_args(opts) # detect the execution environment and spawn the appropriate # powershell executable for the payload architecture. # + # ARM64 note: [IntPtr]::Size cannot tell an ARM64 process apart from an x64 + # one, so PROCESSOR_ARCHITECTURE (and PROCESSOR_ARCHITEW6432 for a 32-bit + # process on Windows-on-ARM) is consulted first. A payload_arch of + # 'aarch64' targets the native ARM64 powershell.exe under System32 + # (reached via sysnative when the current process is 32-bit). + # # @param ps_code [String] Powershell code - # @param payload_arch [String] The payload architecture 'x86'/'x86_64' + # @param payload_arch [String] The payload architecture 'x86'/'x86_64'/'aarch64' # @param encoded [Boolean] Indicates whether ps_code is encoded or not # @param opts [Hash] The options for generate_psh_args # @@ -240,20 +246,51 @@ def self.run_hidden_psh(ps_code, payload_arch, encoded, opts={}) EOS process_start_info.gsub!("\n", ';') - archictecure_detection = <