/// <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) { this.messageHandler.OnMessage(WixErrors.InvalidBundle(this.fileExe)); return(false); } this.Version = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_VERSION); if (BURN_SECTION_VERSION != this.Version) { this.messageHandler.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) { this.messageHandler.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); }
/// <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)) { this.messageHandler.OnMessage(WixErrors.InvalidStubExe(this.fileExe)); return(false); } this.peOffset = BurnCommon.ReadUInt32(bytes, IMAGE_DOS_HEADER_OFFSET_NTHEADER); } return(true); }
/// <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) { this.messageHandler.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)) { this.messageHandler.OnMessage(WixErrors.StubWixburnSectionTooSmall(this.fileExe)); return(false); } this.wixburnDataOffset = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_POINTERTORAWDATA); } return(true); }
/// <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)) { this.messageHandler.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); }
/// <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)); }