Example #1
0
        /// <summary>
        /// Checks the first 512 bytes for the Android magic sequence
        /// </summary>
        /// <param name="path"></param>
        /// <param name="foundPos">The byte where the magic sequence was found.</param>
        /// <returns></returns>
        private static bool AndroidMagicFound(string path, out int foundPos)
        {
            using (var fs = new FileStream(path, FileMode.Open))
            {
                //fs.Seek(0, SeekOrigin.Begin);
                for (var i = 0; i <= 512; i++)
                {
                    foundPos = i;

                    //fs.Seek(i, SeekOrigin.Begin);
                    var asdf = new Byte[BootImgHeader.BootMagicSize];

                    fs.Read(asdf, i, BootImgHeader.BootMagicSize);

                    if (asdf.SequenceEqual(BootImgHeader.BootMagic))
                    {
                        Console.WriteLine("Android boot magic found");
                        return true;
                    }
                }

                foundPos = 0;
                return false;
            }
        }
Example #2
0
        public static bool CompareByteArrays(Byte[] a, Byte[] b)
        {
            // gleiche Länge?
            if (a.Length == b.Length)
            {
                return a.SequenceEqual(b);
            }

            else
                return false;
        }
Example #3
0
        public void Each_Byte_Each_Scheme()
        {
            for(var numShares = 2; numShares < 256; numShares++)
            {
                for(var threshold = 2; threshold <= numShares; threshold++)
                {
                    for(var theByte = 0; theByte < 256; theByte++)
                    {
                        var secret = new Byte[1] { (byte)theByte };
                        var shares = _handler.Split(secret, threshold, numShares);

                        foreach(var permutation in GetAllPermutations(shares, threshold))
                        {
                            var restoredSecret = _handler.Restore(permutation);
                            Assert.IsTrue(secret.SequenceEqual(restoredSecret));
                        }
                    }
                }
            }
        }
        public void EncryptionDecriptionTest()
        {
            var testVector = Utils.GetTestVector(40);

            var transform = new RC4CryptoTransform(testVector.Key);

            var inputBuffer = testVector.Data;
            var outputBuffer = new Byte[inputBuffer.Length];

            var encrypted = transform.TransformBlock(inputBuffer, 0, inputBuffer.Length, outputBuffer, 0);

            Assert.AreEqual(encrypted, inputBuffer.Length);

            var decryptedData = new Byte[inputBuffer.Length];

            var transform2 = new RC4CryptoTransform(testVector.Key);

            transform2.TransformBlock(outputBuffer, 0, outputBuffer.Length, decryptedData, 0);

            Assert.IsTrue(decryptedData.SequenceEqual(inputBuffer));
        }
Example #5
0
        /// <summary>
        /// Given the first few bytes of content, decide what the FileCategory
        /// should be, based on what's in the Content.<br/>
        /// This should be called before deciding how to set the content.
        /// </summary>
        /// <param name="firstBytes">At least the first four bytes of the file read in binary form - can be longer if you wish</param>
        /// <returns>The type that should be used to store this file.</returns>
        public static FileCategory IdentifyCategory(byte[] firstBytes)
        {
            var firstFour = new Byte[4];
            int atMostFour = Math.Min(4, firstBytes.Length);
            Array.Copy(firstBytes, 0, firstFour, 0, atMostFour);
            var returnCat = (atMostFour < 4) ? FileCategory.TOOSHORT : FileCategory.OTHER; // default if none of the conditions pass

            if (firstFour.SequenceEqual(CompiledObject.MagicId))
            {
                returnCat = FileCategory.KSM;
            }
            else
            {
                bool isAscii = firstFour.All(b => b == (byte)'\n' || b == (byte)'\t' || b == (byte)'\r' || (b >= (byte)32 && b <= (byte)127));
                if (isAscii)
                    returnCat = FileCategory.ASCII;
            }
            return returnCat;

            // There is not currently an explicit test for KERBOSRIPT versus other types of ASCII.
            // At current, any time you want to test for is Kerboscript, make sure to test for is ASCII too,
            // since nothing causes a file to become type kerboscript yet.
        }
            public void Test_Bytes()
            {
                Byte[] value = new Byte[] { 0x1, 0x2, 0x3, 0x4, 0x5 };
                InformationElement infoElement = new InformationElement(
                    InformationElement.ElementId.VendorSpecific, value);

                Byte[] ieArray = infoElement.Bytes;

                Assert.AreEqual(7, ieArray.Length);
                Assert.AreEqual((Byte)InformationElement.ElementId.VendorSpecific, ieArray[0]);
                Assert.AreEqual(5, ieArray[1]);

                Byte[] actualValue = new Byte[5];
                Array.Copy(ieArray, 2, actualValue, 0, 5);
                Assert.IsTrue(value.SequenceEqual(actualValue));
            }
