private IEnumerable <HarmonyImportLibrary> ResolveImports(Image image) { IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->ImportTable : image.OptionalHeader32->ImportTable; if (directory.Size == 0 || (_loadFlags & HarmonyLoadFlags.NoImports) != 0) { return(Enumerable.Empty <HarmonyImportLibrary>()); } Dictionary <string, HarmonyLibrary> otherLibraryLookup = _otherLibraries.ToDictionary(l => (Path.GetFileName(l.Name) ?? l.Name).ToLowerInvariant()); List <HarmonyImportLibrary> imports = new List <HarmonyImportLibrary>(); IMAGE_IMPORT_DESCRIPTOR *importDescriptor = (IMAGE_IMPORT_DESCRIPTOR *)(image.BasePtr + directory.VirtualAddress); for (; !Kernel32.IsBadReadPtr((UIntPtr)importDescriptor, (uint)sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDescriptor->Name != 0; importDescriptor++) { HarmonyImportLibrary import = LoadImport(image.BasePtr, image.Size, importDescriptor, otherLibraryLookup, _loadFlags); imports.Add(import); } return(imports); }
public unsafe int GetMetadata( IntPtr self, string filename, uint imageTimestamp, uint imageSize, IntPtr mvid, uint mdRva, uint flags, uint bufferSize, IntPtr buffer, int *pDataSize) { if (buffer == IntPtr.Zero) { return(E_INVALIDARG); } string?filePath = _dataTarget.BinaryLocator.FindBinary(filename, imageTimestamp, imageSize, true); if (filePath is null) { return(E_FAIL); } // We do not put a using statement here to prevent needing to load/unload the binary over and over. PEImage?peimage = _dataTarget.LoadPEImage(filePath); if (peimage is null || peimage.OptionalHeader is null) { return(E_FAIL); } DebugOnly.Assert(peimage.IsValid); uint rva = mdRva; uint size = bufferSize; if (rva == 0) { IMAGE_DATA_DIRECTORY comDescriptor = peimage.OptionalHeader.ComDescriptorDirectory; if (comDescriptor.VirtualAddress == 0) { return(E_FAIL); } rva = comDescriptor.VirtualAddress; size = Math.Min(bufferSize, comDescriptor.Size); } checked { int read = peimage.Read((int)rva, new Span <byte>(buffer.ToPointer(), (int)size)); if (pDataSize != null) { *pDataSize = read; } } return(S_OK); }
public Int32 GetModuleCount() { Int32 count = 0; IntPtr codeBase = this._module.codeBase; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[1]; if (directory.Size > 0) { IMAGE_IMPORT_DESCRIPTOR importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress); while (importDesc.Name > 0) { Int32 str = codeBase.ToInt32() + (Int32)importDesc.Name; String tmp = Marshal.PtrToStringAnsi(new IntPtr(str)); Int32 handle = Win32Imports.LoadLibrary(tmp); if (handle == -1) { break; } count++; importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, (UInt32)(directory.VirtualAddress + (Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * (count)))); } } return(count); }
public uint GetProcAddress(string name) { unsafe { IntPtr codeBase = module.codeBase; int idx = -1; uint i; IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return(0); } var exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); var nameRef = (uint *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); var ordinal = (ushort *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); for (i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { var str = codeBase + (int)(*nameRef); string tmp = Marshal.PtrToStringAnsi(str); if (tmp == name) { idx = *ordinal; break; } } var tmpaa = (uint *)(codeBase.ToInt32() + (exports.AddressOfFunctions + (idx * 4))); var addr = (uint)((codeBase.ToInt32()) + (*tmpaa)); return(addr); } }
public void ImageDataDirectoryConstructorWorks_Test() { var dataDirectory = new IMAGE_DATA_DIRECTORY(RawStructures.RawDataDirectory, 2); Assert.Equal((uint)0x44332211, dataDirectory.VirtualAddress); Assert.Equal(0x88776655, dataDirectory.Size); }
private ExportDictionaries GetExportDictionaries(Image image) { Dictionary <string, HarmonyExport> exportsByName = new Dictionary <string, HarmonyExport>(); Dictionary <ushort, HarmonyExport> exportsByOrdinal = new Dictionary <ushort, HarmonyExport>(); IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->ExportTable : image.OptionalHeader32->ExportTable; if (directory.VirtualAddress == 0) { return(new ExportDictionaries(exportsByName, exportsByOrdinal)); } IMAGE_EXPORT_DIRECTORY *exportDirectory = (IMAGE_EXPORT_DIRECTORY *)(image.BasePtr + directory.VirtualAddress); UIntPtr nameRef = (UIntPtr)(image.BasePtr + exportDirectory->AddressOfNames); UIntPtr ordinalRef = (UIntPtr)(image.BasePtr + exportDirectory->AddressOfNameOrdinals); ushort ordinalBase = (ushort)exportDirectory->Base; for (int i = 0; i < exportDirectory->NumberOfNames; i++, nameRef += sizeof(UInt32), ordinalRef += sizeof(UInt16)) { byte * namePtr = image.BasePtr + (int)*(UInt32 *)nameRef; string name = StringOperations.NulTerminatedBytesToString(namePtr, image.BasePtr, image.Size); ushort ordinal = *(UInt16 *)ordinalRef; IntPtr exportAddress = (IntPtr)(image.BasePtr + (int)*(UInt32 *)(image.BasePtr + exportDirectory->AddressOfFunctions + ordinal * sizeof(UInt32))); ushort displayOrdinal = (ushort)(ordinal + ordinalBase); HarmonyExport export = new HarmonyExport(name, displayOrdinal, exportAddress); exportsByName[name] = export; exportsByOrdinal[displayOrdinal] = export; } return(new ExportDictionaries(exportsByName, exportsByOrdinal)); }
public String[] GetProcedures() { unsafe { IntPtr codeBase = this._module.codeBase; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return new String[] { } } ; IMAGE_EXPORT_DIRECTORY exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); UInt32 *nameRef = (UInt32 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); UInt16 *ordinal = (UInt16 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); String[] result = new String[exports.NumberOfNames]; for (UInt32 i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { IntPtr str = new IntPtr(codeBase.ToInt32() + (Int32)(*nameRef)); result[i] = Marshal.PtrToStringAnsi(str); } return(result); } }
private static void PatchRelocations(JLibrary.PortableExecutable.PortableExecutable image, IntPtr pAlloc) { IMAGE_DATA_DIRECTORY image_data_directory = image.NTHeader.OptionalHeader.DataDirectory[5]; if (image_data_directory.Size > 0) { IMAGE_BASE_RELOCATION image_base_relocation; uint num = 0; uint num2 = ((uint)pAlloc.ToInt32()) - image.NTHeader.OptionalHeader.ImageBase; uint ptrFromRVA = image.GetPtrFromRVA(image_data_directory.VirtualAddress); uint num4 = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); while ((num < image_data_directory.Size) && image.Read <IMAGE_BASE_RELOCATION>((long)ptrFromRVA, SeekOrigin.Begin, out image_base_relocation)) { int num5 = (int)((image_base_relocation.SizeOfBlock - num4) / 2); uint num6 = image.GetPtrFromRVA(image_base_relocation.VirtualAddress); for (int i = 0; i < num5; i++) { ushort num7; if (image.Read <ushort>((ptrFromRVA + num4) + (i << 1), SeekOrigin.Begin, out num7) && (((num7 >> 12) & 3) != 0)) { uint num8; uint num10 = num6 + ((uint)(num7 & 0xfff)); if (!image.Read <uint>((long)num10, SeekOrigin.Begin, out num8)) { throw image.GetLastError(); } image.Write <uint>(-4L, SeekOrigin.Current, num8 + num2); } } num += image_base_relocation.SizeOfBlock; ptrFromRVA += image_base_relocation.SizeOfBlock; } } }
public int GetModuleCount() { int count = 0; IntPtr codeBase = module.codeBase; IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[1]; if (directory.Size > 0) { var importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, directory.VirtualAddress); while (importDesc.Name > 0) { var str = codeBase + (int)importDesc.Name; string tmp = Marshal.PtrToStringAnsi(str); int handle = Win32Imports.LoadLibrary(tmp); if (handle == -1) { break; } count++; importDesc = PointerHelpers.ToStruct <IMAGE_IMPORT_DESCRIPTOR>(codeBase, (uint)(directory.VirtualAddress + (Marshal.SizeOf(typeof(IMAGE_IMPORT_DESCRIPTOR)) * (count)))); } } return(count); }
// Token: 0x06000121 RID: 289 RVA: 0x0000DB90 File Offset: 0x0000BD90 private static void PatchRelocations(PortableExecutable image, IntPtr pAlloc) { IMAGE_DATA_DIRECTORY image_DATA_DIRECTORY = image.NTHeader.OptionalHeader.DataDirectory[5]; if (image_DATA_DIRECTORY.Size > 0u) { uint num = 0u; uint num2 = (uint)((long)pAlloc.ToInt32() - (long)((ulong)image.NTHeader.OptionalHeader.ImageBase)); uint num3 = image.GetPtrFromRVA(image_DATA_DIRECTORY.VirtualAddress); uint num4 = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_BASE_RELOCATION image_BASE_RELOCATION; while (num < image_DATA_DIRECTORY.Size && image.Read <IMAGE_BASE_RELOCATION>((long)((ulong)num3), SeekOrigin.Begin, out image_BASE_RELOCATION)) { int num5 = (int)((image_BASE_RELOCATION.SizeOfBlock - num4) / 2u); uint ptrFromRVA = image.GetPtrFromRVA(image_BASE_RELOCATION.VirtualAddress); for (int i = 0; i < num5; i++) { ushort num6; if (image.Read <ushort>((long)((ulong)(num3 + num4) + (ulong)((long)((long)i << 1))), SeekOrigin.Begin, out num6) && (num6 >> 12 & 3) != 0) { uint num7 = (uint)((ulong)ptrFromRVA + (ulong)((long)(num6 & 4095))); uint num8; if (!image.Read <uint>((long)((ulong)num7), SeekOrigin.Begin, out num8)) { throw image.GetLastError(); } image.Write <uint>(-4L, SeekOrigin.Current, num8 + num2); } } num += image_BASE_RELOCATION.SizeOfBlock; num3 += image_BASE_RELOCATION.SizeOfBlock; } } }
public static PE64DataDirectory FromNativeStruct(IMAGE_DATA_DIRECTORY nativeStruct) { return(new PE64DataDirectory { VirtualAddress = nativeStruct.VirtualAddress, Size = nativeStruct.Size }); }
/// <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); } }
public static IMAGE_DATA_DIRECTORY Deserialize(MultiPartFile file) { IMAGE_DATA_DIRECTORY idd = new IMAGE_DATA_DIRECTORY(); idd.VirtualAddress = file.ReadUInt32(); idd.Size = file.ReadUInt32(); return(idd); }
IntPtr GetPtrFromFuncName(string funcName) { if (Disposed) { throw new ObjectDisposedException("DLLFromMemory"); } if (string.IsNullOrEmpty(funcName)) { throw new ArgumentException("funcName"); } if (!IsDll) { throw new InvalidOperationException("Loaded Module is not a DLL"); } if (!_initialized) { throw new InvalidOperationException("Dll is not initialized"); } IntPtr pDirectory = PtrAdd(pNTHeaders, Of.IMAGE_NT_HEADERS_OptionalHeader + (Is64BitProcess ? Of64.IMAGE_OPTIONAL_HEADER_ExportTable: Of32.IMAGE_OPTIONAL_HEADER_ExportTable)); IMAGE_DATA_DIRECTORY Directory = PtrRead <IMAGE_DATA_DIRECTORY>(pDirectory); if (Directory.Size == 0) { throw new DllException("Dll has no export table"); } IntPtr pExports = PtrAdd(pCode, Directory.VirtualAddress); IMAGE_EXPORT_DIRECTORY Exports = PtrRead <IMAGE_EXPORT_DIRECTORY>(pExports); if (Exports.NumberOfFunctions == 0 || Exports.NumberOfNames == 0) { throw new DllException("Dll exports no functions"); } IntPtr pNameRef = PtrAdd(pCode, Exports.AddressOfNames); IntPtr pOrdinal = PtrAdd(pCode, Exports.AddressOfNameOrdinals); for (int i = 0; i < Exports.NumberOfNames; i++, pNameRef = PtrAdd(pNameRef, sizeof(uint)), pOrdinal = PtrAdd(pOrdinal, sizeof(ushort))) { uint NameRef = PtrRead <uint>(pNameRef); ushort Ordinal = PtrRead <ushort>(pOrdinal); string curFuncName = Marshal.PtrToStringAnsi(PtrAdd(pCode, NameRef)); if (curFuncName == funcName) { if (Ordinal > Exports.NumberOfFunctions) { throw new DllException("Invalid function ordinal"); } IntPtr pAddressOfFunction = PtrAdd(pCode, (Exports.AddressOfFunctions + (uint)(Ordinal * 4))); return(PtrAdd(pCode, PtrRead <uint>(pAddressOfFunction))); } } throw new DllException("Dll exports no function named " + funcName); }
public static List <string> ExportTable(string dllPath) { var hModule = LoadLibraryEx(dllPath, IntPtr.Zero, LoadLibraryFlags.DONT_RESOLVE_DLL_REFERENCES); if (hModule == IntPtr.Zero) { throw new Win32Exception(GetLastError()); } try { var imageDosHeader = Marshal.PtrToStructure <IMAGE_DOS_HEADER>(hModule); if (!imageDosHeader.IsValid) { throw new Exception($"IMAGE_DOS_HEADER is invalid: {dllPath}"); } #if WIN64 var imageNtHeaders = Marshal.PtrToStructure <IMAGE_NT_HEADERS64>(hModule + imageDosHeader.e_lfanew); #else var imageNtHeaders = Marshal.PtrToStructure <IMAGE_NT_HEADERS32>(hModule + imageDosHeader.e_lfanew); #endif if (!imageNtHeaders.IsValid) { throw new Exception($"IMAGE_NT_HEADERS is invalid: {dllPath}"); } IMAGE_DATA_DIRECTORY exportTabledataDirectory = imageNtHeaders.OptionalHeader.ExportTable; if (exportTabledataDirectory.Size == 0) { return(new List <string>()); } var exportTable = Marshal.PtrToStructure <IMAGE_EXPORT_DIRECTORY>(hModule + exportTabledataDirectory.VirtualAddress); var names = new List <string>(); for (var i = 0; i < exportTable.NumberOfNames; i++) { var name = Marshal.PtrToStringAnsi(hModule + Marshal.ReadInt32(hModule + exportTable.AddressOfNames + (i * 4))); if (name == null) { continue; } names.Add(name); } return(names); } finally { FreeLibrary(hModule); } }
internal DataDirectory(PortableExecutableImage image, DataDirectories dataDirs, DataDirectoryType dirType, IMAGE_DATA_DIRECTORY dataDirectory, ulong imageBase) { _image = image; _type = dirType; _header = dataDirectory; _imageBase = imageBase; _sectionName = new Lazy <string>(DoGetSectionName); _section = new Lazy <Section>(DoGetSection); Directories = dataDirs; }
internal ExportedFunctionsParser( byte[] buff, IMAGE_EXPORT_DIRECTORY exportDirectory, IMAGE_SECTION_HEADER[] sectionHeaders, IMAGE_DATA_DIRECTORY exportDataDir ) : base(buff, 0) { _exportDirectory = exportDirectory; _sectionHeaders = sectionHeaders; _exportDataDir = exportDataDir; }
/// <inheritdoc /> public bool TryGetDirectoryHeader(ImageDirectoryEntry type, out IMAGE_DATA_DIRECTORY entry) { int index = (int)type; if (0 <= index && index < _dataDirectories.Length) { entry = _dataDirectories[index]; return(true); } entry = default(IMAGE_DATA_DIRECTORY); return(false); }
public static PDBContainer FromBinaryReader(BinaryReader r, PEHeaderParser parser, bool parsingFile = true) { IMAGE_DATA_DIRECTORY selectDirectory = parser.NTHeader.OptionalHeader.DebuggingInformation; long addr = 0; if (parsingFile) { for (int i = 0; i < parser.SectionHeaders.Count; ++i) { var section = parser.SectionHeaders[i]; if (selectDirectory.VirtualAddress >= section.VirtualAddress && selectDirectory.VirtualAddress <= section.VirtualAddress + section.VirtualSize) { addr = selectDirectory.VirtualAddress - section.VirtualAddress + section.PointerToRawData; } } } else { addr = selectDirectory.VirtualAddress; } if (selectDirectory.Size > 0 && addr > 0) { r.BaseStream.Position = addr; byte[] buf = r.ReadBytes(unchecked ((int)selectDirectory.Size)); using (BinaryReader bufFetcher = new BinaryReader(new MemoryStream(buf))) { bufFetcher.BaseStream.Position = 0; DebugDataDirectory debugData = new DebugDataDirectory(); debugData.Characteristics = bufFetcher.ReadUInt32(); debugData.TimeDateStamp = bufFetcher.ReadUInt32(); debugData.MajorVersion = bufFetcher.ReadUInt16(); debugData.MinorVersion = bufFetcher.ReadUInt16(); debugData.Type = bufFetcher.ReadUInt32(); debugData.SizeOfData = bufFetcher.ReadUInt32(); debugData.AddressOfRawData = bufFetcher.ReadUInt32(); debugData.PointerToRawData = bufFetcher.ReadUInt32(); if (debugData.SizeOfData > 0 && debugData.PointerToRawData != 0) { PDBContainer pdbContainer = new PDBContainer(debugData.SizeOfData, parser); r.BaseStream.Position = debugData.PointerToRawData; pdbContainer.RawPdb = r.ReadBytes(unchecked ((int)debugData.SizeOfData)); pdbContainer.FillBaseInfo(0, parser.FileSize, selectDirectory.VirtualAddress); return(pdbContainer); } } } return(null); }
private static void PatchRelocations(PortableExecutable image, IntPtr pAlloc) { // Base relocations are essentially Microsofts ingenious way of preserving portability in images. // for all absolute address calls/jmps/references...etc, an entry is made into the base relocation // table telling the loader exactly where an "absolute" address is being used. This allows the loader // to iterate through the relocations and patch these absolute values to ensure they are correct when // the image is loaded somewhere that isn't its preferred base address. IMAGE_DATA_DIRECTORY relocDir = image.NTHeader.OptionalHeader.DataDirectory[(int)DATA_DIRECTORIES.BaseRelocTable]; if (relocDir.Size > 0) //check if there are in fact any relocations. { uint n = 0; uint delta = (uint)(pAlloc.ToInt32() - image.NTHeader.OptionalHeader.ImageBase); //The difference in loaded/preferred addresses. uint pReloc = image.GetPtrFromRVA(relocDir.VirtualAddress); uint szReloc = (uint)Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_BASE_RELOCATION reloc; while (n < relocDir.Size && image.Read(pReloc, SeekOrigin.Begin, out reloc)) { // A relocation block consists of an IMAGE_BASE_RELOCATION, and an array of WORDs. // To calculate the number of relocations (represented by WORDs), just do some simple math. int nrelocs = (int)((reloc.SizeOfBlock - szReloc) / sizeof(ushort)); uint pageVa = image.GetPtrFromRVA(reloc.VirtualAddress); //The Page RVA for this set of relocations (usually a 4K boundary). ushort vreloc; uint old; for (int i = 0; i < nrelocs; i++) { // There are only 2 types of relocations on Intel machines: ABSOLUTE (padding, nothing needs to be done) and HIGHLOW (0x03) // Highlow means that all 32 bits of the "delta" value need to be added to the relocation value. if (image.Read(pReloc + szReloc + (i << 1), SeekOrigin.Begin, out vreloc) && (vreloc >> 12 & 3) != 0) { uint vp = (uint)(pageVa + (vreloc & 0x0FFF)); if (image.Read <uint>(vp, SeekOrigin.Begin, out old)) { image.Write <uint>(-4, SeekOrigin.Current, (uint)(old + delta)); } else { throw image.GetLastError(); //unlikely, but I hate crashing targets because something in the PE was messed up. } } } n += reloc.SizeOfBlock; pReloc += reloc.SizeOfBlock; } } }
private static IReadOnlyDictionary <ImageDataDirectoryEntry, ImageDataDirectory> ReadDirectoryEntries(MemoryMappedViewAccessor view, long location, int count) { var dictionary = new Dictionary <ImageDataDirectoryEntry, ImageDataDirectory>(); var dataDirectories = new IMAGE_DATA_DIRECTORY[count]; view.ReadArray(location, dataDirectories, 0, dataDirectories.Length); for (var i = 0; i < dataDirectories.Length; i++) { var entry = new ImageDataDirectory { Size = dataDirectories[i].Size, VirtualAddress = dataDirectories[i].VirtualAddress }; dictionary.Add((ImageDataDirectoryEntry)i, entry); } return(dictionary); }
private IMAGE_DATA_DIRECTORY[] ReadDataDirectories() { IMAGE_DATA_DIRECTORY[] directories = new IMAGE_DATA_DIRECTORY[ImageDataDirectoryCount]; if (!IsValid) { return(directories); } SeekTo(DataDirectoryOffset); for (int i = 0; i < directories.Length; i++) { directories[i] = Read <IMAGE_DATA_DIRECTORY>() ?? default; } return(directories); }
public static IMAGE_OPTIONAL_HEADER Deserialize(MultiPartFile file) { IMAGE_OPTIONAL_HEADER ioh = new IMAGE_OPTIONAL_HEADER(); ioh.Magic = file.ReadUInt16(); ioh.MajorLinkerVersion = file.ReadByte(); ioh.MinorLinkerVersion = file.ReadByte(); ioh.SizeOfCode = file.ReadUInt32(); ioh.SizeOfInitializedData = file.ReadUInt32(); ioh.SizeOfUninitializedData = file.ReadUInt32(); ioh.AddressOfEntryPoint = file.ReadUInt32(); ioh.BaseOfCode = file.ReadUInt32(); ioh.BaseOfData = file.ReadUInt32(); ioh.ImageBase = file.ReadUInt32(); ioh.SectionAlignment = file.ReadUInt32(); ioh.FileAlignment = file.ReadUInt32(); ioh.MajorOperatingSystemVersion = file.ReadUInt16(); ioh.MinorOperatingSystemVersion = file.ReadUInt16(); ioh.MajorImageVersion = file.ReadUInt16(); ioh.MinorImageVersion = file.ReadUInt16(); ioh.MajorSubsystemVersion = file.ReadUInt16(); ioh.MinorSubsystemVersion = file.ReadUInt16(); ioh.Reserved1 = file.ReadUInt32(); ioh.SizeOfImage = file.ReadUInt32(); ioh.SizeOfHeaders = file.ReadUInt32(); ioh.CheckSum = file.ReadUInt32(); ioh.Subsystem = file.ReadUInt16(); ioh.DllCharacteristics = file.ReadUInt16(); ioh.SizeOfStackReserve = file.ReadUInt32(); ioh.SizeOfStackCommit = file.ReadUInt32(); ioh.SizeOfHeapReserve = file.ReadUInt32(); ioh.SizeOfHeapCommit = file.ReadUInt32(); ioh.LoaderFlags = file.ReadUInt32(); ioh.NumberOfRvaAndSizes = file.ReadUInt32(); ioh.DataDirectory = new IMAGE_DATA_DIRECTORY[Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; for (int i = 0; i < Constants.IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) { ioh.DataDirectory[i] = IMAGE_DATA_DIRECTORY.Deserialize(file); } return(ioh); }
private void PerformBaseRelocation(Image image, long delta) { IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->BaseRelocationTable : image.OptionalHeader32->BaseRelocationTable; if (directory.Size == 0) { return; } IMAGE_BASE_RELOCATION *relocation = (IMAGE_BASE_RELOCATION *)(image.BasePtr + directory.VirtualAddress); while (relocation->VirtualAddress > 0) { ApplyRelocationBlock(image, delta, relocation); relocation = (IMAGE_BASE_RELOCATION *)((byte *)relocation + relocation->BlockSizeInclusive); } }
public void PerformBaseRelocation(uint delta) { IntPtr codeBase = module.codeBase; int sizeOfBase = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY directory = module.headers.OptionalHeader.DataDirectory[5]; int cnt = 0; if (directory.Size > 0) { var relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, 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: var patchAddrHl = (uint *)((dest) + (offset)); * patchAddrHl += delta; break; } } } cnt += (int)relocation.SizeOfBlock; relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, (uint)(directory.VirtualAddress + cnt)); } } }
/// <summary> /// Create a new IMAGE_OPTIONAL_HEADER object. /// </summary> /// <param name="buff">A PE file as a byte array.</param> /// <param name="offset">Raw offset to the optional header.</param> /// <param name="is64Bit">Set to true, if header is for a x64 application.</param> public IMAGE_OPTIONAL_HEADER(byte[] buff, uint offset, bool is64Bit) : base(buff, offset) { _is64Bit = is64Bit; DataDirectory = new IMAGE_DATA_DIRECTORY[16]; for (uint i = 0; i < 16; i++) { if (!_is64Bit) { DataDirectory[i] = new IMAGE_DATA_DIRECTORY(buff, offset + 0x60 + i * 0x8); } else { DataDirectory[i] = new IMAGE_DATA_DIRECTORY(buff, offset + 0x70 + i * 0x8); } } }
public void PerformBaseRelocation(UInt32 delta) { IntPtr codeBase = _module.codeBase; Int32 sizeOfBase = Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION)); IMAGE_DATA_DIRECTORY directory = _module.headers.OptionalHeader.DataDirectory[5]; Int32 cnt = 0; if (directory.Size > 0) { IMAGE_BASE_RELOCATION relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, directory.VirtualAddress); while (relocation.VirtualAddress > 0) { unsafe { IntPtr dest = (IntPtr)(codeBase.ToInt32() + (int)relocation.VirtualAddress); UInt16 *relInfo = (UInt16 *)(codeBase.ToInt32() + (int)directory.VirtualAddress + sizeOfBase); UInt16 i; for (i = 0; i < ((relocation.SizeOfBlock - Marshal.SizeOf(typeof(IMAGE_BASE_RELOCATION))) / 2); i++, relInfo++) { Int32 type = *relInfo >> 12; Int32 offset = (*relInfo & 0xfff); switch (type) { case 0x00: break; case 0x03: UInt32 *patchAddrHl = (UInt32 *)((dest.ToInt32()) + (offset)); * patchAddrHl += delta; break; } } } cnt += (Int32)relocation.SizeOfBlock; relocation = PointerHelpers.ToStruct <IMAGE_BASE_RELOCATION>(codeBase, (UInt32)(directory.VirtualAddress + cnt)); } } }
public void ExecuteTlsFunctions(Image image, DllCallType callType) { IMAGE_DATA_DIRECTORY directory = Environment.Is64BitProcess ? image.OptionalHeader64->TLSTable : image.OptionalHeader32->TLSTable; if (directory.VirtualAddress == 0) { return; } if (directory.VirtualAddress > image.Size - sizeof(IntPtr)) { throw new LoadFailedException("This library's TLS table is damaged or invalid."); } IMAGE_TLS_DIRECTORY32 *tlsDirectory32 = (IMAGE_TLS_DIRECTORY32 *)(image.BasePtr + directory.VirtualAddress); IntPtr callbacks = (IntPtr)tlsDirectory32->AddressOfCallBacks; IntPtr endPtr = (IntPtr)(image.BasePtr + image.Size - sizeof(IntPtr)); if (callbacks != IntPtr.Zero) { IntPtr callback; while ((callback = *(IntPtr *)callbacks) != IntPtr.Zero) { if ((long)callback > (long)endPtr) { throw new LoadFailedException("One of this library's TLS functions is damaged or invalid."); } DllEntryProc dllEntryProc = (DllEntryProc)Marshal.GetDelegateForFunctionPointer(callback, typeof(DllEntryProc)); uint succeeded = dllEntryProc((IntPtr)image.BasePtr, DllCallType.PROCESS_ATTACH, IntPtr.Zero); if (succeeded == 0) { throw new LoadFailedException("One of this library's TLS functions returned false in response to " + callType + "."); } } } }
public UInt32?GetProcAddress(String name) { unsafe { IntPtr codeBase = this._module.codeBase; Int32? idx = null; IMAGE_DATA_DIRECTORY directory = this._module.headers.OptionalHeader.DataDirectory[0]; if (directory.Size == 0) { return(null); } IMAGE_EXPORT_DIRECTORY exports = PointerHelpers.ToStruct <IMAGE_EXPORT_DIRECTORY>(codeBase, directory.VirtualAddress); UInt32 *nameRef = (UInt32 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNames); UInt16 *ordinal = (UInt16 *)new IntPtr(codeBase.ToInt32() + exports.AddressOfNameOrdinals); for (UInt32 i = 0; i < exports.NumberOfNames; i++, nameRef++, ordinal++) { IntPtr str = new IntPtr(codeBase.ToInt32() + (Int32)(*nameRef)); String tmp = Marshal.PtrToStringAnsi(str); if (tmp == name) { idx = *ordinal; break; } } if (idx.HasValue) { UInt32 *tmpaa = (UInt32 *)(codeBase.ToInt32() + (exports.AddressOfFunctions + (idx.Value * 4))); UInt32 addr = (UInt32)((codeBase.ToInt32()) + (*tmpaa)); return(addr); } else { return(null); } } }
public IMAGE_DATA_DIRECTORY_Values() { Values = new IMAGE_DATA_DIRECTORY[16]; }
private async Task LoadAsync() { if (!_stream.CanSeek) { throw new PortableExecutableImageException(this, "Cannot seek in stream."); } if (!_stream.CanRead) { throw new PortableExecutableImageException(this, "Cannot read from stream."); } IMAGE_DOS_HEADER dosHeader; try { dosHeader = await _stream.ReadStructAsync <IMAGE_DOS_HEADER>(DOSHeader.Size).ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Cannot read DOS header from stream.", ex); } if (dosHeader.e_magic != DOSHeader.DOS_MAGIC_MZ) { throw new PortableExecutableImageException(this, "Incorrect magic number specified in DOS header."); } if (dosHeader.e_lfanew == 0) { throw new PortableExecutableImageException(this, "No new header location specified in DOS header, most likely a 16-bit executable."); } if (dosHeader.e_lfanew >= (256 * (1024 * 1024))) { throw new PortableExecutableImageException(this, "New header location specified in MS-DOS header is beyond 256mb boundary (see RtlImageNtHeaderEx)."); } if (dosHeader.e_lfanew % 4 != 0) { throw new PortableExecutableImageException(this, "New header location specified in MS-DOS header is not properly aligned."); } if (dosHeader.e_lfanew < DOSHeader.Size) { throw new PortableExecutableImageException(this, "New header location specified is invalid."); } var stubOffset = DOSHeader.Size; var stubSize = dosHeader.e_lfanew - DOSHeader.Size; var stubRead = await _stream.SkipBytesAsync(stubSize).ConfigureAwait(false); if (stubRead < stubSize) { throw new PortableExecutableImageException(this, "Could not read DOS stub from stream."); } _stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin); var ntOffset = _stream.Position; uint peSig; try { peSig = await _stream.ReadUInt32Async().ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read PE signature from stream.", ex); } if (peSig != NTHeaders.PE_MAGIC_MZ) { throw new PortableExecutableImageException(this, "Incorrect PE signature found in NT Header."); } IMAGE_FILE_HEADER fileHdr; try { fileHdr = await _stream.ReadStructAsync <IMAGE_FILE_HEADER>(FileHeader.Size).ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read NT Header from stream.", ex); } ushort magic = 0; try { magic = await _stream.ReadUInt16Async().ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read Optional Header magic number from stream.", ex); } Is32Bit = (magic == (ushort)MagicType.PE32); Is64Bit = (magic == (ushort)MagicType.PE32plus); if (!Is32Bit && !Is64Bit) { throw new PortableExecutableImageException(this, "Unknown PE type."); } byte[] optionalHeaderBytes; try { var optionalHeaderSize = (Is32Bit ? Utils.SizeOf <IMAGE_OPTIONAL_HEADER32>() : Utils.SizeOf <IMAGE_OPTIONAL_HEADER64>()); optionalHeaderBytes = await _stream.ReadBytesAsync(optionalHeaderSize).ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read Optional Header from stream.", ex); } IMAGE_OPTIONAL_HEADER32 optionalHeader32 = new IMAGE_OPTIONAL_HEADER32(); IMAGE_OPTIONAL_HEADER64 optionalHeader64 = new IMAGE_OPTIONAL_HEADER64(); var dirCount = 0; if (Is32Bit) { optionalHeader32 = Utils.Read <IMAGE_OPTIONAL_HEADER32>(optionalHeaderBytes); dirCount = optionalHeader32.NumberOfRvaAndSizes.ToInt32(); } else { optionalHeader64 = Utils.Read <IMAGE_OPTIONAL_HEADER64>(optionalHeaderBytes); dirCount = optionalHeader64.NumberOfRvaAndSizes.ToInt32(); } var dataDirs = new IMAGE_DATA_DIRECTORY[dirCount]; var dataDirSize = Utils.SizeOf <IMAGE_DATA_DIRECTORY>(); for (var i = 0; i < dirCount; i++) { try { dataDirs[i] = await _stream.ReadStructAsync <IMAGE_DATA_DIRECTORY>(dataDirSize).ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read data directory from stream.", ex); } } var sectionTableEntrySize = Utils.SizeOf <IMAGE_SECTION_HEADER>(); var sectionTable = new IMAGE_SECTION_HEADER[fileHdr.NumberOfSections]; for (var i = 0; i < fileHdr.NumberOfSections; i++) { try { sectionTable[i] = await _stream.ReadStructAsync <IMAGE_SECTION_HEADER>(sectionTableEntrySize).ConfigureAwait(false); } catch (Exception ex) { throw new PortableExecutableImageException(this, "Could not read section table entry from stream.", ex); } } IsCLR = false; var clrIndex = (int)DataDirectoryType.CLRRuntimeHeader; if (clrIndex >= 0 && clrIndex <= (dataDirs.Length - 1)) { var clrDirectory = dataDirs[clrIndex]; if (clrDirectory.VirtualAddress > 0 && clrDirectory.Size > 0) { IsCLR = true; } } IsSigned = false; var certIndex = (int)DataDirectoryType.CertificateTable; if (certIndex >= 0 && certIndex <= (dataDirs.Length - 1)) { var certDirectory = dataDirs[certIndex]; if (certDirectory.VirtualAddress > 0 && certDirectory.Size > 0) { IsSigned = true; } } var imageBase = (Is32Bit ? optionalHeader32.ImageBase : optionalHeader64.ImageBase); DOSHeader = new DOSHeader(this, dosHeader, imageBase); DOSStub = new DOSStub(this, stubOffset.ToUInt64(), stubSize.ToUInt32(), imageBase); var fileHeader = new FileHeader(this, fileHdr, DOSStub.Location.FileOffset + DOSStub.Location.FileSize + 4, imageBase); OptionalHeader optionalHeader; if (Is32Bit) { optionalHeader = new OptionalHeader32(this, optionalHeader32, fileHeader.Location.FileOffset + fileHeader.Location.FileSize, imageBase, magic); } else { optionalHeader = new OptionalHeader64(this, optionalHeader64, fileHeader.Location.FileOffset + fileHeader.Location.FileSize, imageBase, magic); } var dataDirectories = new DataDirectories(this, optionalHeader, dataDirs); NTHeaders = new NTHeaders(this, ntOffset.ToUInt64(), imageBase, fileHeader, optionalHeader, dataDirectories); SectionTable = new SectionTable(this, sectionTable, NTHeaders.Location.FileOffset + NTHeaders.Location.FileSize, imageBase); Sections = new Sections(this, SectionTable); }