/// <summary> /// Manually map module into current process. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="pModule">Pointer to the module base.</param> /// <param name="pImage">Pointer to the PEINFO image.</param> /// <param name="PEINFO">PE_META_DATA of the module being mapped.</param> /// <returns>PE_MANUAL_MAP object</returns> public static PE.PE_MANUAL_MAP MapModuleToMemory(IntPtr pModule, IntPtr pImage, PE.PE_META_DATA PEINFO) { // Check module matches the process architecture if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4)) { Marshal.FreeHGlobal(pModule); throw new InvalidOperationException("The module architecture does not match the process architecture."); } // Write PE header to memory UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders; UInt32 BytesWritten = DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), pImage, pModule, SizeOfHeaders); // Write sections to memory foreach (PE.IMAGE_SECTION_HEADER ish in PEINFO.Sections) { // Calculate offsets IntPtr pVirtualSectionBase = (IntPtr)((UInt64)pImage + ish.VirtualAddress); IntPtr pRawSectionBase = (IntPtr)((UInt64)pModule + ish.PointerToRawData); // Write data BytesWritten = DynamicInvoke.Native.NtWriteVirtualMemory((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData); if (BytesWritten != ish.SizeOfRawData) { throw new InvalidOperationException("Failed to write to memory."); } } // Perform relocations RelocateModule(PEINFO, pImage); // Rewrite IAT RewriteModuleIAT(PEINFO, pImage); // Set memory protections SetModuleSectionPermissions(PEINFO, pImage); // Free temp HGlobal Marshal.FreeHGlobal(pModule); // Prepare return object PE.PE_MANUAL_MAP ManMapObject = new PE.PE_MANUAL_MAP { ModuleBase = pImage, PEINFO = PEINFO }; return(ManMapObject); }
/// <summary> /// Load a signed decoy module into memory creating legitimate file-backed memory sections within the process. Afterwards overload that /// module by manually mapping a payload in it's place causing the payload to execute from what appears to be file-backed memory. /// </summary> /// <author>The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)</author> /// <param name="Payload">Full byte array for the payload module.</param> /// <param name="DecoyModulePath">Optional, full path the decoy module to overload in memory.</param> /// <returns>PE.PE_MANUAL_MAP</returns> public static PE.PE_MANUAL_MAP OverloadModule(byte[] Payload, string DecoyModulePath = null) { // Verify process & architecture bool isWOW64 = DynamicInvoke.Native.NtQueryInformationProcessWow64Information((IntPtr)(-1)); if (IntPtr.Size == 4 && isWOW64) { throw new InvalidOperationException("Module overloading in WOW64 is not supported."); } // Did we get a DecoyModule? if (!string.IsNullOrEmpty(DecoyModulePath)) { if (!File.Exists(DecoyModulePath)) { throw new InvalidOperationException("Decoy filepath not found."); } byte[] DecoyFileBytes = File.ReadAllBytes(DecoyModulePath); if (DecoyFileBytes.Length < Payload.Length) { throw new InvalidOperationException("Decoy module is too small to host the payload."); } } else { DecoyModulePath = FindDecoyModule(Payload.Length); if (string.IsNullOrEmpty(DecoyModulePath)) { throw new InvalidOperationException("Failed to find suitable decoy module."); } } // Map decoy from disk Execute.PE.PE_MANUAL_MAP DecoyMetaData = Map.MapModuleFromDisk(DecoyModulePath); IntPtr RegionSize = DecoyMetaData.PEINFO.Is32Bit ? (IntPtr)DecoyMetaData.PEINFO.OptHeader32.SizeOfImage : (IntPtr)DecoyMetaData.PEINFO.OptHeader64.SizeOfImage; // Change permissions to RW DynamicInvoke.Native.NtProtectVirtualMemory((IntPtr)(-1), ref DecoyMetaData.ModuleBase, ref RegionSize, Execute.Win32.WinNT.PAGE_READWRITE); // Zero out memory DynamicInvoke.Native.RtlZeroMemory(DecoyMetaData.ModuleBase, (int)RegionSize); // Overload module in memory PE.PE_MANUAL_MAP OverloadedModuleMetaData = Map.MapModuleToMemory(Payload, DecoyMetaData.ModuleBase); OverloadedModuleMetaData.DecoyModule = DecoyModulePath; return(OverloadedModuleMetaData); }
/// <summary> /// Free a module that was mapped into the current process. /// </summary> /// <author>The Wover (@TheRealWover)</author> /// <param name="PEMapped">The metadata of the manually mapped module.</param> public static void FreeModule(PE.PE_MANUAL_MAP PEMapped) { // Check if PE was mapped via module overloading if (!string.IsNullOrEmpty(PEMapped.DecoyModule)) { DynamicInvoke.Native.NtUnmapViewOfSection((IntPtr)(-1), PEMapped.ModuleBase); } // If PE not mapped via module overloading, free the memory. else { PE.PE_META_DATA PEINFO = PEMapped.PEINFO; // Get the size of the module in memory IntPtr size = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; IntPtr pModule = PEMapped.ModuleBase; DynamicInvoke.Native.NtFreeVirtualMemory((IntPtr)(-1), ref pModule, ref size, Execute.Win32.Kernel32.AllocationType.Release); } }
/// <summary> /// Maps a DLL from disk into a Section using NtCreateSection. /// </summary> /// <author>The Wover (@TheRealWover), Ruben Boonen (@FuzzySec)</author> /// <param name="DLLPath">Full path fo the DLL on disk.</param> /// <returns>PE.PE_MANUAL_MAP</returns> public static PE.PE_MANUAL_MAP MapModuleFromDisk(string DLLPath) { // Check file exists if (!File.Exists(DLLPath)) { throw new InvalidOperationException("Filepath not found."); } // Open file handle Execute.Native.UNICODE_STRING ObjectName = new Execute.Native.UNICODE_STRING(); DynamicInvoke.Native.RtlInitUnicodeString(ref ObjectName, (@"\??\" + DLLPath)); IntPtr pObjectName = Marshal.AllocHGlobal(Marshal.SizeOf(ObjectName)); Marshal.StructureToPtr(ObjectName, pObjectName, true); Execute.Native.OBJECT_ATTRIBUTES objectAttributes = new Execute.Native.OBJECT_ATTRIBUTES(); objectAttributes.Length = Marshal.SizeOf(objectAttributes); objectAttributes.ObjectName = pObjectName; objectAttributes.Attributes = 0x40; // OBJ_CASE_INSENSITIVE Execute.Native.IO_STATUS_BLOCK ioStatusBlock = new Execute.Native.IO_STATUS_BLOCK(); IntPtr hFile = IntPtr.Zero; DynamicInvoke.Native.NtOpenFile( ref hFile, Execute.Win32.Kernel32.FileAccessFlags.FILE_READ_DATA | Execute.Win32.Kernel32.FileAccessFlags.FILE_EXECUTE | Execute.Win32.Kernel32.FileAccessFlags.FILE_READ_ATTRIBUTES | Execute.Win32.Kernel32.FileAccessFlags.SYNCHRONIZE, ref objectAttributes, ref ioStatusBlock, Execute.Win32.Kernel32.FileShareFlags.FILE_SHARE_READ | Execute.Win32.Kernel32.FileShareFlags.FILE_SHARE_DELETE, Execute.Win32.Kernel32.FileOpenFlags.FILE_SYNCHRONOUS_IO_NONALERT | Execute.Win32.Kernel32.FileOpenFlags.FILE_NON_DIRECTORY_FILE ); // Create section from hFile IntPtr hSection = IntPtr.Zero; ulong MaxSize = 0; Execute.Native.NTSTATUS ret = DynamicInvoke.Native.NtCreateSection( ref hSection, (UInt32)Execute.Win32.WinNT.ACCESS_MASK.SECTION_ALL_ACCESS, IntPtr.Zero, ref MaxSize, Execute.Win32.WinNT.PAGE_READONLY, Execute.Win32.WinNT.SEC_IMAGE, hFile ); // Map view of file IntPtr pBaseAddress = IntPtr.Zero; DynamicInvoke.Native.NtMapViewOfSection( hSection, (IntPtr)(-1), ref pBaseAddress, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref MaxSize, 0x2, 0x0, Execute.Win32.WinNT.PAGE_READWRITE ); // Prepare return object PE.PE_MANUAL_MAP SecMapObject = new PE.PE_MANUAL_MAP { PEINFO = DynamicInvoke.Generic.GetPeMetaData(pBaseAddress), ModuleBase = pBaseAddress }; return(SecMapObject); }