コード例 #1
0
        internal GPT(byte[] GPTBuffer)
        {
            this.GPTBuffer = GPTBuffer;
            UInt32?TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART");

            if (TempHeaderOffset == null)
            {
                throw new Exception("Bad GPT");
            }
            HeaderOffset       = (UInt32)TempHeaderOffset;
            HeaderSize         = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x0C);
            TableOffset        = HeaderOffset + 0x200;
            FirstUsableSector  = ByteOperations.ReadUInt64(GPTBuffer, HeaderOffset + 0x28);
            LastUsableSector   = ByteOperations.ReadUInt64(GPTBuffer, HeaderOffset + 0x30);
            MaxPartitions      = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x50);
            PartitionEntrySize = ByteOperations.ReadUInt32(GPTBuffer, HeaderOffset + 0x54);
            TableSize          = MaxPartitions * PartitionEntrySize;
            if ((TableOffset + TableSize) > GPTBuffer.Length)
            {
                throw new Exception("Bad GPT");
            }

            UInt32 PartitionOffset = TableOffset;

            while (PartitionOffset < (TableOffset + TableSize))
            {
                string Name = ByteOperations.ReadUnicodeString(GPTBuffer, PartitionOffset + 0x38, 0x48).TrimEnd(new char[] { (char)0, ' ' });
                if (Name.Length == 0)
                {
                    break;
                }
                Partition CurrentPartition = new Partition();
                CurrentPartition.Name              = Name;
                CurrentPartition.FirstSector       = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x20);
                CurrentPartition.LastSector        = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x28);
                CurrentPartition.PartitionTypeGuid = ByteOperations.ReadGuid(GPTBuffer, PartitionOffset + 0x00);
                CurrentPartition.PartitionGuid     = ByteOperations.ReadGuid(GPTBuffer, PartitionOffset + 0x10);
                CurrentPartition.Attributes        = ByteOperations.ReadUInt64(GPTBuffer, PartitionOffset + 0x30);
                Partitions.Add(CurrentPartition);
                PartitionOffset += PartitionEntrySize;
            }

            HasChanged = false;
        }
コード例 #2
0
 public byte[] GetResultingBuffer()
 {
     byte[] StoreHeaderBuffer = new byte[0xF8];
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0, UpdateType);
     ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x04, MajorVersion);
     ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x06, MinorVersion);
     ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x08, FullFlashMajorVersion);
     ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x0A, FullFlashMinorVersion);
     ByteOperations.WriteAsciiString(StoreHeaderBuffer, 0x0C, PlatformId);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xCC, BlockSizeInBytes);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD0, WriteDescriptorCount);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD4, WriteDescriptorLength);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD8, ValidateDescriptorCount);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xDC, ValidateDescriptorLength);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE0, InitialTableIndex);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE4, InitialTableCount);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE8, FlashOnlyTableIndex);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xEC, FlashOnlyTableCount);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF0, FinalTableIndex);
     ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF4, FinalTableCount);
     return(StoreHeaderBuffer);
 }