Example #7
0
        ///  <summary>
        ///  Destructor.
        ///  </summary>
        /*
        ~ADS1298device()
        {
            ;
        }
        */
        ///  <summary>
        ///  In order to initialize the device we must have a valid class guid and device path name.
        ///  Use FindDevice from UsbDevice to look up connected devices.
        ///  </summary>
        ///
        ///  <param name="devicePath"> Unique device path. </param>
        ///  
        ///  <returns>  True if successful. </returns>
        internal override Boolean InitializeDevice(String devPath = null)
        {
            Byte[] configBuffer = new Byte[Marshal.SizeOf(regConfig)];

            deviceConfigured = false;
            processingData = true;

            // Check for a valid device path.
            if (devPath != null)
                DevicePath = devPath;
            else if ((DevicePath == null) && (devPath == null))
                return false;

            // Check if this devices exists.
            DeviceFound = usbDev.CheckDevice(DeviceClassGuid, ref devInfo.devicePath);

            if (DeviceFound)
            {
                // Pass the devices path name & get the device handle.
                DeviceAttached = winUsbDev.GetDeviceHandle(this.DevicePath);

                if (DeviceAttached)
                {
                    // Initialize this device
                    DeviceAttached = winUsbDev.InitializeDevice();

                    if (DeviceAttached)
                    {
                        // Lets get the descriptor so we can read the product & vendor id.
                        DeviceAttached = winUsbDev.GetUsbDeviceDescriptor();
                        VendorID = winUsbDev.usbDevDescriptor.idVendor;
                        ProductID = winUsbDev.usbDevDescriptor.idProduct;

                        // Flush the pipes.
                        winUsbDev.FlushPipe(PIPE_COMMAND_IN);
                        winUsbDev.FlushPipe(PIPE_COMMAND_OUT);
                        winUsbDev.FlushPipe(PIPE_DATA_IN);

                        // Read configuration
                        ReadConfiguration();

                        while (!deviceConfigured)
                        {
                            // Let's do a double check here, save the current config & re-read it from the device
                            configBuffer = StructureToByteArray(ref regConfig);
                            ReadConfiguration();
                            if (configBuffer.SequenceEqual(StructureToByteArray(ref regConfig)))
                                deviceConfigured = true;
                        }

                        DeviceName = winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct);
                        if (String.IsNullOrEmpty(winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct)))
                        {
                            DeviceName = String.Concat(DeviceName,
                                String.Concat(Guid.NewGuid().ToString().Replace("-", "").Substring(1, 4)));     // Append random numbers
                        }
                        else
                            DeviceName = String.Concat(DeviceName, " ", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iSerialNumber));

                        SampleLength = SAMPLELENGTH;
                        ResolutionBits = RESOLUTION;
                        InputDifferantialVoltagePositive = INPUT_DIFFERANTIAL_VOLTAGE_POSITIVE;
                        InputDifferantialVoltageNegative = INPUT_DIFFERANTIAL_VOLTAGE_NEGATIVE;

                        EPdeviceType = this.ToString().Substring(this.ToString().LastIndexOf(".") + 1);
                    }
                }
                else
                    winUsbDev.CloseDeviceHandle();
            }

            return (DeviceFound && DeviceAttached && deviceConfigured);
        }
