Beispiel #1
0
        /// <summary>
        /// Initialize the common information about a Burn engine.
        /// </summary>
        /// <param name="reader">Binary reader open against a Burn engine.</param>
        /// <returns>True if initialized.</returns>
        protected bool Initialize(BinaryReader reader)
        {
            if (!GetWixburnSectionInfo(reader))
            {
                return(false);
            }

            reader.BaseStream.Seek(this.wixburnDataOffset, SeekOrigin.Begin);
            byte[] bytes  = reader.ReadBytes((int)BURN_SECTION_SIZE);
            UInt32 uint32 = 0;

            uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_MAGIC);
            if (BURN_SECTION_MAGIC != uint32)
            {
                Messaging.Instance.OnMessage(WixErrors.InvalidBundle(this.fileExe));
                return(false);
            }

            this.Version = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_VERSION);
            if (BURN_SECTION_VERSION != this.Version)
            {
                Messaging.Instance.OnMessage(WixErrors.BundleTooNew(this.fileExe, this.Version));
                return(false);
            }

            uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_FORMAT); // We only know how to deal with CABs right now
            if (1 != uint32)
            {
                Messaging.Instance.OnMessage(WixErrors.InvalidBundle(this.fileExe));
                return(false);
            }

            this.StubSize                = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_STUBSIZE);
            this.OriginalChecksum        = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALCHECKSUM);
            this.OriginalSignatureOffset = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET);
            this.OriginalSignatureSize   = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE);

            this.ContainerCount = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_COUNT);
            this.UXAddress      = this.StubSize;
            this.UXSize         = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_UXSIZE);

            // If there is an original signature use that to determine the engine size.
            if (0 < this.OriginalSignatureOffset)
            {
                this.EngineSize = this.OriginalSignatureOffset + this.OriginalSignatureSize;
            }
            else if (0 < this.SignatureOffset && 2 > this.ContainerCount) // if there is a signature and no attached containers, use the current signature.
            {
                this.EngineSize = this.SignatureOffset + this.SignatureSize;
            }
            else // just use the stub and UX container as the size of the engine.
            {
                this.EngineSize = this.StubSize + this.UXSize;
            }

            this.AttachedContainerAddress = this.ContainerCount > 1 ? this.EngineSize : 0;
            this.AttachedContainerSize    = this.ContainerCount > 1 ? BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE) : 0;

            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Appends a container to the exe and updates the ".wixburn" section data to point to it.
        /// </summary>
        /// <param name="containerStream">File stream to append to the current exe.</param>
        /// <param name="burnSectionOffsetSize">Offset of size field for this container in ".wixburn" section data.</param>
        /// <returns>true if the container data is successfully appended; false otherwise</returns>
        private bool AppendContainer(Stream containerStream, UInt32 containerSize, UInt32 burnSectionOffsetSize, UInt32 burnSectionCount)
        {
            if (this.invalidBundle)
            {
                return(false);
            }

            // Update the ".wixburn" section data
            this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, burnSectionCount);
            this.WriteToBurnSectionOffset(burnSectionOffsetSize, containerSize);

            // Append the container to the end of the existing bits.
            this.binaryWriter.BaseStream.Seek(0, SeekOrigin.End);
            BurnCommon.CopyStream(containerStream, this.binaryWriter.BaseStream, (int)containerSize);
            this.binaryWriter.BaseStream.Flush();

            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Checks for a valid DOS header in the current exe.
        /// </summary>
        /// <returns>true if the exe starts with a DOS stub; false otherwise</returns>
        private bool EnsureDosHeader(BinaryReader reader)
        {
            if (UInt32.MaxValue == this.peOffset)
            {
                byte[] bytes = reader.ReadBytes((int)IMAGE_DOS_HEADER_SIZE);

                // Verify the DOS 'MZ' signature.
                if (IMAGE_DOS_SIGNATURE != BurnCommon.ReadUInt16(bytes, IMAGE_DOS_HEADER_OFFSET_MAGIC))
                {
                    Messaging.Instance.OnMessage(WixErrors.InvalidStubExe(this.fileExe));
                    return(false);
                }

                this.peOffset = BurnCommon.ReadUInt32(bytes, IMAGE_DOS_HEADER_OFFSET_NTHEADER);
            }

            return(true);
        }
