internal static FlashingPayload[] GetOptimizedPayloads(FlashPart[] flashParts, UInt32 chunkSize) { 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); 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); } } } return(flashingPayloads.ToArray()); }
internal static (FlashPart[], ulong, List <GPT.Partition> partitions) GetImageSlices(Stream stream, UInt32 chunkSize, string[] excluded) { byte[] GPTBuffer = new byte[chunkSize]; stream.Read(GPTBuffer, 0, (Int32)chunkSize); UInt32 sectorsInAChunk = chunkSize / 512u; GPT GPT = new GPT(GPTBuffer); List <GPT.Partition> Partitions = GPT.Partitions; bool isUnlocked = GPT.GetPartition("IS_UNLOCKED") != null; bool isUnlockedSpecA = GPT.GetPartition("HACK") != null && GPT.GetPartition("BACKUP_BS_NV") != null; if (isUnlocked) { Logging.Log("The phone is an unlocked Spec B phone, UEFI_BS_NV will be kept in the FFU image for the unlock to work"); } if (isUnlockedSpecA) { Logging.Log("The phone is an UEFI unlocked Spec A phone, UEFI_BS_NV will be kept in the FFU image for the unlock to work"); } List <FlashPart> flashParts = new List <FlashPart>(); Logging.Log("Partitions with a * appended are ignored partitions"); Logging.Log(""); bool previouswasexcluded = true; FlashPart currentFlashPart = null; ulong PlatEnd = 0; foreach (GPT.Partition partition in Partitions.OrderBy(x => x.FirstSector)) { if (partition.Name == "PLAT") { PlatEnd = partition.LastSector / sectorsInAChunk; } bool isExcluded = false; if (excluded.Any(x => x == partition.Name)) { isExcluded = true; if (isUnlocked && partition.Name == "UEFI_BS_NV") { isExcluded = false; } if (isUnlockedSpecA && partition.Name == "UEFI_BS_NV") { isExcluded = false; } } string outputstring = (isExcluded ? "*" : "") + partition.Name + new String(' ', 50); outputstring = outputstring.Insert(25, " - " + partition.FirstSector); outputstring = outputstring.Insert(40, " - " + partition.LastSector); Logging.Log(outputstring, isExcluded ? Logging.LoggingLevel.Warning : Logging.LoggingLevel.Information); if (isExcluded) { previouswasexcluded = true; if (currentFlashPart != null) { if ((currentFlashPart.StartLocation / 512) % 256 != 0) { Logging.Log("- The stream doesn't start on a chunk boundary, a chunk is 256 sectors", Logging.LoggingLevel.Error); throw new Exception(); } if (((currentFlashPart.Stream.Length / 512) % sectorsInAChunk) != 0) { Logging.Log("- The stream doesn't finish on a chunk boundary, a chunk is 256 sectors", Logging.LoggingLevel.Error); throw new Exception(); } flashParts.Add(currentFlashPart); currentFlashPart = null; } continue; } if (previouswasexcluded) { currentFlashPart = new FlashPart(stream, partition.FirstSector * 512); } previouswasexcluded = false; currentFlashPart.Stream = new PartialStream(stream, (Int64)currentFlashPart.StartLocation, (Int64)(partition.LastSector + 1) * 512); } if (!previouswasexcluded) { if (currentFlashPart != null) { currentFlashPart.Stream = new PartialStream(stream, (Int64)currentFlashPart.StartLocation, stream.Length); if ((currentFlashPart.StartLocation / 512) % 256 != 0) { Logging.Log("- The stream doesn't start on a chunk boundary, a chunk is 256 sectors", Logging.LoggingLevel.Error); throw new Exception(); } if (((currentFlashPart.Stream.Length / 512) % sectorsInAChunk) != 0) { Logging.Log("- The stream doesn't finish on a chunk boundary, a chunk is 256 sectors", Logging.LoggingLevel.Error); throw new Exception(); } flashParts.Add(currentFlashPart); } } Logging.Log(""); Logging.Log("Plat end: " + PlatEnd); Logging.Log(""); Logging.Log("Inserting GPT back into the FFU image"); flashParts.Insert(0, new FlashPart(new MemoryStream(GPTBuffer), 0)); return(flashParts.OrderBy(x => x.StartLocation).ToArray(), PlatEnd, Partitions); }
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()); }
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(""); }
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()); }
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(""); }