public static void DecryptNgxRom(string inPath, string outPath) { File.Copy(inPath, outPath, true); using (var fs = File.Open(outPath, FileMode.Open, FileAccess.ReadWrite)) { BinaryReader br = new BinaryReader(fs); fs.Seek(-8, SeekOrigin.End); int unencryptedStart = br.ReadInt32() ^ 0x12345678; int unencryptedEnd = br.ReadInt32() ^ 0x12345678; int keyLength; byte[] keyData = GetNgxRomKey(br, unencryptedStart, unencryptedEnd, out keyLength); BurnCacheHeader header = null; CryptNgxRom(fs, ref header, keyData, keyLength); // Swap sprite and text blocks BinaryWriter bw = new BinaryWriter(fs); fs.Seek(header.Blocks[1].Offset, SeekOrigin.Begin); byte[] textBlock = br.ReadBytes((int)header.GetLength(1)); byte[] spriteBlock = br.ReadBytes((int)header.GetLength(2)); fs.Seek(header.Blocks[1].Offset, SeekOrigin.Begin); bw.Write(spriteBlock); header.Blocks[2].Offset = (uint)fs.Position; bw.Write(textBlock); // Update header fs.Seek(0, SeekOrigin.Begin); header.Write(bw); fs.SetLength(fs.Length - 8); } }
static void CryptNgxRom(Stream fs, ref BurnCacheHeader header, byte[] keyData, int keyLength) { BinaryReader br = new BinaryReader(fs); BinaryWriter bw = new BinaryWriter(fs); // Crypt cache header fs.Seek(0, SeekOrigin.Begin); byte[] cacheHeader = br.ReadBytes(0x100); for (int i = 0; i < cacheHeader.Length; ++i) { cacheHeader[i] ^= keyData[i % keyLength]; } fs.Seek(0, SeekOrigin.Begin); bw.Write(cacheHeader); if (header == null) { using (MemoryStream ms = new MemoryStream(cacheHeader)) { BinaryReader hbr = new BinaryReader(ms); header = new BurnCacheHeader(); header.Read(hbr); } } // Encryption map (key index -> cache block) Dictionary <int, int> encryptionMap = new Dictionary <int, int> { { 1, 0 }, // Code { 2, 3 }, // PCM A { 3, 4 }, // PCM B { 4, 5 }, // Sprite Attr { 5, 6 } // Text Attr }; foreach (var pair in encryptionMap) { CryptNeoGeoBlock(fs, header.Blocks[pair.Value].Offset, header.GetLength(pair.Value), keyData, pair.Key * ROM_KEY_OFFSET_MULTIPLE, keyLength); } }