Esempio n. 1
0
        /// <summary>
        /// Parse a PE.
        /// </summary>
        /// <param name="stream">A stream of the PE contents.</param>
        private void Parse(Stream stream)
        {
            rawData = new byte[stream.Length];
            stream.Read(rawData, 0, (int)stream.Length);
            stream.Seek(0, SeekOrigin.Begin);

            BinaryReader reader = new BinaryReader(stream);

            dosHeader = PEUtility.FromBinaryReader <IMAGE_DOS_HEADER>(reader);

            int stubSize = (int)dosHeader.e_lfanew - Marshal.SizeOf(typeof(IMAGE_DOS_HEADER));

            dosStub = reader.ReadBytes(stubSize);

            // Add 4 bytes to the offset
            stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
            ntSignature     = PEUtility.FromBinaryReader <IMAGE_NT_HEADERS>(reader);
            fileHeader      = PEUtility.FromBinaryReader <IMAGE_FILE_HEADER>(reader);
            optionalHeader  = PEUtility.FromBinaryReader <IMAGE_OPTIONAL_HEADER32>(reader);
            dataDirectories = PEUtility.FromBinaryReader <IMAGE_DATA_DIRECTORIES>(reader);

            sections = new List <PESection>();
            for (int i = 0; i < fileHeader.NumberOfSections; i++)
            {
                IMAGE_SECTION_HEADER header  = PEUtility.FromBinaryReader <IMAGE_SECTION_HEADER>(reader);
                PESection            section = new PESection(header);
                section.Parse(ref rawData);
                sections.Add(section);
            }
        }
Esempio n. 2
0
        private void Serialize(uint totalSize)
        {
            /* Allocate enough space to contain the whole new file */
            byte[] file         = new byte[totalSize];
            uint   filePosition = SerializeHeader(ref file);

            Array.Copy(PEUtility.RawSerialize(dataDirectories), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_DATA_DIRECTORIES)));
            filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_DATA_DIRECTORIES));

            // XXX: Sections must be sorted in layout order!
            foreach (PESection section in sections)
            {
                Array.Copy(PEUtility.RawSerialize(section.Header), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)));
                filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER));
            }

            /* Copy the section data */
            filePosition = optionalHeader.SizeOfHeaders;
            sections.Sort(new SectionPhysicalComparer());
            foreach (PESection s in sections)
            {
                Array.Copy(s.Data, 0, file, filePosition, s.Data.Length);
                filePosition += s.RawSize;
                break;
            }

            /* Overwrite the container data */
            rawData = file;
        }
Esempio n. 3
0
        private void Parse(Stream stream)
        {
            rawData = new byte[stream.Length];
            stream.Read(rawData, 0, (int)stream.Length);
            stream.Seek(0, SeekOrigin.Begin);
            BinaryReader reader = new BinaryReader(stream);

            fileHeader = PEUtility.FromBinaryReader <IMAGE_FILE_HEADER>(reader);

            // Read the sections
            sections = new List <PESection>();
            for (int i = 0; i < fileHeader.NumberOfSections; i++)
            {
                IMAGE_SECTION_HEADER header;
                header = PEUtility.FromBinaryReader <IMAGE_SECTION_HEADER>(reader);
                PESection section = new PESection(this, header);
                section.Parse(ref rawData);
                sections.Add(section);
            }

            // Read the symbol table from fileHeader.PointerToSymbolTable
            symbolTable = new SymbolTable(fileHeader.NumberOfSymbols);
            stream.Seek(fileHeader.PointerToSymbolTable, SeekOrigin.Begin);
            for (int i = 0; i < fileHeader.NumberOfSymbols; i++)
            {
                IMAGE_SYMBOL symbol;
                symbol = PEUtility.FromBinaryReader <IMAGE_SYMBOL>(reader);
                symbolTable.AddSymbol(symbol, i);
            }

            uint pointerToStringTable = fileHeader.PointerToSymbolTable +
                                        (uint)(fileHeader.NumberOfSymbols * Marshal.SizeOf(typeof(IMAGE_SYMBOL)));

            stream.Seek(pointerToStringTable, SeekOrigin.Begin);
            uint stringTableSize = PEUtility.FromBinaryReader <UInt32>(reader);

            for (ushort i = (ushort)Marshal.SizeOf(typeof(UInt32)); i < stringTableSize;)
            {
                String stringEntry = PEUtility.StringFromBinaryReader(reader);
                symbolTable.AddString(stringEntry, i);
                i += (ushort)(stringEntry.Length + 1); // include NULL terminator
            }

            Console.WriteLine("Object File: {0}", sourceFile);
            Console.WriteLine(symbolTable.ToString());
            Console.WriteLine("Sections:");
            foreach (PESection s in sections)
            {
                Console.WriteLine(s.ToString());
            }
            Console.WriteLine();
        }
