Ejemplo n.º 1
0
        /// <summary>
        /// Connects to the WebSocket server.
        /// </summary>
        /// <param name="uri">The URI of the WebSocket server.</param>
        /// <param name="customHeaders">Custom headers to send with the request.</param>
        /// <returns></returns>
        public override async Task ConnectAsync(Uri uri, IReadOnlyDictionary <string, string> customHeaders = null)
        {
            SocketMessageQueue = new ConcurrentQueue <string>();
            TokenSource        = new CancellationTokenSource();

            StreamDecompressor?.Dispose();
            CompressedStream?.Dispose();
            DecompressedStream?.Dispose();

            DecompressedStream = new MemoryStream();
            CompressedStream   = new MemoryStream();
            StreamDecompressor = new DeflateStream(CompressedStream, CompressionMode.Decompress);

            Socket = new ClientWebSocket();
            Socket.Options.KeepAliveInterval = TimeSpan.FromSeconds(20);
            if (Proxy != null) // because mono doesn't implement this properly
            {
                Socket.Options.Proxy = Proxy;
            }

            if (customHeaders != null)
            {
                foreach (var kvp in customHeaders)
                {
                    Socket.Options.SetRequestHeader(kvp.Key, kvp.Value);
                }
            }

            await Socket.ConnectAsync(uri, Token).ConfigureAwait(false);

            await OnConnectedAsync().ConfigureAwait(false);

            WsListener = Task.Run(ListenAsync, Token);
        }
Ejemplo n.º 2
0
        public override void WriteTo(Stream outputStream)
        {
            var compressedData = new MemoryStream();

            DecompressedStream.Position = 0;
            var compressorStream = CompressionAlgorithm.Compress(compressedData);

            DecompressedStream.CopyTo(compressorStream);
            compressorStream.Close();
            compressedData.Position = 0;
            Header.Length           = 1 + compressedData.Length; // algorithm byte + length
            base.WriteTo(outputStream);
            outputStream.WriteByte((byte)CompressionAlgorithm.Id);
            compressedData.CopyTo(outputStream);
        }
Ejemplo n.º 3
0
        internal async Task ListenAsync()
        {
            await Task.Yield();

            var buff    = new byte[BUFFER_SIZE];
            var buffseg = new ArraySegment <byte>(buff);

            byte[] resultbuff             = null;
            WebSocketReceiveResult result = null;
            SocketCloseEventArgs   close  = null;

            var token = Token;

            try
            {
                while (!token.IsCancellationRequested && Socket.State == WebSocketState.Open)
                {
                    using (var ms = new MemoryStream())
                    {
                        do
                        {
                            result = await Socket.ReceiveAsync(buffseg, token).ConfigureAwait(false);

                            if (result.MessageType == WebSocketMessageType.Close)
                            {
                                var cc = result.CloseStatus != null ? (int)result.CloseStatus.Value : -1;
                                close = new SocketCloseEventArgs(null)
                                {
                                    CloseCode = cc, CloseMessage = result.CloseStatusDescription
                                };
                            }
                            else
                            {
                                ms.Write(buff, 0, result.Count);
                            }
                        }while (!result.EndOfMessage);

                        resultbuff = ms.ToArray();
                    }

                    if (close != null)
                    {
                        break;
                    }

                    var resultstr = "";
                    if (result.MessageType == WebSocketMessageType.Binary)
                    {
                        if (resultbuff[0] == 0x78)
                        {
                            await CompressedStream.WriteAsync(resultbuff, 2, resultbuff.Length - 2).ConfigureAwait(false);
                        }
                        else
                        {
                            await CompressedStream.WriteAsync(resultbuff, 0, resultbuff.Length).ConfigureAwait(false);
                        }

                        await CompressedStream.FlushAsync().ConfigureAwait(false);

                        CompressedStream.Position = 0;

                        // partial credit to FiniteReality
                        // overall idea is their
                        // I tuned the finer details
                        // -Emzi
                        var sfix = BitConverter.ToUInt16(resultbuff, resultbuff.Length - 2);
                        if (sfix != ZLIB_STREAM_SUFFIX)
                        {
                            using (var zlib = new DeflateStream(CompressedStream, CompressionMode.Decompress, true))
                            {
                                await zlib.CopyToAsync(DecompressedStream).ConfigureAwait(false);
                            }
                        }
                        else
                        {
                            await StreamDecompressor.CopyToAsync(DecompressedStream).ConfigureAwait(false);
                        }

                        resultbuff = DecompressedStream.ToArray();
                        DecompressedStream.Position = 0;
                        DecompressedStream.SetLength(0);
                        CompressedStream.Position = 0;
                        CompressedStream.SetLength(0);
                    }

                    resultstr = UTF8.GetString(resultbuff, 0, resultbuff.Length);
                    await CallOnMessageAsync(resultstr).ConfigureAwait(false);
                }
            }
            catch (Exception e)
            {
                close = new SocketCloseEventArgs(null)
                {
                    CloseCode = -1, CloseMessage = e.Message
                };
            }

            await DisconnectAsync(close).ConfigureAwait(false);
        }