Beispiel #4
0
        /// <summary>
        /// Finds the ".wixburn" section in the current exe.
        /// </summary>
        /// <returns>true if the ".wixburn" section is successfully found; false otherwise</returns>
        private bool GetWixburnSectionInfo(BinaryReader reader)
        {
            if (UInt32.MaxValue == this.wixburnDataOffset)
            {
                if (!EnsureNTHeader(reader))
                {
                    return(false);
                }

                UInt32 wixburnSectionOffset = UInt32.MaxValue;
                byte[] bytes = new byte[IMAGE_SECTION_HEADER_SIZE];

                reader.BaseStream.Seek(this.firstSectionOffset, SeekOrigin.Begin);
                for (UInt16 sectionIndex = 0; sectionIndex < this.sections; ++sectionIndex)
                {
                    reader.Read(bytes, 0, bytes.Length);

                    if (IMAGE_SECTION_WIXBURN_NAME == BurnCommon.ReadUInt64(bytes, IMAGE_SECTION_HEADER_OFFSET_NAME))
                    {
                        wixburnSectionOffset = this.firstSectionOffset + (IMAGE_SECTION_HEADER_SIZE * sectionIndex);
                        break;
                    }
                }

                if (UInt32.MaxValue == wixburnSectionOffset)
                {
                    Messaging.Instance.OnMessage(WixErrors.StubMissingWixburnSection(this.fileExe));
                    return(false);
                }

                // we need 56 bytes for the manifest header, which is always going to fit in
                // the smallest alignment (512 bytes), but just to be paranoid...
                if (BURN_SECTION_SIZE > BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA))
                {
                    Messaging.Instance.OnMessage(WixErrors.StubWixburnSectionTooSmall(this.fileExe));
                    return(false);
                }

                this.wixburnDataOffset = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_POINTERTORAWDATA);
            }

            return(true);
        }
Beispiel #5
0
        /// <summary>
        /// Gets the attached container from the exe and extracts its contents to the output directory.
        /// </summary>
        /// <param name="outputDirectory">Directory to write extracted files to.</param>
        /// <returns>True if successful, false otherwise</returns>
        public bool ExtractAttachedContainer(string outputDirectory, string tempDirectory)
        {
            // No attached container to extract
            if (this.AttachedContainerAddress == 0 || this.AttachedContainerSize == 0)
            {
                return(false);
            }

            if (this.invalidBundle)
            {
                return(false);
            }

            Directory.CreateDirectory(outputDirectory);
            string tempCabPath = Path.Combine(tempDirectory, "attached.cab");

            this.binaryReader.BaseStream.Seek(this.AttachedContainerAddress, SeekOrigin.Begin);
            using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
            {
                BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize);
            }

            using (WixExtractCab extract = new WixExtractCab())
            {
                extract.Extract(tempCabPath, outputDirectory);
            }

            foreach (DictionaryEntry entry in this.attachedContainerPayloadNames)
            {
                string sourcePath      = Path.Combine(outputDirectory, (string)entry.Key);
                string destinationPath = Path.Combine(outputDirectory, (string)entry.Value);

                Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
                File.Delete(destinationPath);
                File.Move(sourcePath, destinationPath);
            }

            return(true);
        }