Esempio n. 4
0
        /// <summary>
        /// Updates the physical location of all sections, and updates the amount of initialized data
        /// </summary>
        public void UpdatePhysicalLayout()
        {
            uint fileAlignment, filePosition;

            switch (optionalStandard.Magic)
            {
            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32:
                fileAlignment = optionalHeader32.FileAlignment;
                filePosition  = optionalHeader32.SizeOfHeaders;
                break;

            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_ROM:
                throw new NotSupportedException();

            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32PLUS:
                fileAlignment = optionalHeader32plus.FileAlignment;
                filePosition  = optionalHeader32plus.SizeOfHeaders;
                break;

            default:
                throw new ArgumentException();
            }

            uint initializedDataSize = 0;

            /* Layout the sections in physical order */
            foreach (var s in sections)
            {
                if (s.ContributesToFileSize)
                {
                    //TODO use null coalecing operator somehow
                    if (s.Data != null)
                    {
                        s.RawSize = PEUtility.AlignUp((uint)s.Data.Length, fileAlignment);
                    }
                    else
                    {
                        s.RawSize = PEUtility.AlignUp(s.RawSize, fileAlignment);
                    }
                    s.PhysicalAddress = filePosition;

                    filePosition        += s.RawSize;
                    initializedDataSize += s.RawSize;
                }
            }

            optionalStandard.SizeOfInitializedData = initializedDataSize;
        }
Esempio n. 5
0
        void ParseRelocations(ref byte[] file)
        {
            relocations = new List <IMAGE_RELOCATION>();

            if (!HasRelocations)
            {
                return;
            }

            MemoryStream stream = new MemoryStream(file);

            stream.Seek(header.PointerToRelocations, SeekOrigin.Begin);
            BinaryReader reader = new BinaryReader(stream);

            for (int i = 0; i < header.NumberOfRelocations; i++)
            {
                IMAGE_RELOCATION reloc;
                reloc = PEUtility.FromBinaryReader <IMAGE_RELOCATION>(reader);
                relocations.Add(reloc);
            }
        }
Esempio n. 6
0
        private uint SerializeHeader(ref byte[] file)
        {
            uint filePosition = 0;

            Array.Copy(PEUtility.RawSerialize(dosHeader), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)));
            filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_DOS_HEADER));

            Array.Copy(dosStub, 0, file, filePosition, dosStub.Length);
            filePosition += (uint)dosStub.Length;

            Array.Copy(PEUtility.RawSerialize(ntSignature), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_NT_HEADERS)));
            filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_NT_HEADERS));

            Array.Copy(PEUtility.RawSerialize(fileHeader), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_FILE_HEADER)));
            filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_FILE_HEADER));

            Array.Copy(PEUtility.RawSerialize(optionalHeader), 0, file, filePosition, Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32)));
            filePosition += (uint)Marshal.SizeOf(typeof(IMAGE_OPTIONAL_HEADER32));

            return(filePosition);
        }
