public APK(Stream stream) { using (BinaryReader reader = new BinaryReader(stream)) { SectionSet sections = SectionIO.ReadAll(reader); // TODO: Figure out what hash is calculated from and validate hash. PACKHEDR hedr = sections.Get <PACKHEDR>(); GENESTRT nameTable = sections.Get <GENESTRT>(); this.Name = nameTable.Strings[(int)hedr.NameIndex]; PACKTOC toc = sections.Get <PACKTOC>(); this.RootDirectory = this.BuildContentTree(stream, nameTable, toc, (PACKTOC.DirectoryEntry)toc.Entries[0]); PACKFSLS fileSetList = sections.Get <PACKFSLS>(); foreach (PACKFSLS.FileSetEntry entry in fileSetList.FileSets) { stream.Seek((long)entry.Offset, SeekOrigin.Begin); byte[] fileSetData = reader.ReadBytes((int)entry.Size); string fileSetName = nameTable.Strings[(int)entry.NameIndex]; if (!Enumerable.SequenceEqual(new MD5CryptoServiceProvider().ComputeHash(fileSetData), entry.Hash)) { throw new Exception("Hash mismatch in file set \"" + fileSetName + "\"."); } using (MemoryStream fileSetStream = new MemoryStream(fileSetData)) { this.FileSets.Add(this.ReadFileSet(fileSetStream, fileSetName)); } } } }
public IDX(params string[] apkFiles) { this.sections = new SectionSet(); this.sections.Add(new ENDILTLE()); List <SectionSet> apks = new List <SectionSet>(); foreach (string apkFile in apkFiles) { using (FileStream stream = File.OpenRead(apkFile)) { apks.Add(SectionIO.ReadAll(stream)); } } PACKTOC combinedToc = new PACKTOC(); PACKFSLS combinedFsls = new PACKFSLS(); GENESTRT combinedStrt = new GENESTRT(); foreach (SectionSet set in apks) { PACKHEDR hedr = set.Get <PACKHEDR>(); GENESTRT strt = set.Get <GENESTRT>(); hedr.NameIndex = combinedStrt.AddString(strt.Strings[(int)hedr.NameIndex]); this.sections.Add(hedr); } uint packageIndex = 0; foreach (SectionSet set in apks) { PACKTOC toc = set.Get <PACKTOC>(); PACKFSLS fsls = set.Get <PACKFSLS>(); GENESTRT strt = set.Get <GENESTRT>(); foreach (PACKTOC.Entry entry in toc.Entries) { entry.NameIndex = combinedStrt.AddString(strt.Strings[(int)entry.NameIndex]); entry.PackageIndex = packageIndex; combinedToc.Entries.Add(entry); } foreach (PACKFSLS.FileSetEntry entry in fsls.FileSets) { entry.NameIndex = combinedStrt.AddString(strt.Strings[(int)entry.NameIndex]); entry.PackageIndex = packageIndex; combinedFsls.FileSets.Add(entry); } packageIndex++; } this.sections.Add(combinedToc); this.sections.Add(combinedFsls); this.sections.Add(combinedStrt); this.sections.Add(new GENEEOF()); }
public void Write(Stream stream) { GENESTRT nameTable = new GENESTRT(); nameTable.Strings.Add(this.Name); PACKHEDR packhedr = new PACKHEDR(); packhedr.Unknown1 = 0x10000; packhedr.NameIndex = 0; packhedr.DataOffset = 0; // Filled in later. packhedr.Unknown3 = 1; packhedr.Hash = new byte[16]; // TODO PACKTOC toc = new PACKTOC(); byte[] fileData; using (MemoryStream fileStream = new MemoryStream()) { this.WriteFiles(fileStream, toc, nameTable); fileData = fileStream.ToArray(); } PACKFSLS fsls = new PACKFSLS(); List <byte[]> fileSetDatas = new List <byte[]>(); uint nameIndex = (uint)nameTable.Strings.Count; foreach (FileSet fileSet in this.FileSets) { byte[] fileSetData; using (MemoryStream fileSetStream = new MemoryStream()) { this.WriteFileSet(fileSetStream, fileSet); fileSetData = fileSetStream.ToArray(); } PACKFSLS.FileSetEntry entry = new PACKFSLS.FileSetEntry(); entry.NameIndex = nameTable.AddString(fileSet.Name); entry.PackageIndex = 0; entry.Offset = 0; // Filled in later. entry.Size = (ulong)fileSetData.Length; entry.Hash = new MD5CryptoServiceProvider().ComputeHash(fileSetData); fsls.FileSets.Add(entry); fileSetDatas.Add(fileSetData); } SectionSet set = new SectionSet(); set.Add(new ENDILTLE()); set.Add(packhedr); set.Add(toc); set.Add(fsls); set.Add(nameTable); set.Add(new GENEEOF()); ulong headersSize; using (MemoryStream sizeTestStream = new MemoryStream()) { SectionIO.WriteAll(sizeTestStream, set); headersSize = (ulong)sizeTestStream.Length; } ulong currOffset = NumberUtil.Align(headersSize, 0x800); packhedr.DataOffset = (uint)currOffset; foreach (PACKTOC.Entry entry in toc.Entries) { if (entry is PACKTOC.UncompressedFileEntry uFileEntry) { uFileEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + uFileEntry.Size, 0x200); } else if (entry is PACKTOC.CompressedFileEntry cFileEntry) { cFileEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + cFileEntry.CompressedSize, 0x200); } } currOffset = NumberUtil.Align(currOffset, 0x800); foreach (PACKFSLS.FileSetEntry fileSetEntry in fsls.FileSets) { fileSetEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + fileSetEntry.Size, 0x800); } SectionIO.WriteAll(stream, set); stream.PadTo(0x800); stream.Write(fileData); foreach (byte[] fileSetData in fileSetDatas) { stream.PadTo(0x800); stream.Write(fileSetData); } }
private static int Main(string[] args) { OpenFileDialog fd = new OpenFileDialog(); fd.Filter = "AKB 1/48 Guam apk files|*.apk"; if (fd.ShowDialog() == DialogResult.OK) { FolderBrowserDialog fbd = new FolderBrowserDialog(); fbd.SelectedPath = "C:\\"; if (fbd.ShowDialog() == DialogResult.OK) { FileStream filestream = new FileStream("out.txt", FileMode.Create); var streamwriter = new StreamWriter(filestream); streamwriter.AutoFlush = true; Console.SetOut(streamwriter); Console.SetError(streamwriter); using (EndianBinaryReader reader = new EndianBinaryReader(EndianBitConverter.Little, File.Open(fd.FileName, FileMode.Open))) { reader.ReadBytes(16); if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKHEDR") { return(-1); } PACKHEDR pkhdr = new PACKHEDR(); pkhdr.headerSize = reader.ReadInt64(); pkhdr.dummy = reader.ReadInt32(); pkhdr.zero = reader.ReadInt32(); pkhdr.dummySize = reader.ReadInt32(); pkhdr.dummy2 = reader.ReadInt32(); pkhdr.dummystring = Encoding.ASCII.GetString(reader.ReadBytes(16)); if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKTOC ") { return(-1); } PACKTOC pktoc = new PACKTOC(); pktoc.size = reader.ReadInt64(); pktoc.offset = reader.BaseStream.Position; pktoc.entrySize = reader.ReadInt32(); pktoc.files = reader.ReadInt32(); pktoc.folders = reader.ReadInt32(); pktoc.zero = reader.ReadInt32(); GENESTRT gene1 = GetGENESTRT(reader, pktoc.offset, pktoc.size); //FOLDERS fldrs = new FOLDERS(pktoc.folders); for (int k = 0; k < pktoc.folders; k++) { /* * fldrs.dummystring.Add(reader.ReadBytes(pktoc.entrySize)); * fldrs.nameIdx.Add(fldrs.dummystring[k].ElementAt(4)); * fldrs.fileNum.Add(fldrs.dummystring[k].ElementAt(16)); * fldrs.subFiles.Add(fldrs.dummystring[k].ElementAt(20)); * fldrs.foldernames[k] = gene1.stringlist[fldrs.nameIdx[k]]; */ reader.ReadBytes(pktoc.entrySize); } for (int l = pktoc.folders; l < pktoc.files; l++) { long tocpos = reader.BaseStream.Position; reader.ReadInt32(); //always 0x200 (512) int idx = reader.ReadInt32(); reader.ReadInt32(); //always 0 reader.ReadInt32(); //always 0 long offset = reader.ReadInt64(); long size = reader.ReadInt64(); long zsize = reader.ReadInt64(); Console.WriteLine("TOC offset: {4} file: {0} offset: {1} size: {2} zsize: {3}", gene1.stringlist[idx], offset, size, zsize, tocpos); if (size != 0) { string fname = gene1.stringlist[idx]; if (zsize == 0) { long tmpstreampos = reader.BaseStream.Position; reader.BaseStream.Position = offset; //Console.WriteLine("File: {0} is not compressed. Writing to {1}", fname, fbd.SelectedPath + "\\" + fname); using (FileStream nfstrm = new FileStream(fbd.SelectedPath + "\\" + fname, FileMode.Create)) { nfstrm.Write(reader.ReadBytes((int)size), 0, (int)size); reader.BaseStream.Position = tmpstreampos; } } else { long tempstrmpos = reader.BaseStream.Position; reader.BaseStream.Position = offset + 2; //Console.WriteLine("File: {0} is compressed. Writing to {1}", fname, fbd.SelectedPath + "\\" + fname); MemoryStream tmpmemstrm = new MemoryStream(reader.ReadBytes((int)zsize)); using (FileStream cpfs = new FileStream(fbd.SelectedPath + "\\" + fname, FileMode.Create)) { using (DeflateStream dfstrm = new DeflateStream(tmpmemstrm, CompressionMode.Decompress)) { dfstrm.CopyTo(cpfs); } } reader.BaseStream.Position = tempstrmpos; } } } reader.BaseStream.Position = pktoc.offset + pktoc.size; if (Encoding.ASCII.GetString(reader.ReadBytes(8)) != "PACKFSLS") { return(-1); } PACKFSLS pkfls = new PACKFSLS(); pkfls.headerSize = reader.ReadInt64(); pkfls.headerOffset = reader.BaseStream.Position; pkfls.archives = reader.ReadInt32(); pkfls.dummy = reader.ReadInt32(); pkfls.dummy2 = reader.ReadInt32(); pkfls.zero = reader.ReadInt32(); for (int archive = 0; archive < pkfls.archives; archive++) { int tmpidx = reader.ReadInt32(); reader.ReadInt32(); long archiveoffset = reader.ReadInt64(); long archivesize = reader.ReadInt64(); reader.ReadBytes(16); string aname = gene1.stringlist[tmpidx]; long tmppos = reader.BaseStream.Position; extractArchives(reader, archiveoffset, aname, fbd.SelectedPath); reader.BaseStream.Position = tmppos; } } filestream.Close(); } } return(1); }