Пример #1
0
        public static void PatchFunction(string path)
        {
            if (IsFileLocked(path))
            {
                Form1.SetStatus("Error: Executable is locked. Can't patch.", System.Drawing.Color.Red);
                Form1.SetProgress(100, System.Drawing.Color.Red);
                return;
            }
            CheckBackup(path);
            byte[] exe      = File.ReadAllBytes(path);
            var    patterns = new Pattern.Byte[][] { Pattern.Transform("9A 99 05 42"),
                                                     Pattern.Transform("9A 99 85 41") };
            bool isPatched = true;

            foreach (Pattern.Byte[] pb in patterns)
            {
                if (!Pattern.Find(exe, pb, out long offsetFound))
                {
                    Form1.SetStatus("Error: FPS Limit could not be found. Already patched or unsupported version.", System.Drawing.Color.Red);
                    Form1.SetProgress(100, System.Drawing.Color.Red);
                    return;
                }
                if (!PatchFile(exe, offsetFound, path))
                {
                    Form1.SetStatus("Error: Executable file could not be patched.", System.Drawing.Color.Red);
                    isPatched = false;
                    break;
                }
            }
            if (isPatched)
            {
                Form1.SetStatus("Game patched!", System.Drawing.Color.Green);
            }
        }
Пример #2
0
        private bool InitInlinedKeys(CryptoKey[] keys, MemoryStream ms)
        {
            // Key1 find routine
            var patKey1 = new Pattern.Byte[][] {
                Pattern.Transform("B8 ?? ?? 00 00 7E"),
                Pattern.Transform("BA ?? ?? 00 00 85"),
            };

            long key1Offset = -1;

            for (int keyIndex = 0; keyIndex < patKey1.Length; keyIndex++)
            {
                if (Pattern.Find(_data, patKey1[keyIndex], out key1Offset, ms.Position, ms.Position + 500))
                {
                    ms.Position = key1Offset + 1;
                    break;
                }
            }
            if (key1Offset == -1)
            {
                Console.WriteLine($"[TargetPE::InitInlinedKeys]: Unable to find key1.");
                return(false);
            }
            DWORD dword = ms.ReadStructure <DWORD>();

            keys[0] = new CryptoKey((ms.Position - 4), (ushort)dword.sValue1,
                                    (long)Calculator.OffsetToVA((ulong)(ms.Position - 4)));

            // Key2 find routine
            // TODO(Gilad): Key got inlined by multiple asm instructions...Will need to implement algorithm to
            // calculate from instructions region of what's the key value (TryGettingInlinedKey2Value()).
            keys[1] = new CryptoKey(-1, 0xFFFF, -1);

            // Key3 find routine
            var patKey2 = new Pattern.Byte[][] {
                Pattern.Transform("8D 94 02 ?? ?? 00 00 7C"),
                Pattern.Transform("B8 ?? ?? 00 00 8D"),
                Pattern.Transform("B8 ?? ?? 00 00 2B"),
            };

            long key2Offset = -1;

            for (int keyIndex = 0; keyIndex < patKey2.Length; keyIndex++)
            {
                if (Pattern.Find(_data, patKey2[keyIndex], out key2Offset, ms.Position, ms.Position + 700))
                {
                    ms.Position = key2Offset + (keyIndex == 0 ? 3 : 1);
                    break;
                }
            }
            if (key2Offset == -1)
            {
                Console.WriteLine($"[TargetPE::InitInlinedKeys]: Unable to find key2.");
                return(false);
            }
            dword   = ms.ReadStructure <DWORD>();
            keys[2] = new CryptoKey((ms.Position - 4), (ushort)dword.sValue1,
                                    (long)Calculator.OffsetToVA((ulong)(ms.Position - 4)));

            return(true);
        }
