/// <summary> /// This function loads the header and PE header at the /// specified address in memory. /// </summary> /// <param name="process"></param> /// <param name="address"></param> public HeaderReader(System.Diagnostics.Process process, UInt64 address) { this.BaseAddress = address; codeStartAddress = 0; codeLength = 0; // Read in the Image Dos Header importTable = new List <IMPORT_FUNCTION>(0); byte[] headerData = MemoryFunctions.ReadMemory(process, (IntPtr)address, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))); dosHeader = (IMAGE_DOS_HEADER)MemoryFunctions.RawDataToObject(ref headerData, typeof(IMAGE_DOS_HEADER)); // Load the PE Address UInt64 PE_header = 0; if (dosHeader.e_magic == 0x5A4D) { // Load the PE header address PE_header = dosHeader.e_lfanew + address; } else { PE_header = address; } // Read in the PE token byte[] PE_Token = MemoryFunctions.ReadMemory(process, (IntPtr)PE_header, 4); if (!(PE_Token[0] == 'P' & PE_Token[1] == 'E' & PE_Token[2] == 0 & PE_Token[3] == 0)) { // Problem, we are not pointing at a correct PE header. Abort. Console.WriteLine("Failed to read PE header from block " + address.ToString("X") + " with PE header located at " + PE_header.ToString() + "."); return; } // Input the COFFHeader byte[] coffHeader_rawData = MemoryFunctions.ReadMemory(process, (IntPtr)(PE_header + 4), (uint)Marshal.SizeOf(typeof(COFFHeader))); coffHeader = (COFFHeader)MemoryFunctions.RawDataToObject(ref coffHeader_rawData, typeof(COFFHeader)); // Read in the PEOptHeader if it exists if (coffHeader.SizeOfOptionalHeader != 0 && coffHeader.SizeOfOptionalHeader < 0x1000) { // Read in the optHeader byte[] optHeader_rawData = MemoryFunctions.ReadMemory(process, (IntPtr)(PE_header + 4 + (uint)Marshal.SizeOf(typeof(COFFHeader))), coffHeader.SizeOfOptionalHeader); optHeader = new PEOptHeader(ref optHeader_rawData, 0, coffHeader.SizeOfOptionalHeader); // Confirm that it loaded correctly if ((optHeader.signature & 0xffff) != 0x10b && (optHeader.signature & 0xffff) != 0x20b) { Console.WriteLine("Failed to read optHeader; Expected signature does not match read in signature of " + optHeader.signature.ToString() + "."); return; } // Load the sections UInt64 sectionAddress = PE_header + 4 + (UInt64)Marshal.SizeOf(typeof(COFFHeader)) + coffHeader.SizeOfOptionalHeader; List <section> sections = new List <section>(coffHeader.NumberOfSections); for (int i = 0; i < coffHeader.NumberOfSections; i++) { sections.Add(new section(process, sectionAddress)); sectionAddress += (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)); } // Extract the names of the functions and corresponding table entries Int64 importTableAddress = (Int64)optHeader.DataDirectory2_import.VirtualAddress + (Int64)address; // Read in the first import descriptor structure /* * byte[] image_import_descriptor_rawData = oMemoryFunctions.readMemory(process, importTableAddress, (uint)Marshal.SizeOf(typeof(image_import_descriptor))); * image_import_descriptor descriptor = (image_import_descriptor)oMemoryFunctions.RawDataToObject(ref image_import_descriptor_rawData, typeof(image_import_descriptor)); * List<image_import_by_name> imports = new List<image_import_by_name>(0); * while (descriptor.FirstThunk != 0 || descriptor.OriginalFirstThunk != 0 || descriptor.Name != 0) * { * // Process this descriptor * imports.Add(new image_import_by_name(process, descriptor, address)); * * // Read next descriptor * image_import_descriptor_rawData = oMemoryFunctions.readMemory(process, importTableAddress + (long)(imports.Count * Marshal.SizeOf(typeof(image_import_descriptor))), (uint)Marshal.SizeOf(typeof(image_import_descriptor))); * descriptor = (image_import_descriptor)oMemoryFunctions.RawDataToObject(ref image_import_descriptor_rawData, typeof(image_import_descriptor)); * } * * // Now lets process the array of descriptors * foreach (image_import_by_name dllDescriptor in imports) * { * for (int i = 0; i < dllDescriptor.ImportTableAddresses.Count; i++) * { * // Process this function import * IMPORT_FUNCTION newImport = new IMPORT_FUNCTION(); * newImport.name = dllDescriptor.Names[i]; * newImport.memoryAddress = dllDescriptor.ImportTableAddresses[i]; * newImport.targetAddress = oMemoryFunctions.readMemoryDword(process, newImport.memoryAddress); * importTable.Add(newImport); * } * } */ // Extract the names of the functions and corresponding table entries Int64 exportTableAddress = (Int64)optHeader.DataDirectory1_export.VirtualAddress + (Int64)address; // Read in the first _IMAGE_EXPORT_DIRECTORY structure byte[] export_directory_rawData = MemoryFunctions.ReadMemory(process, exportTableAddress, (uint)Marshal.SizeOf(typeof(_IMAGE_EXPORT_DIRECTORY))); _IMAGE_EXPORT_DIRECTORY export_directory = (_IMAGE_EXPORT_DIRECTORY)MemoryFunctions.RawDataToObject(ref export_directory_rawData, typeof(_IMAGE_EXPORT_DIRECTORY)); exports = new Hashtable(20); UInt64 functionNameArray = (UInt64)export_directory.AddressOfNames + address; string exportName = MemoryFunctions.ReadString(process, (UInt64)export_directory.Name + address, MemoryFunctions.STRING_TYPE.ascii); UInt64 functionOrdinalArray = (UInt64)export_directory.AddressOfNameOrdinal + address; UInt64 functionAddressArray = (UInt64)export_directory.AddressOfFunctions + address; for (int i = 0; i < export_directory.NumberOfNames; i++) { int ordinal_relative = (int)MemoryFunctions.ReadMemoryUShort(process, functionOrdinalArray + (UInt64)i * 2); int ordinal = ordinal_relative + (int)export_directory.Base; if (ordinal_relative < export_directory.NumberOfFunctions) { // Continue with importing this function string name = ""; if (i < export_directory.NumberOfNames) { name = MemoryFunctions.ReadString(process, (UInt64)MemoryFunctions.ReadMemoryDword(process, functionNameArray + (UInt64)i * 4) + address, MemoryFunctions.STRING_TYPE.ascii); } else { name = "oridinal" + ordinal.ToString(); } // Lookup the function rva now try { UInt64 offset = (UInt64)MemoryFunctions.ReadMemoryDword(process, functionAddressArray + (UInt64)ordinal_relative * 4); // Check to see if this is a forwarded export if (offset < optHeader.DataDirectory1_export.VirtualAddress || offset > optHeader.DataDirectory1_export.VirtualAddress + optHeader.DataDirectory1_export.Size) { // Lookup privilege of heap to confirm it requests execute privileges. We only want to list exported functions, not variables. foreach (section exp in sections) { if (exp.Contains(offset)) { if (exp.IsExecutable()) { // Add this exported function export new_export = new export(offset + address, name, ordinal); exports.Add(name.ToLower(), new_export); } break; } } } else { // Forwarded export. Ignore it. } } catch (Exception e) { Console.WriteLine("Warning, failed to parse PE header export directory entry for name '" + name + "'."); } } } } else { // No COFFHeader found Console.WriteLine("Warning, no COFFHeader found for address " + address.ToString("X") + "."); return; } }
/// <summary> /// This checks whether the specified heap is /// a valid pe header. /// </summary> /// <param name="process"></param> /// <param name="address"></param> /// <returns></returns> public static bool isPeHeader(System.Diagnostics.Process process, UInt64 address) { // Read in the Image Dos Header byte[] headerData = MemoryFunctions.ReadMemory(process, (IntPtr)address, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER))); IMAGE_DOS_HEADER dosHeader = (IMAGE_DOS_HEADER)MemoryFunctions.RawDataToObject(ref headerData, typeof(IMAGE_DOS_HEADER)); // Load the PE Address UInt64 PE_header = 0; if (dosHeader.e_magic == 0x5A4D) { // Load the PE header address PE_header = dosHeader.e_lfanew + address; } else { PE_header = address; return(false); } if (PE_header <= 0x7FFFFFFF) { // Read in the PE token byte[] PE_Token = MemoryFunctions.ReadMemory(process, (IntPtr)PE_header, 4); if (!(PE_Token[0] == 'P' & PE_Token[1] == 'E' & PE_Token[2] == 0 & PE_Token[3] == 0)) { // Problem, we are not pointing at a correct PE header. Abort. return(false); } // Input the COFFHeader byte[] coffHeader_rawData = MemoryFunctions.ReadMemory(process, (IntPtr)(PE_header + 4), (uint)Marshal.SizeOf(typeof(COFFHeader))); COFFHeader coffHeader = (COFFHeader)MemoryFunctions.RawDataToObject(ref coffHeader_rawData, typeof(COFFHeader)); // Read in the PEOptHeader if it exists if (coffHeader.SizeOfOptionalHeader != 0 && coffHeader.SizeOfOptionalHeader < 0x1000) { // Read in the optHeader byte[] optHeader_rawData = MemoryFunctions.ReadMemory(process, (IntPtr)(PE_header + 4 + (uint)Marshal.SizeOf(typeof(COFFHeader))), coffHeader.SizeOfOptionalHeader); PEOptHeader optHeader = new PEOptHeader(ref optHeader_rawData, 0, optHeader_rawData.Length); // Confirm that it loaded correctly if ((optHeader.signature & 0xffff) != 0x10b && (optHeader.signature & 0xffff) != 0x20b) { return(false); } if (optHeader.SizeOfCode == 0) { return(false); } } else { // No COFFHeader found return(false); } return(true); } else { return(false); } }