/// <summary> /// Rewrite IAT for manually mapped module. /// </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 RewriteModuleIAT(Data.PE.PE_META_DATA peMetaData, IntPtr moduleMemoryBase) { var idd = peMetaData.Is32Bit ? peMetaData.OptHeader32.ImportTable : peMetaData.OptHeader64.ImportTable; if (idd.VirtualAddress == 0) { return; } var pImportTable = (IntPtr)((ulong)moduleMemoryBase + idd.VirtualAddress); var osVersion = new Data.Native.OSVERSIONINFOEX(); Native.RtlGetVersion(ref osVersion); var apiSetDict = new Dictionary <string, string>(); if (osVersion.MajorVersion >= 10) { apiSetDict = Generic.GetApiSetMapping(); } var counter = 0; var iid = new Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR(); iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((ulong)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR) ); while (iid.Name != 0) { var dllName = string.Empty; try { dllName = Marshal.PtrToStringAnsi((IntPtr)((ulong)moduleMemoryBase + iid.Name)); } catch { // ignore } if (dllName == string.Empty) { throw new InvalidOperationException("Failed to read DLL name."); } var lookupKey = dllName !.Substring(0, dllName.Length - 6) + ".dll"; if (osVersion.MajorVersion >= 10 && (dllName.StartsWith("api-") || dllName.StartsWith("ext-")) && apiSetDict.ContainsKey(lookupKey) && apiSetDict[lookupKey].Length > 0) { dllName = apiSetDict[lookupKey]; } var hModule = Generic.GetLoadedModuleAddress(dllName); if (hModule == IntPtr.Zero) { hModule = Generic.LoadModuleFromDisk(dllName); if (hModule == IntPtr.Zero) { throw new FileNotFoundException(dllName + ", unable to find the specified file."); } } if (peMetaData.Is32Bit) { var oft_itd = new Data.PE.IMAGE_THUNK_DATA32(); for (var i = 0;; i++) { oft_itd = (Data.PE.IMAGE_THUNK_DATA32)Marshal.PtrToStructure( (IntPtr)((ulong)moduleMemoryBase + iid.OriginalFirstThunk + (uint)(i * sizeof(uint))), typeof(Data.PE.IMAGE_THUNK_DATA32)); var ft_itd = (IntPtr)((ulong)moduleMemoryBase + iid.FirstThunk + (ulong)(i * sizeof(uint))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x80000000) { var pImpByName = (IntPtr)((ulong)moduleMemoryBase + oft_itd.AddressOfData + sizeof(ushort)); var pFunc = IntPtr.Zero; pFunc = Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; var pFunc = IntPtr.Zero; pFunc = Generic.GetNativeExportAddress(hModule, (short)fOrdinal); Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } } } else { var oft_itd = new Data.PE.IMAGE_THUNK_DATA64(); for (var i = 0;; i++) { oft_itd = (Data.PE.IMAGE_THUNK_DATA64)Marshal.PtrToStructure( (IntPtr)((ulong)moduleMemoryBase + iid.OriginalFirstThunk + (ulong)(i * sizeof(ulong))), typeof(Data.PE.IMAGE_THUNK_DATA64)); var ft_itd = (IntPtr)((ulong)moduleMemoryBase + iid.FirstThunk + (ulong)(i * sizeof(ulong))); if (oft_itd.AddressOfData == 0) { break; } if (oft_itd.AddressOfData < 0x8000000000000000) // !IMAGE_ORDINAL_FLAG64 { var pImpByName = (IntPtr)((ulong)moduleMemoryBase + oft_itd.AddressOfData + sizeof(ushort)); var pFunc = IntPtr.Zero; pFunc = Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } else { var fOrdinal = oft_itd.AddressOfData & 0xFFFF; var pFunc = IntPtr.Zero; pFunc = Generic.GetNativeExportAddress(hModule, (short)fOrdinal); Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } } } counter++; iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((ulong)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR) ); } }
/// <summary> /// Rewrite IAT for manually mapped module. /// </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 RewriteModuleIAT(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase) { Data.PE.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+ Data.Native.OSVERSIONINFOEX OSVersion = new Data.Native.OSVERSIONINFOEX(); DynamicInvoke.Native.RtlGetVersion(ref OSVersion); Dictionary <string, string> ApiSetDict = new Dictionary <string, string>(); if (OSVersion.MajorVersion >= 10) { ApiSetDict = DynamicInvoke.Generic.GetApiSetMapping(); } // Loop IID's int counter = 0; Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR iid = new Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR(); iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Data.Win32.Kernel32.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 InvalidOperationException("Failed to read DLL name."); } else { // API Set DLL? if (OSVersion.MajorVersion >= 10 && (DllName.StartsWith("api-") || DllName.StartsWith("ext-")) && ApiSetDict.ContainsKey(DllName) && ApiSetDict[DllName].Length > 0) { // Not all API set DLL's have a registered host mapping DllName = ApiSetDict[DllName]; } // Check and / or load DLL IntPtr hModule = DynamicInvoke.Generic.GetLoadedModuleAddress(DllName); if (hModule == IntPtr.Zero) { hModule = DynamicInvoke.Generic.LoadModuleFromDisk(DllName); if (hModule == IntPtr.Zero) { throw new FileNotFoundException(DllName + ", unable to find the specified file."); } } // Loop thunks if (PEINFO.Is32Bit) { Data.PE.IMAGE_THUNK_DATA32 oft_itd = new Data.PE.IMAGE_THUNK_DATA32(); for (int i = 0; true; i++) { oft_itd = (Data.PE.IMAGE_THUNK_DATA32)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt32)(i * (sizeof(UInt32)))), typeof(Data.PE.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 = IntPtr.Zero; pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); // Write ProcAddress Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; IntPtr pFunc = IntPtr.Zero; pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, (short)fOrdinal); // Write ProcAddress Marshal.WriteInt32(ft_itd, pFunc.ToInt32()); } } } else { Data.PE.IMAGE_THUNK_DATA64 oft_itd = new Data.PE.IMAGE_THUNK_DATA64(); for (int i = 0; true; i++) { oft_itd = (Data.PE.IMAGE_THUNK_DATA64)Marshal.PtrToStructure((IntPtr)((UInt64)ModuleMemoryBase + iid.OriginalFirstThunk + (UInt64)(i * (sizeof(UInt64)))), typeof(Data.PE.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 = IntPtr.Zero; pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, Marshal.PtrToStringAnsi(pImpByName)); // Write pointer Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } else { ulong fOrdinal = oft_itd.AddressOfData & 0xFFFF; IntPtr pFunc = IntPtr.Zero; pFunc = DynamicInvoke.Generic.GetNativeExportAddress(hModule, (short)fOrdinal); // Write pointer Marshal.WriteInt64(ft_itd, pFunc.ToInt64()); } } } counter++; iid = (Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR)Marshal.PtrToStructure( (IntPtr)((UInt64)pImportTable + (uint)(Marshal.SizeOf(iid) * counter)), typeof(Data.Win32.Kernel32.IMAGE_IMPORT_DESCRIPTOR) ); } } }