private void decompressButton_Click(object sender, System.EventArgs e) { SaveFileDialog sfd = new SaveFileDialog(); sfd.FileName = Path.GetFileName(bundleStream.Name) + ".unpacked"; sfd.Filter = "All types (*.*)|*.*"; if (sfd.ShowDialog() == DialogResult.OK) { note.Text = "Decompressing..."; decompressButton.Enabled = false; bundleFilename = sfd.FileName; FileStream fileStream = new FileStream(sfd.FileName, FileMode.Create); BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += delegate { bundle.Unpack(reader, new AssetsFileWriter(fileStream)); fileStream.Position = 0; bundle = new AssetsBundleFile(); bundle.Read(new AssetsFileReader(fileStream), false); fileStream.Close(); }; bw.RunWorkerCompleted += delegate { note.Text = "Done. Click Load to open the file."; decompressButton.Enabled = false; loadButton.Enabled = true; }; bw.RunWorkerAsync(); } }
//AssetsBundleFile public static void Write(this AssetsBundleFile file, AssetsFileWriter writer, byte[] assetsFileBinary /*AssetsFile assetsFile, AssetsReplacer[] replacers*/) { file.bundleHeader6.Write(writer, 0); file.bundleInf6.Write(writer, writer.Position); writer.Write(assetsFileBinary); //assetsFile.Write(writer, writer.Position, replacers, 0); }
public static AssetsBundleFile CreateBlankBundle(string engineVersion, int contentSize) { AssetsBundleHeader06 header = new AssetsBundleHeader06() { signature = "UnityFS", fileVersion = 6, minPlayerVersion = "5.x.x", fileEngineVersion = engineVersion, totalFileSize = (ulong)(0x82 + engineVersion.Length + contentSize), compressedSize = 0x5B, decompressedSize = 0x5B, flags = 0x40 }; AssetsBundleBlockInfo06 blockInf = new AssetsBundleBlockInfo06 { decompressedSize = (uint)contentSize, compressedSize = (uint)contentSize, flags = 0x0040 }; AssetsBundleDirectoryInfo06 dirInf = new AssetsBundleDirectoryInfo06 { offset = 0, decompressedSize = (uint)contentSize, flags = 4, name = GenerateCabName() }; AssetsBundleBlockAndDirectoryList06 info = new AssetsBundleBlockAndDirectoryList06() { checksumLow = 0, checksumHigh = 0, blockCount = 1, blockInf = new AssetsBundleBlockInfo06[] { blockInf }, directoryCount = 1, dirInf = new AssetsBundleDirectoryInfo06[] { dirInf } }; AssetsBundleFile bundle = new AssetsBundleFile() { bundleHeader6 = header, bundleInf6 = info }; return(bundle); }
private void DecompressBundle(string path) { //from uabe AssetsFileReader reader = new AssetsFileReader(new FileStream(path, FileMode.Open)); AssetsBundleFile bundle = new AssetsBundleFile(); bundle.Read(reader, true); reader.Position = 0; AssetsFileWriter writer = new AssetsFileWriter(new FileStream(path + ".up", FileMode.Create)); bundle.Unpack(reader, writer); //writer.BaseStream.Position = 0; //bundle = new AssetsBundleFile(); //bundle.Read(new AssetsFileReader(writer.BaseStream), false); reader.BaseStream.Close(); writer.BaseStream.Close(); }
private void openToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Unity content (*.unity3d;*.assets)|*.unity3d;*.assets|Bundle file (*.unity3d)|*.unity3d|Assets file (*.assets)|*.assets|All types (*.*)|*.*"; if (ofd.ShowDialog() == DialogResult.OK) { //try //{ //todo, use using FileStream stream = new FileStream(ofd.FileName, FileMode.Open, FileAccess.ReadWrite); AssetsFileReader tempReader = new AssetsFileReader(stream); //todo .assets sanity check if (tempReader.ReadStringLength(7) != "UnityFS") { tempReader.Position = 0; AssetViewer av = new AssetViewer(stream, Path.GetDirectoryName(stream.Name), Path.GetFileName(stream.Name)); av.ShowDialog(); } else { tempReader.Position = 0; BundleLoader bl = new BundleLoader(stream); bl.ShowDialog(); if (bl.loaded) { bundleContents.Enabled = true; exportButton.Enabled = true; importButton.Enabled = true; infoButton.Enabled = true; foreach (AssetsBundleDirectoryInfo06 di in bl.bundle.bundleInf6.dirInf) { bundleContents.Items.Add(di.name); } bundleContents.SelectedIndex = 0; bundlePath = bl.bundleFilename; fileName.Text = Path.GetFileName(bundlePath); bundle = bl.bundle; } } tempReader = null; //} catch (Exception ex) //{ // MessageBox.Show("Unable to open the file!\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); //} } }
private static byte[] GetBundleData(string bunPath, int index) { AssetsFileReader r = new AssetsFileReader(File.Open(bunPath, FileMode.Open, FileAccess.Read, FileShare.Read)); AssetsBundleFile bun = new AssetsBundleFile(); bun.Read(r, true); //if the bundle doesn't have this section return empty if (index >= bun.bundleInf6.dirInf.Length) { return(new byte[0]); } AssetsBundleDirectoryInfo06 dirInf = bun.bundleInf6.dirInf[index]; int start = (int)(bun.bundleHeader6.GetFileDataOffset() + dirInf.offset); int length = (int)dirInf.decompressedSize; byte[] data; r.BaseStream.Position = start; data = r.ReadBytes(length); return(data); }
private void ReadBundle(FileStream stream) { reader = new AssetsFileReader(stream); bundle = new AssetsBundleFile(); bundleFilename = stream.Name; bundle.Read(reader, true); reader.Position = 0; switch (bundle.bundleHeader6.flags & 0x3F) { case 0: compressionMethod.Text = "Compression Method: None"; break; case 1: compressionMethod.Text = "Compression Method: LZMA"; break; case 2: case 3: compressionMethod.Text = "Compression Method: LZ4"; break; default: compressionMethod.Text = "Compression Method: Unknown"; break; } if ((bundle.bundleHeader6.flags & 0x3F) == 0) { note.Text = "Bundle is not compressed. You can load it or compress it."; compressButton.Enabled = true; loadButton.Enabled = true; } else { note.Text = "Bundle is compressed. You must decompress the bundle to load."; decompressButton.Enabled = true; } }
public static AssetsBundleFile CreateBlankBundle(string engineVersion, int contentSize, int contentSizeSA, string sceneName) { uint infSize = (uint)(0x7B + sceneName.Length * 2); AssetsBundleHeader06 header = new AssetsBundleHeader06() { signature = "UnityFS", fileVersion = 6, minPlayerVersion = "5.x.x", fileEngineVersion = engineVersion, totalFileSize = (ulong)(0x82 + engineVersion.Length + contentSize + contentSizeSA), compressedSize = infSize, //0x5B, decompressedSize = infSize, //0x5B, flags = 0x40 }; AssetsBundleBlockInfo06 blockInfSharedAssets = new AssetsBundleBlockInfo06 { decompressedSize = (uint)contentSizeSA, compressedSize = (uint)contentSizeSA, flags = 0x0040 }; AssetsBundleDirectoryInfo06 dirInfSharedAssets = new AssetsBundleDirectoryInfo06 { offset = 0, decompressedSize = (uint)contentSizeSA, flags = 4, name = "BuildPlayer-" + sceneName + ".sharedAssets" }; AssetsBundleBlockInfo06 blockInf = new AssetsBundleBlockInfo06 { decompressedSize = (uint)contentSize, compressedSize = (uint)contentSize, flags = 0x0040 }; AssetsBundleDirectoryInfo06 dirInf = new AssetsBundleDirectoryInfo06 { offset = (ulong)contentSizeSA, decompressedSize = (uint)contentSize, flags = 4, name = "BuildPlayer-" + sceneName }; AssetsBundleBlockAndDirectoryList06 info = new AssetsBundleBlockAndDirectoryList06() { checksumLow = 0, checksumHigh = 0, blockCount = 2, blockInf = new AssetsBundleBlockInfo06[] { blockInfSharedAssets, blockInf }, directoryCount = 2, dirInf = new AssetsBundleDirectoryInfo06[] { dirInfSharedAssets, dirInf } }; AssetsBundleFile bundle = new AssetsBundleFile() { bundleHeader6 = header, bundleInf6 = info }; return(bundle); }
public static byte[] CreateBundleFromLevel(AssetsManager am, /*byte[] data,*/ AssetsFileInstance inst, string sceneName, DiffFile diffFile, string bunPath) { AssetsFile file = inst.file; AssetsFileTable table = inst.table; string folderName = Path.GetDirectoryName(inst.path); //string sceneName = Path.GetFileNameWithoutExtension(inst.path) + "_mod"; List <AssetsReplacer> assetsSA = new List <AssetsReplacer>(); List <AssetFileInfoEx> infos = table.pAssetFileInfo.ToList(); //List<int> typeIds = new List<int>(); //foreach (AssetFileInfoEx info in infos) //{ // int typeId = (int)info.curFileType; // if (!typeIds.Contains(typeId) && typeId != 0x72) // typeIds.Add(typeId); //} assetsSA.Add(PreloadData.CreatePreloadData(1)); assetsSA.Add(BundleMeta.CreateBundleInformation(sceneName, 2)); //todo: pull from original assets file, cldb is not always update to date List <Type_0D> types = new List <Type_0D>(); //foreach (int typeId in typeIds) //{ // types.Add(C2T5.Cldb2TypeTree(am.classFile, typeId)); //} List <Type_0D> typesSA = new List <Type_0D> { C2T5.Cldb2TypeTree(am.classFile, 0x96), //PreloadData C2T5.Cldb2TypeTree(am.classFile, 0x8E) //AssetBundle }; const string ver = "2017.4.10f1"; List <AssetsReplacer> replacers = new List <AssetsReplacer>(); //UnityEngine.Debug.Log("HKWE DM " + diffFile.magic); //UnityEngine.Debug.Log("HKWE GC " + diffFile.changes.Count + diffFile.adds.Count + diffFile.removes.Count); //AssetsReplacerFromMemory mem = MoveTest.RunMoveTest(table.getAssetInfo(2642), am.GetATI(file, table.getAssetInfo(2642)).GetBaseField(), 2642) as AssetsReplacerFromMemory; foreach (GameObjectChange goChange in diffFile.changes) { //UnityEngine.Debug.Log("HKWE GO " + goChange.pathId); foreach (ComponentChangeOrAdd compChange in goChange.changes) { AssetFileInfoEx goInfo = table.getAssetInfo((ulong)goChange.pathId); AssetTypeValueField goBaseField = am.GetATI(file, goInfo).GetBaseField(); AssetTypeValueField compPptr = goBaseField.Get("m_Component").Get("Array")[(uint)compChange.componentIndex].Get("component"); AssetsManager.AssetExternal compExt = am.GetExtAsset(inst, compPptr); AssetFileInfoEx compInfo = compExt.info; AssetTypeValueField compBaseField = compExt.instance.GetBaseField(); //UnityEngine.Debug.Log("HKWE LR " + compInfo.index); AssetsReplacer imAlreadyReplacer = ComponentDiffReplacer.DiffComponent(compInfo, compBaseField, am.classFile, compChange, compInfo.index); replacers.Add(imAlreadyReplacer); } } AssetsManager amBun = new AssetsManager(); //we create a new manager because the two filenames will probably conflict amBun.classFile = am.classFile; //we can just reuse the classfile which is kinda hacky AssetsFileInstance bunInst = amBun.LoadAssetsFile(new MemoryStream(GetBundleData(bunPath, 0)), "HKWEDiffs", false); //placeholder path since we have no deps //rearrange the pathids immediately after the //last one from the level to keep unity happy ulong levelLargestPathID = 0; foreach (AssetFileInfoEx inf in table.pAssetFileInfo) { if (inf.index > levelLargestPathID) { levelLargestPathID = inf.index; } } ReferenceCrawler.ReorderIds(amBun, bunInst, levelLargestPathID + 1); byte[] bunSAInst = GetBundleData(bunPath, 1); //HashSet<ulong> addedDeps = new HashSet<ulong>(); foreach (AssetFileInfoEx inf in bunInst.table.pAssetFileInfo) { replacers.Add(MakeReplacer(inf.index, am, bunInst, inst, inf, bunSAInst, types)); } //foreach (GameObjectInfo inf in diffFile.infos) //{ // Debug.Log("7"); // ulong bunPathId = GetBundlePathId(amBun, bunInst, inf); // // AssetFileInfoEx objInf = bunInst.table.getAssetInfo(bunPathId); // replacers.Add(MakeReplacer(bunPathId, am, bunInst, inst, objInf, bunSAInst, types)); // // List<ulong> deps = ReferenceCrawler.CrawlPPtrs(amBun, bunInst, bunPathId); // foreach (ulong dep in deps) // { // if (!addedDeps.Contains(dep)) // { // addedDeps.Add(dep); // AssetFileInfoEx depInf = bunInst.table.getAssetInfo(dep); // //if (depInf.curFileType == 0x01 || depInf.curFileType == 0x04 || depInf.curFileType == 0xD4 || depInf.curFileType == 0x15 || depInf.curFileType == 0xD5) // //{ // // continue; // //} // replacers.Add(MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types)); // } // } // ////its possible to get a collision but very unlikely since unity already randomizes ids which are 8 bytes long // ////there's nothing here to test if a collision would be created so just hope that you don't win the lottery // //ulong bunPathId = GetBundlePathId(amBun, bunInst, inf); // ////AssetFileInfoEx afInf = bunInst.table.getAssetInfo(bunPathId); // ////replacers.Add(MakeReplacer(bunPathId, afInf, bunInst.stream)); // //List<ulong> deps = ReferenceCrawler.CrawlPPtrs(am, bunInst, bunPathId); // ////if (info.curFileType == 0x01 || info.curFileType == 0x04 || info.curFileType == 0xD4) // ////{ // //// continue; // ////} // //foreach (ulong dep in deps) // //{ // // AssetFileInfoEx depInf = bunInst.table.getAssetInfo(dep); // // //MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types); // // AssetsReplacerFromMemory ar = MakeReplacer(dep, am, bunInst, inst, depInf, bunSAInst, types); // // //todo- I guess this was just for testing purposes to block out everything, remove this at some point // // if (depInf.curFileType == 0x01 || depInf.curFileType == 0x04 || depInf.curFileType == 0xD4 || depInf.curFileType == 0x15 || depInf.curFileType == 0xD5) //depInf.curFileType == 0x1C // // { // // continue; // // } // // replacers.Add(ar); // //} //} byte[] data = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { //file.typeTree.hasTypeTree = true; //so we don't have to calculate hashes //foreach (Type_0D type in file.typeTree.pTypes_Unity5) //{ // if (!types.Any(t => t.classId == type.classId)) // { // types.Insert(0, C2T5.Cldb2TypeTree(am.classFile, type.classId)); // } //} file.typeTree.pTypes_Unity5 = file.typeTree.pTypes_Unity5.Concat(types.ToArray()).ToArray(); //file.typeTree.pTypes_Unity5 = types.ToArray(); file.typeTree.fieldCount = (uint)file.typeTree.pTypes_Unity5.Length; //file.typeTree.fieldCount = (uint)types.Count; file.Write(writer, 0, replacers.ToArray(), 0); data = ms.ToArray(); } //File.WriteAllBytes("_bundlefinal1.unity3d", data); byte[] blankDataSA = BundleCreator.CreateBlankAssets(ver, typesSA); AssetsFile blankFileSA = new AssetsFile(new AssetsFileReader(new MemoryStream(blankDataSA))); byte[] dataSA = null; using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { blankFileSA.Write(writer, 0, assetsSA.ToArray(), 0); dataSA = ms.ToArray(); } using (MemoryStream ms = new MemoryStream()) using (AssetsFileWriter writer = new AssetsFileWriter(ms)) { AssetsBundleFile bundle = BundleCreator.CreateBlankBundle(ver, data.Length, dataSA.Length, sceneName); bundle.Write(writer); writer.Write(dataSA); writer.Write(data); return(ms.ToArray()); } }