Example #1
0
        private void LoadPEImage()
        {
            long fileDataSize = rdr.Bytes.Length - xexData.header.header_size;

            BeImageReader memRdr    = new BeImageReader(xexData.memoryData);
            DOSHeader     dosHeader = memRdr.ReadStruct <DOSHeader>();

            dosHeader.Validate();

            memRdr.Offset = dosHeader.e_lfanew;

            UInt32 peSignature = memRdr.ReadUInt32();

            if (peSignature != 0x50450000)
            {
                throw new BadImageFormatException("PE: Invalid or Missing PE Signature");
            }

            COFFHeader coffHeader = memRdr.ReadStruct <COFFHeader>();

            if (coffHeader.Machine != 0x1F2)
            {
                throw new BadImageFormatException($"PE: Machine type does not match Xbox360 (found 0x{coffHeader.Machine:X})");
            }

            if ((coffHeader.Characteristics & 0x0100) == 0)
            {
                throw new BadImageFormatException("PE: Only 32-bit images are supported");
            }

            if (coffHeader.SizeOfOptionalHeader != 224)
            {
                throw new BadImageFormatException($"PE: Invalid size of optional header (got {coffHeader.SizeOfOptionalHeader}");
            }

            PEOptHeader optHeader = memRdr.ReadStruct <PEOptHeader>();

            if (optHeader.signature != 0x10b)
            {
                throw new BadImageFormatException($"PE: Invalid signature of optional header (got 0x{optHeader.signature})");
            }

            if (optHeader.Subsystem != IMAGE_SUBSYSTEM_XBOX)
            {
                throw new BadImageFormatException($"PE: Invalid subsystem (got {optHeader.Subsystem})");
            }

            xexData.peHeader = optHeader;

            uint extendedMemorySize = 0;
            uint numSections        = coffHeader.NumberOfSections;

            List <PESection> peSections = new List <PESection>();

            for (uint i = 0; i < numSections; i++)
            {
                COFFSection section = memRdr.ReadStruct <COFFSection>();

                string sectionName = Encoding.ASCII.GetString(section.Name).Trim('\0');

                uint lastMemoryAddress = section.VirtualAddress + section.VirtualSize;
                if (lastMemoryAddress > extendedMemorySize)
                {
                    extendedMemorySize = lastMemoryAddress;
                }

                if (section.SizeOfRawData == 0)
                {
                    decompilerEventListener.Info(new NullCodeLocation(""),
                                                 $"Skipping empty section {sectionName}"
                                                 );
                    continue;
                }

                byte[] sectionData = memRdr.ReadAt <byte[]>(section.PointerToRawData, rdr => rdr.ReadBytes(section.SizeOfRawData));

                AccessMode acc = AccessMode.Read;
                if (section.Flags.HasFlag(PESectionFlags.IMAGE_SCN_MEM_WRITE))
                {
                    acc |= AccessMode.Write;
                }
                if (section.Flags.HasFlag(PESectionFlags.IMAGE_SCN_MEM_EXECUTE))
                {
                    acc |= AccessMode.Execute;
                }

                PESection managedSection = new PESection(section);
                peSections.Add(managedSection);

                ImageSegment seg = new ImageSegment(sectionName, new MemoryArea(
                                                        new Address32(managedSection.PhysicalOffset + xexData.exe_address), sectionData
                                                        ), acc);
                segments.Add(seg);
            }

            if (extendedMemorySize > xexData.memorySize)
            {
                decompilerEventListener.Info(new NullCodeLocation(""),
                                             $"PE: Image sections extend beyond virtual memory range loaded from file ({extendedMemorySize} > {xexData.memorySize}). Extending by {extendedMemorySize - xexData.memorySize} bytes."
                                             );

                UInt32 oldMemorySize = xexData.memorySize;

                byte[] newMemoryData = new byte[extendedMemorySize];
                Array.Copy(xexData.memoryData, newMemoryData, xexData.memorySize);
                xexData.memorySize = extendedMemorySize;
                xexData.memoryData = newMemoryData;

                for (int i = 0; i < peSections.Count; i++)
                {
                    PESection section = peSections[i];

                    if (section.PhysicalSize == 0)
                    {
                        continue;
                    }

                    if (section.PhysicalSize + section.PhysicalOffset > fileDataSize)
                    {
                        decompilerEventListener.Warn(new NullCodeLocation(""),
                                                     $"PE: Section '{section.Name}' lies outside any phyisical data we have {section.PhysicalOffset} (size {section.PhysicalSize})"
                                                     );
                        continue;
                    }

                    if (section.VirtualOffset >= oldMemorySize)
                    {
                        uint sizeToCopy = section.PhysicalSize;
                        if (section.VirtualSize < sizeToCopy)
                        {
                            sizeToCopy = section.VirtualSize;
                        }

                        Array.Copy(
                            xexData.memoryData, section.PhysicalOffset,
                            newMemoryData, section.VirtualOffset,
                            sizeToCopy);
                    }
                }
            }
        }
        /// <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 oHeaderReader(Process process, UInt64 address)
        {
            codeStartAddress = 0;
            codeLength = 0;
            invalidCodeAddresses = new List<ADDRESS_RANGE>(0);

            // Read in the Image Dos Header
            importTable = new List<IMPORT_FUNCTION>(0);
            byte[] headerData = oMemoryFunctions.readMemory(process, address, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)));
            dosHeader = (IMAGE_DOS_HEADER)oMemoryFunctions.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 = oMemoryFunctions.readMemory(process, 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.
                oConsole.printMessage("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 = oMemoryFunctions.readMemory(process, PE_header + 4, (uint)Marshal.SizeOf(typeof(COFFHeader)));
            coffHeader = (COFFHeader)oMemoryFunctions.RawDataToObject(ref coffHeader_rawData, typeof(COFFHeader));

            // Read in the PEOptHeader if it exists
            if (coffHeader.SizeOfOptionalHeader != 0)
            {
                if (coffHeader.SizeOfOptionalHeader != (ushort)Marshal.SizeOf(typeof(PEOptHeader)))
                {
                    // Problem!
                    oConsole.printMessage("Failed to read COFFHeader as a result of size mismatch. Size of expected COFFHeader, " + ((ushort)Marshal.SizeOf(typeof(PEOptHeader))).ToString() + ", does not equal size of SizeOfOptionalHeader, " + coffHeader.SizeOfOptionalHeader.ToString() + ".");
                    return;
                }
                else
                {
                    // Read in the optHeader
                    byte[] optHeader_rawData = oMemoryFunctions.readMemory(process, PE_header + 4 + (uint)Marshal.SizeOf(typeof(COFFHeader)), (uint)Marshal.SizeOf(typeof(PEOptHeader)));
                    optHeader = (PEOptHeader)oMemoryFunctions.RawDataToObject(ref optHeader_rawData, typeof(PEOptHeader));

                    // Confirm that it loaded correctly
                    if (optHeader.signature != 267)
                    {
                        oConsole.printMessage("Failed to read optHeader; Expected signature of 267 does not match read in signature of " + optHeader.signature.ToString() + ".");
                        return;
                    }
                }
            }
            else
            {
                // No COFFHeader found
                oConsole.printMessage("Warning, no COFFHeader found for address " + address.ToString("X") + ".");
                return;
            }

            // Add all the directories as invalid code ranges
            try
            {
                if (optHeader.DataDirectory1_export.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory1_export.VirtualAddress),
                            optHeader.DataDirectory1_export.Size));
                if (optHeader.DataDirectory2_import.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory2_import.VirtualAddress),
                            optHeader.DataDirectory2_import.Size));
                if (optHeader.DataDirectory3.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory3.VirtualAddress),
                            optHeader.DataDirectory3.Size));
                if (optHeader.DataDirectory4.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory4.VirtualAddress),
                            optHeader.DataDirectory4.Size));
                if (optHeader.DataDirectory5.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory5.VirtualAddress),
                            optHeader.DataDirectory5.Size));
                if (optHeader.DataDirectory6.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory6.VirtualAddress),
                            optHeader.DataDirectory6.Size));
                if (optHeader.DataDirectory7.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory7.VirtualAddress),
                            optHeader.DataDirectory7.Size));
                if (optHeader.DataDirectory8.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory8.VirtualAddress),
                            optHeader.DataDirectory8.Size));
                if (optHeader.DataDirectory9.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory9.VirtualAddress),
                            optHeader.DataDirectory9.Size));
                if (optHeader.DataDirectory10.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory10.VirtualAddress),
                            optHeader.DataDirectory10.Size));
                if (optHeader.DataDirectory11.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory11.VirtualAddress),
                            optHeader.DataDirectory11.Size));
                if (optHeader.DataDirectory12.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory12.VirtualAddress),
                            optHeader.DataDirectory12.Size));
                if (optHeader.DataDirectory13.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory13.VirtualAddress),
                            optHeader.DataDirectory13.Size));
                if (optHeader.DataDirectory14.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory14.VirtualAddress),
                            optHeader.DataDirectory14.Size));
                if (optHeader.DataDirectory15.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory15.VirtualAddress),
                            optHeader.DataDirectory15.Size));
                if (optHeader.DataDirectory16.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory16.VirtualAddress),
                            optHeader.DataDirectory16.Size));
            }catch
            {
                // Ignore exceptions, this is not cretical.
            }

            // Extract the names of the functions and corresponding table entries
            uint importTableAddress = oMemoryFunctions.addressAdd(optHeader.DataDirectory2_import.VirtualAddress,(uint) address);
            uint exportTableAddress = oMemoryFunctions.addressAdd(optHeader.DataDirectory1_export.VirtualAddress, (uint) address);

            // 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));
            }

            // Load the import directory
            loadImportTable(process, importTableAddress, optHeader.DataDirectory2_import.Size, (uint)address);

            // Load the export directory
            loadExportTable(process, exportTableAddress, optHeader.DataDirectory1_export.Size, (uint) address, optHeader, sections);

            // Load the section structures
            int numSections = coffHeader.NumberOfSections;
            sections = new List<IMAGE_SECTION_HEADER_MOD>(numSections);
            for( uint i = 0; i < numSections; i++ )
            {
                ulong sectionBase = PE_header + 4 + (ulong)Marshal.SizeOf(typeof(COFFHeader)) + (uint)Marshal.SizeOf(typeof(PEOptHeader)) + i * (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
                byte[] sectionData = oMemoryFunctions.readMemory(process, sectionBase, (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)));
                IMAGE_SECTION_HEADER section = (IMAGE_SECTION_HEADER)oMemoryFunctions.RawDataToObject(ref sectionData, typeof(IMAGE_SECTION_HEADER));

                // Convert the raw section to a more friendly section type
                sections.Add(new IMAGE_SECTION_HEADER_MOD(section));
            }
        }
        private void loadExportTable(Process process, uint exportTableAddress, uint length, uint baseAddress, PEOptHeader optHeader, List<section> sections)
        {
          // 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 + "'.");
                  }
              }
          }
      }
        /// <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(Process process, UInt64 address)
        {
            // Read in the Image Dos Header
            byte[] headerData = oMemoryFunctions.readMemory(process, address,
                                                            (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)));
            IMAGE_DOS_HEADER dosHeader = (IMAGE_DOS_HEADER)oMemoryFunctions.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 = oMemoryFunctions.readMemory(process, 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 = oMemoryFunctions.readMemory(process, PE_header + 4, (uint)Marshal.SizeOf(typeof(COFFHeader)));
                COFFHeader coffHeader = (COFFHeader)oMemoryFunctions.RawDataToObject(ref coffHeader_rawData, typeof(COFFHeader));

                // Read in the PEOptHeader if it exists
                if (coffHeader.SizeOfOptionalHeader != 0)
                {
                    if (coffHeader.SizeOfOptionalHeader != (ushort)Marshal.SizeOf(typeof(PEOptHeader)))
                    {
                        // Problem!
                        return false;
                    }
                    else
                    {
                        // Read in the optHeader
                        byte[] optHeader_rawData = oMemoryFunctions.readMemory(process, PE_header + 4 + (uint)Marshal.SizeOf(typeof(COFFHeader)), (uint)Marshal.SizeOf(typeof(PEOptHeader)));
                        PEOptHeader optHeader = (PEOptHeader)oMemoryFunctions.RawDataToObject(ref optHeader_rawData, typeof(PEOptHeader));

                        // Confirm that it loaded correctly
                        if (optHeader.signature != 267)
                        {
                            return false;
                        }

                        if( optHeader.SizeOfCode == 0 )
                            return false;
                    }
                }
                else
                {
                    // No COFFHeader found
                    return false;
                }


                return true;
            }
            else
            {
                return false;

            }
        }
        /// <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 oHeaderReader(Process process, UInt64 address)
        {
            codeStartAddress = 0;
            codeLength = 0;
            invalidCodeAddresses = new List<ADDRESS_RANGE>(0);

            // Read in the Image Dos Header
            importTable = new List<IMPORT_FUNCTION>(0);
            byte[] headerData = oMemoryFunctions.readMemory(process, address, (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)));
            dosHeader = (IMAGE_DOS_HEADER)oMemoryFunctions.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 = oMemoryFunctions.readMemory(process, 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.
                oConsole.printMessage("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 = oMemoryFunctions.readMemory(process, PE_header + 4, (uint)Marshal.SizeOf(typeof(COFFHeader)));
            coffHeader = (COFFHeader)oMemoryFunctions.RawDataToObject(ref coffHeader_rawData, typeof(COFFHeader));

            // Read in the PEOptHeader if it exists
            if (coffHeader.SizeOfOptionalHeader != 0)
            {
                if (coffHeader.SizeOfOptionalHeader != (ushort)Marshal.SizeOf(typeof(PEOptHeader)))
                {
                    // Problem!
                    oConsole.printMessage("Failed to read COFFHeader as a result of size mismatch. Size of expected COFFHeader, " + ((ushort)Marshal.SizeOf(typeof(PEOptHeader))).ToString() + ", does not equal size of SizeOfOptionalHeader, " + coffHeader.SizeOfOptionalHeader.ToString() + ".");
                    return;
                }
                else
                {
                    // Read in the optHeader
                    byte[] optHeader_rawData = oMemoryFunctions.readMemory(process, PE_header + 4 + (uint)Marshal.SizeOf(typeof(COFFHeader)), (uint)Marshal.SizeOf(typeof(PEOptHeader)));
                    optHeader = (PEOptHeader)oMemoryFunctions.RawDataToObject(ref optHeader_rawData, typeof(PEOptHeader));

                    // Confirm that it loaded correctly
                    if (optHeader.signature != 267)
                    {
                        oConsole.printMessage("Failed to read optHeader; Expected signature of 267 does not match read in signature of " + optHeader.signature.ToString() + ".");
                        return;
                    }
                }
            }
            else
            {
                // No COFFHeader found
                oConsole.printMessage("Warning, no COFFHeader found for address " + address.ToString("X") + ".");
                return;
            }
            

            // Add all the directories as invalid code ranges
            try
            {
                if (optHeader.DataDirectory1_export.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory1_export.VirtualAddress),
                            optHeader.DataDirectory1_export.Size));
                if (optHeader.DataDirectory2_import.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory2_import.VirtualAddress),
                            optHeader.DataDirectory2_import.Size));
                if (optHeader.DataDirectory3.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory3.VirtualAddress),
                            optHeader.DataDirectory3.Size));
                if (optHeader.DataDirectory4.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory4.VirtualAddress),
                            optHeader.DataDirectory4.Size));
                if (optHeader.DataDirectory5.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory5.VirtualAddress),
                            optHeader.DataDirectory5.Size));
                if (optHeader.DataDirectory6.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory6.VirtualAddress),
                            optHeader.DataDirectory6.Size));
                if (optHeader.DataDirectory7.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory7.VirtualAddress),
                            optHeader.DataDirectory7.Size));
                if (optHeader.DataDirectory8.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory8.VirtualAddress),
                            optHeader.DataDirectory8.Size));
                if (optHeader.DataDirectory9.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory9.VirtualAddress),
                            optHeader.DataDirectory9.Size));
                if (optHeader.DataDirectory10.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory10.VirtualAddress),
                            optHeader.DataDirectory10.Size));
                if (optHeader.DataDirectory11.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory11.VirtualAddress),
                            optHeader.DataDirectory11.Size));
                if (optHeader.DataDirectory12.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory12.VirtualAddress),
                            optHeader.DataDirectory12.Size));
                if (optHeader.DataDirectory13.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory13.VirtualAddress),
                            optHeader.DataDirectory13.Size));
                if (optHeader.DataDirectory14.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory14.VirtualAddress),
                            optHeader.DataDirectory14.Size));
                if (optHeader.DataDirectory15.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory15.VirtualAddress),
                            optHeader.DataDirectory15.Size));
                if (optHeader.DataDirectory16.Size > 0)
                    invalidCodeAddresses.Add(
                        new ADDRESS_RANGE(
                            oMemoryFunctions.addressAdd(address, optHeader.DataDirectory16.VirtualAddress),
                            optHeader.DataDirectory16.Size));
            }catch
            {
                // Ignore exceptions, this is not cretical.
            }

            // Extract the names of the functions and corresponding table entries
            uint importTableAddress = oMemoryFunctions.addressAdd(optHeader.DataDirectory2_import.VirtualAddress,(uint) address);
            uint exportTableAddress = oMemoryFunctions.addressAdd(optHeader.DataDirectory1_export.VirtualAddress, (uint) address);

            // 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));
            }  

            // Load the import directory
            loadImportTable(process, importTableAddress, optHeader.DataDirectory2_import.Size, (uint)address);

            // Load the export directory
            loadExportTable(process, exportTableAddress, optHeader.DataDirectory1_export.Size, (uint) address, optHeader, sections);

            // Load the section structures
            int numSections = coffHeader.NumberOfSections;
            sections = new List<IMAGE_SECTION_HEADER_MOD>(numSections);
            for( uint i = 0; i < numSections; i++ )
            {
                ulong sectionBase = PE_header + 4 + (ulong)Marshal.SizeOf(typeof(COFFHeader)) + (uint)Marshal.SizeOf(typeof(PEOptHeader)) + i * (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
                byte[] sectionData = oMemoryFunctions.readMemory(process, sectionBase, (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)));
                IMAGE_SECTION_HEADER section = (IMAGE_SECTION_HEADER)oMemoryFunctions.RawDataToObject(ref sectionData, typeof(IMAGE_SECTION_HEADER));

                // Convert the raw section to a more friendly section type
                sections.Add(new IMAGE_SECTION_HEADER_MOD(section));
            }
        }