Example #8
0
        private void breakSAV()
        {
            int[] offset = new int[2];
            byte[] empty = new Byte[232];
            byte[] emptyekx = new Byte[232];
            byte[] ekxdata = new Byte[232];
            byte[] pkx = new Byte[232];
            byte[] slotsKey = new byte[0];
            byte[] save1Save = break1;
            #region Finding the User Specific Data: Using Valid to keep track of progress...
            // Do Break. Let's first do some sanity checking to find out the 2 offsets we're dumping from.
            // Loop through save file to find
            int fo = savefile.Length / 2 + 0x20000; // Initial Offset, can tweak later.
            int success = 0;

            string result = "";

            for (int d = 0; d < 2; d++)
            {
                // Do this twice to get both box offsets.
                for (int i = fo; i < 0xEE000; i++)
                {
                    int err = 0;
                    // Start at findoffset and see if it matches pattern
                    if ((break1[i + 4] == break2[i + 4]) && (break1[i + 4 + 232] == break2[i + 4 + 232]))
                    {
                        // Sanity Placeholders are the same
                        for (int j = 0; j < 4; j++)
                            if (break1[i + j] == break2[i + j])
                                err++;

                        if (err < 4)
                        {
                            // Keystream ^ PID doesn't match entirely. Keep checking.
                            for (int j = 8; j < 232; j++)
                                if (break1[i + j] == break2[i + j])
                                    err++;

                            if (err < 20)
                            {
                                // Tolerable amount of difference between offsets. We have a result.
                                offset[d] = i;
                                break;
                            }
                        }
                    }
                }
                fo = offset[d] + 232 * 30;  // Fast forward out of this box to find the next.
            }

            // Now that we have our two box offsets...
            // Check to see if we actually have them.

            if ((offset[0] == 0) || (offset[1] == 0))
            {
                // We have a problem. Don't continue.
                result = "Unable to Find Box.\n";
            }
            else
            {
                // Let's go deeper. We have the two box offsets.
                // Chunk up the base streams.
                byte[,] estream1 = new Byte[30, 232];
                byte[,] estream2 = new Byte[30, 232];
                // Stuff 'em.
                for (int i = 0; i < 30; i++)    // Times we're iterating
                {
                    for (int j = 0; j < 232; j++)   // Stuff the Data
                    {
                        estream1[i, j] = break1[offset[0] + 232 * i + j];
                        estream2[i, j] = break2[offset[1] + 232 * i + j];
                    }
                }

                // Okay, now that we have the encrypted streams, formulate our EKX.
                string nick = eggnames[1];
                // Stuff in the nickname to our blank EKX.
                byte[] nicknamebytes = Encoding.Unicode.GetBytes(nick);
                Array.Resize(ref nicknamebytes, 24);
                Array.Copy(nicknamebytes, 0, empty, 0x40, nicknamebytes.Length);

                // Encrypt the Empty PKX to EKX.
                Array.Copy(empty, emptyekx, 232);
                emptyekx = encryptArray(emptyekx);
                // Not gonna bother with the checksum, as this empty file is temporary.

                // Sweet. Now we just have to find the E0-E3 values. Let's get our polluted streams from each.
                // Save file 1 has empty box 1. Save file 2 has empty box 2.
                byte[,] pstream1 = new Byte[30, 232]; // Polluted Keystream 1
                byte[,] pstream2 = new Byte[30, 232]; // Polluted Keystream 2
                for (int i = 0; i < 30; i++)    // Times we're iterating
                {
                    for (int j = 0; j < 232; j++)   // Stuff the Data
                    {
                        pstream1[i, j] = (byte)(estream1[i, j] ^ emptyekx[j]);
                        pstream2[i, j] = (byte)(estream2[i, j] ^ emptyekx[j]);
                    }
                }

                // Cool. So we have a fairly decent keystream to roll with. We now need to find what the E0-E3 region is.
                // 0x00000000 Encryption Constant has the D block last.
                // We need to make sure our Supplied Encryption Constant Pokemon have the D block somewhere else (Pref in 1 or 3).

                // First, let's get out our polluted EKX's.
                byte[,] polekx = new Byte[6, 232];
                for (int i = 0; i < 6; i++)
                    for (int j = 0; j < 232; j++) // Save file 1 has them in the second box. XOR them out with the Box2 Polluted Stream
                        polekx[i, j] = (byte)(break1[offset[1] + 232 * i + j] ^ pstream2[i, j]);

                uint[] encryptionconstants = new uint[6]; // Array for all 6 Encryption Constants.
                int valid = 0;
                for (int i = 0; i < 6; i++)
                {
                    encryptionconstants[i] = (uint)polekx[i, 0];
                    encryptionconstants[i] += (uint)polekx[i, 1] * 0x100;
                    encryptionconstants[i] += (uint)polekx[i, 2] * 0x10000;
                    encryptionconstants[i] += (uint)polekx[i, 3] * 0x1000000;
                    // EC Obtained. Check to see if Block D is not last.
                    if (getDloc(encryptionconstants[i]) != 3)
                    {
                        valid++;
                        // Find the Origin/Region data.
                        byte[] encryptedekx = new Byte[232];
                        byte[] decryptedpkx = new Byte[232];
                        for (int z = 0; z < 232; z++)
                            encryptedekx[z] = polekx[i, z];

                        decryptedpkx = decryptArray(encryptedekx);

                        // finalize data

                        // Okay, now that we have the encrypted streams, formulate our EKX.
                        nick = eggnames[decryptedpkx[0xE3] - 1];
                        // Stuff in the nickname to our blank EKX.
                        nicknamebytes = Encoding.Unicode.GetBytes(nick);
                        Array.Resize(ref nicknamebytes, 24);
                        Array.Copy(nicknamebytes, 0, empty, 0x40, nicknamebytes.Length);

                        // Dump it into our Blank EKX. We have won!
                        empty[0xE0] = decryptedpkx[0xE0];
                        empty[0xE1] = decryptedpkx[0xE1];
                        empty[0xE2] = decryptedpkx[0xE2];
                        empty[0xE3] = decryptedpkx[0xE3];
                        break;
                    }
                }
            #endregion

                if (valid == 0) // We didn't get any valid EC's where D was not in last. Tell the user to try again with different specimens.
                    result = "The 6 supplied Pokemon are not suitable. \nRip new saves with 6 different ones that originated from your save file.\n";

                else
                {
                    #region Fix up our Empty File
                    // We can continue to get our actual keystream.
                    // Let's calculate the actual checksum of our empty pkx.
                    uint chk = 0;
                    for (int i = 8; i < 232; i += 2) // Loop through the entire PKX
                        chk += BitConverter.ToUInt16(empty, i);

                    // Apply New Checksum
                    Array.Copy(BitConverter.GetBytes(chk), 0, empty, 06, 2);

                    // Okay. So we're now fixed with the proper blank PKX. Encrypt it!
                    Array.Copy(empty, emptyekx, 232);
                    emptyekx = encryptArray(emptyekx);
                    Array.Resize(ref emptyekx, 232); // ensure it's 232 bytes.

                    // Empty EKX obtained. Time to set up our key file.
                    savkey = new Byte[0xB4AD4];
                    // Copy over 0x10-0x1F (Save Encryption Unused Data so we can track data).
                    Array.Copy(break1, 0x10, savkey, 0, 0x10);
                    // Include empty data
                    savkey[0x10] = empty[0xE0]; savkey[0x11] = empty[0xE1]; savkey[0x12] = empty[0xE2]; savkey[0x13] = empty[0xE3];
                    // Copy over the scan offsets.
                    Array.Copy(BitConverter.GetBytes(offset[0]), 0, savkey, 0x1C, 4);

                    for (int i = 0; i < 30; i++)    // Times we're iterating
                    {
                        for (int j = 0; j < 232; j++)   // Stuff the Data temporarily...
                        {
                            savkey[0x100 + i * 232 + j] = (byte)(estream1[i, j] ^ emptyekx[j]);
                            savkey[0x100 + (30 * 232) + i * 232 + j] = (byte)(estream2[i, j] ^ emptyekx[j]);
                        }
                    }
                    #endregion
                    // Let's extract some of the information now for when we set the Keystream filename.
                    #region Keystream Naming
                    byte[] data1 = new Byte[232];
                    byte[] data2 = new Byte[232];
                    for (int i = 0; i < 232; i++)
                    {
                        data1[i] = (byte)(savkey[0x100 + i] ^ break1[offset[0] + i]);
                        data2[i] = (byte)(savkey[0x100 + i] ^ break2[offset[0] + i]);
                    }
                    byte[] data1a = new Byte[232]; byte[] data2a = new Byte[232];
                    Array.Copy(data1, data1a, 232); Array.Copy(data2, data2a, 232);
                    byte[] pkx1 = decryptArray(data1);
                    byte[] pkx2 = decryptArray(data2);
                    ushort chk1 = 0;
                    ushort chk2 = 0;
                    for (int i = 8; i < 232; i += 2)
                    {
                        chk1 += BitConverter.ToUInt16(pkx1, i);
                        chk2 += BitConverter.ToUInt16(pkx2, i);
                    }
                    if (verifyCHK(pkx1) && Convert.ToBoolean(BitConverter.ToUInt16(pkx1, 8)))
                    {
                        // Save 1 has the box1 data
                        pkx = pkx1;
                        success = 1;
                    }
                    else if (verifyCHK(pkx2) && Convert.ToBoolean(BitConverter.ToUInt16(pkx2, 8)))
                    {
                        // Save 2 has the box1 data
                        pkx = pkx2;
                        success = 1;
                    }
                    else
                    {
                        // Data isn't decrypting right...
                        for (int i = 0; i < 232; i++)
                        {
                            data1a[i] ^= empty[i];
                            data2a[i] ^= empty[i];
                        }
                        pkx1 = decryptArray(data1a); pkx2 = decryptArray(data2a);
                        if (verifyCHK(pkx1) && Convert.ToBoolean(BitConverter.ToUInt16(pkx1, 8)))
                        {
                            // Save 1 has the box1 data
                            pkx = pkx1;
                            success = 1;
                        }
                        else if (verifyCHK(pkx2) && Convert.ToBoolean(BitConverter.ToUInt16(pkx2, 8)))
                        {
                            // Save 2 has the box1 data
                            pkx = pkx2;
                            success = 1;
                        }
                        else
                        {
                            // Sigh...
                        }
                    }
                    #endregion
                }
            }
            if (success == 1)
            {
                byte[] diff1 = new byte[31*30*232];
                byte[] diff2 = new byte[31*30*232];
                for(uint i = 0; i < 31*30*232; ++i)
                {
                    diff1[i] = (byte)(break1[offset[0] + i] ^ break1[offset[0] + i - 0x7F000]);
                }
                for(uint i = 0; i < 31*30*232; ++i)
                {
                    diff2[i] = (byte)(break2[offset[0] + i] ^ break2[offset[0] + i - 0x7F000]);
                }
                if (diff1.SequenceEqual(diff2))
                {
                    bool break3is1 = true;
                    for(uint i = (uint)offset[0]; i<offset[0] + 31*30*232; ++i)
                    {
                        if(!(break2[i] == break3[i]))
                        {
                            break3is1 = false;
                            break;
                        }
                    }
                    if (break3is1) save1Save = break3;
                    slotsKey = diff1;
                }
                else success = 0;
            }
            if (success == 1)
            {
                // Markup the save to know that boxes 1 & 2 are dumpable.
                savkey[0x20] = 3; // 00000011 (boxes 1 & 2)

                // Clear the keystream file...
                for (int i = 0; i < 31; i++)
                {
                    Array.Copy(zerobox, 0, savkey, 0x00100 + i * (232 * 30), 232 * 30);
                    Array.Copy(zerobox, 0, savkey, 0x40000 + i * (232 * 30), 232 * 30);
                }

                // Copy the key for the slot selector
                Array.Copy(save1Save, 0x168, savkey, 0x80000, 4);

                // Copy the key for the other save slot
                Array.Copy(slotsKey, 0, savkey, 0x80004, 232*30*31);

                // Since we don't know if the user put them in in the wrong order, let's just markup our keystream with data.
                byte[] data1 = new Byte[232];
                byte[] data2 = new Byte[232];
                for (int i = 0; i < 31; i++)
                {
                    for (int j = 0; j < 30; j++)
                    {
                        Array.Copy(break1, offset[0] + i * (232 * 30) + j * 232, data1, 0, 232);
                        Array.Copy(break2, offset[0] + i * (232 * 30) + j * 232, data2, 0, 232);
                        if (data1.SequenceEqual(data2))
                        {
                            // Just copy data1 into the key file.
                            Array.Copy(data1, 0, savkey, 0x00100 + i * (232 * 30) + j * 232, 232);
                        }
                        else
                        {
                            // Copy both datas into their keystream spots.
                            Array.Copy(data1, 0, savkey, 0x00100 + i * (232 * 30) + j * 232, 232);
                            Array.Copy(data2, 0, savkey, 0x40000 + i * (232 * 30) + j * 232, 232);
                        }
                    }
                }

                // Save file diff is done, now we're essentially done. Save the keystream.

                // Success
                result = "Keystreams were successfully bruteforced!\n\n";
                result += "Save your keystream now...";
                MessageBox.Show(result);

                // From our PKX data, fetch some details to name our key file...
                string ot = TrimFromZero(Encoding.Unicode.GetString(pkx, 0xB0, 24));
                ushort tid = BitConverter.ToUInt16(pkx, 0xC);
                ushort sid = BitConverter.ToUInt16(pkx, 0xE);
                ushort tsv = (ushort)((tid ^ sid) >> 4);
                SaveFileDialog sfd = new SaveFileDialog();
                string ID = sfd.InitialDirectory;
                sfd.InitialDirectory = Path.Combine(path_exe, "data");
                sfd.RestoreDirectory = true;
                sfd.FileName = CleanFileName(String.Format("SAV Key - {0} - ({1}.{2}) - TSV {3}.bin", ot, tid.ToString("00000"), sid.ToString("00000"), tsv.ToString("0000")));
                sfd.Filter = "Save Key|*.bin";
                if (sfd.ShowDialog() == DialogResult.OK)
                    File.WriteAllBytes(sfd.FileName, savkey);
                else
                    MessageBox.Show("Chose not to save keystream.", "Alert");

                sfd.InitialDirectory = ID; sfd.RestoreDirectory = true;
            }
            else // Failed
                MessageBox.Show(result + "Keystreams were NOT bruteforced!\n\nStart over and try again :(");
        }
