// Magic! internal byte[] Patch() { byte[] SecurityDxe = GetFile("SecurityDxe"); ClearEfiChecksum(SecurityDxe); UInt32?PatchOffset = ByteOperations.FindPattern(SecurityDxe, new byte[] { 0xF0, 0x41, 0x2D, 0xE9, 0xFF, 0xFF, 0xB0, 0xE1, 0x28, 0xD0, 0x4D, 0xE2, 0xFF, 0xFF, 0xA0, 0xE1, 0x00, 0x00, 0xFF, 0x13, 0x20, 0xFF, 0xA0, 0xE3 }, new byte[] { 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00 }, null); if (PatchOffset == null) { throw new BadImageFormatException(); } Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 }, 0, SecurityDxe, (int)PatchOffset, 8); ReplaceFile("SecurityDxe", SecurityDxe); byte[] SecurityServicesDxe = GetFile("SecurityServicesDxe"); ClearEfiChecksum(SecurityServicesDxe); PatchOffset = ByteOperations.FindPattern(SecurityServicesDxe, new byte[] { 0x10, 0xFF, 0xFF, 0xE5, 0x80, 0xFF, 0x10, 0xE3, 0xFF, 0xFF, 0xFF, 0x0A }, new byte[] { 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00 }, null); if (PatchOffset == null) { throw new BadImageFormatException(); } ByteOperations.WriteUInt8(SecurityServicesDxe, (UInt32)PatchOffset + 0x0B, 0xEA); PatchOffset = ByteOperations.FindPattern(SecurityServicesDxe, new byte[] { 0x11, 0xFF, 0xFF, 0xE5, 0x40, 0xFF, 0x10, 0xE3, 0xFF, 0xFF, 0xFF, 0x0A }, new byte[] { 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00 }, null); if (PatchOffset == null) { throw new BadImageFormatException(); } ByteOperations.WriteUInt8(SecurityServicesDxe, (UInt32)PatchOffset + 0x0B, 0xEA); ReplaceFile("SecurityServicesDxe", SecurityServicesDxe); return(Rebuild()); }
internal static List <QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash) { List <QualcommPartition> Result = new(); try { foreach (string FilePath in Directory.EnumerateFiles(Path)) { try { FileInfo Info = new(FilePath); if (Info.Length <= 0x80000) { QualcommPartition Loader; #if DEBUG System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath); #endif byte[] Binary = ParseAsHexFile(FilePath); Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary); // Make sure the RootKeyHash is not blank // If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH // We expect the user to know what he is doing in such case and we will ignore checks if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, new byte[RootKeyHash.Length])) { if (StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash) && (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload. { Result.Add(Loader); } } else { if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload. { Result.Add(Loader); } } } } catch { } } } catch { } return(Result); }
// Magic! internal byte[] Patch() { UInt32?PatchOffset = ByteOperations.FindPattern(Binary, new byte[] { 0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1 }, null, null); if (PatchOffset == null) { throw new BadImageFormatException(); } Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4); return(Binary); }
internal static bool IsFFU(string FileName) { bool Result = false; FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read); byte[] Signature = new byte[0x10]; FFUFile.Read(Signature, 0, 0x10); Result = ByteOperations.ReadAsciiString(Signature, 0x04, 0x0C) == "SignedImage "; FFUFile.Close(); return(Result); }
internal static List <QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash) { List <QualcommPartition> Result = new List <QualcommPartition>(); try { IEnumerable <string> FilePaths = Directory.EnumerateFiles(Path); foreach (string FilePath in FilePaths) { try { FileInfo Info = new FileInfo(FilePath); if (Info.Length <= 0x80000) { QualcommPartition Loader; #if DEBUG System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath); #endif byte[] Binary = ParseAsHexFile(FilePath); if (Binary == null) { Loader = new QualcommPartition(FilePath); } else { Loader = new QualcommPartition(Binary); } if ((StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash)) && (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload. { Result.Add(Loader); } } } catch { } } } catch { } return(Result); }
private void SetEDEPath() { QualcommPartition Programmer; string TempEDEPath; try { if (_EDEPath != null) { Programmer = new QualcommPartition(_EDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) { return; } } } catch { } try { TempEDEPath = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\WPInternals", "EDEPath", null); if (TempEDEPath != null) { Programmer = new QualcommPartition(TempEDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) { EDEPath = TempEDEPath; return; } } } catch { } TempEDEPath = LumiaV2UnlockBootViewModel.GetProgrammerPath(RootKeyHash, ProductType); if (TempEDEPath != null) { Programmer = new QualcommPartition(TempEDEPath); if (ByteOperations.Compare(Programmer.RootKeyHash, RootKeyHash)) { EDEPath = TempEDEPath; return; } } }
internal GPT(byte[] GPTBuffer) { this.GPTBuffer = GPTBuffer; UInt32?TempHeaderOffset = ByteOperations.FindAscii(GPTBuffer, "EFI PART"); if (TempHeaderOffset == null) { throw new WPinternalsException("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 WPinternalsException("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; }
private bool HasNewBootloaderFromMassStorage() { bool Result = false; MassStorage Phone = (MassStorage)PhoneNotifier.CurrentModel; Phone.OpenVolume(false); byte[] GPTBuffer = Phone.ReadSectors(1, 33); GPT GPT = new WPinternals.GPT(GPTBuffer); Partition Partition = GPT.GetPartition("UEFI"); byte[] UefiBuffer = Phone.ReadSectors(Partition.FirstSector, Partition.LastSector - Partition.FirstSector + 1); UEFI UEFI = new UEFI(UefiBuffer); string BootMgrName = UEFI.EFIs.Where(efi => ((efi.Name != null) && ((efi.Name.Contains("BootMgrApp")) || (efi.Name.Contains("FlashApp"))))).First().Name; byte[] BootMgr = UEFI.GetFile(BootMgrName); // "Header V2" Result = (ByteOperations.FindAscii(BootMgr, "Header V2") != null); Phone.CloseVolume(); return(Result); }
private bool VerifyFileChecksum(byte[] Image, UInt32 Offset) { // This function only checks fixed checksum-values 0x55 and 0xAA. UInt16 FileHeaderSize = 0x18; UInt32 FileSize = ByteOperations.ReadUInt24(Image, Offset + 0x14); byte[] Header = new byte[FileHeaderSize - 1]; System.Buffer.BlockCopy(Image, (int)Offset, Header, 0, FileHeaderSize - 1); ByteOperations.WriteUInt16(Header, 0x10, 0); // Clear checksum byte CurrentHeaderChecksum = ByteOperations.ReadUInt8(Image, Offset + 0x10); byte CalculatedHeaderChecksum = ByteOperations.CalculateChecksum8(Header, 0, (UInt32)FileHeaderSize - 1); if (CurrentHeaderChecksum != CalculatedHeaderChecksum) { return(false); } byte FileAttribs = ByteOperations.ReadUInt8(Image, Offset + 0x13); byte CurrentFileChecksum = ByteOperations.ReadUInt8(Image, Offset + 0x11); if ((FileAttribs & 0x40) > 0) { // Calculate file checksum byte CalculatedFileChecksum = ByteOperations.CalculateChecksum8(Image, Offset + FileHeaderSize, FileSize - FileHeaderSize); if (CurrentFileChecksum != CalculatedFileChecksum) { return(false); } } else { // Fixed file checksum if ((CurrentFileChecksum != 0xAA) && (CurrentFileChecksum != 0x55)) { return(false); } } return(true); }
internal static void PatchImg(string dump) { using (var fil = File.Open(dump, FileMode.Open)) { byte[] gptbuffer = new byte[0x4200]; fil.Seek(0x200, SeekOrigin.Begin); fil.Read(gptbuffer, 0, 0x4200); uint BackupLBA = ByteOperations.ReadUInt32(gptbuffer, 0x20); uint LastUsableLBA = ByteOperations.ReadUInt32(gptbuffer, 0x30); LogFile.Log("Previous BackupLBA: " + BackupLBA, LogType.ConsoleOnly); LogFile.Log("Previous LastUsableLBA: " + LastUsableLBA, LogType.ConsoleOnly); uint NewBackupLBA = 62078975u; uint NewLastUsableLBA = 62078942u; ByteOperations.WriteUInt32(gptbuffer, 0x20, NewBackupLBA); ByteOperations.WriteUInt32(gptbuffer, 0x30, NewLastUsableLBA); uint HeaderSize = ByteOperations.ReadUInt32(gptbuffer, 0x0C); uint PrevCRC = ByteOperations.ReadUInt32(gptbuffer, 0x10); LogFile.Log("Previous CRC: " + PrevCRC, LogType.ConsoleOnly); ByteOperations.WriteUInt32(gptbuffer, 0x10, 0); uint NewCRC = ByteOperations.CRC32(gptbuffer, 0, HeaderSize); LogFile.Log("New CRC: " + NewCRC, LogType.ConsoleOnly); ByteOperations.WriteUInt32(gptbuffer, 0x10, NewCRC); LogFile.Log("Writing", LogType.ConsoleOnly); fil.Seek(0x200, SeekOrigin.Begin); fil.Write(gptbuffer, 0, 0x4200); LogFile.Log("Done!", LogType.ConsoleOnly); } }
public void SwitchMode(SaharaMode Mode) { byte[] SwitchModeCommand = new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ByteOperations.WriteUInt32(SwitchModeCommand, 8, (UInt32)Mode); byte[] ResponsePattern = null; switch (Mode) { case SaharaMode.ImageTransferPending: ResponsePattern = new byte[] { 0x04, 0x00, 0x00, 0x00 }; break; case SaharaMode.MemoryDebug: ResponsePattern = new byte[] { 0x09, 0x00, 0x00, 0x00 }; break; case SaharaMode.Command: ResponsePattern = new byte[] { 0x0B, 0x00, 0x00, 0x00 }; break; } Serial.SendCommand(SwitchModeCommand, ResponsePattern); }
public bool ConnectToProgrammerInTestMode() { byte[] HelloPacketFromPcToProgrammer = new byte[0x20C]; ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730); ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730); ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730); ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445); bool HandshakeCompleted = ConnectToProgrammer(HelloPacketFromPcToProgrammer); if (HandshakeCompleted) { LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly); } else { LogFile.Log("Handshake with programmer failed", LogType.FileOnly); } return(HandshakeCompleted); }
internal static byte[] Decompress(byte[] Input, UInt32 Offset, UInt32 InputSize) { byte[] Properties = new byte[5]; Buffer.BlockCopy(Input, (int)Offset, Properties, 0, 5); UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5); SevenZip.Compression.LZMA.Decoder Coder = new SevenZip.Compression.LZMA.Decoder(); Coder.SetDecoderProperties(Properties); MemoryStream InStream = new MemoryStream(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D); byte[] Output = new byte[OutputSize]; MemoryStream OutStream = new MemoryStream(Output, true); Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null); OutStream.Flush(); OutStream.Close(); InStream.Close(); return(Output); }
public bool Handshake() { bool Result = true; try { byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 }); // Incoming Hello packet: // 00000001 = Hello command id // xxxxxxxx = Length // xxxxxxxx = Protocol version // xxxxxxxx = Supported version // xxxxxxxx = Max packet length // xxxxxxxx = Expected mode // 6 dwords reserved space LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly); LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly); LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly); LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly); byte[] HelloResponse = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] Ready = Serial.SendCommand(HelloResponse, new byte[] { 0x03, 0x00, 0x00, 0x00 }); } catch { Result = false; } return(Result); }
internal SBL3(string FileName) { Binary = null; // First try to parse as FFU try { if (FFU.IsFFU(FileName)) { FFU FFUFile = new FFU(FileName); Binary = FFUFile.GetPartition("SBL3"); } } catch { } // If not succeeded, then try to parse it as raw image if (Binary == null) { byte[] SBL3Header; byte[] SBL3Pattern = new byte[] { 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF }; byte[] SBL3Mask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }; UInt32?Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out SBL3Header); if (Offset != null) { UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size Binary = new byte[Length]; FileStream Stream = new FileStream(FileName, FileMode.Open, FileAccess.Read); Stream.Seek((long)Offset, SeekOrigin.Begin); Stream.Read(Binary, 0, (int)Length); Stream.Close(); } } }
private void CalculateFileChecksum(byte[] Image, UInt32 Offset) { UInt16 FileHeaderSize = 0x18; UInt32 FileSize = ByteOperations.ReadUInt24(Image, Offset + 0x14); ByteOperations.WriteUInt16(Image, Offset + 0x10, 0); // Clear checksum byte NewChecksum = ByteOperations.CalculateChecksum8(Image, Offset, (UInt32)FileHeaderSize - 1); ByteOperations.WriteUInt8(Image, Offset + 0x10, NewChecksum); // File-Header checksum byte FileAttribs = ByteOperations.ReadUInt8(Image, Offset + 0x13); if ((FileAttribs & 0x40) > 0) { // Calculate file checksum byte CalculatedFileChecksum = ByteOperations.CalculateChecksum8(Image, Offset + FileHeaderSize, FileSize - FileHeaderSize); ByteOperations.WriteUInt8(Image, Offset + 0x11, CalculatedFileChecksum); } else { // Fixed file checksum ByteOperations.WriteUInt8(Image, Offset + 0x11, 0xAA); } }
internal UEFI(byte[] UefiBinary) { Binary = UefiBinary; string VolumeHeaderMagic; UInt32?Offset = ByteOperations.FindAscii(Binary, "_FVH"); if (Offset == null) { throw new BadImageFormatException(); } else { VolumeHeaderOffset = (UInt32)Offset - 0x28; } if (!VerifyVolumeChecksum(Binary, VolumeHeaderOffset)) { throw new BadImageFormatException(); } VolumeSize = ByteOperations.ReadUInt32(Binary, VolumeHeaderOffset + 0x20); // TODO: This is actually a QWORD VolumeHeaderSize = ByteOperations.ReadUInt16(Binary, VolumeHeaderOffset + 0x30); PaddingByteValue = (ByteOperations.ReadUInt32(Binary, VolumeHeaderOffset + 0x2C) & 0x00000800) > 0 ? (byte)0xFF : (byte)0x00; // EFI_FVB_ERASE_POLARITY = 0x00000800 // In the volume look for a file of type EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE (0x0B) FileHeaderOffset = VolumeHeaderOffset + VolumeHeaderSize; bool VolumeFound = false; int FileType; UInt32 FileSize; do { if (!VerifyFileChecksum(Binary, FileHeaderOffset)) { throw new BadImageFormatException(); } FileType = ByteOperations.ReadUInt8(Binary, FileHeaderOffset + 0x12); FileSize = ByteOperations.ReadUInt24(Binary, FileHeaderOffset + 0x14); if (FileType == 0x0B) // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE { VolumeFound = true; } else { FileHeaderOffset += FileSize; // FileHeaderOffset in Volume-body must be Align 8 // In the file-header-attributes the file-alignment relative to the start of the volume is always set to 1, // so that alignment can be ignored. FileHeaderOffset = ByteOperations.Align(VolumeHeaderOffset + VolumeHeaderSize, FileHeaderOffset, 8); } }while (!VolumeFound && (FileHeaderOffset < (VolumeHeaderOffset + VolumeSize))); if (!VolumeFound) { throw new BadImageFormatException(); } // Look in file for section of type EFI_SECTION_GUID_DEFINED (0x02) SectionHeaderOffset = FileHeaderOffset + 0x18; int SectionType; UInt32 SectionSize; UInt16 SectionHeaderSize = 0; bool DecompressedVolumeFound = false; do { SectionType = ByteOperations.ReadUInt8(Binary, SectionHeaderOffset + 0x03); SectionSize = ByteOperations.ReadUInt24(Binary, SectionHeaderOffset + 0x00); if (SectionType == 0x02) // EFI_SECTION_GUID_DEFINED { SectionHeaderSize = ByteOperations.ReadUInt16(Binary, SectionHeaderOffset + 0x14); DecompressedVolumeFound = true; } else { SectionHeaderOffset += SectionSize; // SectionHeaderOffset in File-body must be Align 4 SectionHeaderOffset = ByteOperations.Align(FileHeaderOffset + 0x18, SectionHeaderOffset, 4); } }while (!DecompressedVolumeFound && (SectionHeaderOffset < (FileHeaderOffset + FileSize))); if (!DecompressedVolumeFound) { throw new BadImageFormatException(); } // Decompress subvolume CompressedSubImageOffset = SectionHeaderOffset + SectionHeaderSize; CompressedSubImageSize = SectionSize - SectionHeaderSize; // DECOMPRESS HERE DecompressedImage = LZMA.Decompress(Binary, CompressedSubImageOffset, CompressedSubImageSize); // Extracted volume contains Sections at its root level DecompressedVolumeSectionHeaderOffset = 0; DecompressedVolumeFound = false; do { SectionType = ByteOperations.ReadUInt8(DecompressedImage, DecompressedVolumeSectionHeaderOffset + 0x03); SectionSize = ByteOperations.ReadUInt24(DecompressedImage, DecompressedVolumeSectionHeaderOffset + 0x00); SectionHeaderSize = ByteOperations.ReadUInt16(DecompressedImage, DecompressedVolumeSectionHeaderOffset + 0x14); if (SectionType == 0x17) // EFI_SECTION_FIRMWARE_VOLUME_IMAGE { DecompressedVolumeFound = true; } else { DecompressedVolumeSectionHeaderOffset += SectionSize; // SectionHeaderOffset in File-body must be Align 4 DecompressedVolumeSectionHeaderOffset = ByteOperations.Align(FileHeaderOffset + 0x18, DecompressedVolumeSectionHeaderOffset, 4); } }while (!DecompressedVolumeFound && (DecompressedVolumeSectionHeaderOffset < DecompressedImage.Length)); if (!DecompressedVolumeFound) { throw new BadImageFormatException(); } DecompressedVolumeHeaderOffset = DecompressedVolumeSectionHeaderOffset + 4; // PARSE COMPRESSED VOLUME VolumeHeaderMagic = ByteOperations.ReadAsciiString(DecompressedImage, DecompressedVolumeHeaderOffset + 0x28, 0x04); if (VolumeHeaderMagic != "_FVH") { throw new BadImageFormatException(); } if (!VerifyVolumeChecksum(DecompressedImage, DecompressedVolumeHeaderOffset)) { throw new BadImageFormatException(); } Int32 DecompressedVolumeSize = ByteOperations.ReadInt32(DecompressedImage, DecompressedVolumeHeaderOffset + 0x20); // TODO: This is actually a QWORD UInt16 DecompressedVolumeHeaderSize = ByteOperations.ReadUInt16(DecompressedImage, DecompressedVolumeHeaderOffset + 0x30); // The files in this decompressed volume are the real EFI's. UInt32 DecompressedFileHeaderOffset = DecompressedVolumeHeaderOffset + DecompressedVolumeHeaderSize; EFI CurrentEFI; do { if ((DecompressedFileHeaderOffset + 0x18) >= (DecompressedVolumeHeaderOffset + DecompressedVolumeSize)) { break; } bool ContentFound = false; for (int i = 0; i < 0x18; i++) { if (DecompressedImage[DecompressedFileHeaderOffset + i] != PaddingByteValue) { ContentFound = true; break; } } if (!ContentFound) { break; } FileSize = ByteOperations.ReadUInt24(DecompressedImage, DecompressedFileHeaderOffset + 0x14); if ((DecompressedFileHeaderOffset + FileSize) >= (DecompressedVolumeHeaderOffset + DecompressedVolumeSize)) { break; } if (!VerifyFileChecksum(DecompressedImage, DecompressedFileHeaderOffset)) { throw new BadImageFormatException(); } CurrentEFI = new EFI(); CurrentEFI.Type = ByteOperations.ReadUInt8(DecompressedImage, DecompressedFileHeaderOffset + 0x12); byte[] FileGuidBytes = new byte[0x10]; System.Buffer.BlockCopy(DecompressedImage, (int)DecompressedFileHeaderOffset + 0x00, FileGuidBytes, 0, 0x10); CurrentEFI.Guid = new Guid(FileGuidBytes); // Parse sections of the EFI CurrentEFI.FileOffset = DecompressedFileHeaderOffset; UInt32 DecompressedSectionHeaderOffset = DecompressedFileHeaderOffset + 0x18; do { SectionType = ByteOperations.ReadUInt8(DecompressedImage, DecompressedSectionHeaderOffset + 0x03); SectionSize = ByteOperations.ReadUInt24(DecompressedImage, DecompressedSectionHeaderOffset + 0x00); // SectionTypes that are relevant here: // 0x10 = PE File // 0x19 = RAW // 0x15 = Description // Not all section headers in the UEFI specs are 4 bytes long, // but the sections that are used in Windows Phone EFI's all have a header of 4 bytes. if (SectionType == 0x15) { CurrentEFI.Name = ByteOperations.ReadUnicodeString(DecompressedImage, DecompressedSectionHeaderOffset + 0x04, SectionSize - 0x04).TrimEnd(new char[] { (char)0, ' ' }); } else if ((SectionType == 0x10) || (SectionType == 0x19)) { CurrentEFI.SectionOffset = DecompressedSectionHeaderOffset; CurrentEFI.BinaryOffset = DecompressedSectionHeaderOffset + 0x04; CurrentEFI.Size = SectionSize - 0x04; } DecompressedSectionHeaderOffset += SectionSize; // SectionHeaderOffset in File-body must be Align 4 DecompressedSectionHeaderOffset = ByteOperations.Align(DecompressedFileHeaderOffset + 0x18, DecompressedSectionHeaderOffset, 4); }while (DecompressedSectionHeaderOffset < (DecompressedFileHeaderOffset + FileSize)); DecompressedFileHeaderOffset += FileSize; // FileHeaderOffset in Volume-body must be Align 8 // In the file-header-attributes the file-alignment relative to the start of the volume is always set to 1, // so that alignment can be ignored. DecompressedFileHeaderOffset = ByteOperations.Align(DecompressedVolumeHeaderOffset + DecompressedVolumeHeaderSize, DecompressedFileHeaderOffset, 8); EFIs.Add(CurrentEFI); }while (DecompressedFileHeaderOffset < (DecompressedVolumeHeaderOffset + DecompressedVolumeSize)); }
internal QualcommPartition(byte[] Binary, uint Offset = 0) { #if DEBUG System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, 0, Binary.Length), "")); #endif this.Binary = Binary; byte[] LongHeaderPattern = new byte[] { 0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; byte[] LongHeaderMask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (ByteOperations.FindPattern(Binary, Offset, 4, new byte[] { 0x7F, 0x45, 0x4C, 0x46 }, new byte[] { 0x00, 0x00, 0x00, 0x00 }, null) == 0) { // This is an ELF image // First program header is a reference to the elf-header // Second program header is a reference to the signed hash-table HeaderType = QualcommPartitionHeaderType.Short; UInt32 ProgramHeaderOffset; UInt16 ProgramHeaderEntrySize; UInt32 HashTableProgramHeaderOffset; if (Binary[Offset + 0x04] == 1) { // 32-bit elf image ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c); ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a); HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize; ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04); HeaderOffset = ImageOffset + 8; } else if (Binary[Offset + 0x04] == 2) { // 64-bit elf image ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20); ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36); HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize; ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08); HeaderOffset = ImageOffset + 8; } else { throw new WPinternalsException("Invalid programmer"); } } else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null) { HeaderType = QualcommPartitionHeaderType.Short; ImageOffset = Offset; HeaderOffset = ImageOffset + 8; } else { HeaderType = QualcommPartitionHeaderType.Long; ImageOffset = Offset; HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length; } if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0) { ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00); } else if (HeaderType == QualcommPartitionHeaderType.Short) { ImageOffset += 0x28; } else { ImageOffset += 0x50; } ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04); ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08); CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C); SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10); SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14); SignatureOffset = SignatureAddress - ImageAddress + ImageOffset; CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18); CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C); CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset; uint CurrentCertificateOffset = CertificatesOffset; uint CertificateSize = 0; while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize)) { if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82)) { CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian! if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize)) { // This is the last certificate. So this is the root key. RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize); #if DEBUG System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, "")); #endif } #if DEBUG else { System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize), "")); } #endif CurrentCertificateOffset += CertificateSize; } else { if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset)) { CurrentCertificateOffset -= CertificateSize; // This is the last certificate. So this is the root key. RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize); #if DEBUG System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, "")); #endif } break; } } }
public bool ConnectToProgrammerInTestMode() { // Behaviour of old firehose: // Takes about 20 ms to be started. // Then PC has to start talking to the phone. // Behaviour of new firehose: // After 2000 ms the firehose starts talking to the PC // // For the duration of 2.5 seconds we will send Hello packages // And also wait for incoming messages // An incoming message can be a response to our outgoing Hello packet (read incoming until "response value") // Or it can be an incoming Hello-packet from the programmer (always 2 packets, starting with "Chip serial num") // Sending the hello-packet can succeed immediately, or it can timeout. // When sending succeeds, an answer should be incoming immediately to complete the handshake. // When an incoming Hello was received, the phone still expects to receive another Hello. byte[] HelloPacketFromPcToProgrammer = new byte[0x20C]; ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730); ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730); ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730); ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445); int HelloSendCount = 0; bool HandshakeCompleted = false; string Incoming; do { Serial.SetTimeOut(200); HelloSendCount++; try { LogFile.Log("Send Hello to programmer (" + HelloSendCount.ToString() + ")", LogType.FileOnly); Serial.SendData(HelloPacketFromPcToProgrammer); LogFile.Log("Hello packet accepted", LogType.FileOnly); } catch { LogFile.Log("Hello packet not accepted", LogType.FileOnly); } try { Serial.SetTimeOut(500); Incoming = System.Text.Encoding.ASCII.GetString(Serial.GetResponse(null)); LogFile.Log("In: " + Incoming, LogType.FileOnly); Serial.SetTimeOut(200); if (Incoming.Contains("Chip serial num")) { Incoming = System.Text.Encoding.ASCII.GetString(Serial.GetResponse(null)); LogFile.Log("In: " + Incoming, LogType.FileOnly); LogFile.Log("Incoming Hello-packets received", LogType.FileOnly); } while (Incoming.IndexOf("response value") < 0) { Incoming = System.Text.Encoding.ASCII.GetString(Serial.GetResponse(null)); LogFile.Log("In: " + Incoming, LogType.FileOnly); } ; LogFile.Log("Incoming Hello-response received", LogType.FileOnly); HandshakeCompleted = true; } catch { } }while (!HandshakeCompleted && (HelloSendCount < 6)); if (HandshakeCompleted) { LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly); } else { LogFile.Log("Handshake with programmer failed", LogType.FileOnly); } return(HandshakeCompleted); }
// V3 exploit // Magic // internal async static Task LumiaV3CustomFlash(PhoneNotifierViewModel Notifier, List <FlashPart> FlashParts, bool CheckSectorAlignment = true, SetWorkingStatus SetWorkingStatus = null, UpdateWorkingStatus UpdateWorkingStatus = null, ExitSuccess ExitSuccess = null, ExitFailure ExitFailure = null) { if (SetWorkingStatus == null) { SetWorkingStatus = (m, s, v, a, st) => { } } ; if (UpdateWorkingStatus == null) { UpdateWorkingStatus = (m, s, v, st) => { } } ; if (ExitSuccess == null) { ExitSuccess = (m, s) => { } } ; if (ExitFailure == null) { ExitFailure = (m, s) => { } } ; uint chunkSize = 131072u; int chunkSizes = 131072; if (FlashParts != null) { foreach (FlashPart Part in FlashParts) { if (Part.Stream == null) { throw new ArgumentException("Stream is null"); } if (!Part.Stream.CanSeek) { throw new ArgumentException("Streams must be seekable"); } if (((Part.StartSector * 0x200) % chunkSize) != 0) { throw new ArgumentException("Invalid StartSector alignment"); } if (CheckSectorAlignment) { if ((Part.Stream.Length % chunkSize) != 0) { throw new ArgumentException("Invalid Data length"); } } } } try { NokiaFlashModel Model = (NokiaFlashModel)Notifier.CurrentModel; PhoneInfo Info = Model.ReadPhoneInfo(); if ((Info.SecureFfuSupportedProtocolMask & ((ushort)FfuProtocol.ProtocolSyncV2)) == 0) // Exploit needs protocol v2 -> This check is not conclusive, because old phones also report support for this protocol, although it is really not supported. { throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that it does not support the Protocol Sync V2."); } if (Info.FlashAppProtocolVersionMajor < 2) // Old phones do not support the hack. These phones have Flash protocol 1.x. { throw new WPinternalsException("Flash failed!", "Protocols not supported. The phone reports that Flash App communication protocol is lower than 2. Reported version by the phone: " + Info.FlashAppProtocolVersionMajor + "."); } if (Info.UefiSecureBootEnabled) { throw new WPinternalsException("Flash failed!", "UEFI Secureboot must be disabled for the Flash V3 exploit to work."); } // The payloads must be ordered by the number of locations // // FlashApp processes payloads like this: // - First payloads which are with one location, those can be sent in bulk // - Then payloads with more than one location, those should not be sent in bulk // // If you do not order payloads like this, you will get an error, most likely hash mismatch // LumiaV2UnlockBootViewModel.FlashingPayload[] payloads = new LumiaV2UnlockBootViewModel.FlashingPayload[0]; if (FlashParts != null) { payloads = LumiaV2UnlockBootViewModel.GetNonOptimizedPayloads(FlashParts, chunkSizes, (uint)(Info.WriteBufferSize / chunkSize), SetWorkingStatus, UpdateWorkingStatus).OrderBy(x => x.TargetLocations.Count()).ToArray(); } MemoryStream Headerstream1 = new MemoryStream(); // ============================== // Header 1 start ImageHeader image = new ImageHeader(); FullFlash ffimage = new FullFlash(); Store simage = new Store(); // Todo make this read the image itself ffimage.OSVersion = "10.0.11111.0"; ffimage.DevicePlatformId0 = Info.PlatformID; ffimage.AntiTheftVersion = "1.1"; simage.SectorSize = 512; simage.MinSectorCount = Info.EmmcSizeInSectors; //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 // ============================== MemoryStream Headerstream2 = new MemoryStream(); // ============================== // Header 2 start StoreHeader store = new StoreHeader(); store.WriteDescriptorCount = (UInt32)payloads.Count(); store.FinalTableIndex = (UInt32)payloads.Count() - store.FinalTableCount; store.PlatformId = Info.PlatformID; foreach (LumiaV2UnlockBootViewModel.FlashingPayload payload in payloads) { store.WriteDescriptorLength += payload.GetStoreHeaderSize(); } foreach (LumiaV2UnlockBootViewModel.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 (LumiaV2UnlockBootViewModel.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 (LumiaV2UnlockBootViewModel.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 (LumiaV2UnlockBootViewModel.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); MemoryStream retstream = new MemoryStream(); 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(); retstream.Write(buff, 0, buff.Length); buff = new byte[Headerstream2.Length]; Headerstream2.Read(buff, 0, (Int32)Headerstream2.Length); Headerstream2.Close(); retstream.Write(buff, 0, buff.Length); // -------- // Go back to the beginning retstream.Seek(0, SeekOrigin.Begin); byte[] FfuHeader = new byte[retstream.Length]; await retstream.ReadAsync(FfuHeader, 0, (int)retstream.Length); retstream.Close(); byte Options = 0; if (!Info.IsBootloaderSecure) { Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); } LogFile.Log("Flash in progress...", LogType.ConsoleOnly); SetWorkingStatus("Flashing...", null, (UInt64?)payloads.Count(), Status: WPinternalsStatus.Flashing); Model.SendFfuHeaderV1(FfuHeader, Options); UInt64 counter = 0; int numberOfPayloadsToSendAtOnce = (int)Math.Round((double)Info.WriteBufferSize / chunkSize); byte[] payloadBuffer; for (int i = 0; i < payloads.Count(); i += numberOfPayloadsToSendAtOnce) { if (i + numberOfPayloadsToSendAtOnce - 1 >= payloads.Count()) { numberOfPayloadsToSendAtOnce = payloads.Count() - i; } payloadBuffer = new byte[numberOfPayloadsToSendAtOnce * chunkSizes]; string ProgressText = "Flashing resources"; for (int j = 0; j < numberOfPayloadsToSendAtOnce; j++) { LumiaV2UnlockBootViewModel.FlashingPayload payload = payloads[i + j]; UInt32 StreamIndex = payload.StreamIndexes.First(); FlashPart flashPart = FlashParts[(int)StreamIndex]; if (flashPart.ProgressText != null) { ProgressText = flashPart.ProgressText; } Stream Stream = flashPart.Stream; Stream.Seek(payload.StreamLocations.First(), SeekOrigin.Begin); Stream.Read(payloadBuffer, j * chunkSizes, chunkSizes); counter++; } Model.SendFfuPayloadV2(payloadBuffer, int.Parse((counter * 100 / (ulong)payloads.Count()).ToString())); UpdateWorkingStatus(ProgressText, null, counter, WPinternalsStatus.Flashing); } Model.ResetPhone(); await Notifier.WaitForRemoval(); ExitSuccess("Flash succeeded!", null); } catch { throw new WPinternalsException("Custom flash failed"); } } } }
public bool SendImage(string Path) { bool Result = true; LogFile.Log("Sending programmer: " + Path, LogType.FileOnly); int Step = 0; UInt32 Offset = 0; UInt32 Length = 0; byte[] ImageBuffer = null; try { Step = 1; byte[] Hello = null; Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 }); // Incoming Hello packet: // 00000001 = Hello command id // xxxxxxxx = Length // xxxxxxxx = Protocol version // xxxxxxxx = Supported version // xxxxxxxx = Max packet length // xxxxxxxx = Expected mode // 6 dwords reserved space LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly); LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly); LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly); LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly); // Packet: // 00000002 = Hello response command id // 00000030 = Length // 00000002 = Protocol version // 00000001 = Supported version // 00000000 = Status OK // 00000000 = Mode // rest is reserved space Step = 2; byte[] HelloResponse = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Serial.SendData(HelloResponse); Step = 3; using (System.IO.FileStream FileStream = new System.IO.FileStream(Path, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { while (true) { Step = 4; byte[] ReadDataRequest = Serial.GetResponse(null); UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0); if (ResponseID == 4) { break; } if (ResponseID != 3) { Step = 5; throw new BadConnectionException(); } Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C); Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10); if ((ImageBuffer == null) || (ImageBuffer.Length != Length)) { ImageBuffer = new byte[Length]; } if (FileStream.Position != Offset) { FileStream.Seek(Offset, System.IO.SeekOrigin.Begin); } Step = 6; FileStream.Read(ImageBuffer, 0, (int)Length); Step = 7; Serial.SendData(ImageBuffer); } } } catch (Exception Ex) { LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8")); Result = false; } if (Result) { LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly); } return(Result); }
internal byte[] GenerateExtraSector(byte[] PartitionHeader) { UInt32?Offset = ByteOperations.FindPattern(Binary, new byte[] { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, null, null); if (Offset == null) { throw new BadImageFormatException(); } UInt32 PartitionLoaderTableOffset = (UInt32)Offset; byte[] FoundPattern = new byte[0x10]; Offset = ByteOperations.FindPattern(Binary, new byte[] { 0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF }, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }, FoundPattern); if (Offset == null) { throw new BadImageFormatException(); } UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C); UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28; Offset = ByteOperations.FindPattern(Binary, new byte[] { 0x01, 0xFF, 0xA0, 0xE3, 0xFF, 0xFF, 0xA0, 0xE1, 0x1C, 0xD0, 0x8D, 0xE2, 0xF0, 0x4F, 0xBD, 0xE8, 0x1E, 0xFF, 0x2F, 0xE1 }, new byte[] { 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, null); if (Offset == null) { throw new BadImageFormatException(); } UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress; byte[] Sector = new byte[0x200]; Array.Clear(Sector, 0, 0x200); byte[] Content = new byte[] { 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0xBD, 0x02, 0x00, 0xD8, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE3, 0x3C, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0xC1, 0xE5, 0x38, 0x00, 0x9F, 0xE5, 0x38, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x34, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x30, 0x00, 0x9F, 0xE5, 0x20, 0x10, 0x9F, 0xE5, 0x2C, 0x30, 0x9F, 0xE5, 0x00, 0x20, 0x90, 0xE5, 0x00, 0x20, 0x81, 0xE5, 0x04, 0x00, 0x80, 0xE2, 0x04, 0x10, 0x81, 0xE2, 0x03, 0x00, 0x50, 0xE1, 0xF9, 0xFF, 0xFF, 0xBA, 0x14, 0xF0, 0x9F, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x90, 0xBF, 0x02, 0x00, 0xD0, 0xBF, 0x02, 0x00, 0xA0, 0xBD, 0x02, 0x00, 0xA0, 0xBE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] PartitionTypeGuid = new byte[] { 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74 }; Buffer.BlockCopy(Content, 0, Sector, 0, Content.Length); // Overwrite first part of partition-header with model-specific header Buffer.BlockCopy(PartitionHeader, 0, Sector, 0, PartitionHeader.Length); ByteOperations.WriteUInt32(Sector, 0x70, GlobalIsSecurityEnabledAddress); ByteOperations.WriteUInt32(Sector, 0x88, ReturnAddress); Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xA0, 0x50); ByteOperations.WriteUInt32(Sector, 0xA0 + 0x30, 0); Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xF0, 0x50); ByteOperations.WriteUInt32(Sector, 0xF0 + 0x2C, 0); ByteOperations.WriteUInt32(Sector, 0xF0 + 0x38, 0x210F0); Buffer.BlockCopy(PartitionTypeGuid, 0, Sector, 0x190, 0x10); ByteOperations.WriteUInt32(Sector, 0x1FC, 0x0002BD28); return(Sector); }
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); }
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 FFU(string Path) { this.Path = Path; try { OpenFile(); // Read Security Header byte[] ShortSecurityHeader = new byte[0x20]; FFUFile.Read(ShortSecurityHeader, 0, 0x20); if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ") { throw new BadImageFormatException(); } ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024; UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00); UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18); UInt32 HashTableSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x1C); SecurityHeader = new byte[RoundUpToChunks(SecurityHeaderSize + CatalogSize + HashTableSize)]; FFUFile.Seek(0, SeekOrigin.Begin); FFUFile.Read(SecurityHeader, 0, SecurityHeader.Length); // Read Image Header byte[] ShortImageHeader = new byte[0x1C]; FFUFile.Read(ShortImageHeader, 0, 0x1C); if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ") { throw new BadImageFormatException(); } UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00); UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10); ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)]; FFUFile.Seek(SecurityHeader.Length, SeekOrigin.Begin); FFUFile.Read(ImageHeader, 0, ImageHeader.Length); // Read Store Header byte[] ShortStoreHeader = new byte[248]; FFUFile.Read(ShortStoreHeader, 0, 248); PlatformID = ByteOperations.ReadAsciiString(ShortStoreHeader, 0x0C, 192).TrimEnd(new char[] { (char)0, ' ' }); int WriteDescriptorCount = ByteOperations.ReadInt32(ShortStoreHeader, 208); UInt32 WriteDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 212); UInt32 ValidateDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 220); StoreHeader = new byte[RoundUpToChunks(248 + WriteDescriptorLength + ValidateDescriptorLength)]; FFUFile.Seek(SecurityHeader.Length + ImageHeader.Length, SeekOrigin.Begin); FFUFile.Read(StoreHeader, 0, StoreHeader.Length); // Parse Chunk Indexes int HighestChunkIndex = 0; UInt32 LocationCount; int ChunkIndex; int ChunkCount; int DiskAccessMethod; UInt32 WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength; int FFUChunkIndex = 0; for (int i = 0; i < WriteDescriptorCount; i++) { LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00); ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04); for (int j = 0; j < LocationCount; j++) { DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08))); ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08))); if (DiskAccessMethod == 0 && (ChunkIndex + ChunkCount - 1) > HighestChunkIndex) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT. { HighestChunkIndex = ChunkIndex + ChunkCount - 1; } } WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08); FFUChunkIndex += ChunkCount; } ChunkIndexes = new int?[HighestChunkIndex + 1]; WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength; FFUChunkIndex = 0; for (int i = 0; i < WriteDescriptorCount; i++) { LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00); ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04); for (int j = 0; j < LocationCount; j++) { DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08))); ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08))); if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT. { for (int k = 0; k < ChunkCount; k++) { ChunkIndexes[ChunkIndex + k] = FFUChunkIndex + k; } } } WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08); FFUChunkIndex += ChunkCount; } byte[] GPTBuffer = GetSectors(0x01, 0x21); GPT = new GPT(GPTBuffer); HeaderSize = (UInt64)(SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length); TotalChunkCount = (UInt64)FFUChunkIndex; PayloadSize = TotalChunkCount * (UInt64)ChunkSize; TotalSize = HeaderSize + PayloadSize; if (TotalSize != (UInt64)FFUFile.Length) { throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + "."); } } catch (WPinternalsException) { throw; } catch (Exception Ex) { throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + Ex.Message, Ex); } finally { CloseFile(); } }
private void ClearEfiChecksum(byte[] EfiFile) { UInt32 PEHeaderOffset = ByteOperations.ReadUInt32(EfiFile, 0x3C); ByteOperations.WriteUInt32(EfiFile, PEHeaderOffset + 0x58, 0); }