/// <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> public static void RelocateModule(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { Data.PE.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) { Data.PE.IMAGE_BASE_RELOCATION ibr = new Data.PE.IMAGE_BASE_RELOCATION(); ibr = (Data.PE.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(pRelocTable, typeof(Data.PE.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 InvalidOperationException("Memory access violation."); } } } // Check for next block pRelocTable = (IntPtr)((UInt64)pRelocTable + ibr.SizeOfBlock); nextRelocTableBlock = Marshal.ReadInt32(pRelocTable); } }
/// <summary> /// Relocates a module in memory. /// </summary> /// <author>Ruben Boonen (@FuzzySec)</author> /// <param name="peMetaData">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 RelocateModule(Data.PE.PE_META_DATA peMetaData, IntPtr moduleMemoryBase) { var idd = peMetaData.Is32Bit ? peMetaData.OptHeader32.BaseRelocationTable : peMetaData.OptHeader64.BaseRelocationTable; var imageDelta = peMetaData.Is32Bit ? (long)((ulong)moduleMemoryBase - peMetaData.OptHeader32.ImageBase) : (long)((ulong)moduleMemoryBase - peMetaData.OptHeader64.ImageBase); var pRelocTable = (IntPtr)((ulong)moduleMemoryBase + idd.VirtualAddress); var nextRelocTableBlock = -1; while (nextRelocTableBlock != 0) { var ibr = new Data.PE.IMAGE_BASE_RELOCATION(); ibr = (Data.PE.IMAGE_BASE_RELOCATION)Marshal.PtrToStructure(pRelocTable, typeof(Data.PE.IMAGE_BASE_RELOCATION)); var relocCount = (ibr.SizeOfBlock - Marshal.SizeOf(ibr)) / 2; for (var i = 0; i < relocCount; i++) { var pRelocEntry = (IntPtr)((ulong)pRelocTable + (ulong)Marshal.SizeOf(ibr) + (ulong)(i * 2)); var relocValue = (ushort)Marshal.ReadInt16(pRelocEntry); var relocType = (ushort)(relocValue >> 12); var relocPatch = (ushort)(relocValue & 0xfff); if (relocType == 0) { continue; } try { var pPatch = (IntPtr)((ulong)moduleMemoryBase + ibr.VirtualAdress + relocPatch); if (relocType == 0x3) { var originalPtr = Marshal.ReadInt32(pPatch); Marshal.WriteInt32(pPatch, originalPtr + (int)imageDelta); } else { var originalPtr = Marshal.ReadInt64(pPatch); Marshal.WriteInt64(pPatch, originalPtr + imageDelta); } } catch { throw new InvalidOperationException("Memory access violation."); } } pRelocTable = (IntPtr)((ulong)pRelocTable + ibr.SizeOfBlock); nextRelocTableBlock = Marshal.ReadInt32(pRelocTable); } }