예제 #1
0
        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);
        }
예제 #2
0
        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();
        }
예제 #3
0
        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);
            }
        }