static void ModeSpareFix() { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + "_fixed"; } Console.WriteLine($"Reading spare from {filePath}..."); using (var fixedStream = new MemoryStream()) { using (var reader = new BinaryReader(File.OpenRead(filePath))) { bool isBlockSpare = true; if (reader.BaseStream.Length == 64 * 1024) { // must be a block-spare already, just copy it all to the fixed stream so we can fix up the ECC byte[] spare = reader.ReadBytes(64 * 1024); fixedStream.Write(spare, 0, 64 * 1024); } else { int numSkip = 0; if (reader.BaseStream.Length == 1024 * 1024) // overdump, just skip 0xF0 after each read { numSkip = 0xF0; } else if (reader.BaseStream.Length == 1024 * 1024 * 2) // page-spare dump, we only want the spare of the last page in each block { numSkip = 0x1F0; reader.BaseStream.Position = 0x1F0; } else { Console.WriteLine("Spare isn't overdump/page-spare/block-spare dump?"); return; } if (generateFullSpare) { if (numSkip != 0x1F0) { Console.WriteLine("Invalid spare used with -gp (-fullspare)"); Console.WriteLine("This switch only works with page/block-spares, not overdumps!"); return; } // user gave -gp switch, so just copy the whole page-spare instead of reducing to block-spare reader.BaseStream.Position = 0; byte[] spare = reader.ReadBytes(1024 * 1024 * 2); fixedStream.Write(spare, 0, 1024 * 1024 * 2); isBlockSpare = false; } else { while (reader.BaseStream.Position < reader.BaseStream.Length) { byte[] spare = reader.ReadBytes(0x10); spare[6] = 0; // fix page-spare dump to match format of block-spare dump fixedStream.Write(spare, 0, 0x10); if (reader.BaseStream.Position < reader.BaseStream.Length) // with raw page-spare dumps we're at the end here, so check for that { reader.BaseStream.Position += numSkip; } } } } // if nand.bin is specified, read from it and correct the spare data if (!string.IsNullOrEmpty(extraPath)) { var nand = new iQueNand(extraPath); nand.Read(); var fixedSpare = nand.GenerateSpareData(isBlockSpare, fixedStream.ToArray()); // todo: make a stream-based GenerateSpareData method? fixedStream.Position = 0; fixedStream.Write(fixedSpare, 0, fixedSpare.Length); } } File.WriteAllBytes(outputFile, fixedStream.ToArray()); } Console.WriteLine($"Saved fixed spare to {outputFile}!"); }
static void ModeNAND() { Console.WriteLine($"Opening NAND image from {filePath}..."); Console.WriteLine(); if (!string.IsNullOrEmpty(outputFile) && !string.IsNullOrEmpty(updateKernelPath)) { // we're updating kernel with output file specified, so copy the input file to specified output file and work with that instead if (File.Exists(outputFile)) { File.Delete(outputFile); } File.Copy(filePath, outputFile); filePath = outputFile; } var nandFile = new iQueNand(filePath) { SkipVerifyFsChecksums = skipVerifyChecksums, InodesOffset = isBadDump ? 0x10 : 0 }; if (!nandFile.Read()) { Console.WriteLine($"[!] Failed to read NAND image!"); return; } if (printInfo) { Console.WriteLine(nandFile.ToString(true, true, showAllFsInfo)); } if (writeInfo) { File.WriteAllText(filePath + ".txt", nandFile.ToString(true, false, showAllFsInfo)); Console.WriteLine($"Wrote detailed NAND info to {filePath}.txt"); } if (!string.IsNullOrEmpty(updateKernelPath)) { Console.WriteLine($"Updating NAND SKSA to {updateKernelPath}"); nandFile.SetSKSAData(updateKernelPath); } else { // extract / extractkernel can only be used if we aren't updating kernel in the same session if (extractAll) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + "_ext"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (!Directory.Exists(outputFile)) { Directory.CreateDirectory(outputFile); } int count = 0; foreach (var file in nandFile.MainFsInodes) { if (!file.IsValid) { continue; } var extPath = Path.Combine(outputFile, file.NameString); Console.WriteLine($"Writing file to {extPath}"); File.WriteAllBytes(extPath, nandFile.GetInodeData(file)); count++; } Console.WriteLine($"Extracted {count} files to {outputFile}"); } if (extractKernel) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + ".sksa.bin"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (extractAll) // if we just extracted the fs files we'll extract SKSA into the same folder { outputFile = Path.Combine(outputFile, "sksa.bin"); } File.WriteAllBytes(outputFile, nandFile.GetSKSAData()); Console.WriteLine($"Extracted SKSA to {outputFile}"); } } if (!string.IsNullOrEmpty(generateSparePath)) { File.WriteAllBytes(generateSparePath, nandFile.GenerateSpareData(!generateFullSpare)); Console.WriteLine($"Wrote generated {(generateFullSpare ? "page" : "block")}-spare data to {generateSparePath}"); } }
static void ModeNAND() { Console.WriteLine($"Opening NAND image from {filePath}..."); Console.WriteLine(); if (!string.IsNullOrEmpty(outputFile) && !string.IsNullOrEmpty(updateKernelPath)) { // we're updating kernel with output file specified, so copy the input file to specified output file and work with that instead if (File.Exists(outputFile)) { File.Delete(outputFile); } File.Copy(filePath, outputFile); filePath = outputFile; } var nandFile = new iQueNand(filePath) { SkipVerifyFsChecksums = skipVerifyChecksums || fixFsChecksums, InodesOffset = isBadDump ? 0x10 : 0 }; if (!nandFile.Read()) { Console.WriteLine($"[!] Failed to read NAND image!"); return; } if (!string.IsNullOrEmpty(addFiles) || !string.IsNullOrEmpty(addFilesList)) { var filesToAdd = new List <string>(); if (!string.IsNullOrEmpty(addFiles)) { var files = addFiles.Split(','); filesToAdd.AddRange(files); } if (!string.IsNullOrEmpty(addFilesList)) { if (File.Exists(addFilesList)) { var files = File.ReadAllLines(addFilesList); filesToAdd.AddRange(files); } else { Console.WriteLine($"[!] -al (addlist) failed, list {addFilesList} doesn't exist!"); } } if (filesToAdd.Count > 0) { int successful = 0; foreach (var file in filesToAdd) { if (File.Exists(file)) { Console.WriteLine($"Adding file to NAND: {file}"); BbInode node = new BbInode(); if (nandFile.FileWrite(Path.GetFileName(file), File.ReadAllBytes(file), ref node)) { Console.WriteLine($"File added successfully! name: {node.NameString}, block: {node.BlockIdx}"); successful++; } else { Console.WriteLine($"[!] Failed to add file, likely not enough free space in nand!"); } } else { Console.WriteLine($"[!] Failed to add non-existing file:{Environment.NewLine}\t{file}"); } } if (successful > 0) { Console.WriteLine("Writing updated FS to NAND..."); if (nandFile.WriteFilesystem()) { Console.WriteLine($"Added {successful} files successfully!"); } else { Console.WriteLine("[!] Failed to write updated FS, couldn't find FS block to write?"); } } } else { Console.WriteLine("[!] -al (addlist) failed, no files to add!"); } } if (!string.IsNullOrEmpty(deleteFiles)) { var filesToDelete = deleteFiles.Split(','); int successful = 0; foreach (var file in filesToDelete) { // lazy way to get proper 8.3 name for this file.. BbInode inode = new BbInode(); inode.NameString = Path.GetFileName(file); if (nandFile.FileDelete(inode.NameString)) { Console.WriteLine($"File {inode.NameString} removed from NAND!"); successful++; } else { Console.WriteLine($"Failed to remove file {inode.NameString} from NAND..."); } } if (successful > 0) { Console.WriteLine("Writing updated FS to NAND..."); if (nandFile.WriteFilesystem()) { Console.WriteLine($"Removed {successful} files successfully!"); } else { Console.WriteLine("[!] Failed to write updated FS, couldn't find FS block to write?"); } } } if (fixFsChecksums) { nandFile.RepairFsChecksums(); } if (printInfo) { Console.WriteLine(nandFile.ToString(true, true, showAllFsInfo)); } if (writeInfo) { File.WriteAllText(filePath + ".txt", nandFile.ToString(true, false, showAllFsInfo)); Console.WriteLine($"Wrote detailed NAND info to {filePath}.txt"); } if (!string.IsNullOrEmpty(updateKernelPath)) { Console.WriteLine($"Updating NAND SKSA to {updateKernelPath}"); nandFile.SetSKSAData(updateKernelPath); } else { // extract / extractkernel can only be used if we aren't updating kernel in the same session if (extractAll) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + "_ext"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (!Directory.Exists(outputFile)) { Directory.CreateDirectory(outputFile); } int count = 0; foreach (var file in nandFile.MainFsInodes) { if (!file.IsValid) { continue; } var extPath = Path.Combine(outputFile, file.NameString); Console.WriteLine($"Writing file to {extPath}"); File.WriteAllBytes(extPath, nandFile.FileRead(file)); count++; } Console.WriteLine($"Extracted {count} files to {outputFile}"); } if (extractKernel) { if (string.IsNullOrEmpty(outputFile)) { outputFile = filePath + ".sksa.bin"; Console.WriteLine("[!] No output path (-o) given, set path to:"); Console.WriteLine($"- {outputFile}"); Console.WriteLine(); } if (extractAll) // if we just extracted the fs files we'll extract SKSA into the same folder { outputFile = Path.Combine(outputFile, "sksa.bin"); } File.WriteAllBytes(outputFile, nandFile.GetSKSAData()); Console.WriteLine($"Extracted SKSA to {outputFile}"); } } if (!string.IsNullOrEmpty(generateSparePath)) { File.WriteAllBytes(generateSparePath, nandFile.GenerateSpareData(!generateFullSpare)); Console.WriteLine($"Wrote generated {(generateFullSpare ? "page" : "block")}-spare data to {generateSparePath}"); } }