コード例 #3
0
        internal static FlashingPayload[] GetOptimizedPayloads(FlashPart[] flashParts, UInt32 chunkSize, ulong PlatEnd)
        {
            List <FlashingPayload> flashingPayloads = new List <FlashingPayload>();

            if (flashParts == null)
            {
                return(flashingPayloads.ToArray());
            }

            Int64 TotalProcess1 = 0;

            for (Int32 j = 0; j < flashParts.Count(); j++)
            {
                FlashPart flashPart = flashParts[j];
                TotalProcess1 += flashPart.Stream.Length / chunkSize;
            }

            Int64    CurrentProcess1 = 0;
            DateTime startTime       = DateTime.Now;

            Logging.Log("Hashing resources...");

            using (SHA256 crypto = SHA256.Create())
            {
                for (UInt32 j = 0; j < flashParts.Count(); j++)
                {
                    FlashPart flashPart = flashParts[(Int32)j];

                    flashPart.Stream.Seek(0, SeekOrigin.Begin);
                    Int64 totalChunkCount = flashPart.Stream.Length / chunkSize;

                    for (UInt32 i = 0; i < totalChunkCount; i++)
                    {
                        byte[] buffer   = new byte[chunkSize];
                        Int64  position = flashPart.Stream.Position;
                        flashPart.Stream.Read(buffer, 0, (Int32)chunkSize);
                        byte[] hash = crypto.ComputeHash(buffer);

                        byte[] emptyness = new byte[] { 0xFA, 0x43, 0x23, 0x9B, 0xCE, 0xE7, 0xB9, 0x7C, 0xA6, 0x2F, 0x00, 0x7C, 0xC6, 0x84, 0x87, 0x56, 0x0A, 0x39, 0xE1, 0x9F, 0x74, 0xF3, 0xDD, 0xE7, 0x48, 0x6D, 0xB3, 0xF9, 0x8D, 0xF8, 0xE4, 0x71 };

                        if ((((UInt32)flashPart.StartLocation / chunkSize) + i) < PlatEnd || !ByteOperations.Compare(emptyness, hash))
                        {
                            flashingPayloads.Add(new FlashingPayload(1, new byte[][] { hash }, new UInt32[] { ((UInt32)flashPart.StartLocation / chunkSize) + i }, new UInt32[] { j }, new Int64[] { position }));
                        }

                        /*if (flashingPayloads.Any(x => ByteOperations.Compare(x.ChunkHashes.First(), hash)))
                         * {
                         *  var payloadIndex = flashingPayloads.FindIndex(x => ByteOperations.Compare(x.ChunkHashes.First(), hash));
                         *  var locationList = flashingPayloads[payloadIndex].TargetLocations.ToList();
                         *  locationList.Add(((UInt32)flashPart.StartLocation / chunkSize) + i);
                         *  flashingPayloads[payloadIndex].TargetLocations = locationList.ToArray();
                         * }
                         * else
                         * {
                         *  flashingPayloads.Add(new FlashingPayload(1, new byte[][] { hash }, new UInt32[] { ((UInt32)flashPart.StartLocation / chunkSize) + i }, new UInt32[] { j }, new Int64[] { position }));
                         * }*/

                        CurrentProcess1++;
                        ShowProgress(CurrentProcess1, TotalProcess1, startTime, (((UInt32)flashPart.StartLocation / chunkSize) + i) < PlatEnd);
                    }
                }
            }

            return(flashingPayloads.ToArray());
        }