Beispiel #6
0
        /// <summary>
        /// Checks for a valid Windows PE signature (IMAGE_NT_SIGNATURE) in the current exe.
        /// </summary>
        /// <returns>true if the exe is a Windows executable; false otherwise</returns>
        private bool EnsureNTHeader(BinaryReader reader)
        {
            if (UInt32.MaxValue == this.firstSectionOffset)
            {
                if (!EnsureDosHeader(reader))
                {
                    return(false);
                }

                reader.BaseStream.Seek(this.peOffset, SeekOrigin.Begin);
                byte[] bytes = reader.ReadBytes((int)IMAGE_NT_HEADER_SIZE);

                // Verify the NT signature...
                if (IMAGE_NT_SIGNATURE != BurnCommon.ReadUInt32(bytes, IMAGE_NT_HEADER_OFFSET_SIGNATURE))
                {
                    Messaging.Instance.OnMessage(WixErrors.InvalidStubExe(this.fileExe));
                    return(false);
                }

                ushort sizeOptionalHeader = BurnCommon.ReadUInt16(bytes, IMAGE_NT_HEADER_OFFSET_SIZEOFOPTIONALHEADER);

                this.sections           = BurnCommon.ReadUInt16(bytes, IMAGE_NT_HEADER_OFFSET_NUMBEROFSECTIONS);
                this.firstSectionOffset = this.peOffset + IMAGE_NT_HEADER_SIZE + sizeOptionalHeader;

                this.checksumOffset = this.peOffset + IMAGE_NT_HEADER_SIZE + IMAGE_OPTIONAL_OFFSET_CHECKSUM;
                this.certificateTableSignatureOffset = this.peOffset + IMAGE_NT_HEADER_SIZE + sizeOptionalHeader - IMAGE_OPTIONAL_NEGATIVE_OFFSET_CERTIFICATETABLE;
                this.certificateTableSignatureSize   = this.certificateTableSignatureOffset + 4; // size is in the DWORD after the offset.

                bytes                = reader.ReadBytes(sizeOptionalHeader);
                this.Checksum        = BurnCommon.ReadUInt32(bytes, IMAGE_OPTIONAL_OFFSET_CHECKSUM);
                this.SignatureOffset = BurnCommon.ReadUInt32(bytes, sizeOptionalHeader - IMAGE_OPTIONAL_NEGATIVE_OFFSET_CERTIFICATETABLE);
                this.SignatureSize   = BurnCommon.ReadUInt32(bytes, sizeOptionalHeader - IMAGE_OPTIONAL_NEGATIVE_OFFSET_CERTIFICATETABLE + 4);
            }

            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// Gets the UX container from the exe and extracts its contents to the output directory.
        /// </summary>
        /// <param name="outputDirectory">Directory to write extracted files to.</param>
        /// <returns>True if successful, false otherwise</returns>
        public bool ExtractUXContainer(string outputDirectory, string tempDirectory)
        {
            // No UX container to extract
            if (this.UXAddress == 0 || this.UXSize == 0)
            {
                return(false);
            }

            if (this.invalidBundle)
            {
                return(false);
            }

            Directory.CreateDirectory(outputDirectory);
            string tempCabPath          = Path.Combine(tempDirectory, "ux.cab");
            string manifestOriginalPath = Path.Combine(outputDirectory, "0");
            string manifestPath         = Path.Combine(outputDirectory, "manifest.xml");

            this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin);
            using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
            {
                BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize);
            }

            using (WixExtractCab extract = new WixExtractCab())
            {
                extract.Extract(tempCabPath, outputDirectory);
            }

            Directory.CreateDirectory(Path.GetDirectoryName(manifestPath));
            File.Delete(manifestPath);
            File.Move(manifestOriginalPath, manifestPath);

            XmlDocument document = new XmlDocument();

            document.Load(manifestPath);
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);

            namespaceManager.AddNamespace("burn", BurnCommon.BurnNamespace);
            XmlNodeList uxPayloads = document.SelectNodes("/burn:BurnManifest/burn:UX/burn:Payload", namespaceManager);
            XmlNodeList payloads   = document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager);

            foreach (XmlNode uxPayload in uxPayloads)
            {
                XmlNode sourcePathNode = uxPayload.Attributes.GetNamedItem("SourcePath");
                XmlNode filePathNode   = uxPayload.Attributes.GetNamedItem("FilePath");

                string sourcePath      = Path.Combine(outputDirectory, sourcePathNode.Value);
                string destinationPath = Path.Combine(outputDirectory, filePathNode.Value);

                Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
                File.Delete(destinationPath);
                File.Move(sourcePath, destinationPath);
            }

            foreach (XmlNode payload in payloads)
            {
                XmlNode sourcePathNode = payload.Attributes.GetNamedItem("SourcePath");
                XmlNode filePathNode   = payload.Attributes.GetNamedItem("FilePath");
                XmlNode packagingNode  = payload.Attributes.GetNamedItem("Packaging");

                string sourcePath      = sourcePathNode.Value;
                string destinationPath = filePathNode.Value;
                string packaging       = packagingNode.Value;

                if (packaging.Equals("embedded", StringComparison.OrdinalIgnoreCase))
                {
                    this.attachedContainerPayloadNames.Add(new DictionaryEntry(sourcePath, destinationPath));
                }
            }

            return(true);
        }
Beispiel #8
0
 /// <summary>
 /// Reads a UInt64 value in little-endian format from an offset in an array of bytes.
 /// </summary>
 /// <param name="bytes">Array from which to read.</param>
 /// <param name="offset">Beginning offset from which to read.</param>
 /// <returns>value at offset</returns>
 private static UInt64 ReadUInt64(byte[] bytes, UInt32 offset)
 {
     Debug.Assert(offset + 8 <= bytes.Length);
     return(BurnCommon.ReadUInt32(bytes, offset) + ((UInt64)(BurnCommon.ReadUInt32(bytes, offset + 4)) << 32));
 }