Esempio n. 1
0
        public static void ParseBackup(
            [NotNull] string pathToBackup,
            BackupType backupType,
            [NotNull] string resultInternalDataPath,
            [NotNull] string resultExternalDataPath,
            //[NotNull] string resultObbPath,
            [NotNull] ITempFolderProvider tempFolderProvider
            )
        {
            Guard.NotNullArgument(pathToBackup, nameof(pathToBackup));
            Guard.NotNullArgument(resultInternalDataPath, nameof(resultInternalDataPath));
            Guard.NotNullArgument(resultExternalDataPath, nameof(resultExternalDataPath));
            //Guard.NotNullArgument(resultObbPath, nameof(resultObbPath));
            Guard.NotNullArgument(tempFolderProvider, nameof(tempFolderProvider));

            switch (backupType)
            {
            case BackupType.Titanium:
            {
                #region Структура

                /*
                 *
                 *  data
                 *      data
                 *          .external.appname
                 *              .
                 *                  данные
                 *          appname
                 *              .
                 *                  данные
                 */

                #endregion

                using (var extractedBackup = TempUtils.UseTempFolder(tempFolderProvider))
                {
                    ExtractTarByEntry(pathToBackup, extractedBackup.TempFolder);

                    string path = Path.Combine(extractedBackup.TempFolder, "data", "data");

                    foreach (string dir in LDirectory.EnumerateDirectories(path))
                    {
                        string dirName = Path.GetFileName(dir);
                        if (string.IsNullOrEmpty(dirName))
                        {
                            continue;
                        }

                        switch (dirName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)[0])
                        {
                        case "external obb":
                            //CreateArchive(dir, resultObbPath);
                            break;

                        case "external":
                            CreateArchive(dir, resultExternalDataPath);
                            break;

                        default:
                            CreateArchive(dir, resultInternalDataPath);
                            break;
                        }
                    }
                }

                break;
            }

            case BackupType.RomToolbox:
            {
                #region Структура

                /*
                 *
                 *  data
                 *      data
                 *          appname
                 *              данные
                 *  storage\emulated\legacy
                 *      Android
                 *          data
                 *              appname
                 *                  данные
                 *
                 */

                #endregion

                using (var extractedBackup = TempUtils.UseTempFolder(tempFolderProvider))
                {
                    ExtractTarByEntry(pathToBackup, extractedBackup.TempFolder);

                    IEnumerable <string> firstLevelDirs = LDirectory.EnumerateDirectories(extractedBackup.TempFolder);

                    foreach (string firstLevelDir in firstLevelDirs)
                    {
                        if (Path.GetFileName(firstLevelDir) == "data")
                        {
                            string path = Path.Combine(firstLevelDir, "data");

                            string dir = LDirectory.EnumerateDirectories(path).FirstOrDefault();
                            if (dir == default)
                            {
                                continue;
                            }

                            CreateArchive(dir, Path.Combine(resultInternalDataPath));
                        }
                        else
                        {
                            string dir = LDirectory.EnumerateDirectories(firstLevelDir, "Android", SearchOption.AllDirectories).FirstOrDefault();
                            if (dir == default)
                            {
                                continue;
                            }

                            string path = Path.Combine(dir, "data");

                            string dir2 = LDirectory.EnumerateDirectories(path).FirstOrDefault();
                            if (dir2 == default)
                            {
                                continue;
                            }

                            CreateArchive(dir2, resultExternalDataPath);
                        }
                    }
                }

                break;
            }

            case BackupType.LuckyPatcher:
            {
                #region Структура

                /*
                 *
                 *  appname
                 *      data.lpbkp
                 *          данные
                 *      sddata.lpbkp
                 *          данные
                 *
                 */

                #endregion

                string dataFile   = Path.Combine(pathToBackup, "data.lpbkp");
                string sddataFile = Path.Combine(pathToBackup, "sddata.lpbkp");

                if (LFile.Exists(dataFile))
                {
                    LFile.Move(dataFile, resultInternalDataPath);
                }

                if (LFile.Exists(sddataFile))
                {
                    LFile.Move(sddataFile, resultExternalDataPath);
                }

                break;
            }

            default:
                throw new NotSupportedException($"`{backupType}` is not supported at the moment");
            }
        }
        private void ProcessAll()
        {
            Dispatcher.Invoke(LogBox.Clear);

            Log(
                string.Format(
                    "{0}{1}Start{1}{0}ExePath = {2}{0}Resources = {3}",
                    Environment.NewLine,
                    Line,
                    _globalVariables.PathToExe,
                    _globalVariables.PathToResources
                    )
                );

            const int totalSteps = 3;

            _visualProgress.SetBarUsual();
            _visualProgress.ShowBar();

            _taskBarManager.SetProgress(0);
            _taskBarManager.SetUsualState();

            void SetStep(int currentStep, string status)
            {
                int percentage = (currentStep - 1) * 100 / totalSteps;

                _visualProgress.SetBarValue(percentage);
                _visualProgress.SetLabelText(status);
                _taskBarManager.SetProgress(percentage);
            }

            #region Инициализация

            SetStep(1, MainResources.StepInitializing);
            _visualProgress.ShowIndeterminateLabel();

            string sourceApkPath      = ViewModel.CurrentApk.Value;
            bool   alternativeSigning = _settings.AlternativeSigning;

            string popupText     = ViewModel.PopupBoxText.Value;
            int    messagesCount = ViewModel.MessagesCount.Value;

            bool needSave;
            bool needMessage;
            {
                bool onlySave        = ViewModel.OnlySave.Value;
                bool savePlusMessage = ViewModel.SavePlusMess.Value;
                bool onlyMessage     = ViewModel.OnlyMess.Value;

                needSave    = onlySave || savePlusMessage;
                needMessage = (savePlusMessage || onlyMessage) && !string.IsNullOrEmpty(popupText) && messagesCount > 0;
            }

            BackupType backupType = ViewModel.BackupType.Value;

            ITempFileProvider   tempFileProvider   = _tempUtils.CreateTempFileProvider();
            ITempFolderProvider tempFolderProvider = _tempUtils.CreateTempFolderProvider();

            string resultApkPath = sourceApkPath.Remove(sourceApkPath.Length - Path.GetExtension(sourceApkPath).Length) + "_mod.apk";
            string pathToSave    = ViewModel.CurrentSave.Value;

            IApktool            apktool     = _apktoolProvider.Get();
            IProcessDataHandler dataHandler = new ProcessDataCombinedHandler(data => Log(data));

            #endregion

            #region Изменение apk

            using (var tempApk = ATempUtils.UseTempFile(tempFileProvider))
            {
                LFile.Copy(sourceApkPath, tempApk.TempFile, true);

                #region Добавление данных

                SetStep(2, MainResources.StepAddingData);

                var aes = new AesManaged {
                    KeySize = 128
                };
                aes.GenerateIV();
                aes.GenerateKey();

                bool backupFilesAdded = false;
                // adding local and external backup files
                if (needSave)
                {
                    using (var internalDataBackup = ATempUtils.UseTempFile(tempFileProvider))
                        using (var externalDataBackup = ATempUtils.UseTempFile(tempFileProvider))
                        {
                            ApkModifer.ParseBackup(
                                pathToBackup: pathToSave,
                                backupType: backupType,
                                resultInternalDataPath: internalDataBackup.TempFile,
                                resultExternalDataPath: externalDataBackup.TempFile,
                                tempFolderProvider: tempFolderProvider
                                );

                            string internalBackup = internalDataBackup.TempFile;
                            string externalBackup = externalDataBackup.TempFile;

                            var fileToAssetsName = new Dictionary <string, string>
                            {
                                { internalBackup, "data.save" },
                                { externalBackup, "extdata.save" }
                            };

                            foreach (var(file, assetsName) in fileToAssetsName.Enumerate())
                            {
                                if (!LFile.Exists(file) || FileUtils.FileLength(file) == 0)
                                {
                                    continue;
                                }

                                using (var tempEncrypted = ATempUtils.UseTempFile(tempFileProvider))
                                {
                                    CommonUtils.EncryptFile(
                                        filePath: file,
                                        outputPath: tempEncrypted.TempFile,
                                        iv: aes.IV,
                                        key: aes.Key
                                        );

                                    ApkModifer.AddFileToZip(
                                        zipPath: tempApk.TempFile,
                                        filePath: tempEncrypted.TempFile,
                                        pathInZip: "assets/" + assetsName,
                                        newEntryCompression: CompressionType.Store
                                        );
                                }

                                backupFilesAdded = true;
                            }
                        }
                }

                // adding smali file for restoring
                if (backupFilesAdded || needMessage)
                {
                    using (var decompiledFolder = ATempUtils.UseTempFolder(tempFolderProvider))
                    {
                        apktool.Baksmali(
                            apkPath: tempApk.TempFile,
                            resultFolder: decompiledFolder.TempFolder,
                            tempFolderProvider: tempFolderProvider,
                            dataHandler: dataHandler
                            );

                        var manifestPath = Path.Combine(decompiledFolder.TempFolder, "AndroidManifest.xml");

                        apktool.ExtractSimpleManifest(
                            apkPath: tempApk.TempFile,
                            resultManifestPath: manifestPath,
                            tempFolderProvider: tempFolderProvider
                            );

                        // have to have smali folders in the same directory as manifest
                        // to find the main smali
                        var manifest = new AndroidManifest(manifestPath);

                        if (manifest.MainSmaliFile == null)
                        {
                            throw new Exception("main smali file not found");
                        }

                        // using this instead of just pasting "folder/smali" as there can be
                        // no smali folder sometimes (smali_1, etc)
                        string smaliDir = manifest.MainSmaliPath.Substring(decompiledFolder.TempFolder.Length + 1);
                        smaliDir = smaliDir.Substring(0, smaliDir.IndexOf(Path.DirectorySeparatorChar));

                        string saveGameDir = Path.Combine(decompiledFolder.TempFolder, smaliDir, "com", "savegame");

                        LDirectory.CreateDirectory(saveGameDir);

                        CommonUtils.GenerateAndSaveSmali(
                            filePath: Path.Combine(saveGameDir, "SavesRestoringPortable.smali"),
                            iv: aes.IV,
                            key: aes.Key,
                            addSave: backupFilesAdded,
                            message: needMessage ? popupText : string.Empty,
                            messagesCount: needMessage ? messagesCount : 0
                            );

                        manifest.MainSmaliFile.AddTextToMethod(FileResources.MainSmaliCall);
                        manifest.MainSmaliFile.Save();

                        using (var folderWithDexes = ATempUtils.UseTempFolder(tempFolderProvider))
                        {
                            apktool.Smali(
                                folderWithSmali: decompiledFolder.TempFolder,
                                resultFolder: folderWithDexes.TempFolder,
                                dataHandler: dataHandler
                                );

                            string[] dexes = LDirectory.GetFiles(folderWithDexes.TempFolder, "*.dex");

                            ApkModifer.AddFilesToZip(
                                zipPath: tempApk.TempFile,
                                filePaths: dexes,
                                pathsInZip: Array.ConvertAll(dexes, Path.GetFileName),
                                newEntryCompression: CompressionType.Store
                                );
                        }
                    }
                }

                #endregion

                #region Подпись

                SetStep(3, MainResources.StepSigning);

                Log(Line);
                Log(MainResources.StepSigning);
                Log(Line);

                apktool.Sign(
                    sourceApkPath: tempApk.TempFile,
                    signedApkPath: resultApkPath,
                    tempFileProvider: tempFileProvider,
                    dataHandler: dataHandler,
                    deleteMetaInf: !alternativeSigning
                    );

                #endregion
            }

            #endregion

            _visualProgress.HideIndeterminateLabel();
            SetStep(4, MainResources.AllDone);
            Log(MainResources.AllDone);
            Log(string.Empty, false);
            Log($"{MainResources.Path_to_file} {resultApkPath}");

            _globalVariables.LatestModdedApkPath = resultApkPath;

            if (_settings.Notifications)
            {
                _notificationManager.Show(
                    title: MainResources.Information_Title,
                    text: MainResources.ModificationCompletedContent
                    );
            }

            string dialogResult = MessBox.ShowDial(
                $"{MainResources.Path_to_file} {resultApkPath}",
                MainResources.Successful,
                MainResources.OK, MainResources.Open, MainResources.Install
                );

            _visualProgress.HideBar();
            _taskBarManager.SetNoneState();

            if (dialogResult == MainResources.Open)
            {
                Process.Start("explorer.exe", $"/select,{resultApkPath}");
            }
            else if (dialogResult == MainResources.Install)
            {
                Dispatcher.Invoke(() => _adbInstallWindowProvider.Get().ShowDialog());
            }
        }
