internal byte[] Rebuild() { // The new binary will include the Qualcomm header, but not the signature and certificates, because they won't match anyway. byte[] NewBinary = new byte[Binary.Length]; Buffer.BlockCopy(Binary, 0, NewBinary, 0, (int)CompressedSubImageOffset); ByteOperations.WriteUInt32(NewBinary, 0x10, ByteOperations.ReadUInt32(NewBinary, 0x14)); // Complete image size - does not include signature and certs anymore ByteOperations.WriteUInt32(NewBinary, 0x18, 0x00000000); // Address of signature ByteOperations.WriteUInt32(NewBinary, 0x1C, 0x00000000); // Signature length ByteOperations.WriteUInt32(NewBinary, 0x20, 0x00000000); // Address of certificate ByteOperations.WriteUInt32(NewBinary, 0x24, 0x00000000); // Certificate length // Compress volume byte[] NewCompressedImage = LZMA.Compress(DecompressedImage, 0, (UInt32)DecompressedImage.Length); // Replace compressed volume and add correct padding // First copy new image Buffer.BlockCopy(NewCompressedImage, 0, NewBinary, (int)CompressedSubImageOffset, NewCompressedImage.Length); // Determine padding UInt32 OldSectionPadding = ByteOperations.Align(0, CompressedSubImageSize, 4) - CompressedSubImageSize; UInt32 NewSectionPadding = ByteOperations.Align(0, (UInt32)NewCompressedImage.Length, 4) - (UInt32)NewCompressedImage.Length; UInt32 OldFileSize = ByteOperations.ReadUInt24(Binary, FileHeaderOffset + 0x14); // Filesize includes fileheader. But it does not include the padding-bytes. Not even the padding bytes of the last section. UInt32 NewFileSize; if ((CompressedSubImageOffset + CompressedSubImageSize + OldSectionPadding) >= (FileHeaderOffset + OldFileSize)) { // Compressed image is the last section of this file NewFileSize = CompressedSubImageOffset - FileHeaderOffset + (UInt32)NewCompressedImage.Length; } else { // Compressed image is NOT the last section of this file NewFileSize = OldFileSize - CompressedSubImageSize - OldSectionPadding + (UInt32)NewCompressedImage.Length + NewSectionPadding; } // Add section padding for (int i = 0; i < NewSectionPadding; i++) { NewBinary[CompressedSubImageOffset + NewCompressedImage.Length + i] = PaddingByteValue; } // If there are more bytes after the section padding of the compressed image, then copy the trailing sections if (((Int32)FileHeaderOffset + OldFileSize - CompressedSubImageOffset - CompressedSubImageSize - OldSectionPadding) > 0) { Buffer.BlockCopy(Binary, (int)(CompressedSubImageOffset + CompressedSubImageSize + OldSectionPadding), NewBinary, (int)(CompressedSubImageOffset + NewCompressedImage.Length + NewSectionPadding), (int)(FileHeaderOffset + OldFileSize - CompressedSubImageOffset - CompressedSubImageSize - OldSectionPadding)); } // Add file padding // Filesize does not include last section padding or file padding UInt32 OldFilePadding = ByteOperations.Align(0, OldFileSize, 8) - OldFileSize; UInt32 NewFilePadding = ByteOperations.Align(0, NewFileSize, 8) - NewFileSize; for (int i = 0; i < NewFilePadding; i++) { NewBinary[FileHeaderOffset + NewFileSize + i] = PaddingByteValue; } if (NewCompressedImage.Length > CompressedSubImageSize) { Buffer.BlockCopy(Binary, (int)(FileHeaderOffset + OldFileSize + OldFilePadding), NewBinary, (int)(FileHeaderOffset + NewFileSize + NewFilePadding), (int)(VolumeHeaderOffset + VolumeSize - FileHeaderOffset - NewFileSize - NewFilePadding)); } else { Buffer.BlockCopy(Binary, (int)(FileHeaderOffset + OldFileSize + OldFilePadding), NewBinary, (int)(FileHeaderOffset + NewFileSize + NewFilePadding), (int)(VolumeHeaderOffset + VolumeSize - FileHeaderOffset - OldFileSize - OldFilePadding)); for (int i = (int)(VolumeHeaderOffset + VolumeSize - OldFileSize - OldFilePadding + NewFileSize + NewFilePadding); i < VolumeHeaderOffset + VolumeSize; i++) { NewBinary[i] = PaddingByteValue; } } CompressedSubImageSize = (UInt32)NewCompressedImage.Length; // Fix section ByteOperations.WriteUInt24(NewBinary, SectionHeaderOffset, CompressedSubImageSize + ByteOperations.ReadUInt16(Binary, SectionHeaderOffset + 0x14)); // Fix file ByteOperations.WriteUInt24(NewBinary, FileHeaderOffset + 0x14, NewFileSize); CalculateFileChecksum(NewBinary, FileHeaderOffset); // Fix volume (volume size is fixed) CalculateVolumeChecksum(NewBinary, VolumeHeaderOffset); Binary = NewBinary; return(Binary); }
internal void ReplaceFile(string Name, byte[] Binary) { EFI File = EFIs.Where(f => (string.Compare(Name, f.Name, true) == 0) || (string.Compare(Name, f.Guid.ToString(), true) == 0)).FirstOrDefault(); if (File == null) { throw new ArgumentOutOfRangeException(); } UInt32 OldBinarySize = File.Size; UInt32 NewBinarySize = (UInt32)Binary.Length; UInt32 OldSectionPadding = ByteOperations.Align(0, OldBinarySize, 4) - OldBinarySize; UInt32 NewSectionPadding = ByteOperations.Align(0, NewBinarySize, 4) - NewBinarySize; UInt32 OldFileSize = ByteOperations.ReadUInt24(DecompressedImage, File.FileOffset + 0x14); UInt32 NewFileSize = OldFileSize - OldBinarySize - OldSectionPadding + NewBinarySize + NewSectionPadding; UInt32 OldFilePadding = ByteOperations.Align(0, OldFileSize, 8) - OldFileSize; UInt32 NewFilePadding = ByteOperations.Align(0, NewFileSize, 8) - NewFileSize; if ((OldBinarySize + OldSectionPadding) != (NewBinarySize + NewSectionPadding)) { byte[] NewImage = new byte[DecompressedImage.Length - OldFileSize - OldFilePadding + NewFileSize + NewFilePadding]; // Also preserve space for File-alignement here // Copy Volume-head and File-head Buffer.BlockCopy(DecompressedImage, 0, NewImage, 0, (int)File.BinaryOffset); // Copy new binary Buffer.BlockCopy(Binary, 0, NewImage, (int)File.BinaryOffset, Binary.Length); // Insert section-padding for (int i = 0; i < NewSectionPadding; i++) { NewImage[File.BinaryOffset + NewBinarySize + i] = PaddingByteValue; } // Copy file-tail Buffer.BlockCopy( DecompressedImage, (int)(File.BinaryOffset + OldBinarySize + OldSectionPadding), NewImage, (int)(File.BinaryOffset + NewBinarySize + NewSectionPadding), (int)(File.FileOffset + OldFileSize - File.BinaryOffset - OldBinarySize - OldSectionPadding)); // Insert file-padding for (int i = 0; i < NewFilePadding; i++) { NewImage[File.BinaryOffset + NewFileSize + i] = PaddingByteValue; } // Copy volume-tail Buffer.BlockCopy( DecompressedImage, (int)(File.FileOffset + OldFileSize + OldFilePadding), NewImage, (int)(File.FileOffset + NewFileSize + NewFilePadding), (int)(DecompressedImage.Length - File.FileOffset - OldFileSize - OldFilePadding)); Int32 NewOffset = (int)(NewFileSize + NewFilePadding) - (int)(OldFileSize - OldFilePadding); // Fix section-size ByteOperations.WriteUInt24(NewImage, File.SectionOffset, (UInt32)(ByteOperations.ReadUInt24(NewImage, File.SectionOffset) + NewOffset)); // Fix file-size ByteOperations.WriteUInt24(NewImage, File.FileOffset + 0x14, (UInt32)(ByteOperations.ReadUInt24(NewImage, File.FileOffset + 0x14) + NewOffset)); // Fix volume-size - TODO: This is actually a QWORD ByteOperations.WriteUInt32(NewImage, DecompressedVolumeHeaderOffset + 0x20, (UInt32)(ByteOperations.ReadUInt32(NewImage, DecompressedVolumeHeaderOffset + 0x20) + NewOffset)); // Fix section-size ByteOperations.WriteUInt24(NewImage, DecompressedVolumeSectionHeaderOffset, (UInt32)(ByteOperations.ReadUInt24(NewImage, DecompressedVolumeSectionHeaderOffset) + NewOffset)); DecompressedImage = NewImage; // Modify all sizes in EFI's foreach (EFI CurrentFile in EFIs) { if (CurrentFile.FileOffset > File.FileOffset) { CurrentFile.FileOffset = (UInt32)(CurrentFile.FileOffset + NewOffset); CurrentFile.SectionOffset = (UInt32)(CurrentFile.SectionOffset + NewOffset); CurrentFile.BinaryOffset = (UInt32)(CurrentFile.BinaryOffset + NewOffset); } } } else { Buffer.BlockCopy(Binary, 0, DecompressedImage, (int)File.BinaryOffset, Binary.Length); for (int i = 0; i < NewSectionPadding; i++) { DecompressedImage[File.BinaryOffset + Binary.Length + i] = PaddingByteValue; } } // Calculate File-checksum CalculateFileChecksum(DecompressedImage, File.FileOffset); // Calculate Volume-checksum CalculateVolumeChecksum(DecompressedImage, DecompressedVolumeHeaderOffset); }