コード例 #4
0
        private static void GenerateFFU(string ImageFile, string FFUFile, string PlatformId, UInt32 chunkSize, string AntiTheftVersion, string Osversion, string[] excluded, UInt32 BlankSectorBufferSize)
        {
            Logging.Log("Input image: " + ImageFile);
            Logging.Log("Destination image: " + FFUFile);
            Logging.Log("Platform ID: " + PlatformId);
            Logging.Log("");

            Stream stream;

            if (ImageFile.ToLower().Contains(@"\\.\physicaldrive"))
            {
                stream = new DeviceStream(ImageFile, FileAccess.Read);
            }
            else
            {
                stream = new FileStream(ImageFile, FileMode.Open);
            }

            (FlashPart[] flashParts, ulong PlatEnd, List <GPT.Partition> partitions) = ImageSplitter.GetImageSlices(stream, chunkSize, excluded);

            IOrderedEnumerable <FlashingPayload> payloads = FlashingPayloadGenerator.GetOptimizedPayloads(flashParts, chunkSize, BlankSectorBufferSize).OrderBy(x => x.TargetLocations.First()); // , PlatEnd

            Logging.Log("");
            Logging.Log("Building image headers...");

            string     header1       = Path.GetTempFileName();
            FileStream Headerstream1 = new FileStream(header1, FileMode.OpenOrCreate);

            // ==============================
            // Header 1 start

            ImageHeader image   = new ImageHeader();
            FullFlash   ffimage = new FullFlash();
            Store       simage  = new Store();

            // Todo make this read the image itself
            ffimage.OSVersion         = Osversion;
            ffimage.DevicePlatformId0 = PlatformId;
            ffimage.AntiTheftVersion  = AntiTheftVersion;

            simage.SectorSize     = 512;
            simage.MinSectorCount = (UInt32)(stream.Length / 512);

            Logging.Log("Generating image manifest...");
            string manifest = ManifestIni.BuildUpManifest(ffimage, simage, partitions);

            byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(manifest);

            image.ManifestLength = (UInt32)TextBytes.Length;

            byte[] ImageHeaderBuffer = new byte[0x18];

            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0, image.Size);
            ByteOperations.WriteAsciiString(ImageHeaderBuffer, 0x04, image.Signature);
            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x10, image.ManifestLength);
            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x14, image.ChunkSize);

            Headerstream1.Write(ImageHeaderBuffer, 0, 0x18);
            Headerstream1.Write(TextBytes, 0, TextBytes.Length);

            RoundUpToChunks(Headerstream1, chunkSize);

            // Header 1 stop + round
            // ==============================

            string     header2       = Path.GetTempFileName();
            FileStream Headerstream2 = new FileStream(header2, FileMode.OpenOrCreate);

            // ==============================
            // Header 2 start

            StoreHeader store = new StoreHeader();

            store.WriteDescriptorCount = (UInt32)payloads.Count();
            store.FinalTableIndex      = (UInt32)payloads.Count() - store.FinalTableCount;
            store.PlatformId           = PlatformId;

            foreach (FlashingPayload payload in payloads)
            {
                store.WriteDescriptorLength += payload.GetStoreHeaderSize();
            }

            foreach (FlashingPayload payload in payloads)
            {
                if (payload.TargetLocations.First() > PlatEnd)
                {
                    break;
                }
                store.FlashOnlyTableIndex += 1;
            }

            byte[] StoreHeaderBuffer = new byte[0xF8];
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0, store.UpdateType);
            ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x04, store.MajorVersion);
            ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x06, store.MinorVersion);
            ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x08, store.FullFlashMajorVersion);
            ByteOperations.WriteUInt16(StoreHeaderBuffer, 0x0A, store.FullFlashMinorVersion);
            ByteOperations.WriteAsciiString(StoreHeaderBuffer, 0x0C, store.PlatformId);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xCC, store.BlockSizeInBytes);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD0, store.WriteDescriptorCount);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD4, store.WriteDescriptorLength);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xD8, store.ValidateDescriptorCount);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xDC, store.ValidateDescriptorLength);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE0, store.InitialTableIndex);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE4, store.InitialTableCount);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xE8, store.FlashOnlyTableIndex);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xEC, store.FlashOnlyTableCount);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF0, store.FinalTableIndex);
            ByteOperations.WriteUInt32(StoreHeaderBuffer, 0xF4, store.FinalTableCount);
            Headerstream2.Write(StoreHeaderBuffer, 0, 0xF8);

            byte[] descriptorsBuffer = new byte[store.WriteDescriptorLength];

            UInt32 NewWriteDescriptorOffset = 0;

            foreach (FlashingPayload payload in payloads)
            {
                ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x00, (UInt32)payload.TargetLocations.Count()); // Location count
                ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x04, payload.ChunkCount);                      // Chunk count
                NewWriteDescriptorOffset += 0x08;

                foreach (UInt32 location in payload.TargetLocations)
                {
                    ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x00, 0x00000000);                          // Disk access method (0 = Begin, 2 = End)
                    ByteOperations.WriteUInt32(descriptorsBuffer, NewWriteDescriptorOffset + 0x04, location);                            // Chunk index
                    NewWriteDescriptorOffset += 0x08;
                }
            }

            Headerstream2.Write(descriptorsBuffer, 0, (Int32)store.WriteDescriptorLength);

            RoundUpToChunks(Headerstream2, chunkSize);

            // Header 2 stop + round
            // ==============================

            SecurityHeader security = new SecurityHeader();

            Headerstream1.Seek(0, SeekOrigin.Begin);
            Headerstream2.Seek(0, SeekOrigin.Begin);

            security.HashTableSize = 0x20 * (UInt32)((Headerstream1.Length + Headerstream2.Length) / chunkSize);

            foreach (FlashingPayload payload in payloads)
            {
                security.HashTableSize += payload.GetSecurityHeaderSize();
            }

            byte[]       HashTable = new byte[security.HashTableSize];
            BinaryWriter bw        = new BinaryWriter(new MemoryStream(HashTable));

            SHA256 crypto = SHA256.Create();

            for (int i = 0; i < Headerstream1.Length / chunkSize; i++)
            {
                byte[] buffer = new byte[chunkSize];
                Headerstream1.Read(buffer, 0, (Int32)chunkSize);
                byte[] hash = crypto.ComputeHash(buffer);
                bw.Write(hash, 0, hash.Length);
            }

            for (int i = 0; i < Headerstream2.Length / chunkSize; i++)
            {
                byte[] buffer = new byte[chunkSize];
                Headerstream2.Read(buffer, 0, (Int32)chunkSize);
                byte[] hash = crypto.ComputeHash(buffer);
                bw.Write(hash, 0, hash.Length);
            }

            foreach (FlashingPayload payload in payloads)
            {
                bw.Write(payload.ChunkHashes[0], 0, payload.ChunkHashes[0].Length);
            }

            bw.Close();

            Logging.Log("Generating image catalog...");
            byte[] catalog = GenerateCatalogFile(HashTable);

            security.CatalogSize = (UInt32)catalog.Length;

            byte[] SecurityHeaderBuffer = new byte[0x20];

            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0, security.Size);
            ByteOperations.WriteAsciiString(SecurityHeaderBuffer, 0x04, security.Signature);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x10, security.ChunkSizeInKb);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x14, security.HashAlgorithm);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x18, security.CatalogSize);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x1C, security.HashTableSize);

            FileStream retstream = new FileStream(FFUFile, FileMode.CreateNew);

            retstream.Write(SecurityHeaderBuffer, 0, 0x20);

            retstream.Write(catalog, 0, (Int32)security.CatalogSize);
            retstream.Write(HashTable, 0, (Int32)security.HashTableSize);

            RoundUpToChunks(retstream, chunkSize);

            Headerstream1.Seek(0, SeekOrigin.Begin);
            Headerstream2.Seek(0, SeekOrigin.Begin);

            byte[] buff = new byte[Headerstream1.Length];
            Headerstream1.Read(buff, 0, (Int32)Headerstream1.Length);

            Headerstream1.Close();
            File.Delete(header1);

            retstream.Write(buff, 0, buff.Length);

            buff = new byte[Headerstream2.Length];
            Headerstream2.Read(buff, 0, (Int32)Headerstream2.Length);

            Headerstream2.Close();
            File.Delete(header2);

            retstream.Write(buff, 0, buff.Length);

            Logging.Log("Writing payloads...");
            UInt64 counter = 0;

            DateTime startTime = DateTime.Now;

            foreach (FlashingPayload payload in payloads)
            {
                UInt32    StreamIndex = payload.StreamIndexes.First();
                FlashPart flashPart   = flashParts[StreamIndex];
                Stream    Stream      = flashPart.Stream;
                Stream.Seek(payload.StreamLocations.First(), SeekOrigin.Begin);
                byte[] buffer = new byte[chunkSize];
                Stream.Read(buffer, 0, (Int32)chunkSize);
                retstream.Write(buffer, 0, (Int32)chunkSize);
                counter++;
                ShowProgress((UInt64)payloads.Count() * chunkSize, startTime, counter * chunkSize, counter * chunkSize, payload.TargetLocations.First() * chunkSize < PlatEnd);
            }

            retstream.Close();
            Logging.Log("");
        }