Esempio n. 3
0
        private void ProcessAll()
        {
            Dispatcher.Invoke(LogBox.Clear);

            Log(
                string.Format(
                    "{0}{1}Start{1}{0}ExePath = {2}{0}Resources = {3}",
                    Environment.NewLine,
                    Line,
                    _globalVariables.PathToExe,
                    _globalVariables.PathToResources
                    )
                );

            const int totalSteps = 3;

            _visualProgress.SetBarUsual();
            _visualProgress.ShowBar();

            _taskBarManager.SetProgress(0);
            _taskBarManager.SetUsualState();

            void SetStep(int currentStep, string status)
            {
                int percentage = (currentStep - 1) * 100 / totalSteps;

                _visualProgress.SetBarValue(percentage);
                _visualProgress.SetLabelText(status);
                _taskBarManager.SetProgress(percentage);
            }

            #region Инициализация

            SetStep(1, MainResources.StepInitializing);
            _visualProgress.ShowIndeterminateLabel();

            string sourceApkPath      = ViewModel.CurrentApk.Value;
            bool   alternativeSigning = _settings.AlternativeSigning;

            string popupText     = ViewModel.PopupBoxText.Value;
            int    messagesCount = ViewModel.MessagesCount.Value;

            bool needMessage = true;

            BackupType backupType = ViewModel.BackupType.Value;

            ITempFileProvider   tempFileProvider   = _tempUtils.CreateTempFileProvider();
            ITempFolderProvider tempFolderProvider = _tempUtils.CreateTempFolderProvider();

            string resultApkPath = sourceApkPath.Remove(sourceApkPath.Length - Path.GetExtension(sourceApkPath).Length) + "_signed.apk";
            string pathToSave    = ViewModel.CurrentSave.Value;

            IApktool            apktool     = _apktoolProvider.Get();
            IProcessDataHandler dataHandler = new ProcessDataCombinedHandler(data => Log(data));

            #endregion

            #region Change apk
            // Temp
            using (var tempApk = ATempUtils.UseTempFile(tempFileProvider))
            {
                LFile.Copy(sourceApkPath, tempApk.TempFile, true); //Copy apk file to temp

                #region Adding data
                SetStep(2, MainResources.StepAddingData);

                var aes = new AesManaged {
                    KeySize = 128
                };
                aes.GenerateIV();
                aes.GenerateKey();

                // adding smali file for restoring
                using (var decompiledFolder = ATempUtils.UseTempFolder(tempFolderProvider))
                {
                    apktool.Baksmali(
                        apkPath: tempApk.TempFile,
                        resultFolder: decompiledFolder.TempFolder,
                        tempFolderProvider: tempFolderProvider,
                        dataHandler: dataHandler
                        );

                    var manifestPath = Path.Combine(decompiledFolder.TempFolder, "AndroidManifest.xml");

                    apktool.ExtractSimpleManifest(
                        apkPath: tempApk.TempFile,
                        resultManifestPath: manifestPath,
                        tempFolderProvider: tempFolderProvider
                        );

                    // have to have smali folders in the same directory as manifest
                    // to find the main smali
                    var manifest = new AndroidManifest(manifestPath);

                    if (manifest.MainSmaliFile == null)
                    {
                        throw new Exception("main smali file not found");
                    }

                    // using this instead of just pasting "folder/smali" as there can be
                    // no smali folder sometimes (smali_1, etc)
                    string smaliDir = manifest.MainSmaliPath.Substring(decompiledFolder.TempFolder.Length + 1);
                    smaliDir = smaliDir.Substring(0, smaliDir.IndexOf(Path.DirectorySeparatorChar));

                    string saveGameDir = Path.Combine(decompiledFolder.TempFolder, smaliDir, "com", "savegame");

                    LDirectory.CreateDirectory(saveGameDir);

                    //Encrypt smali
                    CommonUtils.GenerateAndSaveSmali(
                        filePath: Path.Combine(saveGameDir, "SavesRestoringPortable.smali"),
                        message: needMessage ? popupText : string.Empty,
                        messagesCount: needMessage ? messagesCount : 0
                        );

                    manifest.MainSmaliFile.AddTextToMethod(FileResources.MainSmaliCall);
                    manifest.MainSmaliFile.Save();

                    using (var folderWithDexes = ATempUtils.UseTempFolder(tempFolderProvider))
                    {
                        apktool.Smali(
                            folderWithSmali: decompiledFolder.TempFolder,
                            resultFolder: folderWithDexes.TempFolder,
                            dataHandler: dataHandler
                            );

                        string[] dexes = LDirectory.GetFiles(folderWithDexes.TempFolder, "*.dex");

                        ApkModifer.AddFilesToZip(
                            zipPath: tempApk.TempFile,
                            filePaths: dexes,
                            pathsInZip: Array.ConvertAll(dexes, Path.GetFileName),
                            newEntryCompression: CompressionType.Store
                            );
                    }
                }

                #endregion

                #region Подпись

                SetStep(3, MainResources.StepSigning);

                Log(Line);
                Log(MainResources.StepSigning);
                Log(Line);

                LFile.Copy(tempApk.TempFile, Path.GetDirectoryName(sourceApkPath) + "\\" + Path.GetFileNameWithoutExtension(sourceApkPath) + "_unsigned.apk", true); //Copy apk file to temp

                //Signing
                //tempApk.TempFile "C:\\Users\\xxxxx\\AppData\\Local\\SaveToGame\\temp\\temp_entry_1"
                apktool.Sign(
                    sourceApkPath: tempApk.TempFile,
                    signedApkPath: resultApkPath,
                    tempFileProvider: tempFileProvider,
                    dataHandler: dataHandler,
                    deleteMetaInf: !alternativeSigning
                    );

                #endregion
            }

            #endregion

            _visualProgress.HideIndeterminateLabel();
            SetStep(4, MainResources.AllDone);
            Log(MainResources.AllDone);
            Log(string.Empty, false);
            Log($"{MainResources.Path_to_file} {resultApkPath}");

            _globalVariables.LatestModdedApkPath = resultApkPath;

            if (_settings.Notifications)
            {
                _notificationManager.Show(
                    title: MainResources.Information_Title,
                    text: MainResources.ModificationCompletedContent
                    );
            }

            string dialogResult = MessBox.ShowDial(
                $"{MainResources.Path_to_file} {resultApkPath}",
                MainResources.Successful,
                MainResources.OK, MainResources.Open, MainResources.Install
                );

            _visualProgress.HideBar();
            _taskBarManager.SetNoneState();

            //Dialog result
            if (dialogResult == MainResources.Open)
            {
                Process.Start("explorer.exe", $"/select,{resultApkPath}");
            }
            else if (dialogResult == MainResources.Install)
            {
                Dispatcher.Invoke(() => _adbInstallWindowProvider.Get().ShowDialog());
            }
        }