Example #9
0
        // File Dumping
        // SAV
        private byte[] fetchpkx(byte[] input, byte[] keystream, int pkxoffset, int key1off, int key2off, byte[] blank)
        {
            // Auto updates the keystream when it dumps important data!
            ghost = true;
            byte[] ekx = new Byte[232];
            byte[] key1 = new Byte[232]; Array.Copy(keystream, key1off, key1, 0, 232);
            byte[] key2 = new Byte[232]; Array.Copy(keystream, key2off, key2, 0, 232);
            byte[] encrypteddata = new Byte[232]; Array.Copy(input, pkxoffset, encrypteddata, 0, 232);

            byte[] zeros = new Byte[232];
            byte[] ezeros = encryptArray(zeros); Array.Resize(ref ezeros, 0xE8);
            if (zeros.SequenceEqual(key1) && zeros.SequenceEqual(key2))
                return null;
            else if (zeros.SequenceEqual(key1))
            {
                // Key2 is confirmed to dump the data.
                ekx = xortwos(key2, encrypteddata);
                ghost = false;
            }
            else if (zeros.SequenceEqual(key2))
            {
                // Haven't dumped from this slot yet.
                if (key1.SequenceEqual(encrypteddata))
                {
                    // Slot hasn't changed.
                    return null;
                }
                else
                {
                    // Try and decrypt the data...
                    ekx = xortwos(key1, encrypteddata);
                    if (verifyCHK(decryptArray(ekx)))
                    {
                        // Data has been dumped!
                        // Fill keystream data with our log.
                        Array.Copy(encrypteddata, 0, keystream, key2off, 232);
                    }
                    else
                    {
                        // Try xoring with the empty data.
                        if (verifyCHK(decryptArray(xortwos(ekx, blank))))
                        {
                            ekx = xortwos(ekx, blank);
                            Array.Copy(xortwos(encrypteddata, blank), 0, keystream, key2off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(ekx, ezeros))))
                        {
                            ekx = xortwos(ekx, ezeros);
                            Array.Copy(xortwos(encrypteddata, ezeros), 0, keystream, key2off, 232);
                        }
                        else return null; // Not a failed decryption; we just haven't seen new data here yet.
                    }
                }
            }
            else
            {
                // We've dumped data at least once.
                if (key1.SequenceEqual(encrypteddata) || key1.SequenceEqual(xortwos(encrypteddata,blank)) || key1.SequenceEqual(xortwos(encrypteddata,ezeros)))
                {
                    // Data is back to break state, but we can still dump with the other key.
                    ekx = xortwos(key2, encrypteddata);
                    if (!verifyCHK(decryptArray(ekx)))
                    {
                        if (verifyCHK(decryptArray(xortwos(ekx, blank))))
                        {
                            ekx = xortwos(ekx, blank);
                            Array.Copy(xortwos(key2, blank), 0, keystream, key2off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(ekx, ezeros))))
                        {
                            // Key1 decrypts our data after we remove encrypted zeros.
                            // Copy Key1 to Key2, then zero out Key1.
                            ekx = xortwos(ekx, ezeros);
                            Array.Copy(xortwos(key2, ezeros), 0, keystream, key2off, 232);
                        }
                        else return null; // Decryption Error
                    }
                }
                else if (key2.SequenceEqual(encrypteddata) || key2.SequenceEqual(xortwos(encrypteddata, blank)) || key2.SequenceEqual(xortwos(encrypteddata, ezeros)))
                {
                    // Data is changed only once to a dumpable, but we can still dump with the other key.
                    ekx = xortwos(key1, encrypteddata);
                    if (!verifyCHK(decryptArray(ekx)))
                    {
                        if (verifyCHK(decryptArray(xortwos(ekx, blank))))
                        {
                            ekx = xortwos(ekx, blank);
                            Array.Copy(xortwos(key1, blank), 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(ekx, ezeros))))
                        {
                            ekx = xortwos(ekx, ezeros);
                            Array.Copy(xortwos(key1, ezeros), 0, keystream, key1off, 232);
                        }
                        else return null; // Decryption Error
                    }
                }
                else
                {
                    // Data has been observed to change twice! We can get our exact keystream now!
                    // Either Key1 or Key2 or Save is empty. Whichever one decrypts properly is the empty data.
                    // Oh boy... here we go...
                    ghost = false;
                    bool keydata1, keydata2 = false;
                    byte[] data1 = xortwos(encrypteddata, key1);
                    byte[] data2 = xortwos(encrypteddata, key2);

                    keydata1 =
                        (verifyCHK(decryptArray(data1))
                        ||
                        verifyCHK(decryptArray(xortwos(data1, ezeros)))
                        ||
                        verifyCHK(decryptArray(xortwos(data1, blank)))
                        );
                    keydata2 =
                        (verifyCHK(decryptArray(data2))
                        ||
                        verifyCHK(decryptArray(xortwos(data2, ezeros)))
                        ||
                        verifyCHK(decryptArray(xortwos(data2, blank)))
                        );
                    if (!keydata1 && !keydata2)
                        return null; // All 3 are occupied.
                    if (keydata1 && keydata2)
                    {
                        // Save file is currently empty...
                        // Copy key data from save file if it decrypts with Key1 data properly.

                        if (verifyCHK(decryptArray(data1)))
                        {
                            // No modifications necessary.
                            ekx = data1;
                            Array.Copy(encrypteddata, 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data1, ezeros))))
                        {
                            ekx = ezeros;
                            Array.Copy(xortwos(encrypteddata,ezeros), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data1, blank))))
                        {
                            ekx = ezeros;
                            Array.Copy(xortwos(encrypteddata, blank), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else return null; // unreachable
                    }
                    else if (keydata1) // Key 1 data is empty
                    {
                        if (verifyCHK(decryptArray(data1)))
                        {
                            ekx = data1;
                            Array.Copy(key1, 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data1, ezeros))))
                        {
                            ekx = xortwos(data1, ezeros);
                            Array.Copy(xortwos(key1, ezeros), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data1, blank))))
                        {
                            ekx = xortwos(data1, blank);
                            Array.Copy(xortwos(key1, blank), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else return null; // unreachable
                    }
                    else if (keydata2)
                    {
                        if (verifyCHK(decryptArray(data2)))
                        {
                            ekx = data2;
                            Array.Copy(key2, 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data2, ezeros))))
                        {
                            ekx = xortwos(data2, ezeros);
                            Array.Copy(xortwos(key2, ezeros), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else if (verifyCHK(decryptArray(xortwos(data2, blank))))
                        {
                            ekx = xortwos(data2, blank);
                            Array.Copy(xortwos(key2, blank), 0, keystream, key2off, 232);
                            Array.Copy(zeros, 0, keystream, key1off, 232);
                        }
                        else return null; // unreachable
                    }
                }
            }
            byte[] pkx = decryptArray(ekx);
            if (verifyCHK(pkx))
            {
                slots++;
                return pkx;
            }
            else
                return null; // Slot Decryption error?!
        }