Пример #3
0
        private bool InitKeysOffsets()
        {
            CryptoPatches.Clear();

            // "N3TableBase - Can't open file(read) File Handle..."
            var  pattern = Pattern.Transform("4E 33 54 61 62 6C 65 42 61 73 65 20 2D 20 43"); // "N3TableBase - C"
            long offsetLogWrite;

            if (!Pattern.Find(_data, pattern, out offsetLogWrite))
            {
                Console.WriteLine("[TargetPE::InitKeysOffsets]: Unable to find offset.");
                return(false);
            }

            // Generate pattern for finding all references to that string
            string logWriteVA         = Calculator.OffsetToVA((ulong)offsetLogWrite).ToString("X8");
            string logWriteGenPattern = "68"; // push

            for (int i = logWriteVA.Length - 1; i >= 0; --i)
            {
                logWriteGenPattern += i % 2 == 0 ? " " + logWriteVA.Substring(i, 2) : "";
            }
            logWriteGenPattern += " E8"; // call

            Console.WriteLine($"[TargetPE::InitKeysOffsets]: Generated pattern result: {logWriteGenPattern}");
            var         patternStrRefRegion = Pattern.Transform(logWriteGenPattern);
            List <long> regionStrRefOffsets;

            if (!Pattern.FindAll(_data, patternStrRefRegion, out regionStrRefOffsets))
            {
                Console.WriteLine("[TargetPE::InitKeysOffsets]: No offsets were found.");
                return(false);
            }

            Console.WriteLine($"[TargetPE::InitKeysOffsets]: Found {regionStrRefOffsets.Count} region offsets.");

            var patDecryptRegions = new Pattern.Byte[][] {
                // push ?? <- DWORD as short
                // push ?? <- DWORD as short
                // push ?? <- DWORD as short
                Pattern.Transform("68 ?? ?? 00 00 68 ?? ?? 00 00 68 ?? ?? 00 00 ?? ?? E8"),

                //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 55 FF"),
                //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 56 FF"),
                //Pattern.Transform("FF ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 57 FF"),

                // call ?? <- ReadFile
                // push ebp|esi|edi
                // call ?? <- CloseHandle
                // xor reg,reg
                Pattern.Transform("FF ?? ?? ?? ?? ?? 55 FF"),
                Pattern.Transform("FF ?? ?? ?? ?? ?? 56 FF"),
                Pattern.Transform("FF ?? ?? ?? ?? ?? 57 FF"),
            };

            const int ENCRYPT_REGION_MIN        = 50;
            const int ENCRYPT_REGION_MAX        = 700;
            const int ESTIMATED_DES_RANGE_BYTES = 280;

            bool detectedDesEncryption = false;

            foreach (long regionStrRefOffset in regionStrRefOffsets)
            {
                long decryptRegionOffset = -1;
                bool isInlinedFunction   = false;
                for (int i = 0; i < patDecryptRegions.Length; i++)
                {
                    if (!Pattern.Find(_data, patDecryptRegions[i], out decryptRegionOffset,
                                      regionStrRefOffset + ENCRYPT_REGION_MIN, regionStrRefOffset + ENCRYPT_REGION_MAX))
                    {
                        continue;
                    }

                    // Estimate average distance by bytes, to know whether there is more code for DES encryption before XOR.
                    if (!detectedDesEncryption && (decryptRegionOffset - regionStrRefOffset) > ESTIMATED_DES_RANGE_BYTES)
                    {
                        detectedDesEncryption = true;
                    }

                    // First pattern: we know it's a function that got inlined by the compiler.
                    // +5 for ptr & +2 for xor reg,reg
                    isInlinedFunction = i != 0;
                    if (isInlinedFunction)
                    {
                        CanUpdateKey2        = false;
                        decryptRegionOffset += patDecryptRegions[i].Length + 5 + 2;
                    }

                    break;
                }

                if (decryptRegionOffset == -1)
                {
                    Console.WriteLine($"[TargetPE::InitKeysOffsets]: Unable to find decryption region offset.");
                    continue;
                }

                CryptoKey[] keys = new CryptoKey[CryptoPatch.KEYS_COUNT];

                MemoryStream ms = (MemoryStream)PE.GetStream();
                ms.Seek(decryptRegionOffset, SeekOrigin.Begin);

                if (isInlinedFunction)
                {
                    if (!InitInlinedKeys(keys, ms))
                    {
                        return(false);
                    }
                }
                else
                {
                    for (int i = CryptoPatch.KEYS_COUNT - 1; i >= 0; i--)
                    {
                        DWORD dword;
                        ms.Position++;
                        dword   = ms.ReadStructure <DWORD>();
                        keys[i] = new CryptoKey((ms.Position - 4), (ushort)dword.sValue1,
                                                (long)Calculator.OffsetToVA((ulong)(ms.Position - 4)));
                    }
                }
                long keyVA = (long)Calculator.OffsetToVA((ulong)decryptRegionOffset);
                var  patch = new CryptoPatch(decryptRegionOffset, keyVA, keys, isInlinedFunction);
                CryptoPatches.Add(patch);
            }

            // Update the container cryption type, so we know what we deal with
            CryptoPatches.CryptoType = detectedDesEncryption ? CryptoType.DES_XOR : CryptoType.XOR;

            if (CryptoPatches.Count != regionStrRefOffsets.Count)
            {
                return(false);
            }

            if (!VerifyAllMatchedKeys(CryptoPatches))
            {
                return(false);
            }

            return(true);
        }