Esempio n. 1
0
        // 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());
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        // 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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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;
                }
            }
        }
Esempio n. 7
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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);
            }
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        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);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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();
                }
            }
        }
Esempio n. 16
0
        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);
            }
        }
Esempio n. 17
0
        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));
        }
Esempio n. 18
0
        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;
                }
            }
        }
Esempio n. 19
0
        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);
        }
Esempio n. 20
0
        // 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");
            }
        }
    }
}
Esempio n. 21
0
        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);
        }
Esempio n. 22
0
        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);
        }
Esempio n. 23
0
        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);
        }
Esempio n. 24
0
        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);
        }
Esempio n. 25
0
        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();
            }
        }
Esempio n. 26
0
        private void ClearEfiChecksum(byte[] EfiFile)
        {
            UInt32 PEHeaderOffset = ByteOperations.ReadUInt32(EfiFile, 0x3C);

            ByteOperations.WriteUInt32(EfiFile, PEHeaderOffset + 0x58, 0);
        }