Esempio n. 7
0
        public void UpdateVirtualLayout(uint initialVirtualAddress = StartingVirtualAddress)
        {
            uint virtualAlignment;

            switch (optionalStandard.Magic)
            {
            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32:
                virtualAlignment = optionalHeader32.SectionAlignment;
                break;

            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_ROM:
                throw new NotSupportedException();

            case IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32PLUS:
                virtualAlignment = optionalHeader32plus.SectionAlignment;
                break;

            default:
                throw new ArgumentException();
            }

            /*
             * Fix up virtual addresses of the sections.
             * We start at 0x1000 (seems to be the convention)
             * Text should come first, then followed by data, then reloc
             * As we encounter certain sections, we need to update
             * special fields (data directory entries etc.).
             */
            uint virtualPosition        = initialVirtualAddress;
            bool dataSectionEncountered = false;

            foreach (var s in sections)
            {
                //update optional header
                switch (s.Name)
                {
                case TEXT:
                    optionalStandard.BaseOfCode = virtualPosition;
                    break;

                case RDATA:
                case DATA:
                    //PE32 headers want to know where the data starts
                    if (optionalStandard.Magic == IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32 && !dataSectionEncountered)
                    {
                        dataSectionEncountered      = true;
                        optionalHeader32.BaseOfData = virtualPosition;
                    }
                    break;
                }

                //update virtual address
                if (s.VirtualAddress != virtualPosition)
                {
                    switch (s.Name)
                    {
                    case RSRC:
                        ResourceTable res;
                        using (var ms = new MemoryStream(s.Data))
                        {
                            //need to give it the original RVA 'cause that's important
                            res = new ResourceTable(ms, s.VirtualAddress);
                        }
                        res.UpdateVirtualAddress(virtualPosition);
                        //this is only safe because all I've done is changed the virtual address and reserialized the data
                        //this means the data size can only go DOWN (because of alignment not being included)
                        //do not repeat this anywhere else where the data gets changed
                        s.Data = res.ToArray();
                        goto default;

                    default:
                        s.VirtualAddress = virtualPosition;
                        break;
                    }
                }

                //update size
                if (s.HasUninitializedData)
                {
                    // Leave uninitialized data sizes untouched, their raw size is 0
                }
                else if (s.HasInitializedData && s.HasCode)
                {
                    //TODO really not sure why this is here...
                    // It is possible for the virtual size to be greater than the size of raw data
                    // Leave the virtual size untouched if this is the case
                    if (s.VirtualSize <= s.RawSize)
                    {
                        s.VirtualSize = (uint)s.Data.Length;
                    }
                }

                virtualPosition += PEUtility.AlignUp(s.VirtualSize, virtualAlignment);
            }

            /* Total virtual size is the final virtual address, which includes the initial virtual offset. */
            if (optionalStandard.Magic == IMAGE_OPTIONAL_HEADER_STANDARD.MAGIC_PE32)
            {
                optionalHeader32.SizeOfImage = virtualPosition;
            }
            else
            {
                optionalHeader32plus.SizeOfImage = virtualPosition;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Layout contents of PE file, updating headers and order sections.
        /// </summary>
        /// <returns>Returns bool describing if layout succeeded.</returns>
        public bool Layout()
        {
            uint virtualAlignment    = optionalHeader.SectionAlignment;
            uint fileAlignment       = optionalHeader.FileAlignment;
            uint totalSize           = 0;
            uint initializedDataSize = 0;

            totalSize += optionalHeader.SizeOfHeaders;
            /* Calculate total physical size required */
            foreach (PESection s in sections)
            {
                totalSize += PEUtility.AlignUp((uint)s.Data.Length, fileAlignment);
            }

            /* Layout the sections in physical order */
            uint filePosition = optionalHeader.SizeOfHeaders;

            sections.Sort(new SectionPhysicalComparer());
            foreach (PESection s in sections)
            {
                if (s.ContributesToFileSize())
                {
                    s.RawSize         = PEUtility.AlignUp((uint)s.Data.Length, fileAlignment);
                    s.PhysicalAddress = filePosition;

                    filePosition        += s.RawSize;
                    initializedDataSize += PEUtility.AlignUp((uint)s.Data.Length, fileAlignment);
                }
                break;
            }

            optionalHeader.SizeOfInitializedData = initializedDataSize;

            /*
             * Fix up virtual addresses of the sections.
             * We start at 0x1000 (seems to be the convention)
             * Text should come first, then followed by data, then reloc
             * As we encounter certain sections, we need to update
             * special fields (data directory entries etc.).
             */
            uint virtAddr = 0x1000;
            bool dataSectionEncountered = false;

            sections.Sort(new SectionVirtualComparer());
            foreach (PESection s in sections)
            {
                if (s.Name == ".text")
                {
                    optionalHeader.BaseOfCode = virtAddr;
                }

                if (!dataSectionEncountered &&
                    ((s.Name == ".data") || (s.Name == ".rdata")))
                {
                    dataSectionEncountered    = true;
                    optionalHeader.BaseOfData = virtAddr;
                }

                if (s.Name == ".rdata")
                {
                    dataDirectories.debug.VirtualAddress = virtAddr;
                }

                if (s.Name == ".reloc")
                {
                    dataDirectories.baseReloc.VirtualAddress = virtAddr;
                }

                s.VirtualAddress = virtAddr;

                if (s.HasUninitializedData)
                {
                    // Leave uninitialized data sizes untouched, their raw size is 0
                    virtAddr += PEUtility.AlignUp(s.VirtualSize, virtualAlignment);
                }
                else if (s.HasInitializedData && s.HasCode)
                {
                    // It is possible for the virtual size to be greater than the size of raw data
                    // Leave the virtual size untouched if this is the case
                    if (s.VirtualSize > s.RawSize)
                    {
                        virtAddr += PEUtility.AlignUp(s.VirtualSize, virtualAlignment);
                    }
                    else
                    {
                        s.VirtualSize = (uint)s.Data.Length;
                        virtAddr     += PEUtility.AlignUp((uint)s.Data.Length, virtualAlignment);
                    }
                }

                break;
            }

            /* Total virtual size is the final virtual address, which includes the initial virtual offset. */
            optionalHeader.SizeOfImage = virtAddr;

            /* Serialize and write the header contents */
            Serialize(totalSize);

            return(true);
        }