/// <summary> /// Relocates a module in memory. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> private static void RelocateModule(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { IMAGE_DATA_DIRECTORY idd = PEINFO.Is32Bit ? PEINFO.OptHeader32.BaseRelocationTable : PEINFO.OptHeader64.BaseRelocationTable; Int64 ImageDelta = PEINFO.Is32Bit ? (Int64)((UInt64)ModuleMemoryBase - PEINFO.OptHeader32.ImageBase) : (Int64)((UInt64)ModuleMemoryBase - PEINFO.OptHeader64.ImageBase); // Ptr for the base reloc table IntPtr pRelocTable = (IntPtr)((UInt64)ModuleMemoryBase + idd.VirtualAddress); Int32 nextRelocTableBlock = -1; // Loop reloc blocks while (nextRelocTableBlock != 0) { IMAGE_BASE_RELOCATION ibr; ibr = (IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(pRelocTable, typeof(IMAGE_BASE_RELOCATION)); Int64 RelocCount = ((ibr.SizeOfBlock - Marshal.SizeOf(ibr)) / 2); for (int i = 0; i < RelocCount; i++) { // Calculate reloc entry ptr IntPtr pRelocEntry = (IntPtr)((UInt64)pRelocTable + (UInt64)Marshal.SizeOf(ibr) + (UInt64)(i * 2)); UInt16 RelocValue = (UInt16)Marshal.ReadInt16(pRelocEntry); // Parse reloc value // The type should only ever be 0x0, 0x3, 0xA // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-types UInt16 RelocType = (UInt16)(RelocValue >> 12); UInt16 RelocPatch = (UInt16)(RelocValue & 0xfff); // Perform relocation if (RelocType != 0) // IMAGE_REL_BASED_ABSOLUTE (0 -> skip reloc) { try { IntPtr pPatch = (IntPtr)((UInt64)ModuleMemoryBase + ibr.VirtualAdress + RelocPatch); if (RelocType == 0x3) // IMAGE_REL_BASED_HIGHLOW (x86) { Int32 OriginalPtr = Marshal.ReadInt32(pPatch); Marshal.WriteInt32(pPatch, (OriginalPtr + (Int32)ImageDelta)); } else // IMAGE_REL_BASED_DIR64 (x64) { Int64 OriginalPtr = Marshal.ReadInt64(pPatch); Marshal.WriteInt64(pPatch, (OriginalPtr + ImageDelta)); } } catch { throw new Exception(DSTR(DSTR_MEM_ACCESS_VIOLATION)); } } } // Check for next block pRelocTable = (IntPtr)((UInt64)pRelocTable + ibr.SizeOfBlock); nextRelocTableBlock = Marshal.ReadInt32(pRelocTable); } }
/// <summary> /// Call a manually mapped DLL by DllMain -> DLL_PROCESS_ATTACH. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> private static void CallMappedDLLModule(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { IntPtr lpEntryPoint = PEINFO.Is32Bit ? (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader32.AddressOfEntryPoint) : (IntPtr)((UInt64)ModuleMemoryBase + PEINFO.OptHeader64.AddressOfEntryPoint); DllMain fDllMain = (DllMain)Marshal.GetDelegateForFunctionPointer(lpEntryPoint, typeof(DllMain)); bool CallRes = fDllMain(ModuleMemoryBase, DLL_PROCESS_ATTACH, IntPtr.Zero); if (!CallRes) { throw new Exception(DSTR(DSTR_DINVOKE_MAIN_FAILED)); } }
/// <summary> /// Call a manually mapped DLL by Export. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <param name="ExportName">The name of the export to search for (e.g. "NtAlertResumeThread").</param> /// <param name="FunctionDelegateType">Prototype for the function, represented as a Delegate object.</param> /// <param name="Parameters">Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference.</param> /// <param name="CallEntry">Specify whether to invoke the module's entry point.</param> /// <returns>void</returns> public static object CallMappedDLLModuleExport(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string ExportName, Type FunctionDelegateType, ref object[] Parameters, bool CallEntry = true) { // Call entry point if user has specified if (CallEntry) { CallMappedDLLModule(PEINFO, ModuleMemoryBase); } // Get export pointer IntPtr pFunc = ModuleMapper.GetExportAddress(ModuleMemoryBase, ExportName); // Call export return(DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters)); }
/// <summary> /// Set correct module section permissions. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> public static void SetModuleSectionPermissions(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { // Apply RO to the module header IntPtr BaseOfCode = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.BaseOfCode : (IntPtr)PEINFO.OptHeader64.BaseOfCode; Native.NtProtectVirtualMemoryD((IntPtr)(-1), ref ModuleMemoryBase, ref BaseOfCode, Native.PAGE_READONLY); // Apply section permissions foreach (IMAGE_SECTION_HEADER ish in PEINFO.Sections) { bool isRead = (ish.Characteristics & DataSectionFlags.MEM_READ) != 0; bool isWrite = (ish.Characteristics & DataSectionFlags.MEM_WRITE) != 0; bool isExecute = (ish.Characteristics & DataSectionFlags.MEM_EXECUTE) != 0; uint flNewProtect = 0; if (isRead & !isWrite & !isExecute) { flNewProtect = Native.PAGE_READONLY; } else if (isRead & isWrite & !isExecute) { flNewProtect = Native.PAGE_READWRITE; } else if (isRead & isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE_READWRITE; } else if (isRead & !isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE_READ; } else if (!isRead & !isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE; } else { throw new Exception(DSTR(DSTR_UNK_SEC_FLAG, ish.Characteristics)); } // Calculate base IntPtr pVirtualSectionBase = (IntPtr)((UInt64)ModuleMemoryBase + ish.VirtualAddress); IntPtr ProtectSize = (IntPtr)ish.VirtualSize; // Set protection Native.NtProtectVirtualMemoryD((IntPtr)(-1), ref pVirtualSectionBase, ref ProtectSize, flNewProtect); } }
/// <summary> /// Set correct module section permissions. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external ProcessEx) /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> public void MMSetModuleSectionPermissions(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, byte[] rawData) { // Apply RO to the module header IntPtr BaseOfCode = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.BaseOfCode : (IntPtr)PEINFO.OptHeader64.BaseOfCode; NativeStealth.VirtualProtectEx(Handle, ModuleMemoryBase, BaseOfCode.ToInt32(), (int)Native.PAGE_READONLY, out _); // Apply section permissions foreach (IMAGE_SECTION_HEADER ish in PEINFO.Sections) { bool isRead = (ish.Characteristics & DataSectionFlags.MEM_READ) != 0; bool isWrite = (ish.Characteristics & DataSectionFlags.MEM_WRITE) != 0; bool isExecute = (ish.Characteristics & DataSectionFlags.MEM_EXECUTE) != 0; uint flNewProtect = 0; if (isRead & !isWrite & !isExecute) { flNewProtect = Native.PAGE_READONLY; } else if (isRead & isWrite & !isExecute) { flNewProtect = Native.PAGE_READWRITE; } else if (isRead & isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE_READWRITE; } else if (isRead & !isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE_READ; } else if (!isRead & !isWrite & isExecute) { flNewProtect = Native.PAGE_EXECUTE; } else { throw new InvalidOperationException(DSTR(DSTR_UNK_SEC_FLAG, ish.Characteristics)); } // Calculate base IntPtr pVirtualSectionBase = (IntPtr)((UInt64)ModuleMemoryBase + ish.VirtualAddress); IntPtr ProtectSize = (IntPtr)ish.VirtualSize; // Set protection NativeStealth.VirtualProtectEx(Handle, pVirtualSectionBase, ProtectSize.ToInt32(), (int)flNewProtect, out _); } }
/// <summary> /// Retrieve PE header information from the module base pointer. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="pModule">Pointer to the module base.</param> /// <returns>PE.PE_META_DATA</returns> public static PE_META_DATA GetPeMetaData(IntPtr pModule) { PE_META_DATA PeMetaData = new PE_META_DATA(); try { UInt32 e_lfanew = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + 0x3c)); PeMetaData.Pe = (UInt32)Marshal.ReadInt32((IntPtr)((UInt64)pModule + e_lfanew)); // Validate PE signature if (PeMetaData.Pe != 0x4550) { throw new InvalidOperationException("Invalid PE signature."); } PeMetaData.ImageFileHeader = (IMAGE_FILE_HEADER)Marshal.PtrToStructure((IntPtr)((UInt64)pModule + e_lfanew + 0x4), typeof(IMAGE_FILE_HEADER)); IntPtr OptHeader = (IntPtr)((UInt64)pModule + e_lfanew + 0x18); UInt16 PEArch = (UInt16)Marshal.ReadInt16(OptHeader); // Validate PE arch if (PEArch == 0x010b) // Image is x32 { PeMetaData.Is32Bit = true; PeMetaData.OptHeader32 = (IMAGE_OPTIONAL_HEADER32)Marshal.PtrToStructure(OptHeader, typeof(IMAGE_OPTIONAL_HEADER32)); } else if (PEArch == 0x020b) // Image is x64 { PeMetaData.Is32Bit = false; PeMetaData.OptHeader64 = (IMAGE_OPTIONAL_HEADER64)Marshal.PtrToStructure(OptHeader, typeof(IMAGE_OPTIONAL_HEADER64)); } else { throw new InvalidOperationException("Invalid magic value (PE32/PE32+)."); } // Read sections IMAGE_SECTION_HEADER[] SectionArray = new IMAGE_SECTION_HEADER[PeMetaData.ImageFileHeader.NumberOfSections]; for (int i = 0; i < PeMetaData.ImageFileHeader.NumberOfSections; i++) { IntPtr SectionPtr = (IntPtr)((UInt64)OptHeader + PeMetaData.ImageFileHeader.SizeOfOptionalHeader + (UInt32)(i * 0x28)); SectionArray[i] = (IMAGE_SECTION_HEADER)Marshal.PtrToStructure(SectionPtr, typeof(IMAGE_SECTION_HEADER)); } PeMetaData.Sections = SectionArray; } catch { throw new InvalidOperationException("Invalid module base specified."); } return(PeMetaData); }
/// <summary> /// Manually map module into current process. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external) /// <param name="pModule">Pointer to the module base.</param> /// <returns>PE_MANUAL_MAP object</returns> private static PE_MANUAL_MAP MapModuleToMemory(PointerEx pModule) { // Fetch PE meta data PE_META_DATA PEINFO = GetPeMetaData(pModule); // Check module matches the process architecture if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4)) { Marshal.FreeHGlobal(pModule); throw new Exception(DSTR(DSTR_MOD_ARCHITECTURE_WRONG)); } // Alloc PE image memory -> RW IntPtr BaseAddress = IntPtr.Zero; IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; IntPtr pImage = Native.NtAllocateVirtualMemoryD( (IntPtr)(-1), ref BaseAddress, IntPtr.Zero, ref RegionSize, Native.AllocationType.Commit | Native.AllocationType.Reserve, Native.PAGE_READWRITE ); return(MapModuleToMemory(pModule, pImage, PEINFO)); }
/// <summary> /// Manually map module into remote process. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external ProcessEx) /// <param name="localModuleHandle">Pointer to the module base.</param> /// <returns>PE_MANUAL_MAP object</returns> private PE_MANUAL_MAP MapModuleToMemory(PointerEx localModuleHandle, byte[] moduleRaw) { #if DEBUG DLog($"Attempting to map module of size {moduleRaw.Length}"); #endif // Fetch PE meta data PE_META_DATA PEINFO = GetPeMetaData(localModuleHandle); // Check module matches the process architecture if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4)) { Marshal.FreeHGlobal(localModuleHandle); throw new InvalidOperationException(DSTR(DSTR_MOD_ARCHITECTURE_WRONG)); } // Alloc PE image memory -> RW IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; IntPtr remoteModuleHandle = QuickAlloc(RegionSize); #if DEBUG DLog($"Module memory allocated at 0x{remoteModuleHandle.ToInt64():X16}"); #endif return(__MapModuleToMemory(localModuleHandle, remoteModuleHandle, moduleRaw, PEINFO)); }
/// <summary> /// Rewrite IAT for manually mapped module. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external) /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> private static void RewriteModuleIAT(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { IMAGE_DATA_DIRECTORY idd = PEINFO.Is32Bit ? PEINFO.OptHeader32.ImportTable : PEINFO.OptHeader64.ImportTable; // Check if there is no import table if (idd.VirtualAddress == 0) { // Return so that the rest of the module mapping process may continue. return; } // Ptr for the base import directory IntPtr pImportTable = (IntPtr)((UInt64)ModuleMemoryBase + idd.VirtualAddress); // Get API Set mapping dictionary if on Win10+ Native.OSVERSIONINFOEX OSVersion = new Native.OSVERSIONINFOEX(); Native.RtlGetVersionD(ref OSVersion); if (OSVersion.MajorVersion < 10) { throw new Exception(DSTR(DSTR_OS_VERSION_TOO_OLD)); } // Loop IID's int counter = 0; Native.IMAGE_IMPORT_DESCRIPTOR iid = new Native.IMAGE_IMPORT_DESCRIPTOR(); iid = (Native.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Native.IMAGE_IMPORT_DESCRIPTOR) ); while (iid.Name != 0) { // Get DLL string DllName = string.Empty; try { DllName = Marshal.PtrToStringAnsi((IntPtr)((UInt64)ModuleMemoryBase + iid.Name)); } catch { } // Loop imports if (DllName == string.Empty) { throw new Exception(DSTR(DSTR_MODULE_NAME_INVALID)); } else { // API Set DLL? string dll_resolved; if ((DllName.StartsWith("api-") || DllName.StartsWith("ext-"))) { // for some reason, Lunar's resolve apiset is 1000x better than the dictionary setup done in dinvoke, so we will just use that. // lmfao: https://github.com/cobbr/SharpSploit/issues/58 if ((dll_resolved = EnvironmentEx.ResolveAPISet(DllName)) == null) { throw new Exception(DSTR(DSTR_API_DLL_UNRESOLVED, DllName)); } // Not all API set DLL's have a registered host mapping DllName = dll_resolved; } // Check and / or load DLL IntPtr hModule = GetLoadedModuleAddress(DllName); if (hModule == IntPtr.Zero) { hModule = LoadModuleFromDisk(DllName); if (hModule == IntPtr.Zero) { throw new Exception(DSTR(DSTR_MODULE_FILE_NOT_FOUND, DllName)); } } // Loop thunks if (PEINFO.Is32Bit) { IMAGE_THUNK_DATA32 oft_itd; for (int i = 0; true; i++) { oft_itd = (IMAGE_THUNK_DATA32)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt32)(i * (sizeof(UInt32)))), typeof(IMAGE_THUNK_DATA32)); IntPtr ft_itd = (IntPtr)((UInt64)ModuleMemoryBase + iid.FirstThunk + (UInt64)(i * (sizeof(UInt32)))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x80000000) // !IMAGE_ORDINAL_FLAG32 { IntPtr pImpByName = (IntPtr)((UInt64)ModuleMemoryBase + oft_itd.AddressOfData + sizeof(UInt16)); IntPtr pFunc; pFunc = GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); // Write ProcAddress Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; IntPtr pFunc; pFunc = GetNativeExportAddress(hModule, (short)fOrdinal); // Write ProcAddress Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } } } else { IMAGE_THUNK_DATA64 oft_itd; for (int i = 0; true; i++) { oft_itd = (IMAGE_THUNK_DATA64)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt64)(i * (sizeof(UInt64)))), typeof(IMAGE_THUNK_DATA64)); IntPtr ft_itd = (IntPtr)((UInt64)ModuleMemoryBase + iid.FirstThunk + (UInt64)(i * (sizeof(UInt64)))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x8000000000000000) // !IMAGE_ORDINAL_FLAG64 { IntPtr pImpByName = (IntPtr)((UInt64)ModuleMemoryBase + oft_itd.AddressOfData + sizeof(UInt16)); IntPtr pFunc; pFunc = GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); // Write pointer Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; IntPtr pFunc; pFunc = GetNativeExportAddress(hModule, (short)fOrdinal); // Write pointer Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } } } counter++; iid = (Native.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Native.IMAGE_IMPORT_DESCRIPTOR) ); } } }
/// <summary> /// Manually map module into current process. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="rawModule">Pointer to the module base.</param> /// <param name="allocatedModule">Pointer to the PEINFO image.</param> /// <param name="PEINFO">PE_META_DATA of the module being mapped.</param> /// <returns>PE_MANUAL_MAP object</returns> private static PE_MANUAL_MAP MapModuleToMemory(IntPtr rawModule, IntPtr allocatedModule, PE_META_DATA PEINFO) { // Check module matches the process architecture if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4)) { Marshal.FreeHGlobal(rawModule); throw new Exception(DSTR(DSTR_MOD_ARCHITECTURE_WRONG)); } // Write PE header to memory UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders; UInt32 BytesWritten; Native.NtWriteVirtualMemoryD((IntPtr)(-1), allocatedModule, rawModule, SizeOfHeaders); // Write sections to memory foreach (IMAGE_SECTION_HEADER ish in PEINFO.Sections) { // Calculate offsets IntPtr pVirtualSectionBase = (IntPtr)((UInt64)allocatedModule + ish.VirtualAddress); IntPtr pRawSectionBase = (IntPtr)((UInt64)rawModule + ish.PointerToRawData); // Write data BytesWritten = Native.NtWriteVirtualMemoryD((IntPtr)(-1), pVirtualSectionBase, pRawSectionBase, ish.SizeOfRawData); if (BytesWritten != ish.SizeOfRawData) { throw new Exception(DSTR(DSTR_FAILED_MEMORY_WRITE)); } } // Perform relocations RelocateModule(PEINFO, allocatedModule); // Rewrite IAT RewriteModuleIAT(PEINFO, allocatedModule); // Set memory protections SetModuleSectionPermissions(PEINFO, allocatedModule); // Free temp HGlobal Marshal.FreeHGlobal(rawModule); // Prepare return object PE_MANUAL_MAP ManMapObject = new PE_MANUAL_MAP { ModuleBase = allocatedModule, PEINFO = PEINFO }; return(ManMapObject); }
/// <summary> /// Manually map module into remote process. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external ProcessEx) /// <param name="localModuleHandle">Pointer to the module base.</param> /// <param name="remoteModuleHandle">Pointer to the PEINFO image.</param> /// <param name="PEINFO">PE_META_DATA of the module being mapped.</param> /// <returns>PE_MANUAL_MAP object</returns> private PE_MANUAL_MAP __MapModuleToMemory(IntPtr localModuleHandle, IntPtr remoteModuleHandle, byte[] moduleRaw, PE_META_DATA PEINFO) { // Check module matches the process architecture if ((PEINFO.Is32Bit && IntPtr.Size == 8) || (!PEINFO.Is32Bit && IntPtr.Size == 4)) { Marshal.FreeHGlobal(localModuleHandle); throw new InvalidOperationException(DSTR(DSTR_MOD_ARCHITECTURE_WRONG)); } // Write PE header to memory UInt32 SizeOfHeaders = PEINFO.Is32Bit ? PEINFO.OptHeader32.SizeOfHeaders : PEINFO.OptHeader64.SizeOfHeaders; IntPtr RegionSize = PEINFO.Is32Bit ? (IntPtr)PEINFO.OptHeader32.SizeOfImage : (IntPtr)PEINFO.OptHeader64.SizeOfImage; byte[] moduleRemote = new byte[RegionSize.ToInt32()]; moduleRaw.Take((int)SizeOfHeaders).ToArray().CopyTo(moduleRemote, 0); #if DEBUG DLog($"PE Header written at 0x{remoteModuleHandle.ToInt64():X16}"); #endif // Write sections to memory foreach (IMAGE_SECTION_HEADER ish in PEINFO.Sections) { // Calculate offsets IntPtr pVirtualSectionBase = (IntPtr)(ish.VirtualAddress); moduleRaw.Skip((int)ish.PointerToRawData).Take((int)ish.SizeOfRawData).ToArray().CopyTo(moduleRemote, pVirtualSectionBase.ToInt32()); #if DEBUG DLog($"{new string(ish.Name).Trim().Replace('\x00'.ToString(), "")} written at 0x{pVirtualSectionBase.ToInt64():X16}, Size: 0x{ish.SizeOfRawData:X8}"); #endif } // Perform relocations __MMRelocateModule(PEINFO, remoteModuleHandle, moduleRaw, moduleRemote); // Rewrite IAT __MMRewriteModuleIAT(PEINFO, remoteModuleHandle, moduleRaw, moduleRemote); // Write the module to memory SetBytes(remoteModuleHandle, moduleRemote); // Set memory protections MMSetModuleSectionPermissions(PEINFO, remoteModuleHandle, moduleRaw); // Free temp HGlobal Marshal.FreeHGlobal(localModuleHandle); // Prepare return object PE_MANUAL_MAP ManMapObject = new PE_MANUAL_MAP { ModuleBase = remoteModuleHandle, PEINFO = PEINFO }; return(ManMapObject); }
/// <summary> /// Rewrite IAT for manually mapped remote module. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> (modified for external ProcessEx) /// <param name="PEINFO">Module meta data struct (PE.PE_META_DATA).</param> /// <param name="ModuleMemoryBase">Base address of the module in memory.</param> /// <returns>void</returns> private void __MMRewriteModuleIAT(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, byte[] moduleRaw, byte[] moduleRemote) { IMAGE_DATA_DIRECTORY idd = PEINFO.Is32Bit ? PEINFO.OptHeader32.ImportTable : PEINFO.OptHeader64.ImportTable; // Check if there is no import table if (idd.VirtualAddress == 0) { // Return so that the rest of the module mapping process may continue. return; } // Ptr for the base import directory IntPtr pImportTable = (IntPtr)(idd.VirtualAddress); // Get API Set mapping dictionary if on Win10+ Native.OSVERSIONINFOEX OSVersion = new Native.OSVERSIONINFOEX(); Native.RtlGetVersionD(ref OSVersion); if (OSVersion.MajorVersion < 10) { throw new Exception(DSTR(DSTR_OS_VERSION_TOO_OLD)); } #if DEBUG DLog($"Starting IAT rewrite..."); #endif // Loop IID's int counter = 0; Native.IMAGE_IMPORT_DESCRIPTOR iid = new Native.IMAGE_IMPORT_DESCRIPTOR(); iid = moduleRemote.Skip(pImportTable.ToInt32() + (int)(Marshal.SizeOf(typeof(Native.IMAGE_IMPORT_DESCRIPTOR)) * counter)).Take(Marshal.SizeOf(typeof(Native.IMAGE_IMPORT_DESCRIPTOR))).ToArray().ToStruct <Native.IMAGE_IMPORT_DESCRIPTOR>(); while (iid.Name != 0) { // Get DLL string DllName = string.Empty; try { DllName = moduleRemote.String((int)iid.Name); } catch { } // Loop imports if (DllName == string.Empty) { throw new Exception(DSTR(DSTR_MODULE_NAME_INVALID)); } else { // API Set DLL? string dll_resolved; if ((DllName.StartsWith("api-") || DllName.StartsWith("ext-"))) { // for some reason, Lunar's resolve apiset is 1000x better than the dictionary setup done in dinvoke, so we will just use that. // lmfao: https://github.com/cobbr/SharpSploit/issues/58 if ((dll_resolved = ResolveAPISet(DllName)) == null) { throw new Exception(DSTR(DSTR_API_DLL_UNRESOLVED, DllName)); } // Not all API set DLL's have a registered host mapping DllName = dll_resolved; } #if DEBUG DLog($"Resolving {DllName}..."); #endif // Check and / or load DLL IntPtr hModule = GetLoadedModuleAddress(DllName); if (hModule == IntPtr.Zero) { #if DEBUG DLog($"Unresolved: {DllName}, Loading into memory..."); #endif hModule = LoadAndRegisterDllRemote(DllName).BaseAddress; if (hModule == IntPtr.Zero) { throw new Exception(DSTR(DSTR_MODULE_FILE_NOT_FOUND, DllName)); } } // Locate the module by its base address ProcessModuleEx sModule = FindModuleByAddress(hModule); #if DEBUG DLog($"Resolved Module: {sModule.ModuleName}:{sModule.BaseAddress:X}, {sModule.ModulePath}"); #endif // Loop thunks if (PEINFO.Is32Bit) { IMAGE_THUNK_DATA32 oft_itd = new IMAGE_THUNK_DATA32(); for (int i = 0; true; i++) { oft_itd = moduleRemote.Skip((int)(iid.OriginalFirstThunk + (UInt32)(i * (sizeof(UInt32))))).Take(4).ToArray().ToStruct <IMAGE_THUNK_DATA32>(); IntPtr ft_itd = (IntPtr)((UInt64)iid.FirstThunk + (UInt64)(i * (sizeof(UInt32)))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x80000000) // !IMAGE_ORDINAL_FLAG32 { uint pImpByName = (uint)((uint)oft_itd.AddressOfData + sizeof(UInt16)); var pFunc = GetProcAddress(sModule.ModuleName, moduleRemote.String((int)pImpByName)); // Write ProcAddress BitConverter.GetBytes((int)pFunc).CopyTo(moduleRemote, ft_itd.ToInt32()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; var pFunc = GetModuleExportAddress(sModule.ModuleName, (short)fOrdinal); // Write ProcAddress BitConverter.GetBytes((int)pFunc).CopyTo(moduleRemote, ft_itd.ToInt32()); } } } else { IMAGE_THUNK_DATA64 oft_itd = new IMAGE_THUNK_DATA64(); for (int i = 0; true; i++) { oft_itd = moduleRemote.Skip((int)(iid.OriginalFirstThunk + (uint)(i * sizeof(ulong)))).Take(8).ToArray().ToStruct <IMAGE_THUNK_DATA64>(); IntPtr ft_itd = (IntPtr)((UInt64)iid.FirstThunk + (UInt64)(i * (sizeof(UInt64)))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x8000000000000000) // !IMAGE_ORDINAL_FLAG64 { uint pImpByName = (uint)((uint)oft_itd.AddressOfData + sizeof(UInt16)); var pFunc = GetProcAddress(sModule.ModuleName, moduleRemote.String((int)pImpByName)); // Write pointer BitConverter.GetBytes((long)pFunc).CopyTo(moduleRemote, ft_itd.ToInt32()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; var pFunc = GetModuleExportAddress(sModule.ModuleName, (short)fOrdinal); // Write pointer BitConverter.GetBytes((long)pFunc).CopyTo(moduleRemote, ft_itd.ToInt32()); } } } counter++; iid = moduleRemote.Skip(pImportTable.ToInt32() + (int)(Marshal.SizeOf(typeof(Native.IMAGE_IMPORT_DESCRIPTOR)) * counter)).Take(Marshal.SizeOf(typeof(Native.IMAGE_IMPORT_DESCRIPTOR))).ToArray().ToStruct <Native.IMAGE_IMPORT_DESCRIPTOR>(); } } }