コード例 #5
0
        internal static FlashingPayload[] GetOptimizedPayloads(FlashPart[] flashParts, UInt32 chunkSize, UInt32 BlankSectorBufferSize)
        {
            List <FlashingPayload> flashingPayloads = new List <FlashingPayload>();

            if (flashParts == null)
            {
                return(flashingPayloads.ToArray());
            }

            Int64 TotalProcess1 = 0;

            for (Int32 j = 0; j < flashParts.Count(); j++)
            {
                FlashPart flashPart = flashParts[j];
                TotalProcess1 += flashPart.Stream.Length / chunkSize;
            }

            Int64    CurrentProcess1 = 0;
            DateTime startTime       = DateTime.Now;

            Logging.Log("Hashing resources...");

            ulong maxblank   = BlankSectorBufferSize;
            bool  blankphase = false;
            ulong blankcount = 0;
            List <FlashingPayload> blankbuffer = new List <FlashingPayload>();

            using (SHA256 crypto = SHA256.Create())
            {
                for (UInt32 j = 0; j < flashParts.Count(); j++)
                {
                    FlashPart flashPart = flashParts[(Int32)j];

                    flashPart.Stream.Seek(0, SeekOrigin.Begin);
                    Int64 totalChunkCount = flashPart.Stream.Length / chunkSize;

                    for (UInt32 i = 0; i < totalChunkCount; i++)
                    {
                        byte[] buffer   = new byte[chunkSize];
                        Int64  position = flashPart.Stream.Position;
                        flashPart.Stream.Read(buffer, 0, (Int32)chunkSize);
                        byte[] hash = crypto.ComputeHash(buffer);

                        byte[] emptyness = new byte[] { 0xFA, 0x43, 0x23, 0x9B, 0xCE, 0xE7, 0xB9, 0x7C, 0xA6, 0x2F, 0x00, 0x7C, 0xC6, 0x84, 0x87, 0x56, 0x0A, 0x39, 0xE1, 0x9F, 0x74, 0xF3, 0xDD, 0xE7, 0x48, 0x6D, 0xB3, 0xF9, 0x8D, 0xF8, 0xE4, 0x71 };

                        if (!ByteOperations.Compare(emptyness, hash))
                        {
                            flashingPayloads.Add(new FlashingPayload(1, new byte[][] { hash }, new UInt32[] { ((UInt32)flashPart.StartLocation / chunkSize) + i }, new UInt32[] { j }, new Int64[] { position }));

                            if (blankphase && blankcount < maxblank)
                            {
                                foreach (var blankpay in blankbuffer)
                                {
                                    flashingPayloads.Add(blankpay);
                                }
                            }

                            blankphase = false;
                            blankcount = 0;
                            blankbuffer.Clear();
                        }
                        else if (blankcount < maxblank)
                        {
                            blankphase = true;
                            blankcount++;
                            blankbuffer.Add(new FlashingPayload(1, new byte[][] { hash }, new UInt32[] { ((UInt32)flashPart.StartLocation / chunkSize) + i }, new UInt32[] { j }, new Int64[] { position }));
                        }
                        else if (blankcount >= maxblank && blankbuffer.Count > 0)
                        {
                            foreach (var blankpay in blankbuffer)
                            {
                                flashingPayloads.Add(blankpay);
                            }
                            blankbuffer.Clear();
                        }

                        CurrentProcess1++;
                        ShowProgress(CurrentProcess1, TotalProcess1, startTime, blankphase);
                    }
                }
            }

            return(flashingPayloads.ToArray());
        }