Ejemplo n.º 4
0
        private void SwitchFromFlashToMassStorageMode(bool Continuation = false)
        {
            string ProgressText;

            if (Continuation)
            {
                ProgressText = "And now rebooting phone to Mass Storage mode...";
            }
            else
            {
                ProgressText = "Rebooting phone to Mass Storage mode...";
            }

            NokiaFlashModel FlashModel = (NokiaFlashModel)CurrentModel;

            if (CurrentMode == PhoneInterfaces.Lumia_Bootloader)
            {
                try
                {
                    FlashModel.SwitchToFlashAppContext();
                }
                catch { }
            }
            PhoneInfo Info = FlashModel.ReadPhoneInfo(ExtendedInfo: false);

            MassStorageWarning = null;
            if (Info.FlashAppProtocolVersionMajor < 2)
            {
                MassStorageWarning = "Switching to Mass Storage mode should take about 10 seconds. The phone should be unlocked using an Engineering SBL3 to enable Mass Storage mode. When you unlocked the bootloader, but you did not use an Engineering SBL3, an attempt to boot to Mass Storage mode may result in an unresponsive state. Installing drivers for this interface may also cause to hang the PC. So when this switch is taking too long, you should reboot both the PC and the phone. To reboot the phone, you have to perform a soft-reset. Press and hold the volume-down-button and the power-button at the same time for at least 10 seconds. This will trigger a power-cycle and the phone will reboot. Once fully booted, the phone may show strange behavior, like complaining about mail-accounts, showing old text-messages, inability to load https-websites, etc. This is expected behavior, because the time-settings of the phone are incorrect. Just wait a few seconds for the phone to get a data-connection and have the date/time synced. After that the strange behavior will stop automatically and normal operation is resumed.";
            }
            else
            {
                MassStorageWarning = "When the screen of the phone is black for a while, it could be that the phone is already in Mass Storage Mode, but there is no drive-letter assigned. To resolve this issue, open Device Manager and manually assign a drive-letter to the MainOS partition of your phone, or open a command-prompt and type: diskpart automount enable.";
                if (App.IsPnPEventLogMissing)
                {
                    MassStorageWarning += " It is also possible that the phone is in Mass Storage mode, but the Mass Storage driver on this PC failed. Your PC does not have an eventlog to detect this misbehaviour. But in this case you will see a device with an exclamation mark in Device Manager and then you need to manually reset the phone by pressing and holding the power-button for at least 10 seconds until it vibrates and reboots. After that Windows Phone Internals will revert the changes. After the phone has rebooted to the OS, you can retry to unlock the bootloader.";
                }
            }

            bool IsOldLumia    = (Info.FlashAppProtocolVersionMajor < 2);
            bool IsNewLumia    = (Info.FlashAppProtocolVersionMajor >= 2);
            bool IsUnlockedNew = false;

            if (IsNewLumia)
            {
                GPT GPT = FlashModel.ReadGPT();
                IsUnlockedNew = ((GPT.GetPartition("IS_UNLOCKED") != null) || (GPT.GetPartition("BACKUP_EFIESP") != null));
            }
            bool IsOriginalEngineeringLumia = ((!Info.SecureFfuEnabled || Info.Authenticated || Info.RdcPresent) && !IsUnlockedNew);

            if (IsOldLumia || IsOriginalEngineeringLumia)
            {
                byte[] BootModeFlagCommand        = new byte[] { 0x4E, 0x4F, 0x4B, 0x58, 0x46, 0x57, 0x00, 0x55, 0x42, 0x46, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 }; // NOKFW UBF
                byte[] RebootCommand              = new byte[] { 0x4E, 0x4F, 0x4B, 0x52 };
                byte[] RebootToMassStorageCommand = new byte[] { 0x4E, 0x4F, 0x4B, 0x4D };                                                                         // NOKM
                IsSwitchingInterface = true;
                byte[] RebootCommandResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(RebootToMassStorageCommand);
                if ((RebootCommandResult != null) && (RebootCommandResult.Length == 4)) // This means fail: NOKU (unknow command)
                {
                    BootModeFlagCommand[0x0F] = 0x4D;
                    byte[] BootFlagResult = ((NokiaPhoneModel)CurrentModel).ExecuteRawMethod(BootModeFlagCommand);
                    UInt16 ResultCode     = BitConverter.ToUInt16(BootFlagResult, 6);
                    if (ResultCode == 0)
                    {
                        PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
                        ((NokiaPhoneModel)CurrentModel).ExecuteRawVoidMethod(RebootCommand);
                        ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
                        LogFile.Log("Rebooting phone to Mass Storage mode");
                    }
                    else
                    {
                        ModeSwitchErrorWrapper("Failed to switch to Mass Storage mode");
                        IsSwitchingInterface = false;
                    }
                }
                else
                {
                    PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
                    ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
                    LogFile.Log("Rebooting phone to Mass Storage mode");
                }
            }
            else if (IsUnlockedNew)
            {
                new Thread(async() =>
                {
                    LogFile.BeginAction("SwitchToMassStorageMode");

                    try
                    {
                        // Implementation of writing a partition with SecureBoot variable to the phone
                        ModeSwitchProgressWrapper(ProgressText, MassStorageWarning);
                        LogFile.Log("Preparing phone for Mass Storage Mode", LogType.FileAndConsole);
                        var assembly = System.Reflection.Assembly.GetExecutingAssembly();

                        // Magic!
                        // The SBMSM resource is a compressed version of a raw NV-variable-partition.
                        // In this partition the SecureBoot variable is disabled and an extra variable is added which triggers Mass Storage Mode on next reboot.
                        // It overwrites the variable in a different NV-partition than where this variable is stored usually.
                        // This normally leads to endless-loops when the NV-variables are enumerated.
                        // But the partition contains an extra hack to break out the endless loops.
                        using (var stream = assembly.GetManifestResourceStream("WPinternals.SBMSM"))
                        {
                            using (DecompressedStream dec = new DecompressedStream(stream))
                            {
                                using (System.IO.MemoryStream SB = new System.IO.MemoryStream()) // Must be a seekable stream!
                                {
                                    dec.CopyTo(SB);

                                    // We don't need to check for the BACKUP_BS_NV partition here,
                                    // because the SecureBoot flag is disabled here.
                                    // So either the NV was already backupped or already overwritten.

                                    GPT GPT          = FlashModel.ReadGPT();
                                    Partition Target = GPT.GetPartition("UEFI_BS_NV");

                                    // We've been reading the GPT, so we let the phone reset once more to be sure that memory maps are the same
                                    WPinternalsStatus LastStatus = WPinternalsStatus.Undefined;
                                    List <FlashPart> Parts       = new List <FlashPart>();
                                    FlashPart Part   = new FlashPart();
                                    Part.StartSector = (uint)Target.FirstSector;
                                    Part.Stream      = SB;
                                    Parts.Add(Part);
                                    await LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, null, false, false, Parts, DoResetFirst: true, ClearFlashingStatusAtEnd: false, ShowProgress: false,
                                                                                        SetWorkingStatus: (m, s, v, a, st) =>
                                    {
                                        if (SetWorkingStatus != null)
                                        {
                                            if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
                                            {
                                                SetWorkingStatus(m, s, v, a, st);
                                            }
                                            else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
                                            {
                                                SetWorkingStatus(ProgressText, MassStorageWarning);
                                            }
                                            LastStatus = st;
                                        }
                                    },
                                                                                        UpdateWorkingStatus: (m, s, v, st) =>
                                    {
                                        if (UpdateWorkingStatus != null)
                                        {
                                            if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset))
                                            {
                                                UpdateWorkingStatus(m, s, v, st);
                                            }
                                            else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset))
                                            {
                                                SetWorkingStatus(ProgressText, MassStorageWarning);
                                            }
                                            LastStatus = st;
                                        }
                                    });
                                }
                            }
                        }

                        if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
                        {
                            throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
                        }

                        // Wait for bootloader
                        if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
                        {
                            LogFile.Log("Waiting for Mass Storage Mode (1)...", LogType.FileOnly);
                            await PhoneNotifier.WaitForArrival();
                        }

                        if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
                        {
                            throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
                        }

                        // Wait for mass storage mode
                        if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_MassStorage)
                        {
                            LogFile.Log("Waiting for Mass Storage Mode (2)...", LogType.FileOnly);
                            await PhoneNotifier.WaitForArrival();
                        }

                        if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_BadMassStorage)
                        {
                            throw new WPinternalsException("Phone is in Mass Storage mode, but the driver on PC failed to start");
                        }

                        MassStorage Storage = null;
                        if (PhoneNotifier.CurrentModel is MassStorage)
                        {
                            Storage = (MassStorage)PhoneNotifier.CurrentModel;
                        }

                        if (Storage == null)
                        {
                            ModeSwitchErrorWrapper("Failed to switch to Mass Storage Mode");
                        }
                        else
                        {
                            ModeSwitchSuccessWrapper();
                        }
                    }
                    catch (Exception Ex)
                    {
                        LogFile.LogException(Ex);
                        ModeSwitchErrorWrapper(Ex.Message);
                    }

                    LogFile.EndAction("SwitchToMassStorageMode");
                }).Start();
            }
            else
            {
                ModeSwitchErrorWrapper("Bootloader was not unlocked. First unlock bootloader before you try to switch to Mass Storage Mode.");
            }
        }
