/// <summary> /// Relocates a module in remote memory. /// </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 __MMRelocateModule(PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, byte[] moduleRaw, byte[] moduleRemote) { 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)(idd.VirtualAddress); Int32 nextRelocTableBlock = -1; // Loop reloc blocks while (nextRelocTableBlock != 0) { IMAGE_BASE_RELOCATION ibr = new IMAGE_BASE_RELOCATION(); ibr = moduleRemote.Skip(pRelocTable.ToInt32()).Take(Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION))).ToArray().ToStruct <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)BitConverter.ToUInt16(moduleRemote, pRelocEntry.ToInt32()); // 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)(ibr.VirtualAdress + RelocPatch); if (RelocType == 0x3) // IMAGE_REL_BASED_HIGHLOW (x86) { Int32 OriginalPtr = BitConverter.ToInt32(moduleRemote, pPatch.ToInt32()); BitConverter.GetBytes((OriginalPtr + (Int32)ImageDelta)).CopyTo(moduleRemote, pPatch.ToInt32()); } else // IMAGE_REL_BASED_DIR64 (x64) { Int64 OriginalPtr = BitConverter.ToInt64(moduleRemote, pPatch.ToInt32()); BitConverter.GetBytes((OriginalPtr + ImageDelta)).CopyTo(moduleRemote, pPatch.ToInt32()); } } catch { throw new Exception(DSTR(DSTR_MEM_ACCESS_VIOLATION)); } } } // Check for next block pRelocTable = (IntPtr)((UInt64)pRelocTable + ibr.SizeOfBlock); nextRelocTableBlock = BitConverter.ToInt32(moduleRemote, pRelocTable.ToInt32()); } }
private int GetModuleCount(IntPtr codeBase, IMAGE_DATA_DIRECTORY directory) { int result = 0; if (directory.Size > 0) { IMAGE_IMPORT_DESCRIPTOR importDesc = codeBase.ToStruct<IMAGE_IMPORT_DESCRIPTOR>(directory.VirtualAddress); while (importDesc.Name > 0) { string moduleName = Marshal.PtrToStringAnsi(codeBase.Add(importDesc.Name)); if (Native.LoadLibrary(moduleName) == IntPtr.Zero) break; result++; importDesc = codeBase.ToStruct<IMAGE_IMPORT_DESCRIPTOR>((uint)(directory.VirtualAddress + (Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * result))); } } return result; }
private void PerformBaseRelocation64(ulong delta) { //ConsoleWindow.WriteLine("PerformBaseRelocation: Delta="+delta); IntPtr codeBase = module64.codeBase; int sizeOfBase = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY directory = module64.headers.OptionalHeader.BaseRelocationTable; int cnt = 0; if (directory.Size > 0) { var relocation = codeBase.ToStruct<IMAGE_BASE_RELOCATION>(directory.VirtualAddress); while (relocation.VirtualAddress > 0) { unsafe { var dest = (IntPtr)(codeBase.ToInt32() + (int)relocation.VirtualAddress); var relInfo = (ushort*)(codeBase.ToInt32() + (int)directory.VirtualAddress + sizeOfBase); uint i; for (i = 0; i < ((relocation.SizeOfBlock - Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION))) / 2); i++, relInfo++) { int type = *relInfo >> 12; int offset = (*relInfo & 0xfff); switch (type) { case 0x00: break; case 0x03: uint* patchAddrHl = (uint*)((int)dest + offset); *patchAddrHl += (uint)delta; break; case 0x0A: ulong* patchAddrDIR64 = (ulong*)((long)dest + offset); *patchAddrDIR64 += delta; break; } } } cnt += (int)relocation.SizeOfBlock; relocation = codeBase.ToStruct<IMAGE_BASE_RELOCATION>((uint)(directory.VirtualAddress + cnt)); } } }
private void BuildImportTable64(MEMORYMODULE64 module64) { int moduleCount = 0; IntPtr codeBase = module64.codeBase; IMAGE_DATA_DIRECTORY directory = module64.headers.OptionalHeader.ImportTable; if (directory.Size > 0) { //Log.Console("ImportTable.Size: "+ directory.Size); ulong* nameRef, funcRef; IMAGE_IMPORT_DESCRIPTOR importDesc = codeBase.ToStruct<IMAGE_IMPORT_DESCRIPTOR>(directory.VirtualAddress); while (importDesc.Name > 0) { string moduleName = Marshal.PtrToStringAnsi(codeBase.Add(importDesc.Name)); //Log.Console("Import Module: " + moduleName); IntPtr handle = Native.LoadLibrary(moduleName); if (handle == IntPtr.Zero) break; if (importDesc.CharacteristicsOrOriginalFirstThunk > 0) { nameRef = (ulong*)codeBase.Add(importDesc.CharacteristicsOrOriginalFirstThunk); funcRef = (ulong*)codeBase.Add(importDesc.FirstThunk); } else { nameRef = (ulong*)codeBase.Add(importDesc.FirstThunk); funcRef = (ulong*)codeBase.Add(importDesc.FirstThunk); } for (; *nameRef > 0; nameRef++, funcRef++) { //Log.Console("Import: " + nameRef->ToString("X16") + ", 0x" + funcRef->ToString("x16")); if ((*nameRef & 0x8000000000000000) != 0) { *funcRef = (ulong)Native.GetProcAddress(handle, new IntPtr((long)*nameRef & 0xffff)); } else { string functionName = Marshal.PtrToStringAnsi(codeBase.Add((long)(*nameRef) + 2)); *funcRef = (ulong)Native.GetProcAddress(handle, functionName); //Log.Console("Import Function: " + functionName + " -> 0x" + funcRef->ToString("x16")); } //Log.Console("Import nameRef: 0x" + nameRef->ToString("X16")); //Log.Console("Import funcRef: 0x" + funcRef->ToString("X16")); if (*funcRef == 0) { break; } } moduleCount++; importDesc = codeBase.ToStruct<IMAGE_IMPORT_DESCRIPTOR>(directory.VirtualAddress + (uint)(Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * moduleCount)); } } }
/// <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>(); } } }