private NblChunk loadGroup(Stream fileToLoad, BinaryReader fileLoader) { NblChunk toRet = new NblChunk(); toRet.bigEndian = isBigEndian; long offset = fileToLoad.Position; string formatName = new String(fileLoader.ReadChars(4)); ushort fileVersion = fileLoader.ReadUInt16(); int paddingAmount = fileVersion == 0x1002 ? 0x3F : 0x7FF; uint mask = fileVersion == 0x1002 ? 0xFFFFFFC0 : 0xFFFFF800; ushort chunkFilenameLength = fileLoader.ReadUInt16(); int headerSize = fileLoader.ReadInt32(); int numFiles = fileLoader.ReadInt32(); uint uncompressedSize = fileLoader.ReadUInt32(); uint compressedSize = fileLoader.ReadUInt32(); uint pointerLength = fileLoader.ReadUInt32() / 4; if (formatName.StartsWith("NML")) { decryptKey = fileLoader.ReadUInt32(); } else { fileLoader.ReadUInt32(); } uint size = compressedSize == 0 ? uncompressedSize : compressedSize; uint nmllDataLoc = (uint)((headerSize + paddingAmount) & mask); uint pointerLoc = (uint)(nmllDataLoc + size + paddingAmount) & mask; uint mainHeaderSize = 0x20; if (formatName.StartsWith("NML")) { mainHeaderSize = 0x30; uint tmllHeaderSize = fileLoader.ReadUInt32(); uint tmllDataSizeUncomp = fileLoader.ReadUInt32(); uint tmllDataSizeComp = fileLoader.ReadUInt32(); uint tmllCount = fileLoader.ReadUInt32(); if (tmllCount > 0) { tmllHeaderLoc = (uint)(pointerLoc + pointerLength * 4 + paddingAmount) & mask; } } decryptor = new BlewFish(decryptKey, isBigEndian); FileHeader[] groupHeaders = new FileHeader[numFiles]; for (int i = 0; i < numFiles; i++) { fileToLoad.Seek(mainHeaderSize + 0x60 * i + offset, SeekOrigin.Begin); FileHeader currentHeader = readHeader(fileLoader.ReadBytes(0x60)); groupHeaders[i] = currentHeader; } fileToLoad.Seek(nmllDataLoc + offset, SeekOrigin.Begin); int encryptedSectionSize; if (fileVersion == 0x1002) { //Obfuscation stuff from sega. int rawEncryptedSectionSize = (int)((((compressedSize >> 0xB) ^ compressedSize) & 0xE0) + 0x20); encryptedSectionSize = Math.Min(rawEncryptedSectionSize, (int)compressedSize); } else { encryptedSectionSize = (int)size; } if (encryptedSectionSize % 8 != 0) { encryptedSectionSize -= (encryptedSectionSize % 8); } byte[] decryptedFiles; if (decryptKey != 0 && formatName.StartsWith("NML")) { byte[] encryptedFiles = fileLoader.ReadBytes((int)size); decryptedFiles = decryptor.decryptBlock(encryptedFiles, encryptedSectionSize); } else { decryptedFiles = fileLoader.ReadBytes((int)size + 7); } if (compressedSize != 0) { if (fileVersion == 0x1002) { DeflateStream ds = new DeflateStream(new MemoryStream(decryptedFiles), CompressionMode.Decompress); MemoryStream decompressedStream = new MemoryStream((int)uncompressedSize); ds.CopyTo(decompressedStream); decompressedFiles = decompressedStream.ToArray(); } else { decompressedFiles = PrsCompDecomp.Decompress(decryptedFiles, uncompressedSize); } } else { decompressedFiles = decryptedFiles; } List <int> pointers = new List <int>((int)pointerLength); if (pointerLength > 0) { fileToLoad.Seek(pointerLoc + offset, SeekOrigin.Begin); for (int i = 0; i < pointerLength; i++) { pointers.Add(fileLoader.ReadInt32()); } } List <RawFile> files = new List <RawFile>(numFiles); for (int i = 0; i < numFiles; i++) { RawFile tempFile = new RawFile(); tempFile.filename = groupHeaders[i].fileName; tempFile.subHeader = groupHeaders[i].subHeader; tempFile.chunkSize = groupHeaders[i].chunkSize; tempFile.fileOffset = groupHeaders[i].filePosition; tempFile.fileContents = new byte[groupHeaders[i].fileSize]; Array.Copy(decompressedFiles, groupHeaders[i].filePosition, tempFile.fileContents, 0, groupHeaders[i].fileSize); if (tempFile.fileContents.Length > 0) { tempFile.fileheader = new String(ASCIIEncoding.ASCII.GetChars(tempFile.fileContents, 0, 4)); } if (groupHeaders[i].pointerSize > 0) { tempFile.pointers = pointers.GetRange((int)groupHeaders[i].pointerPosition / 4, (int)groupHeaders[i].pointerSize / 4); } files.Add(tempFile); } toRet.encryptionKey = decryptKey; toRet.encrypted = decryptKey != 0; toRet.compressed = compressedSize != 0; toRet.chunkID = formatName; toRet.versionNumber = (short)fileVersion; toRet.fileContents = files; return(toRet); }
public ScriptFile(string inFilename, byte[] rawData, bool bigEndian = false) { filename = inFilename; int inFilesize, outFilesize; if (!bigEndian) { outFilesize = BitConverter.ToInt32(rawData, 0); inFilesize = BitConverter.ToInt32(rawData, 4); } else { byte[] outFilesizeBytes = new byte[] { rawData[3], rawData[2], rawData[1], rawData[0] }; byte[] inFilesizeBytes = new byte[] { rawData[7], rawData[6], rawData[5], rawData[4] }; if (BitConverter.ToUInt32(inFilesizeBytes, 0) > rawData.Length) { //Stupid hack to try to fix tobitama outFilesize = BitConverter.ToInt32(outFilesizeBytes.Reverse().ToArray(), 0); inFilesize = BitConverter.ToInt32(inFilesizeBytes.Reverse().ToArray(), 0); } else { outFilesize = BitConverter.ToInt32(outFilesizeBytes, 0); inFilesize = BitConverter.ToInt32(inFilesizeBytes, 0); } } byte[] temp = new byte[inFilesize]; Array.Copy(rawData, 0x1C, temp, 0, inFilesize); byte[] decompressed = PrsCompDecomp.Decompress(temp, (uint)outFilesize); MemoryStream scriptStream = new MemoryStream(decompressed); BinaryReader scriptReader; if (bigEndian) { scriptReader = new BigEndianBinaryReader(scriptStream); } else { scriptReader = new BinaryReader(scriptStream); } scriptStream.Seek(4, SeekOrigin.Begin); int stringListPtr = scriptReader.ReadInt32(); int stringListLength = scriptReader.ReadInt32(); scriptStream.Seek(stringListPtr + 0xC, SeekOrigin.Begin); stringNames = new string[stringListLength / 0x20]; for (int i = 0; i < stringNames.Length; i++) { stringNames[i] = ASCIIEncoding.UTF8.GetString(scriptReader.ReadBytes(0x20)); stringNames[i] = stringNames[i].TrimEnd('\0'); } scriptStream.Seek(0xC, SeekOrigin.Begin); //ArrayList subroutines = new ArrayList(); while (scriptStream.Position < stringListPtr) { int nextSubLoc = scriptReader.ReadInt32() + 0xC; string subroutineName = ASCIIEncoding.UTF8.GetString(scriptReader.ReadBytes(0x20)).TrimEnd('\0'); int subLength = scriptReader.ReadInt32(); int subType = scriptReader.ReadLittleEndianInt32(); int locals = scriptReader.ReadInt32(); int currLoc = (int)scriptStream.Position; int subEnd = currLoc + subLength; scriptStream.Seek(subLength, SeekOrigin.Current); int[] localNums = new int[locals]; int[] localLocs = new int[locals]; if (subType == 0x4C) { for (int i = 0; i < locals; i++) { localNums[i] = scriptReader.ReadInt32(); localLocs[i] = scriptReader.ReadInt32() * 4; } } List <operation> operations = new List <operation>(); List <int> opcodeLocs = new List <int>(); scriptStream.Seek(currLoc, SeekOrigin.Begin); while (scriptStream.Position < subEnd) { opcodeLocs.Add((int)(scriptStream.Position - currLoc)); int currOpcode = scriptReader.ReadInt32(); operation tempOp = new operation(); if (opcodeTypes[currOpcode] == 3) { tempOp.floatArg = scriptReader.ReadSingle(); } else if (opcodeTypes[currOpcode] > 1 && opcodeTypes[currOpcode] != 4 && !localLocs.Contains((int)(scriptStream.Position - currLoc))) { tempOp.intArg = scriptReader.ReadInt32(); } else if (localLocs.Contains((int)(scriptStream.Position - currLoc))) { tempOp.strArg = stringNames[localNums[Array.IndexOf(localLocs, (int)(scriptStream.Position - currLoc))]]; tempOp.intArg = scriptReader.ReadInt32(); } if (opcodeTypes[currOpcode] == 99) { tempOp.strArg = ASCIIEncoding.GetEncoding("shift-jis").GetString(scriptReader.ReadBytes(tempOp.intArg * 4)).TrimEnd('\0'); } tempOp.opcode = currOpcode; operations.Add(tempOp); } for (int i = 0; i < operations.Count; i++) { if (((operation)operations[i]).opcode > 0x2B && ((operation)operations[i]).opcode < 0x2F) { int branchSource = opcodeLocs[i] + 0x8; int branchDestRaw = branchSource + 4 * ((operation)operations[i]).intArg; for (int j = 0; j < operations.Count; j++) { if (branchDestRaw == opcodeLocs[j]) { ((operation)operations[i]).intArg = j; break; } } } } subroutine tempSub = new subroutine(); tempSub.name = subroutineName; tempSub.subType = subType; if (subType != 0x4C) { tempSub.miscData = locals; } else { tempSub.miscData = -1; } tempSub.opcodes = operations; subroutines.Add(tempSub); if (nextSubLoc == 0xC) { break; } scriptStream.Seek(nextSubLoc, SeekOrigin.Begin); } scriptReader.Close(); }
private void decryptNMLBToolStripMenuItem_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { byte[] fileContents = File.ReadAllBytes(openFileDialog1.FileName); MemoryStream fileStream = new MemoryStream(fileContents); fileStream.Seek(3, SeekOrigin.Begin); byte endian = (byte)fileStream.ReadByte(); fileStream.Seek(0, SeekOrigin.Begin); BinaryReader fileLoader; bool bigEndian = false; if (endian == 0x42) { fileLoader = new BigEndianBinaryReader(fileStream); bigEndian = true; } else { fileLoader = new BinaryReader(fileStream); } string formatName = new String(fileLoader.ReadChars(4)); ushort fileVersion = fileLoader.ReadUInt16(); ushort chunkFilenameLength = fileLoader.ReadUInt16(); uint headerSize = fileLoader.ReadUInt32(); uint nmllCount = fileLoader.ReadUInt32(); uint uncompressedSize = fileLoader.ReadUInt32(); uint compressedSize = fileLoader.ReadUInt32(); uint pointerLength = fileLoader.ReadUInt32() / 4; uint blowfishKey = fileLoader.ReadUInt32(); uint tmllHeaderSize = fileLoader.ReadUInt32(); uint tmllDataSizeUncomp = fileLoader.ReadUInt32(); uint tmllDataSizeComp = fileLoader.ReadUInt32(); uint tmllCount = fileLoader.ReadUInt32(); uint tmllHeaderLoc = 0; uint pointerLoc = 0; uint size = compressedSize == 0 ? uncompressedSize : compressedSize; uint nmllDataLoc = (uint)((headerSize + 0x7FF) & 0xFFFFF800); pointerLoc = (uint)(nmllDataLoc + size + 0x7FF) & 0xFFFFF800; if (tmllCount > 0) { tmllHeaderLoc = (pointerLoc + pointerLength * 4 + 0x7FF) & 0xFFFFF800; } BlewFish fish = new BlewFish(blowfishKey, bigEndian); for (int i = 0; i < nmllCount; i++) { int headerLoc = 0x40 + i * 0x60; byte[] toDecrypt = new byte[0x30]; Array.Copy(fileContents, headerLoc, toDecrypt, 0, 0x30); toDecrypt = fish.decryptBlock(toDecrypt); Array.Copy(toDecrypt, 0, fileContents, headerLoc, 0x30); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < tmllCount; i++) { uint headerLoc = (uint)(tmllHeaderLoc + 0x30 + i * 0x60); byte[] toDecrypt = new byte[0x30]; Array.Copy(fileContents, headerLoc, toDecrypt, 0, 0x30); toDecrypt = fish.decryptBlock(toDecrypt); Array.Copy(toDecrypt, 0, fileContents, headerLoc, 0x30); sb.Append(ASCIIEncoding.ASCII.GetString(toDecrypt, 0, 0x20).Split('\0')[0] + "\t"); //sb.Append(BitConverter.ToUInt16(fileContents, (int)(headerLoc + 0x4C)) + "\t"); //sb.Append(BitConverter.ToUInt16(fileContents, (int)(headerLoc + 0x4E)) + "\n"); } fileStream.Seek(nmllDataLoc, SeekOrigin.Begin); byte[] encryptedNmll = fileLoader.ReadBytes((int)size); byte[] decryptedNmll = fish.decryptBlock(encryptedNmll); byte[] decompressedNmll = compressedSize != 0 ? PrsCompDecomp.Decompress(decryptedNmll, uncompressedSize) : decryptedNmll; File.WriteAllText(openFileDialog1.FileName + ".tml.list", sb.ToString()); File.WriteAllBytes(openFileDialog1.FileName + ".decrypt", fileContents); File.WriteAllBytes(openFileDialog1.FileName + ".encryptNmll", encryptedNmll); File.WriteAllBytes(openFileDialog1.FileName + ".decryptNmll", decryptedNmll); File.WriteAllBytes(openFileDialog1.FileName + ".decompressNmll", decompressedNmll); } }