Ejemplo n.º 5
0
        internal void FlashPartitionsTask(string EFIESPPath, string MainOSPath, string DataPath)
        {
            new Thread(() =>
            {
                bool Result = true;

                ActivateSubContext(new BusyViewModel("Initializing flash..."));

                NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;

                GPT GPT = Phone.ReadGPT();

                ulong TotalSizeSectors     = 0;
                int PartitionCount         = 0;
                ulong MainOSOldSectorCount = 0;
                ulong MainOSNewSectorCount = 0;
                ulong DataOldSectorCount   = 0;
                ulong DataNewSectorCount   = 0;
                ulong FirstMainOSSector    = 0;

                try
                {
                    if (EFIESPPath != null)
                    {
                        using (Stream Stream = new DecompressedStream(File.Open(EFIESPPath, FileMode.Open)))
                        {
                            ulong StreamLengthInSectors = (ulong)Stream.Length / 0x200;
                            TotalSizeSectors           += StreamLengthInSectors;
                            PartitionCount++;
                            Partition Partition = GPT.Partitions.Where(p => string.Compare(p.Name, "EFIESP", true) == 0).FirstOrDefault();
                            if (StreamLengthInSectors > Partition.SizeInSectors)
                            {
                                LogFile.Log("Flash failed! Size of partition 'EFIESP' is too big.");
                                ExitFailure("Flash failed!", "Size of partition 'EFIESP' is too big.");
                                return;
                            }
                        }
                    }

                    if (MainOSPath != null)
                    {
                        using (Stream Stream = new DecompressedStream(File.Open(MainOSPath, FileMode.Open)))
                        {
                            ulong StreamLengthInSectors = (ulong)Stream.Length / 0x200;
                            TotalSizeSectors           += StreamLengthInSectors;
                            PartitionCount++;
                            Partition Partition  = GPT.Partitions.Where(p => string.Compare(p.Name, "MainOS", true) == 0).FirstOrDefault();
                            MainOSOldSectorCount = Partition.SizeInSectors;
                            MainOSNewSectorCount = StreamLengthInSectors;
                            FirstMainOSSector    = Partition.FirstSector;
                        }
                    }

                    if (DataPath != null)
                    {
                        using (Stream Stream = new DecompressedStream(File.Open(DataPath, FileMode.Open)))
                        {
                            ulong StreamLengthInSectors = (ulong)Stream.Length / 0x200;
                            TotalSizeSectors           += StreamLengthInSectors;
                            PartitionCount++;
                            Partition Partition = GPT.Partitions.Where(p => string.Compare(p.Name, "Data", true) == 0).FirstOrDefault();
                            DataOldSectorCount  = Partition.SizeInSectors;
                            DataNewSectorCount  = StreamLengthInSectors;
                        }
                    }
                }
                catch (Exception Ex)
                {
                    LogFile.LogException(Ex);
                    Result = false;
                }

                if ((MainOSNewSectorCount > 0) && (DataNewSectorCount > 0))
                {
                    if ((MainOSNewSectorCount > MainOSOldSectorCount) || (DataNewSectorCount > DataOldSectorCount))
                    {
                        UInt64 OSSpace = GPT.LastUsableSector - FirstMainOSSector + 1;
                        if ((MainOSNewSectorCount + DataNewSectorCount) <= OSSpace)
                        {
                            // MainOS and Data partitions need to be re-aligned!
                            Partition MainOSPartition  = GPT.Partitions.Where(p => string.Compare(p.Name, "MainOS", true) == 0).Single();
                            Partition DataPartition    = GPT.Partitions.Where(p => string.Compare(p.Name, "Data", true) == 0).Single();
                            MainOSPartition.LastSector = MainOSPartition.FirstSector + MainOSNewSectorCount - 1;
                            DataPartition.FirstSector  = MainOSPartition.LastSector + 1;
                            DataPartition.LastSector   = DataPartition.FirstSector + DataNewSectorCount - 1;
                            Phone.WriteGPT(GPT);
                        }
                        else
                        {
                            LogFile.Log("Flash failed! Size of partitions 'MainOS' and 'Data' together are too big.");
                            ExitFailure("Flash failed!", "Sizes of partitions 'MainOS' and 'Data' together are too big.");
                            return;
                        }
                    }
                }
                else if ((MainOSNewSectorCount > 0) && (MainOSNewSectorCount > MainOSOldSectorCount))
                {
                    LogFile.Log("Flash failed! Size of partition 'MainOS' is too big.");
                    ExitFailure("Flash failed!", "Size of partition 'MainOS' is too big.");
                    return;
                }
                else if ((DataNewSectorCount > 0) && (DataNewSectorCount > DataOldSectorCount))
                {
                    LogFile.Log("Flash failed! Size of partition 'Data' is too big.");
                    ExitFailure("Flash failed!", "Size of partition 'Data' together is too big.");
                    return;
                }

                BusyViewModel Busy      = new BusyViewModel("Flashing...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
                ProgressUpdater Updater = Busy.ProgressUpdater;
                ActivateSubContext(Busy);

                int i = 0;
                if (Result)
                {
                    try
                    {
                        if (EFIESPPath != null)
                        {
                            i++;
                            Busy.Message = "Flashing partition EFIESP (" + i.ToString() + @"/" + PartitionCount.ToString() + ")";
                            Phone.FlashRawPartition(EFIESPPath, "EFIESP", Updater);
                        }
                    }
                    catch (Exception Ex)
                    {
                        LogFile.LogException(Ex);
                        Result = false;
                    }
                }

                if (Result)
                {
                    try
                    {
                        if (MainOSPath != null)
                        {
                            i++;
                            Busy.Message = "Flashing partition MainOS (" + i.ToString() + @"/" + PartitionCount.ToString() + ")";
                            Phone.FlashRawPartition(MainOSPath, "MainOS", Updater);
                        }
                    }
                    catch (Exception Ex)
                    {
                        LogFile.LogException(Ex);
                        Result = false;
                    }
                }

                if (Result)
                {
                    try
                    {
                        if (DataPath != null)
                        {
                            i++;
                            Busy.Message = "Flashing partition Data (" + i.ToString() + @"/" + PartitionCount.ToString() + ")";
                            Phone.FlashRawPartition(DataPath, "Data", Updater);
                        }
                    }
                    catch (Exception Ex)
                    {
                        LogFile.LogException(Ex);
                        Result = false;
                    }
                }

                if (!Result)
                {
                    ExitFailure("Flash failed!", null);
                    return;
                }

                ExitSuccess("Flash successful! Make sure you disable Windows Update on the phone!", null);
            }).Start();
        }
Ejemplo n.º 6
0
        internal void FlashArchiveTask(string ArchivePath)
        {
            new Thread(() =>
            {
                ActivateSubContext(new BusyViewModel("Initializing flash..."));

                NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel;

                ulong TotalSizeSectors     = 0;
                int PartitionCount         = 0;
                ulong MainOSOldSectorCount = 0;
                ulong MainOSNewSectorCount = 0;
                ulong DataOldSectorCount   = 0;
                ulong DataNewSectorCount   = 0;
                ulong FirstMainOSSector    = 0;
                bool GPTChanged            = false;

                try
                {
                    GPT GPT = Phone.ReadGPT();

                    using (FileStream FileStream = new FileStream(ArchivePath, FileMode.Open))
                    {
                        using (ZipArchive Archive = new ZipArchive(FileStream, ZipArchiveMode.Read))
                        {
                            foreach (ZipArchiveEntry Entry in Archive.Entries)
                            {
                                // Determine if there is a partition layout present
                                ZipArchiveEntry PartitionEntry = Archive.GetEntry("Partitions.xml");
                                if (PartitionEntry == null)
                                {
                                    GPT.MergePartitions(null, false, Archive);
                                    GPTChanged |= GPT.HasChanged;
                                }
                                else
                                {
                                    using (Stream ZipStream = PartitionEntry.Open())
                                    {
                                        using (StreamReader ZipReader = new StreamReader(ZipStream))
                                        {
                                            string PartitionXml = ZipReader.ReadToEnd();
                                            GPT.MergePartitions(PartitionXml, false, Archive);
                                            GPTChanged |= GPT.HasChanged;
                                        }
                                    }
                                }

                                // First determine if we need a new GPT!
                                if (!Entry.FullName.Contains("/")) // No subfolders
                                {
                                    string PartitionName = System.IO.Path.GetFileNameWithoutExtension(Entry.Name);
                                    int P = PartitionName.IndexOf('.');
                                    if (P >= 0)
                                    {
                                        PartitionName = PartitionName.Substring(0, P); // Example: Data.bin.gz -> Data
                                    }
                                    Partition Partition = GPT.Partitions.Where(p => string.Compare(p.Name, PartitionName, true) == 0).FirstOrDefault();
                                    if (Partition != null)
                                    {
                                        DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
                                        ulong StreamLengthInSectors           = (ulong)Entry.Length / 0x200;
                                        try
                                        {
                                            StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
                                        }
                                        catch { }

                                        TotalSizeSectors += StreamLengthInSectors;
                                        PartitionCount++;

                                        if (string.Compare(PartitionName, "MainOS", true) == 0)
                                        {
                                            MainOSOldSectorCount = Partition.SizeInSectors;
                                            MainOSNewSectorCount = StreamLengthInSectors;
                                            FirstMainOSSector    = Partition.FirstSector;
                                        }
                                        else if (string.Compare(PartitionName, "Data", true) == 0)
                                        {
                                            DataOldSectorCount = Partition.SizeInSectors;
                                            DataNewSectorCount = StreamLengthInSectors;
                                        }
                                        else if (StreamLengthInSectors > Partition.SizeInSectors)
                                        {
                                            LogFile.Log("Flash failed! Size of partition '" + PartitionName + "' is too big.");
                                            ExitFailure("Flash failed!", "Size of partition '" + PartitionName + "' is too big.");
                                            return;
                                        }
                                    }
                                }
                            }

                            if ((MainOSNewSectorCount > 0) && (DataNewSectorCount > 0))
                            {
                                if ((MainOSNewSectorCount > MainOSOldSectorCount) || (DataNewSectorCount > DataOldSectorCount))
                                {
                                    UInt64 OSSpace = GPT.LastUsableSector - FirstMainOSSector + 1;
                                    if ((MainOSNewSectorCount + DataNewSectorCount) <= OSSpace)
                                    {
                                        // MainOS and Data partitions need to be re-aligned!
                                        Partition MainOSPartition  = GPT.Partitions.Where(p => string.Compare(p.Name, "MainOS", true) == 0).Single();
                                        Partition DataPartition    = GPT.Partitions.Where(p => string.Compare(p.Name, "Data", true) == 0).Single();
                                        MainOSPartition.LastSector = MainOSPartition.FirstSector + MainOSNewSectorCount - 1;
                                        DataPartition.FirstSector  = MainOSPartition.LastSector + 1;
                                        DataPartition.LastSector   = DataPartition.FirstSector + DataNewSectorCount - 1;

                                        GPTChanged = true;
                                    }
                                    else
                                    {
                                        LogFile.Log("Flash failed! Size of partitions 'MainOS' and 'Data' together are too big.");
                                        ExitFailure("Flash failed!", "Sizes of partitions 'MainOS' and 'Data' together are too big.");
                                        return;
                                    }
                                }
                            }
                            else if ((MainOSNewSectorCount > 0) && (MainOSNewSectorCount > MainOSOldSectorCount))
                            {
                                LogFile.Log("Flash failed! Size of partition 'MainOS' is too big.");
                                ExitFailure("Flash failed!", "Size of partition 'MainOS' is too big.");
                                return;
                            }
                            else if ((DataNewSectorCount > 0) && (DataNewSectorCount > DataOldSectorCount))
                            {
                                LogFile.Log("Flash failed! Size of partition 'Data' is too big.");
                                ExitFailure("Flash failed!", "Size of partition 'Data' is too big.");
                                return;
                            }

                            if (GPTChanged)
                            {
                                Phone.WriteGPT(GPT);
                            }

                            if (PartitionCount > 0)
                            {
                                BusyViewModel Busy      = new BusyViewModel("Flashing...", MaxProgressValue: TotalSizeSectors, UIContext: UIContext);
                                ProgressUpdater Updater = Busy.ProgressUpdater;
                                ActivateSubContext(Busy);

                                int i = 0;

                                foreach (ZipArchiveEntry Entry in Archive.Entries)
                                {
                                    // "MainOS.bin.gz" => "MainOS"
                                    string PartitionName = Entry.Name;
                                    int Pos = PartitionName.IndexOf('.');
                                    if (Pos >= 0)
                                    {
                                        PartitionName = PartitionName.Substring(0, Pos);
                                    }

                                    Partition Partition = GPT.Partitions.Where(p => string.Compare(p.Name, PartitionName, true) == 0).FirstOrDefault();
                                    if (Partition != null)
                                    {
                                        Stream DecompressedStream   = new DecompressedStream(Entry.Open());
                                        ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
                                        try
                                        {
                                            StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
                                        }
                                        catch { }

                                        if (StreamLengthInSectors <= Partition.SizeInSectors)
                                        {
                                            i++;
                                            Busy.Message = "Flashing partition " + Partition.Name + " (" + i.ToString() + @"/" + PartitionCount.ToString() + ")";
                                            Phone.FlashRawPartition(DecompressedStream, Partition.Name, Updater);
                                        }
                                        DecompressedStream.Close();
                                    }
                                }
                            }
                            else
                            {
                                LogFile.Log("Flash failed! No valid partitions found in the archive.");
                                ExitFailure("Flash failed!", "No valid partitions found in the archive");
                                return;
                            }
                        }
                    }
                }
                catch (Exception Ex)
                {
                    LogFile.LogException(Ex);
                    if (Ex is WPinternalsException)
                    {
                        ExitFailure("Flash failed!", ((WPinternalsException)Ex).SubMessage);
                    }
                    else
                    {
                        ExitFailure("Flash failed!", null);
                    }
                    return;
                }

                ExitSuccess("Flash successful! Make sure you disable Windows Update on the phone!", null);
            }).Start();
        }
Ejemplo n.º 7
0
        internal void MergePartitions(string Xml, bool RoundToChunks, ZipArchive Archive = null)
        {
            GPT GptToMerge;

            if (Xml == null)
            {
                GptToMerge = new GPT();
            }
            else
            {
                XmlSerializer x = new XmlSerializer(typeof(GPT), "");
                MemoryStream  s = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(Xml));
                GptToMerge = (GPT)x.Deserialize(s);
                s.Dispose();
            }

            if (Archive != null)
            {
                foreach (Partition NewPartition in GptToMerge.Partitions)
                {
                    ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
                    if (Entry == null)
                    {
                        // There is a partition entry in the xml, but this partition is not present in the archive.

                        Partition OldPartition = GetPartition(NewPartition.Name);
                        if (OldPartition == null)
                        {
                            // The partition entry in the xml is also not present in the current partition table.
                            // It must have a know position and length.

                            if (NewPartition.LastSector == 0)
                            {
                                throw new WPinternalsException("Unknown length for partition \"" + NewPartition.Name + "\"");
                            }
                        }
                        else
                        {
                            // The partition entry in the xml is also present in the current partition table.
                            // But since the partition is not present in the archive, the partition cannot be relocated.
                            // If the location of the new partition is specified, it must be the same as the current partition.

                            if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
                            {
                                throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\"");
                            }
                            if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
                            {
                                throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\"");
                            }

                            NewPartition.FirstSector = OldPartition.FirstSector;
                            NewPartition.LastSector  = OldPartition.LastSector;
                        }
                    }
                    else
                    {
                        // The partition in the xml is also present in the archive.
                        // If the length is specified in the xml, it must match the file in the archive.

                        ulong StreamLengthInSectors = (ulong)Entry.Length / 0x200;
                        using (DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open()))
                        {
                            try
                            {
                                StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
                            }
                            catch { }
                        }

                        if (NewPartition.LastSector == 0)
                        {
                            NewPartition.SizeInSectors = StreamLengthInSectors;
                        }
                        else
                        {
                            if (NewPartition.SizeInSectors != StreamLengthInSectors)
                            {
                                throw new WPinternalsException("Inconsistent length specified for partition \"" + NewPartition.Name + "\"");
                            }
                        }
                    }
                }
            }
            else
            {
                foreach (Partition NewPartition in GptToMerge.Partitions)
                {
                    // This is a partition entry in the xml, and there is no archive.

                    Partition OldPartition = GetPartition(NewPartition.Name);
                    if (OldPartition == null)
                    {
                        // The partition entry in the xml is also not present in the current partition table.
                        // It must have a known position and length.

                        if (NewPartition.LastSector == 0)
                        {
                            throw new WPinternalsException("Unknown length for partition \"" + NewPartition.Name + "\"");
                        }
                    }
                    else
                    {
                        // The partition entry in the xml is also present in the current partition table.
                        // But since the partition is not present in the archive, the partition cannot be relocated.
                        // If the location of the new partition is specified, it must be the same as the current partition.

                        if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != OldPartition.FirstSector))
                        {
                            throw new WPinternalsException("Incorrect location for partition \"" + NewPartition.Name + "\"");
                        }
                        if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != OldPartition.LastSector))
                        {
                            throw new WPinternalsException("Incorrect length for partition \"" + NewPartition.Name + "\"");
                        }

                        NewPartition.FirstSector = OldPartition.FirstSector;
                        NewPartition.LastSector  = OldPartition.LastSector;
                    }
                }
            }

            List <Partition> DynamicPartitions = new List <Partition>();

            if (Archive != null)
            {
                // Partitions which are present in the archive, and which have no start-sector in the new GPT data (dynamic relocation),
                // and which can be clustered to the end of emmc, are first removed from the existing GPT.
                IEnumerable <Partition> SortedPartitions = Partitions.OrderBy(p => p.FirstSector);
                for (int i = SortedPartitions.Count() - 1; i >= 0; i--)
                {
                    Partition OldPartition = SortedPartitions.ElementAt(i);

                    // Present in archive?
                    ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
                    if (Entry != null)
                    {
                        // Not present in new GPT or present in GPT without FirstSector?
                        Partition NewPartition = GptToMerge.GetPartition(OldPartition.Name);
                        if ((NewPartition == null) || (NewPartition.FirstSector == 0))
                        {
                            DynamicPartitions.Insert(0, OldPartition);
                            this.Partitions.Remove(OldPartition);
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            // All partitions in the new GPT data should have a start-sector and end-sector by now.
            // The partitions in the new GPT data will be applied to the current partition-table.
            // Existing partitions, which are overwritten by the new partitions will be removed from the existing GPT.
            // Existing partition with the same name in the existing GPT is reused (guids and attribs remain, if not specified).
            UInt64    LowestSector = 0;
            Partition DPP          = this.GetPartition("DPP");

            if (DPP != null)
            {
                LowestSector = DPP.LastSector + 1;
            }
            foreach (Partition NewPartition in GptToMerge.Partitions)
            {
                // If the new partition is a dynamic partition, then skip it here. It will be added later.
                if (DynamicPartitions.Select(p => p.Name).Any(n => string.Compare(n, NewPartition.Name, true) == 0))
                {
                    continue;
                }

                // Sanity check
                if (NewPartition.FirstSector < LowestSector)
                {
                    throw new WPinternalsException("Bad sector alignment for partition: " + NewPartition.Name);
                }

                Partition CurrentPartition = this.GetPartition(NewPartition.Name);
                if (CurrentPartition == null)
                {
                    CurrentPartition      = new Partition();
                    CurrentPartition.Name = NewPartition.Name;
                    this.Partitions.Add(CurrentPartition);
                    HasChanged = true;
                }

                if ((NewPartition.FirstSector != 0) && (NewPartition.FirstSector != CurrentPartition.FirstSector))
                {
                    CurrentPartition.FirstSector = NewPartition.FirstSector;
                    HasChanged = true;
                }
                if ((NewPartition.LastSector != 0) && (NewPartition.LastSector != CurrentPartition.LastSector))
                {
                    CurrentPartition.LastSector = NewPartition.LastSector;
                    HasChanged = true;
                }
                if ((NewPartition.Attributes != 0) && (CurrentPartition.Attributes != NewPartition.Attributes))
                {
                    CurrentPartition.Attributes = NewPartition.Attributes;
                    HasChanged = true;
                }

                if ((NewPartition.PartitionGuid == null) || (NewPartition.PartitionGuid != CurrentPartition.PartitionGuid))
                {
                    HasChanged = true;
                }
                if (NewPartition.PartitionGuid != null)
                {
                    CurrentPartition.PartitionGuid = NewPartition.PartitionGuid;
                }
                if (CurrentPartition.PartitionGuid == null)
                {
                    CurrentPartition.PartitionGuid = Guid.NewGuid();
                }

                if ((NewPartition.PartitionTypeGuid == null) || (NewPartition.PartitionTypeGuid != CurrentPartition.PartitionTypeGuid))
                {
                    HasChanged = true;
                }
                if (NewPartition.PartitionTypeGuid != null)
                {
                    CurrentPartition.PartitionTypeGuid = NewPartition.PartitionTypeGuid;
                }
                if (CurrentPartition.PartitionTypeGuid == null)
                {
                    CurrentPartition.PartitionTypeGuid = Guid.NewGuid();
                }

                for (int i = this.Partitions.Count - 1; i >= 0; i--)
                {
                    if (this.Partitions[i] != CurrentPartition)
                    {
                        if ((CurrentPartition.FirstSector <= this.Partitions[i].LastSector) && (CurrentPartition.LastSector >= this.Partitions[i].FirstSector))
                        {
                            this.Partitions.RemoveAt(i);
                            HasChanged = true;
                        }
                    }
                }
            }

            if (Archive != null)
            {
                // All partitions listed in the archive, which are present in the existing GPT, should overwrite the existing partition.
                // Check if the sizes of the partitions in the archive do not exceed the size of the partition, as listed in the GPT.
                foreach (Partition OldPartition in this.Partitions)
                {
                    ZipArchiveEntry Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, OldPartition.Name, true) == 0) || (e.Name.StartsWith(OldPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
                    if (Entry != null)
                    {
                        DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
                        ulong StreamLengthInSectors           = (ulong)Entry.Length / 0x200;
                        try
                        {
                            StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
                        }
                        catch { }
                        DecompressedStream.Close();

                        UInt64    MaxPartitionSizeInSectors = OldPartition.SizeInSectors;
                        Partition NextPartition             = this.Partitions.Where(p => p.FirstSector > OldPartition.FirstSector).OrderBy(p => p.FirstSector).FirstOrDefault();
                        if (NextPartition != null)
                        {
                            MaxPartitionSizeInSectors = NextPartition.FirstSector - OldPartition.FirstSector;
                        }
                        if (StreamLengthInSectors > MaxPartitionSizeInSectors)
                        {
                            throw new WPinternalsException("Incorrect length for partition \"" + OldPartition.Name + "\"");
                        }

                        if (OldPartition.SizeInSectors != StreamLengthInSectors)
                        {
                            OldPartition.SizeInSectors = StreamLengthInSectors;
                            HasChanged = true;
                        }
                    }
                }

                // All remaining partitions in the archive, which were listed in the original GPT,
                // should be added at the end of the partition-table.
                UInt64 FirstFreeSector = 0x5000;
                if (this.Partitions.Count > 0)
                {
                    FirstFreeSector = this.Partitions.Max(p => p.LastSector) + 1;

                    // Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
                    if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
                    {
                        FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
                    }
                }
                foreach (Partition NewPartition in DynamicPartitions)
                {
                    if (NewPartition.FirstSector != FirstFreeSector)
                    {
                        NewPartition.FirstSector = FirstFreeSector;
                        HasChanged = true;
                    }
                    ZipArchiveEntry    Entry = Archive.Entries.Where(e => ((string.Compare(e.Name, NewPartition.Name, true) == 0) || (e.Name.StartsWith(NewPartition.Name + ".", true, System.Globalization.CultureInfo.GetCultureInfo("en-US"))))).FirstOrDefault();
                    DecompressedStream DecompressedStream = new DecompressedStream(Entry.Open());
                    ulong StreamLengthInSectors           = (ulong)Entry.Length / 0x200;
                    try
                    {
                        StreamLengthInSectors = (ulong)DecompressedStream.Length / 0x200;
                    }
                    catch { }
                    DecompressedStream.Close();
                    if (NewPartition.SizeInSectors != StreamLengthInSectors)
                    {
                        NewPartition.SizeInSectors = StreamLengthInSectors;
                        HasChanged = true;
                    }
                    this.Partitions.Add(NewPartition);
                    FirstFreeSector += StreamLengthInSectors;

                    // Always start a new partition on a new chunk (0x100 sector boundary), to be more flexible during custom flash
                    if (RoundToChunks && (((double)FirstFreeSector % 0x100) != 0))
                    {
                        FirstFreeSector = (UInt64)(Math.Ceiling((double)FirstFreeSector / 0x100) * 0x100);
                    }
                }
            }

            Rebuild();
        }
Ejemplo n.º 8
0
 /// <summary>
 /// Disposes this socket client.
 /// </summary>
 public virtual void Dispose()
 {
     StreamDecompressor?.Dispose();
     CompressedStream?.Dispose();
     DecompressedStream?.Dispose();
 }
        /// <summary>
        /// Connects to the WebSocket server.
        /// </summary>
        /// <param name="uri">The URI of the WebSocket server.</param>
        /// <param name="customHeaders">Custom headers to send with the request.</param>
        /// <returns></returns>
        public override Task ConnectAsync(Uri uri, IReadOnlyDictionary <string, string> customHeaders = null)
        {
            StreamDecompressor?.Dispose();
            CompressedStream?.Dispose();
            DecompressedStream?.Dispose();

            DecompressedStream = new MemoryStream();
            CompressedStream   = new MemoryStream();
            StreamDecompressor = new DeflateStream(CompressedStream, CompressionMode.Decompress);

            _socket = new ws4net.WebSocket(uri.ToString(), customHeaderItems: customHeaders?.ToList());
            if (Proxy != null) // f**k this, I ain't working with that shit
            {
                throw new NotImplementedException("Proxies are not supported on non-Microsoft WebSocket client implementations.");
            }

            _socket.Opened          += HandlerOpen;
            _socket.Closed          += HandlerClose;
            _socket.MessageReceived += HandlerMessage;
            _socket.DataReceived    += HandlerData;
            _socket.Error           += _socket_Error;
            _socket.Open();

            return(Task.FromResult <BaseWebSocketClient>(this));

            void HandlerOpen(object sender, s.EventArgs e)
            => _connect.InvokeAsync().ConfigureAwait(false).GetAwaiter().GetResult();

            void HandlerClose(object sender, s.EventArgs e)
            {
                if (e is ws4net.ClosedEventArgs ea)
                {
                    _disconnect.InvokeAsync(new SocketCloseEventArgs(null)
                    {
                        CloseCode = ea.Code, CloseMessage = ea.Reason
                    }).ConfigureAwait(false).GetAwaiter().GetResult();
                }
                else
                {
                    _disconnect.InvokeAsync(new SocketCloseEventArgs(null)
                    {
                        CloseCode = -1, CloseMessage = "unknown"
                    }).ConfigureAwait(false).GetAwaiter().GetResult();
                }
            }

            void HandlerMessage(object sender, ws4net.MessageReceivedEventArgs e)
            {
                _message.InvokeAsync(new SocketMessageEventArgs {
                    Message = e.Message
                }).ConfigureAwait(false).GetAwaiter().GetResult();
            }

            void HandlerData(object sender, ws4net.DataReceivedEventArgs e)
            {
                string msg;

                if (e.Data[0] == 0x78)
                {
                    CompressedStream.Write(e.Data, 2, e.Data.Length - 2);
                }
                else
                {
                    CompressedStream.Write(e.Data, 0, e.Data.Length);
                }
                CompressedStream.Flush();
                CompressedStream.Position = 0;

                // partial credit to FiniteReality
                // overall idea is his
                // I tuned the finer details
                // -Emzi
                var sfix = BitConverter.ToUInt16(e.Data, e.Data.Length - 2);

                if (sfix != ZLIB_STREAM_SUFFIX)
                {
                    using (var zlib = new DeflateStream(CompressedStream, CompressionMode.Decompress, true))
                        zlib.CopyTo(DecompressedStream);
                }
                else
                {
                    StreamDecompressor.CopyTo(DecompressedStream);
                }

                msg = UTF8.GetString(DecompressedStream.ToArray(), 0, (int)DecompressedStream.Length);

                DecompressedStream.Position = 0;
                DecompressedStream.SetLength(0);
                CompressedStream.Position = 0;
                CompressedStream.SetLength(0);

                _message.InvokeAsync(new SocketMessageEventArgs {
                    Message = msg
                }).ConfigureAwait(false).GetAwaiter().GetResult();
            }
        }