コード例 #6
0
ファイル: Program.cs プロジェクト: WOA-Project/img2ffu
        private static void GenerateFFU(string ImageFile, string FFUFile, string PlatformId, UInt32 chunkSize, string AntiTheftVersion, string Osversion, string[] excluded, UInt32 BlankSectorBufferSize)
        {
            Logging.Log("Input image: " + ImageFile);
            Logging.Log("Destination image: " + FFUFile);
            Logging.Log("Platform ID: " + PlatformId);
            Logging.Log("");

            Stream      stream;
            VirtualDisk destDisk = null;

            if (ImageFile.ToLower().Contains(@"\\.\physicaldrive"))
            {
                stream = new DeviceStream(ImageFile, FileAccess.Read);
            }
            else if (File.Exists(ImageFile) && Path.GetExtension(ImageFile).ToLowerInvariant() == ".vhd")
            {
                DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhd.Disk).Assembly);
                DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhdx.Disk).Assembly);
                destDisk = VirtualDisk.OpenDisk(ImageFile, FileAccess.Read);
                stream   = destDisk.Content;
            }
            else if (File.Exists(ImageFile) && Path.GetExtension(ImageFile).ToLowerInvariant() == ".vhdx")
            {
                DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhd.Disk).Assembly);
                DiscUtils.Setup.SetupHelper.RegisterAssembly(typeof(DiscUtils.Vhdx.Disk).Assembly);
                destDisk = VirtualDisk.OpenDisk(ImageFile, FileAccess.Read);
                stream   = destDisk.Content;
            }
            else if (File.Exists(ImageFile))
            {
                stream = new FileStream(ImageFile, FileMode.Open);
            }
            else
            {
                Logging.Log("Unknown input specified");
                return;
            }

            (FlashPart[] flashParts, ulong PlatEnd, List <GPT.Partition> partitions) = ImageSplitter.GetImageSlices(stream, chunkSize, excluded);

            IOrderedEnumerable <FlashingPayload> payloads = FlashingPayloadGenerator.GetOptimizedPayloads(flashParts, chunkSize, BlankSectorBufferSize).OrderBy(x => x.TargetLocations.First());

            Logging.Log("");
            Logging.Log("Building image headers...");

            string     header1       = Path.GetTempFileName();
            FileStream Headerstream1 = new FileStream(header1, FileMode.OpenOrCreate);

            // ==============================
            // Header 1 start

            ImageHeader image   = new ImageHeader();
            FullFlash   ffimage = new FullFlash();
            Store       simage  = new Store();

            // Todo make this read the image itself
            ffimage.OSVersion         = Osversion;
            ffimage.DevicePlatformId0 = PlatformId;
            ffimage.AntiTheftVersion  = AntiTheftVersion;

            simage.SectorSize     = 512;
            simage.MinSectorCount = (UInt32)(stream.Length / 512);

            Logging.Log("Generating image manifest...");
            string manifest = ManifestIni.BuildUpManifest(ffimage, simage, partitions);

            byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(manifest);

            image.ManifestLength = (UInt32)TextBytes.Length;

            byte[] ImageHeaderBuffer = new byte[0x18];

            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0, image.Size);
            ByteOperations.WriteAsciiString(ImageHeaderBuffer, 0x04, image.Signature);
            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x10, image.ManifestLength);
            ByteOperations.WriteUInt32(ImageHeaderBuffer, 0x14, image.ChunkSize);

            Headerstream1.Write(ImageHeaderBuffer, 0, 0x18);
            Headerstream1.Write(TextBytes, 0, TextBytes.Length);

            RoundUpToChunks(Headerstream1, chunkSize);

            // Header 1 stop + round
            // ==============================

            string     header2       = Path.GetTempFileName();
            FileStream Headerstream2 = new FileStream(header2, FileMode.OpenOrCreate);

            // ==============================
            // Header 2 start

            StoreHeader store = new StoreHeader();

            store.WriteDescriptorCount = (UInt32)payloads.Count();
            store.FinalTableIndex      = (UInt32)payloads.Count() - store.FinalTableCount;
            store.PlatformId           = PlatformId;

            byte[] WriteDescriptorBuffer = GetResultingBuffer(payloads);
            store.WriteDescriptorLength = (UInt32)WriteDescriptorBuffer.Length;

            foreach (FlashingPayload payload in payloads)
            {
                if (payload.TargetLocations.First() > PlatEnd)
                {
                    break;
                }
                store.FlashOnlyTableIndex += 1;
            }

            Headerstream2.Write(store.GetResultingBuffer(), 0, 0xF8);
            Headerstream2.Write(WriteDescriptorBuffer, 0, (Int32)store.WriteDescriptorLength);

            RoundUpToChunks(Headerstream2, chunkSize);

            // Header 2 stop + round
            // ==============================

            SecurityHeader security = new SecurityHeader();

            Headerstream1.Seek(0, SeekOrigin.Begin);
            Headerstream2.Seek(0, SeekOrigin.Begin);

            security.HashTableSize = 0x20 * (UInt32)((Headerstream1.Length + Headerstream2.Length) / chunkSize);

            foreach (FlashingPayload payload in payloads)
            {
                security.HashTableSize += payload.GetSecurityHeaderSize();
            }

            byte[]       HashTable = new byte[security.HashTableSize];
            BinaryWriter bw        = new BinaryWriter(new MemoryStream(HashTable));

            SHA256 crypto = SHA256.Create();

            for (int i = 0; i < Headerstream1.Length / chunkSize; i++)
            {
                byte[] buffer = new byte[chunkSize];
                Headerstream1.Read(buffer, 0, (Int32)chunkSize);
                byte[] hash = crypto.ComputeHash(buffer);
                bw.Write(hash, 0, hash.Length);
            }

            for (int i = 0; i < Headerstream2.Length / chunkSize; i++)
            {
                byte[] buffer = new byte[chunkSize];
                Headerstream2.Read(buffer, 0, (Int32)chunkSize);
                byte[] hash = crypto.ComputeHash(buffer);
                bw.Write(hash, 0, hash.Length);
            }

            foreach (FlashingPayload payload in payloads)
            {
                foreach (var chunkHash in payload.ChunkHashes)
                {
                    bw.Write(chunkHash, 0, chunkHash.Length);
                }
            }

            bw.Close();

            Logging.Log("Generating image catalog...");
            byte[] catalog = GenerateCatalogFile(HashTable);

            security.CatalogSize = (UInt32)catalog.Length;

            byte[] SecurityHeaderBuffer = new byte[0x20];

            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0, security.Size);
            ByteOperations.WriteAsciiString(SecurityHeaderBuffer, 0x04, security.Signature);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x10, security.ChunkSizeInKb);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x14, security.HashAlgorithm);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x18, security.CatalogSize);
            ByteOperations.WriteUInt32(SecurityHeaderBuffer, 0x1C, security.HashTableSize);

            FileStream retstream = new FileStream(FFUFile, FileMode.CreateNew);

            retstream.Write(SecurityHeaderBuffer, 0, 0x20);

            retstream.Write(catalog, 0, (Int32)security.CatalogSize);
            retstream.Write(HashTable, 0, (Int32)security.HashTableSize);

            RoundUpToChunks(retstream, chunkSize);

            Headerstream1.Seek(0, SeekOrigin.Begin);
            Headerstream2.Seek(0, SeekOrigin.Begin);

            byte[] buff = new byte[Headerstream1.Length];
            Headerstream1.Read(buff, 0, (Int32)Headerstream1.Length);

            Headerstream1.Close();
            File.Delete(header1);

            retstream.Write(buff, 0, buff.Length);

            buff = new byte[Headerstream2.Length];
            Headerstream2.Read(buff, 0, (Int32)Headerstream2.Length);

            Headerstream2.Close();
            File.Delete(header2);

            retstream.Write(buff, 0, buff.Length);

            Logging.Log("Writing payloads...");
            UInt64 counter = 0;

            DateTime startTime = DateTime.Now;

            foreach (FlashingPayload payload in payloads)
            {
                for (int i = 0; i < payload.StreamIndexes.Length; i++)
                {
                    UInt32    StreamIndex = payload.StreamIndexes[i];
                    FlashPart flashPart   = flashParts[StreamIndex];
                    Stream    Stream      = flashPart.Stream;
                    Stream.Seek(payload.StreamLocations[i], SeekOrigin.Begin);

                    byte[] buffer = new byte[chunkSize];
                    Stream.Read(buffer, 0, (Int32)chunkSize);
                    retstream.Write(buffer, 0, (Int32)chunkSize);
                    counter++;

                    ShowProgress((UInt64)payloads.Count() * chunkSize, startTime, counter * chunkSize, counter * chunkSize, payload.TargetLocations[i] * chunkSize < PlatEnd);
                }
            }

            retstream.Close();
            if (destDisk != null)
            {
                destDisk.Dispose();
            }
            Logging.Log("");
        }