From db4a052285a1250085332e1202df2a837429cfae Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 18 Nov 2024 01:47:01 +0500 Subject: [PATCH 01/38] Add files via upload --- Directory.Packages.props | 11 +++++ UEAESKeyFinder.sln | 62 ++++++++++++++-------------- UEAESKeyFinder/UEAESKeyFinder.csproj | 26 ++++++++---- 3 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 Directory.Packages.props diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..f5b3650 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,11 @@ + + + true + true + $(NoWarn);NU1507 + + + + + + \ No newline at end of file diff --git a/UEAESKeyFinder.sln b/UEAESKeyFinder.sln index d8365f4..5a222f1 100644 --- a/UEAESKeyFinder.sln +++ b/UEAESKeyFinder.sln @@ -1,31 +1,31 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31105.61 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UEAESKeyFinder", "UEAESKeyFinder\UEAESKeyFinder.csproj", "{A184C3B9-EDEF-4BA5-96E6-207908AC9A46}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|x64.ActiveCfg = Debug|x64 - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|x64.Build.0 = Debug|x64 - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|Any CPU.ActiveCfg = Release|x64 - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|Any CPU.Build.0 = Release|x64 - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|x64.ActiveCfg = Release|x64 - {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B55F5E37-882F-4695-B88E-49404B10CC4E} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35506.116 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UEAESKeyFinder", "UEAESKeyFinder\UEAESKeyFinder.csproj", "{A184C3B9-EDEF-4BA5-96E6-207908AC9A46}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|x64.ActiveCfg = Debug|x64 + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Debug|x64.Build.0 = Debug|x64 + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|Any CPU.ActiveCfg = Release|x64 + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|Any CPU.Build.0 = Release|x64 + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|x64.ActiveCfg = Release|x64 + {A184C3B9-EDEF-4BA5-96E6-207908AC9A46}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B55F5E37-882F-4695-B88E-49404B10CC4E} + EndGlobalSection +EndGlobal diff --git a/UEAESKeyFinder/UEAESKeyFinder.csproj b/UEAESKeyFinder/UEAESKeyFinder.csproj index d3ac3ac..3d58563 100644 --- a/UEAESKeyFinder/UEAESKeyFinder.csproj +++ b/UEAESKeyFinder/UEAESKeyFinder.csproj @@ -1,9 +1,17 @@ - - - - Exe - netcoreapp3.1 - AnyCPU;x64 - - - + + + Exe + netcoreapp8.0 + AnyCPU;x64 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file From e693b0677367539f7c0bc55eff534c248ceacb74 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 18 Nov 2024 02:21:35 +0500 Subject: [PATCH 02/38] Create SpecialForcesGroup3.md --- AESKeys/SpecialForcesGroup3.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 AESKeys/SpecialForcesGroup3.md diff --git a/AESKeys/SpecialForcesGroup3.md b/AESKeys/SpecialForcesGroup3.md new file mode 100644 index 0000000..72596e3 --- /dev/null +++ b/AESKeys/SpecialForcesGroup3.md @@ -0,0 +1,6 @@ +# AES Keys for SpecialForcesGroup3 + +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| 1.7 | 0x27DFBADBB537388ACDE27A7C5F3EBC3721AF0AE0A7602D2D7F8A16548F37D394 | From 29315dc08409329cadcdddb02ea1e01d27214736 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 18 Nov 2024 02:31:47 +0500 Subject: [PATCH 03/38] Create SpecialForcesGroup2.md --- AESKeys/SpecialForcesGroup2.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 AESKeys/SpecialForcesGroup2.md diff --git a/AESKeys/SpecialForcesGroup2.md b/AESKeys/SpecialForcesGroup2.md new file mode 100644 index 0000000..4a12286 --- /dev/null +++ b/AESKeys/SpecialForcesGroup2.md @@ -0,0 +1,6 @@ +# AES Keys for SpecialForcesGroup2 + +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| 4.21 | 0x78E155ECC391708269C2759E867B7D6C01F12B6DB51AE021A4E7B9A4F8A00000 | From 354266ff8e27713477bdf8cb79aa9a159f370774 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 7 Dec 2024 14:54:04 +0500 Subject: [PATCH 04/38] Add files via upload --- Directory.Packages.props | 4 +- UEAESKeyFinder/Program.cs | 390 ++++++++++---------- UEAESKeyFinder/Searcher.cs | 710 ++++++++++++++++++------------------- 3 files changed, 552 insertions(+), 552 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index f5b3650..a51e1cc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ $(NoWarn);NU1507 - - + + \ No newline at end of file diff --git a/UEAESKeyFinder/Program.cs b/UEAESKeyFinder/Program.cs index 5081b7b..1b7d1af 100644 --- a/UEAESKeyFinder/Program.cs +++ b/UEAESKeyFinder/Program.cs @@ -1,196 +1,196 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Threading; -using static Searcher; - -namespace UEAesKeyFinder -{ - class Program - { - [DllImport("ntdll.dll", PreserveSig = false)] - public static extern void NtSuspendProcess(IntPtr processHandle); - public static byte[] GetHex(string hex) - { - var r = new byte[hex.Length / 2]; - for (var i = 0; i < r.Length; i++) r[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); - return r; - } - static void Main(string[] args) - { - Searcher searcher = new Searcher(); - Process game = new Process(); - - Console.Write("Please select from where you want to get the AES Key\n0: Memory\n1: File\n2: Dump File\n3. LibUE4.so File\n4. APK File\nUse: "); - - char method = (char)Console.Read(); - string path; - string EngineVersion = "4.18.0"; - string saveName = ""; - switch (method) - { - case '0': - Console.Write("Enter the name or id of the process: "); - Console.Read(); - Console.Read(); - string ProcessName = Console.ReadLine(); - - bool found = false; - foreach (Process p in Process.GetProcesses()) - { - if (p.ProcessName == ProcessName || p.Id.ToString() == ProcessName) - { - Console.WriteLine($"\nFound {p.ProcessName}"); - saveName = p.ProcessName; - searcher = new Searcher(p); - found = true; - break; - } - } - if (!found) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Failed to find the process."); - Console.ReadLine(); - return; - } - EngineVersion = searcher.SearchEngineVersion(); - if (EngineVersion != "") - { - Console.WriteLine($"Engine Version: {EngineVersion}"); - } - break; - case '1': - Console.Write("Please enter the file path: "); - Console.Read(); - Console.Read(); - path = Console.ReadLine().Replace("\"", ""); - if (!File.Exists(path)) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Failed to find the dump file."); - return; - } - - saveName = path.Split("\\")[path.Split("\\").Length - 1]; - - game = new Process() { StartInfo = { FileName = path } }; - game.Start(); - Thread.Sleep(1000); - // Not required to fully load - NtSuspendProcess(game.Handle); - - searcher = new Searcher(game); - searcher.SetFilePath(path); - EngineVersion = searcher.SearchEngineVersion(); - if (EngineVersion != "") - { - Console.WriteLine($"Engine Version: {EngineVersion}"); - } - break; - case '2': - Console.Write("Please enter the file path: "); - Console.Read(); - Console.Read(); - path = Console.ReadLine().Replace("\"", ""); - if (!File.Exists(path)) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Failed to find the dump file."); - return; - } - - saveName = path.Split("\\")[path.Split("\\").Length-1]; - - searcher = new Searcher(File.ReadAllBytes(path)); - searcher.SetFilePath(path); - EngineVersion = searcher.SearchEngineVersion(); - if (EngineVersion != "") - { - Console.WriteLine($"Engine Version: {EngineVersion}"); - } - break; - case '3': - Console.Write("Please enter the file path: "); - Console.Read(); - Console.Read(); - path = Console.ReadLine().Replace("\"", ""); - - saveName = path.Split("\\")[path.Split("\\").Length - 1]; - - if (!File.Exists(path)) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Failed to find the lib."); - return; - } - - searcher = new Searcher(File.ReadAllBytes(path), true); - break; - case '4': - Console.Write("Please enter the file path: "); - Console.Read(); - Console.Read(); - path = Console.ReadLine().Replace("\"", ""); - - saveName = path.Split("\\")[path.Split("\\").Length - 1]; - - if (!File.Exists(path)) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Failed to find the apk."); - return; - } - searcher = new Searcher(File.ReadAllBytes(path), true, true); - break; - } - - Dictionary aesKeys = searcher.FindAllPattern(out long took); - - if (aesKeys.Count > 0) - { - string WriteToFile = ""; - string txt = aesKeys.Count == 1 ? $"Found {aesKeys.Count} AES Key in {took}ms\n" : $"Found {aesKeys.Count} AES Keys in {took}ms\n"; - - WriteToFile += txt; - - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("\n" + txt); - Console.ForegroundColor = ConsoleColor.White; - int EngineVersionI = 17; - if (EngineVersion != "") EngineVersionI = Convert.ToInt32(EngineVersion.Split(".")[1]); - if (EngineVersionI < 18) - { - foreach (KeyValuePair o in aesKeys) - { - txt = $"{aesKeys[o.Key]} at {o.Key}\n"; - Console.Write(txt); - WriteToFile += txt; - }; - } - else - { - foreach (KeyValuePair o in aesKeys) - { - txt = $"{aesKeys[o.Key]} ({System.Convert.ToBase64String(GetHex(aesKeys[o.Key][2..aesKeys[o.Key].Length]))}) at {o.Key}\n"; - Console.Write(txt); - WriteToFile += txt; - }; - } - - File.WriteAllText(saveName + "_aes_keys.txt", WriteToFile); - } - else - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("\nFailed to find any AES Keys."); - } - - if (method == '1') try { game.Kill(); } catch { }; - - Console.ReadLine(); - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using static Searcher; + +namespace UEAesKeyFinder +{ + class Program + { + [DllImport("ntdll.dll", PreserveSig = false)] + public static extern void NtSuspendProcess(IntPtr processHandle); + public static byte[] GetHex(string hex) + { + var r = new byte[hex.Length / 2]; + for (var i = 0; i < r.Length; i++) r[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); + return r; + } + static void Main(string[] args) + { + Searcher searcher = new Searcher(); + Process game = new Process(); + + Console.Write("Please select from where you want to get the AES Key\n0: Memory\n1: File\n2: Dump File\n3. LibUE4.so File\n4. APK File\nUse: "); + + char method = (char)Console.Read(); + string path; + string EngineVersion = "4.18.0"; + string saveName = ""; + switch (method) + { + case '0': + Console.Write("Enter the name or id of the process: "); + Console.Read(); + Console.Read(); + string ProcessName = Console.ReadLine(); + + bool found = false; + foreach (Process p in Process.GetProcesses()) + { + if (p.ProcessName == ProcessName || p.Id.ToString() == ProcessName) + { + Console.WriteLine($"\nFound {p.ProcessName}"); + saveName = p.ProcessName; + searcher = new Searcher(p); + found = true; + break; + } + } + if (!found) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to find the process."); + Console.ReadLine(); + return; + } + EngineVersion = searcher.SearchEngineVersion(); + if (EngineVersion != "") + { + Console.WriteLine($"Engine Version: {EngineVersion}"); + } + break; + case '1': + Console.Write("Please enter the file path: "); + Console.Read(); + Console.Read(); + path = Console.ReadLine().Replace("\"", ""); + if (!File.Exists(path)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to find the dump file."); + return; + } + + saveName = path.Split("\\")[path.Split("\\").Length - 1]; + + game = new Process() { StartInfo = { FileName = path } }; + game.Start(); + Thread.Sleep(1000); + // Not required to fully load + NtSuspendProcess(game.Handle); + + searcher = new Searcher(game); + searcher.SetFilePath(path); + EngineVersion = searcher.SearchEngineVersion(); + if (EngineVersion != "") + { + Console.WriteLine($"Engine Version: {EngineVersion}"); + } + break; + case '2': + Console.Write("Please enter the file path: "); + Console.Read(); + Console.Read(); + path = Console.ReadLine().Replace("\"", ""); + if (!File.Exists(path)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to find the dump file."); + return; + } + + saveName = path.Split("\\")[path.Split("\\").Length-1]; + + searcher = new Searcher(File.ReadAllBytes(path)); + searcher.SetFilePath(path); + EngineVersion = searcher.SearchEngineVersion(); + if (EngineVersion != "") + { + Console.WriteLine($"Engine Version: {EngineVersion}"); + } + break; + case '3': + Console.Write("Please enter the file path: "); + Console.Read(); + Console.Read(); + path = Console.ReadLine().Replace("\"", ""); + + saveName = path.Split("\\")[path.Split("\\").Length - 1]; + + if (!File.Exists(path)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to find the lib."); + return; + } + + searcher = new Searcher(File.ReadAllBytes(path), true); + break; + case '4': + Console.Write("Please enter the file path: "); + Console.Read(); + Console.Read(); + path = Console.ReadLine().Replace("\"", ""); + + saveName = path.Split("\\")[path.Split("\\").Length - 1]; + + if (!File.Exists(path)) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to find the apk."); + return; + } + searcher = new Searcher(File.ReadAllBytes(path), true, true); + break; + } + + Dictionary aesKeys = searcher.FindAllPattern(out long took); + + if (aesKeys.Count > 0) + { + string WriteToFile = ""; + string txt = aesKeys.Count == 1 ? $"Found {aesKeys.Count} AES Key in {took}ms\n" : $"Found {aesKeys.Count} AES Keys in {took}ms\n"; + + WriteToFile += txt; + + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("\n" + txt); + Console.ForegroundColor = ConsoleColor.White; + int EngineVersionI = 17; + if (EngineVersion != "") EngineVersionI = Convert.ToInt32(EngineVersion.Split(".")[1]); + if (EngineVersionI < 18) + { + foreach (KeyValuePair o in aesKeys) + { + txt = $"{aesKeys[o.Key]} at {o.Key}\n"; + Console.Write(txt); + WriteToFile += txt; + }; + } + else + { + foreach (KeyValuePair o in aesKeys) + { + txt = $"{aesKeys[o.Key]} ({System.Convert.ToBase64String(GetHex(aesKeys[o.Key][2..aesKeys[o.Key].Length]))}) at {o.Key}\n"; + Console.Write(txt); + WriteToFile += txt; + }; + } + + File.WriteAllText(saveName + "_aes_keys.txt", WriteToFile); + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("\nFailed to find any AES Keys."); + } + + if (method == '1') try { game.Kill(); } catch { }; + + Console.ReadLine(); + } + } } \ No newline at end of file diff --git a/UEAESKeyFinder/Searcher.cs b/UEAESKeyFinder/Searcher.cs index 8282c69..dbb2b95 100644 --- a/UEAESKeyFinder/Searcher.cs +++ b/UEAESKeyFinder/Searcher.cs @@ -1,356 +1,356 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; - -public class Searcher -{ - private const int PAGE_SIZE = 4000; - - private bool useUE4Lib = false; - - private IntPtr hProcess; - private Process Process; - private ulong AllocationBase; - private byte[] ProcessMemory; - private string FilePath; - - public Searcher() { } - - public Searcher(Process p) - { - Process = p; - hProcess = p.Handle; - AllocationBase = (ulong)p.MainModule.BaseAddress; - ProcessMemory = new byte[p.MainModule.ModuleMemorySize]; - - // To best honest idk why some regions are 0 if we read all at once ¯\_(ツ)_/¯ - for (int i = 0; i < ProcessMemory.Length; i += 2048) - { - byte[] bytes = new byte[2048]; - Win32.ReadProcessMemory(hProcess, AllocationBase + (ulong)i, bytes, 2048); - for (int ii = 0; ii < bytes.Length; ii++) - { - if (!(i + ii >= ProcessMemory.Length)) ProcessMemory[i + ii] = bytes[ii]; - else break; - }; - } - } - public Searcher(byte[] bytes) - { - AllocationBase = 0; - ProcessMemory = bytes; - } - public Searcher(byte[] bytes, bool useAndroid, bool isAPK = false) - { - if (isAPK) - { - // Find "APK Sig Block" (Opening the whole file is bad...) - int libUE4Offset = 0; - for (int i = bytes.Length - 1; i > 0; i--) - { - if ( - bytes[i] != 0x41 || - bytes[i + 1] != 0x50 || - bytes[i + 1] != 0x50 || - bytes[i + 2] != 0x4B || - bytes[i + 3] != 0x20 || - bytes[i + 4] != 0x53 || - bytes[i + 5] != 0x69 || - bytes[i + 6] != 0x67 || - bytes[i + 7] != 0x20 || - bytes[i + 8] != 0x42 || - bytes[i + 9] != 0x6C || - bytes[i + 10] != 0x6F || - bytes[i + 11] != 0x63 || - bytes[i + 12] != 0x6B - ) continue; - - libUE4Offset = i; - break; - } - - byte[] libUE4 = new byte[] { 0x6C, 0x69, 0x62, 0x2F, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x2D, 0x76, 0x38, 0x61, 0x2F, 0x6C, 0x69, 0x62, 0x55, 0x45, 0x34, 0x2E, 0x73, 0x6F }; - for (int i = libUE4Offset; i < bytes.Length - 1 - libUE4.Length - 1; i++) - { - if (bytes[i] != libUE4[0]) continue; - bool c = false; - for (int ii = 0; ii < libUE4.Length - 1; ii++) - { - if (bytes[ii + i] != libUE4[ii]) - { - c = true; - break; - }; - }; - if (c) continue; - - libUE4Offset = BitConverter.ToInt32(bytes[(i - 4)..(i)]); - } - if (libUE4Offset == 0) throw new Exception("Failed to read LibUE4.so, patterns were not found!"); - - // Read compressed/uncompressed size from the header and then skip it - int compressed = BitConverter.ToInt32(bytes[(libUE4Offset + 18)..(libUE4Offset + 22)]); - int uncompressed = BitConverter.ToInt32(bytes[(libUE4Offset + 22)..(libUE4Offset + 26)]); - libUE4Offset = libUE4Offset + 53; // Header size is hardcoded, but why would it ever change? - - MemoryStream uncompressedLibUE4 = new MemoryStream(); - DeflateStream deflated = new DeflateStream(new MemoryStream(bytes[(libUE4Offset)..(libUE4Offset + compressed)]), CompressionMode.Decompress); - deflated.CopyTo(uncompressedLibUE4); - if (uncompressedLibUE4.Length != uncompressed) throw new Exception("Failed to read LibUE4.so, decompressed size does not match the decompressed size from the header!"); - ProcessMemory = uncompressedLibUE4.ToArray(); - } - else - { - ProcessMemory = bytes; - } - - useUE4Lib = useAndroid; - } - public void SetFilePath(string path) { FilePath = path; } - public string SearchEngineVersion() - { - if (FilePath != null) return FileVersionInfo.GetVersionInfo(FilePath).FileVersion; - - // We search backwards because its mostly at the end - byte[] ProductVersion = new byte[] { 0x01, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x64, 0x00, 0x75, 0x00, 0x63, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00 }; - for (int i = ProcessMemory.Length - 1; i > 0; i--) - { - if (this.ProcessMemory[i] != ProductVersion[0]) continue; - bool c = false; - for (int ii = 0; ii < ProductVersion.Length - 1; ii++) - { - if (this.ProcessMemory[ii + i] != ProductVersion[ii]) - { - c = true; - break; - }; - }; - if (c) continue; - - UnicodeEncoding unicodeEncoding = new UnicodeEncoding(); - return new string(unicodeEncoding.GetChars(this.ProcessMemory[(i + ProductVersion.Length - 2)..(i + ProductVersion.Length - 2 + 14)], 2, 12)); - } - - return ""; - } - public int FollowJMP(int addr) - { - addr = (BitConverter.ToInt32(this.ProcessMemory[(addr + 1)..(addr + 1 + 4)].ToArray()) + 5) + addr; - if ((this.ProcessMemory[addr] == 0x0F && this.ProcessMemory[addr + 4] == 0xE9)) return FollowJMP(addr + 4); - - return addr; - } - public UInt64 DecodeADRP(int adrp) // https://chromium.googlesource.com/chromiumos/third_party/binutils/+/refs/heads/stabilize-7374.B/gold/aarch64.cc#150 - { - const int mask19 = (1 << 19) - 1; - const int mask2 = 3; - - // 21-bit imm encoded in adrp. - int imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); - // Retrieve msb of 21-bit-signed imm for sign extension. - int msbt = (imm >> 20) & 1; - // Real value is imm multipled by 4k. Value now has 33-bit information. - int value = imm << 12; - // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it - // with value. - return (UInt64)(((((int)(1) << 32) - msbt) << 33) | value); - } - public UInt64 DecodeADD(int add) - { - var imm12 = (add & 0x3ffc00) >> 10; - if ((imm12 & 0xc00000) != 0) imm12 <<= 12; - return (UInt64)imm12; - } - public int GetADRLAddress(int ADRPLoc) - { - UInt64 ADRP = DecodeADRP(BitConverter.ToInt32(this.ProcessMemory, ADRPLoc)); - UInt64 ADD = DecodeADD(BitConverter.ToInt32(this.ProcessMemory, ADRPLoc + 4)); - - return (int)((((UInt64)ADRPLoc & 0xFFFFF000) + ADRP + ADD) & 0xFFFFFFFF); - } - public Dictionary FindAllPattern(out long t) - { - Stopwatch timer = Stopwatch.StartNew(); - Dictionary offsets = new Dictionary(); - - // Android - if (useUE4Lib) - { - string aesKey = ""; - // We could (should) use a function to match the pattern but idk (lazy)... - for (int i = 0; i < ProcessMemory.Length - 10; i++) - { - // if this gets no results (or too many) for some reason we could also get the addr that calls this... - - // 01 01 40 AD 01 00 00 AD C0 03 5F D6 - - // First instruction is the adrp, then add... - - // Second instruction - if (this.ProcessMemory[i] != 0x01) continue; - if (this.ProcessMemory[i + 1] != 0x01) continue; - if (this.ProcessMemory[i + 2] != 0x40) continue; - if (this.ProcessMemory[i + 3] != 0xAD) continue; - - // Third instruction - if (this.ProcessMemory[i + 4] != 0x01) continue; - if (this.ProcessMemory[i + 5] != 0x00) continue; - if (this.ProcessMemory[i + 6] != 0x00) continue; - if (this.ProcessMemory[i + 7] != 0xAD) continue; - - // Fourth instruction - if (this.ProcessMemory[i + 8] != 0xC0) continue; - if (this.ProcessMemory[i + 9] != 0x03) continue; - if (this.ProcessMemory[i + 10] != 0x5F) continue; - if (this.ProcessMemory[i + 11] != 0xD6) continue; - - aesKey = ""; - int aesKeyAddr = GetADRLAddress(i - 8); - - aesKey += BitConverter.ToString(this.ProcessMemory[aesKeyAddr..(aesKeyAddr + 32)]).ToString().Replace("-", ""); - offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); - - aesKeyAddr += 0x1000; // Please fix this, idk when its + 0x1000 and when not.... - aesKey = BitConverter.ToString(this.ProcessMemory[aesKeyAddr..(aesKeyAddr + 32)]).ToString().Replace("-", ""); - offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); - } - } - else - { - string EngineVersionStr = SearchEngineVersion(); - int EngineVersion = 17; - if (EngineVersionStr != "") EngineVersion = Convert.ToInt32(EngineVersionStr.Split(".")[1]); - if (EngineVersion < 18) - { - // Let's just try something, not sure if that works for all games - string aesKey = ""; - - for (int i = 0; i < ProcessMemory.Length-10; i++) - { - if (ProcessMemory[i] != 0x00 || ProcessMemory[i + 1] != 0x30 || ProcessMemory[i + 2] != 0x78) continue; - - // Now we need to find where the first 00 starts and go back to that location - int start = i; - while (ProcessMemory[start-1] == 0x00) start -= 1; - - // Key is 64 letters long, lets make sure the first byte before the key is 0x00 - if (ProcessMemory[start - 65] != 0x00) continue; - - aesKey = Encoding.Default.GetString(ProcessMemory[(start - 64)..start]); - - // Lets make sure the key is as valid string - if (Regex.IsMatch(aesKey, @"^[a-zA-Z0-9]+$")) - { - offsets.Add(AllocationBase + (ulong)start-64, aesKey); - break; - } - } - } - - { - // Based on "?Callback@FEncryptionKeyRegistration@@SAXQEAE@Z" - // https://github.com/EpicGames/UnrealEngine/blob/5df54b7ef1714f28fb5da319c3e83d96f0bedf08/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h#L841 - - // Should work for all newer Fortnite versions - // C7 45 D0 ? ? ? ? C7 45 D4 ? ? ? ? C7 45 D8 ? ? ? ? C7 45 DC ? ? ? ? ? ? ? ? C7 45 E0 ? ? ? ? C7 45 E4? ? ? ? C7 45 E8 ? ? ? ? C7 45 EC ? ? ? ? - - string aesKey = ""; - int verify_1 = 0xC7; - for (int i = 0; i < ProcessMemory.Length - 10; i++) - { - try - { - // Should start with smth like 48 8D 64 24 08 and end with it - if (this.ProcessMemory[i - 3] == 0x00 && this.ProcessMemory[i - 2] == 0x00 && this.ProcessMemory[i - 1] == 0x00) continue; - if (this.ProcessMemory[i] != verify_1 || (this.ProcessMemory[i + 1] != 0x45 && this.ProcessMemory[i + 1] != 0x01)) continue; - int verify_2 = this.ProcessMemory[i + 1] == 0x01 ? 0x41 : 0x45; - int verify_3 = this.ProcessMemory[i + 1] == 0x01 ? 0 : 0xD0; - if (this.ProcessMemory[i + 1] == 0x45 && this.ProcessMemory[i + 2] != verify_3) continue; - - // It should be the first keypart - if (this.ProcessMemory[i - 7] == verify_1 && this.ProcessMemory[i - 6] == verify_2) continue; - - verify_3 += 0x04; - // Make sure this address is valid (Not following jumps yet) fuck it, lets also check the jmps - bool c = false; - int addr = i + 4 + 2 + (this.ProcessMemory[i + 1] == 0x01 ? 0 : 1); - aesKey = BitConverter.ToString(this.ProcessMemory[(addr - 4)..addr]).Replace("-", ""); // New valid start, new luck - - while (aesKey.Length != 64) - // 8 parts, we have to skip the instruction with the size of 2-3 and the key itself with the size of 4 - // older versions have a simple mov rcx, but never have mov rcx+4 - { - if (this.ProcessMemory[addr] != verify_1 && this.ProcessMemory[addr] != 0xE9) // Same for all UE4 games - { - // Sometimes one keypart has 4 useless bytes at the end, just skip it if the 3 bytes after it match the new keypart start - // JMP Right after it is possible too - if (this.ProcessMemory[addr] == 0x0F && this.ProcessMemory[addr + 4] == 0xE9) - { - addr += 4; // Skip the useless bytes - // jump to the address and check if the bytes are valid - addr = FollowJMP(addr); - if (this.ProcessMemory[addr] != verify_1 && this.ProcessMemory[addr + 1] != verify_2 && this.ProcessMemory[addr + 2] != verify_3) c = true; - } - else if (this.ProcessMemory[addr + 4] != verify_1 && this.ProcessMemory[addr + 5] != verify_2 && this.ProcessMemory[addr + 6] != verify_3) c = true; - else addr += 4; - }; - - if (this.ProcessMemory[addr] == 0xE9) addr = FollowJMP(addr); - else - { - if (this.ProcessMemory[addr + 1] != verify_2) c = true; - if ((this.ProcessMemory[addr + 2] != verify_3)) c = true; - aesKey = aesKey + BitConverter.ToString(this.ProcessMemory[(addr + 3)..(addr + 7)]).Replace("-", ""); - addr += 4 + 3; // C7 4x xx - verify_3 += 0x04; - }; - - if (aesKey.Length == 64) - { - // This is the last, we should not be able to get another keypart, if so this is not the correct AES Keys. - // if (this.ProcessMemory[addr] == verify_1 && this.ProcessMemory[addr + 1] == verify_2) c = true; - if (this.ProcessMemory[addr] == 0xE9) addr = FollowJMP(addr); - // && this.ProcessMemory[addr + 1] != 0x8D && this.ProcessMemory[addr + 1] != 0x64 && this.ProcessMemory[addr + 1] != 0x24 && this.ProcessMemory[addr + 1] != 0x08 - if (this.ProcessMemory[addr] != 0xC3 && this.ProcessMemory[addr] != 0x48) - { - // There might be movups so lets check 50 bytes if we still get 48 8D - if (this.ProcessMemory[addr] != 0x0F) c = true; - for (int xx = 0; xx < 30; xx++) - { - addr = addr + xx; - if (this.ProcessMemory[addr] == 0x48 && this.ProcessMemory[addr] == 0x8D) break; - } - // We should probably delete this... - if (this.ProcessMemory[addr] != 0x48 && this.ProcessMemory[addr] == 0x8D) c = true; - } - } - if (c) break; - } - if (c) continue; - - offsets.Add(AllocationBase + (ulong)i, $"0x{aesKey}"); - } - catch { } - } - } - } - - t = timer.ElapsedMilliseconds; - return offsets; - } - - public static class Win32 - { - [DllImport("kernel32.dll")] - public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); - - [DllImport("kernel32.dll")] - public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; + +public class Searcher +{ + private const int PAGE_SIZE = 4000; + + private bool useUE4Lib = false; + + private IntPtr hProcess; + private Process Process; + private ulong AllocationBase; + private byte[] ProcessMemory; + private string FilePath; + + public Searcher() { } + + public Searcher(Process p) + { + Process = p; + hProcess = p.Handle; + AllocationBase = (ulong)p.MainModule.BaseAddress; + ProcessMemory = new byte[p.MainModule.ModuleMemorySize]; + + // To best honest idk why some regions are 0 if we read all at once ¯\_(ツ)_/¯ + for (int i = 0; i < ProcessMemory.Length; i += 2048) + { + byte[] bytes = new byte[2048]; + Win32.ReadProcessMemory(hProcess, AllocationBase + (ulong)i, bytes, 2048); + for (int ii = 0; ii < bytes.Length; ii++) + { + if (!(i + ii >= ProcessMemory.Length)) ProcessMemory[i + ii] = bytes[ii]; + else break; + }; + } + } + public Searcher(byte[] bytes) + { + AllocationBase = 0; + ProcessMemory = bytes; + } + public Searcher(byte[] bytes, bool useAndroid, bool isAPK = false) + { + if (isAPK) + { + // Find "APK Sig Block" (Opening the whole file is bad...) + int libUE4Offset = 0; + for (int i = bytes.Length - 1; i > 0; i--) + { + if ( + bytes[i] != 0x41 || + bytes[i + 1] != 0x50 || + bytes[i + 1] != 0x50 || + bytes[i + 2] != 0x4B || + bytes[i + 3] != 0x20 || + bytes[i + 4] != 0x53 || + bytes[i + 5] != 0x69 || + bytes[i + 6] != 0x67 || + bytes[i + 7] != 0x20 || + bytes[i + 8] != 0x42 || + bytes[i + 9] != 0x6C || + bytes[i + 10] != 0x6F || + bytes[i + 11] != 0x63 || + bytes[i + 12] != 0x6B + ) continue; + + libUE4Offset = i; + break; + } + + byte[] libUE4 = new byte[] { 0x6C, 0x69, 0x62, 0x2F, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x2D, 0x76, 0x38, 0x61, 0x2F, 0x6C, 0x69, 0x62, 0x55, 0x45, 0x34, 0x2E, 0x73, 0x6F }; + for (int i = libUE4Offset; i < bytes.Length - 1 - libUE4.Length - 1; i++) + { + if (bytes[i] != libUE4[0]) continue; + bool c = false; + for (int ii = 0; ii < libUE4.Length - 1; ii++) + { + if (bytes[ii + i] != libUE4[ii]) + { + c = true; + break; + }; + }; + if (c) continue; + + libUE4Offset = BitConverter.ToInt32(bytes[(i - 4)..(i)]); + } + if (libUE4Offset == 0) throw new Exception("Failed to read LibUE4.so, patterns were not found!"); + + // Read compressed/uncompressed size from the header and then skip it + int compressed = BitConverter.ToInt32(bytes[(libUE4Offset + 18)..(libUE4Offset + 22)]); + int uncompressed = BitConverter.ToInt32(bytes[(libUE4Offset + 22)..(libUE4Offset + 26)]); + libUE4Offset = libUE4Offset + 53; // Header size is hardcoded, but why would it ever change? + + MemoryStream uncompressedLibUE4 = new MemoryStream(); + DeflateStream deflated = new DeflateStream(new MemoryStream(bytes[(libUE4Offset)..(libUE4Offset + compressed)]), CompressionMode.Decompress); + deflated.CopyTo(uncompressedLibUE4); + if (uncompressedLibUE4.Length != uncompressed) throw new Exception("Failed to read LibUE4.so, decompressed size does not match the decompressed size from the header!"); + ProcessMemory = uncompressedLibUE4.ToArray(); + } + else + { + ProcessMemory = bytes; + } + + useUE4Lib = useAndroid; + } + public void SetFilePath(string path) { FilePath = path; } + public string SearchEngineVersion() + { + if (FilePath != null) return FileVersionInfo.GetVersionInfo(FilePath).FileVersion; + + // We search backwards because its mostly at the end + byte[] ProductVersion = new byte[] { 0x01, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x64, 0x00, 0x75, 0x00, 0x63, 0x00, 0x74, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00 }; + for (int i = ProcessMemory.Length - 1; i > 0; i--) + { + if (this.ProcessMemory[i] != ProductVersion[0]) continue; + bool c = false; + for (int ii = 0; ii < ProductVersion.Length - 1; ii++) + { + if (this.ProcessMemory[ii + i] != ProductVersion[ii]) + { + c = true; + break; + }; + }; + if (c) continue; + + UnicodeEncoding unicodeEncoding = new UnicodeEncoding(); + return new string(unicodeEncoding.GetChars(this.ProcessMemory[(i + ProductVersion.Length - 2)..(i + ProductVersion.Length - 2 + 14)], 2, 12)); + } + + return ""; + } + public int FollowJMP(int addr) + { + addr = (BitConverter.ToInt32(this.ProcessMemory[(addr + 1)..(addr + 1 + 4)].ToArray()) + 5) + addr; + if ((this.ProcessMemory[addr] == 0x0F && this.ProcessMemory[addr + 4] == 0xE9)) return FollowJMP(addr + 4); + + return addr; + } + public UInt64 DecodeADRP(int adrp) // https://chromium.googlesource.com/chromiumos/third_party/binutils/+/refs/heads/stabilize-7374.B/gold/aarch64.cc#150 + { + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + + // 21-bit imm encoded in adrp. + int imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); + // Retrieve msb of 21-bit-signed imm for sign extension. + int msbt = (imm >> 20) & 1; + // Real value is imm multipled by 4k. Value now has 33-bit information. + int value = imm << 12; + // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it + // with value. + return (UInt64)(((((int)(1) << 32) - msbt) << 33) | value); + } + public UInt64 DecodeADD(int add) + { + var imm12 = (add & 0x3ffc00) >> 10; + if ((imm12 & 0xc00000) != 0) imm12 <<= 12; + return (UInt64)imm12; + } + public int GetADRLAddress(int ADRPLoc) + { + UInt64 ADRP = DecodeADRP(BitConverter.ToInt32(this.ProcessMemory, ADRPLoc)); + UInt64 ADD = DecodeADD(BitConverter.ToInt32(this.ProcessMemory, ADRPLoc + 4)); + + return (int)((((UInt64)ADRPLoc & 0xFFFFF000) + ADRP + ADD) & 0xFFFFFFFF); + } + public Dictionary FindAllPattern(out long t) + { + Stopwatch timer = Stopwatch.StartNew(); + Dictionary offsets = new Dictionary(); + + // Android + if (useUE4Lib) + { + string aesKey = ""; + // We could (should) use a function to match the pattern but idk (lazy)... + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + // if this gets no results (or too many) for some reason we could also get the addr that calls this... + + // 01 01 40 AD 01 00 00 AD C0 03 5F D6 + + // First instruction is the adrp, then add... + + // Second instruction + if (this.ProcessMemory[i] != 0x01) continue; + if (this.ProcessMemory[i + 1] != 0x01) continue; + if (this.ProcessMemory[i + 2] != 0x40) continue; + if (this.ProcessMemory[i + 3] != 0xAD) continue; + + // Third instruction + if (this.ProcessMemory[i + 4] != 0x01) continue; + if (this.ProcessMemory[i + 5] != 0x00) continue; + if (this.ProcessMemory[i + 6] != 0x00) continue; + if (this.ProcessMemory[i + 7] != 0xAD) continue; + + // Fourth instruction + if (this.ProcessMemory[i + 8] != 0xC0) continue; + if (this.ProcessMemory[i + 9] != 0x03) continue; + if (this.ProcessMemory[i + 10] != 0x5F) continue; + if (this.ProcessMemory[i + 11] != 0xD6) continue; + + aesKey = ""; + int aesKeyAddr = GetADRLAddress(i - 8); + + aesKey += BitConverter.ToString(this.ProcessMemory[aesKeyAddr..(aesKeyAddr + 32)]).ToString().Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + + aesKeyAddr += 0x1000; // Please fix this, idk when its + 0x1000 and when not.... + aesKey = BitConverter.ToString(this.ProcessMemory[aesKeyAddr..(aesKeyAddr + 32)]).ToString().Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + } + } + else + { + string EngineVersionStr = SearchEngineVersion(); + int EngineVersion = 17; + if (EngineVersionStr != "") EngineVersion = Convert.ToInt32(EngineVersionStr.Split(".")[1]); + if (EngineVersion < 18) + { + // Let's just try something, not sure if that works for all games + string aesKey = ""; + + for (int i = 0; i < ProcessMemory.Length-10; i++) + { + if (ProcessMemory[i] != 0x00 || ProcessMemory[i + 1] != 0x30 || ProcessMemory[i + 2] != 0x78) continue; + + // Now we need to find where the first 00 starts and go back to that location + int start = i; + while (ProcessMemory[start-1] == 0x00) start -= 1; + + // Key is 64 letters long, lets make sure the first byte before the key is 0x00 + if (ProcessMemory[start - 65] != 0x00) continue; + + aesKey = Encoding.Default.GetString(ProcessMemory[(start - 64)..start]); + + // Lets make sure the key is as valid string + if (Regex.IsMatch(aesKey, @"^[a-zA-Z0-9]+$")) + { + offsets.Add(AllocationBase + (ulong)start-64, aesKey); + break; + } + } + } + + { + // Based on "?Callback@FEncryptionKeyRegistration@@SAXQEAE@Z" + // https://github.com/EpicGames/UnrealEngine/blob/5df54b7ef1714f28fb5da319c3e83d96f0bedf08/Engine/Source/Runtime/Core/Public/Modules/ModuleManager.h#L841 + + // Should work for all newer Fortnite versions + // C7 45 D0 ? ? ? ? C7 45 D4 ? ? ? ? C7 45 D8 ? ? ? ? C7 45 DC ? ? ? ? ? ? ? ? C7 45 E0 ? ? ? ? C7 45 E4? ? ? ? C7 45 E8 ? ? ? ? C7 45 EC ? ? ? ? + + string aesKey = ""; + int verify_1 = 0xC7; + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + try + { + // Should start with smth like 48 8D 64 24 08 and end with it + if (this.ProcessMemory[i - 3] == 0x00 && this.ProcessMemory[i - 2] == 0x00 && this.ProcessMemory[i - 1] == 0x00) continue; + if (this.ProcessMemory[i] != verify_1 || (this.ProcessMemory[i + 1] != 0x45 && this.ProcessMemory[i + 1] != 0x01)) continue; + int verify_2 = this.ProcessMemory[i + 1] == 0x01 ? 0x41 : 0x45; + int verify_3 = this.ProcessMemory[i + 1] == 0x01 ? 0 : 0xD0; + if (this.ProcessMemory[i + 1] == 0x45 && this.ProcessMemory[i + 2] != verify_3) continue; + + // It should be the first keypart + if (this.ProcessMemory[i - 7] == verify_1 && this.ProcessMemory[i - 6] == verify_2) continue; + + verify_3 += 0x04; + // Make sure this address is valid (Not following jumps yet) fuck it, lets also check the jmps + bool c = false; + int addr = i + 4 + 2 + (this.ProcessMemory[i + 1] == 0x01 ? 0 : 1); + aesKey = BitConverter.ToString(this.ProcessMemory[(addr - 4)..addr]).Replace("-", ""); // New valid start, new luck + + while (aesKey.Length != 64) + // 8 parts, we have to skip the instruction with the size of 2-3 and the key itself with the size of 4 + // older versions have a simple mov rcx, but never have mov rcx+4 + { + if (this.ProcessMemory[addr] != verify_1 && this.ProcessMemory[addr] != 0xE9) // Same for all UE4 games + { + // Sometimes one keypart has 4 useless bytes at the end, just skip it if the 3 bytes after it match the new keypart start + // JMP Right after it is possible too + if (this.ProcessMemory[addr] == 0x0F && this.ProcessMemory[addr + 4] == 0xE9) + { + addr += 4; // Skip the useless bytes + // jump to the address and check if the bytes are valid + addr = FollowJMP(addr); + if (this.ProcessMemory[addr] != verify_1 && this.ProcessMemory[addr + 1] != verify_2 && this.ProcessMemory[addr + 2] != verify_3) c = true; + } + else if (this.ProcessMemory[addr + 4] != verify_1 && this.ProcessMemory[addr + 5] != verify_2 && this.ProcessMemory[addr + 6] != verify_3) c = true; + else addr += 4; + }; + + if (this.ProcessMemory[addr] == 0xE9) addr = FollowJMP(addr); + else + { + if (this.ProcessMemory[addr + 1] != verify_2) c = true; + if ((this.ProcessMemory[addr + 2] != verify_3)) c = true; + aesKey = aesKey + BitConverter.ToString(this.ProcessMemory[(addr + 3)..(addr + 7)]).Replace("-", ""); + addr += 4 + 3; // C7 4x xx + verify_3 += 0x04; + }; + + if (aesKey.Length == 64) + { + // This is the last, we should not be able to get another keypart, if so this is not the correct AES Keys. + // if (this.ProcessMemory[addr] == verify_1 && this.ProcessMemory[addr + 1] == verify_2) c = true; + if (this.ProcessMemory[addr] == 0xE9) addr = FollowJMP(addr); + // && this.ProcessMemory[addr + 1] != 0x8D && this.ProcessMemory[addr + 1] != 0x64 && this.ProcessMemory[addr + 1] != 0x24 && this.ProcessMemory[addr + 1] != 0x08 + if (this.ProcessMemory[addr] != 0xC3 && this.ProcessMemory[addr] != 0x48) + { + // There might be movups so lets check 50 bytes if we still get 48 8D + if (this.ProcessMemory[addr] != 0x0F) c = true; + for (int xx = 0; xx < 30; xx++) + { + addr = addr + xx; + if (this.ProcessMemory[addr] == 0x48 && this.ProcessMemory[addr] == 0x8D) break; + } + // We should probably delete this... + if (this.ProcessMemory[addr] != 0x48 && this.ProcessMemory[addr] == 0x8D) c = true; + } + } + if (c) break; + } + if (c) continue; + + offsets.Add(AllocationBase + (ulong)i, $"0x{aesKey}"); + } + catch { } + } + } + } + + t = timer.ElapsedMilliseconds; + return offsets; + } + + public static class Win32 + { + [DllImport("kernel32.dll")] + public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); + + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + } } \ No newline at end of file From 543cc19c1173e618ca678eb24f18da47e89d1ae4 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Thu, 19 Dec 2024 20:33:00 +0500 Subject: [PATCH 05/38] Update SpecialForcesGroup3.md --- AESKeys/SpecialForcesGroup3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AESKeys/SpecialForcesGroup3.md b/AESKeys/SpecialForcesGroup3.md index 72596e3..516cd51 100644 --- a/AESKeys/SpecialForcesGroup3.md +++ b/AESKeys/SpecialForcesGroup3.md @@ -3,4 +3,4 @@ ## Closed Alpha | Version | Key | | ----------------- | --------------------------------------------------------------------- | -| 1.7 | 0x27DFBADBB537388ACDE27A7C5F3EBC3721AF0AE0A7602D2D7F8A16548F37D394 | +| 1.7 | 0x77745B271BB1C86196B8549FA395CD404DBC469FB218974AFACA40C949E08A2E | From cb168127d53af9a5ee34115146976cc78ca46e5d Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Fri, 23 May 2025 17:46:17 +0500 Subject: [PATCH 06/38] Update Splitgate.md --- AESKeys/Splitgate.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AESKeys/Splitgate.md b/AESKeys/Splitgate.md index b9a7a4b..d1008ec 100644 --- a/AESKeys/Splitgate.md +++ b/AESKeys/Splitgate.md @@ -1,4 +1,7 @@ # AES Keys for Splitgate Never changed afaik -Key: 0xD73A797940208F2FB29256BE81A7CBC7B74CBF899441BB277F357F7F4577DBBB \ No newline at end of file +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| xxx | 0xD73A797940208F2FB29256BE81A7CBC7B74CBF899441BB277F357F7F4577DBBB | From 58a878af50df7287a7f796ed8775b010a2b7d727 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Fri, 23 May 2025 17:47:52 +0500 Subject: [PATCH 07/38] Update Sword Art Online - Fatal Bullet.md --- AESKeys/Sword Art Online - Fatal Bullet.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AESKeys/Sword Art Online - Fatal Bullet.md b/AESKeys/Sword Art Online - Fatal Bullet.md index 2599c4b..4b7c619 100644 --- a/AESKeys/Sword Art Online - Fatal Bullet.md +++ b/AESKeys/Sword Art Online - Fatal Bullet.md @@ -1,4 +1,7 @@ # AES Keys for Sword Art Online : Fatal Bullet Never changed afaik -Key: h67GrjX2aGMgrAQeNwf9VmCYbt50ylJFeP3rIhbxh4e9bZXnqm8sbvEjWGOi6rgs \ No newline at end of file +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| xxx | h67GrjX2aGMgrAQeNwf9VmCYbt50ylJFeP3rIhbxh4e9bZXnqm8sbvEjWGOi6rgs | From e2a814a298b2b140844d264dcc7c52b71aa2b253 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Fri, 23 May 2025 17:49:22 +0500 Subject: [PATCH 08/38] Update Valorant.md --- AESKeys/Valorant.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AESKeys/Valorant.md b/AESKeys/Valorant.md index 778eef8..698dc2a 100644 --- a/AESKeys/Valorant.md +++ b/AESKeys/Valorant.md @@ -1,4 +1,7 @@ # AES Keys for Valorant Never changed afaik -Key: 0x4BE71AF2459CF83899EC9DC2CB60E22AC4B3047E0211034BBABE9D174C069DD6 \ No newline at end of file +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| xxx | 0x4BE71AF2459CF83899EC9DC2CB60E22AC4B3047E0211034BBABE9D174C069DD6 | From fa0058ca313f77155bd838c7a5cc35f5cdcdc6fa Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Fri, 23 May 2025 17:51:24 +0500 Subject: [PATCH 09/38] Update Blade & Soul.md --- AESKeys/Blade & Soul.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AESKeys/Blade & Soul.md b/AESKeys/Blade & Soul.md index 59c7a64..cb19b05 100644 --- a/AESKeys/Blade & Soul.md +++ b/AESKeys/Blade & Soul.md @@ -1,4 +1,7 @@ # AES Keys for Blade & Soul Never changed afaik -Key: 0xD2E5F7F94E625EFE2726B5360C1039CE7CB9ABB760A94F37BB15A6DC08741656 \ No newline at end of file +## Closed Alpha +| Version | Key | +| ----------------- | --------------------------------------------------------------------- | +| xxx | 0xD2E5F7F94E625EFE2726B5360C1039CE7CB9ABB760A94F37BB15A6DC08741656 | From 6ae5a32e24fc66dc3149362289b764765a977f88 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Fri, 23 May 2025 19:07:36 +0500 Subject: [PATCH 10/38] Update SpecialForcesGroup3.md --- AESKeys/SpecialForcesGroup3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AESKeys/SpecialForcesGroup3.md b/AESKeys/SpecialForcesGroup3.md index 516cd51..6711e30 100644 --- a/AESKeys/SpecialForcesGroup3.md +++ b/AESKeys/SpecialForcesGroup3.md @@ -3,4 +3,4 @@ ## Closed Alpha | Version | Key | | ----------------- | --------------------------------------------------------------------- | -| 1.7 | 0x77745B271BB1C86196B8549FA395CD404DBC469FB218974AFACA40C949E08A2E | +| 1.8 | 0x77745B271BB1C86196B8549FA395CD404DBC469FB218974AFACA40C949E08A2E | From 44687ab149c1c94ed488db17ed56ad5f282b9419 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 06:01:41 +0500 Subject: [PATCH 11/38] Add files via upload --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a51e1cc..2b63181 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,6 +6,6 @@ - + \ No newline at end of file From eb98e893be9647b11b1fd7dd83ff21fa5db2333b Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 06:02:05 +0500 Subject: [PATCH 12/38] Add files via upload From 0373ba1de5713046fc529abfae1fa26f9195dff2 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 06:53:40 +0500 Subject: [PATCH 13/38] Create .github/workflows/build.yml --- .github/workflows/build.yml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..73e44c2 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build UEAESKeyFinder + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + + - name: Restore dependencies + run: dotnet restore UEAESKeyFinder.sln + + - name: Build + run: dotnet build UEAESKeyFinder.sln --configuration Release --no-restore + + - name: Publish (Generate EXE) + run: dotnet publish UEAESKeyFinder.sln -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o publish + + - name: Upload EXE Artifact + uses: actions/upload-artifact@v4 + with: + name: UEAESKeyFinder + path: publish/** \ No newline at end of file From 55d1239d7d912e228729a58e6c47c424fed9c2f8 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 07:18:35 +0500 Subject: [PATCH 14/38] Update build.yml --- .github/workflows/build.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73e44c2..bdeaaff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,11 +2,7 @@ name: Build UEAESKeyFinder on: push: - branches: - - main - pull_request: - branches: - - main + branches: [ main ] workflow_dispatch: jobs: @@ -30,7 +26,7 @@ jobs: run: dotnet build UEAESKeyFinder.sln --configuration Release --no-restore - name: Publish (Generate EXE) - run: dotnet publish UEAESKeyFinder.sln -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o publish + run: dotnet publish UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o publish - name: Upload EXE Artifact uses: actions/upload-artifact@v4 From 5843614bf2fdbf2ffedffd6044ca8c91d020abab Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 08:54:09 +0500 Subject: [PATCH 15/38] Update build.yml --- .github/workflows/build.yml | 50 +++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bdeaaff..78f35f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,8 @@ name: Build UEAESKeyFinder on: push: - branches: [ main ] + branches: + - main workflow_dispatch: jobs: @@ -10,26 +11,27 @@ jobs: runs-on: windows-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: | - 8.0.x - - - name: Restore dependencies - run: dotnet restore UEAESKeyFinder.sln - - - name: Build - run: dotnet build UEAESKeyFinder.sln --configuration Release --no-restore - - - name: Publish (Generate EXE) - run: dotnet publish UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o publish - - - name: Upload EXE Artifact - uses: actions/upload-artifact@v4 - with: - name: UEAESKeyFinder - path: publish/** \ No newline at end of file + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 8.0.x + + - name: Restore dependencies + run: dotnet restore UEAESKeyFinder.sln + + - name: Build Publish Binary + run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: auto-${{ github.run_number }} + name: Авто-релиз ${{ github.run_number }} + body: "Автоматически сгенерированная сборка при пуше в main" + files: ./publish/** + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 85d40dcd54fc086edb5b95da1f313bf6a1f53709 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 08:58:19 +0500 Subject: [PATCH 16/38] Update build.yml --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78f35f1..d2ceebe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,12 +26,12 @@ jobs: - name: Build Publish Binary run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish - - name: Create Release + - name: Create or Update Release uses: softprops/action-gh-release@v2 with: - tag_name: auto-${{ github.run_number }} - name: Авто-релиз ${{ github.run_number }} - body: "Автоматически сгенерированная сборка при пуше в main" + tag_name: latest + name: UEAESKeyFinder Build + body: "Automatically generated build on push to main" files: ./publish/** env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 12977e81e027a9a881895ff5d1efba0795a6346e Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:01:32 +0500 Subject: [PATCH 17/38] Potential fix for code scanning alert no. 2: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d2ceebe..74a1224 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,5 @@ +permissions: + contents: write name: Build UEAESKeyFinder on: From 63e53db89359acba438b3d97ad0535773f7db27a Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:09:31 +0500 Subject: [PATCH 18/38] Update build.yml --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74a1224..6594045 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,6 @@ jobs: with: tag_name: latest name: UEAESKeyFinder Build - body: "Automatically generated build on push to main" files: ./publish/** env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 522cc688c33a49d37185f572b0cdbfeabe947f2f Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:13:28 +0500 Subject: [PATCH 19/38] Update build.yml --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6594045..5e9ea20 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,11 +28,16 @@ jobs: - name: Build Publish Binary run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish + - name: Get DateTime + id: datetime + run: echo "NOW=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV + - name: Create or Update Release uses: softprops/action-gh-release@v2 with: tag_name: latest name: UEAESKeyFinder Build + body: "Build time: ${{ env.NOW }}" files: ./publish/** env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 87bf9d048dca0761cccd3f475b2fe04dc2210bae Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:18:16 +0500 Subject: [PATCH 20/38] Update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e9ea20..6919096 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,14 +30,14 @@ jobs: - name: Get DateTime id: datetime - run: echo "NOW=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV + run: echo "now=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT - name: Create or Update Release uses: softprops/action-gh-release@v2 with: tag_name: latest name: UEAESKeyFinder Build - body: "Build time: ${{ env.NOW }}" + body: "Build time: ${{ steps.datetime.outputs.now }}" files: ./publish/** env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 14a8b226ddc4e50e356c9dffd33b972e9999b53a Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:23:34 +0500 Subject: [PATCH 21/38] Update build.yml --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6919096..95f064d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,14 +30,15 @@ jobs: - name: Get DateTime id: datetime - run: echo "now=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT + shell: bash + run: echo "now=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV - name: Create or Update Release uses: softprops/action-gh-release@v2 with: tag_name: latest name: UEAESKeyFinder Build - body: "Build time: ${{ steps.datetime.outputs.now }}" + body: "Build time: ${{ env.now }}" files: ./publish/** env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From cb8f2a90bcfda4179310e0bbb616f3cb233fe3bb Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:27:36 +0500 Subject: [PATCH 22/38] Update build.yml --- .github/workflows/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 95f064d..1a1b01a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,8 @@ on: jobs: build: runs-on: windows-latest + env: + TZ: Asia/Tashkent # Устанавливаем часовой пояс Узбекистана steps: - name: Checkout @@ -28,16 +30,16 @@ jobs: - name: Build Publish Binary run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish - - name: Get DateTime + - name: Get DateTime Tashkent id: datetime shell: bash - run: echo "now=$(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV + run: echo "now=$(TZ='Asia/Tashkent' date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV - name: Create or Update Release uses: softprops/action-gh-release@v2 with: tag_name: latest - name: UEAESKeyFinder Build + name: "UEAESKeyFinder Build (${{ env.now }})" body: "Build time: ${{ env.now }}" files: ./publish/** env: From e31f92142480de388e286ce8f91a5868570f4bb4 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 09:32:05 +0500 Subject: [PATCH 23/38] Update build.yml --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a1b01a..03e977d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,8 +11,6 @@ on: jobs: build: runs-on: windows-latest - env: - TZ: Asia/Tashkent # Устанавливаем часовой пояс Узбекистана steps: - name: Checkout @@ -30,10 +28,10 @@ jobs: - name: Build Publish Binary run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish - - name: Get DateTime Tashkent + - name: Get DateTime Tashkent/Uzbekistan id: datetime shell: bash - run: echo "now=$(TZ='Asia/Tashkent' date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV + run: echo "now=$(date -u -d '+5 hour' '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV - name: Create or Update Release uses: softprops/action-gh-release@v2 From ff7ae179576b4e3fa4c6be0b5b7b2a071c81bae6 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 23 Aug 2025 20:25:18 +0500 Subject: [PATCH 24/38] Update ReadMe.md --- ReadMe.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 288bfcf..f52aa06 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -25,4 +25,16 @@ Found MyProject Found 1 AES Keys in 720ms 0xD0DE16965D23CC8A46178FFFAB18130651D2C99F7B3D63ECC8FD04D691609572 (0N4Wll0jzIpGF4//qxgTBlHSyZ97PWPsyP0E1pFglXI=) at 140695177160459 -``` \ No newline at end of file + +``` + + From a682cc156994d26f20f8572a28c535d397e54a01 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 25 Aug 2025 15:08:02 +0500 Subject: [PATCH 25/38] Create linux.yml --- .github/workflows/linux.yml | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/linux.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..b490095 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,69 @@ +permissions: + contents: write +name: Build UEAESKeyFinder .deb + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build-deb: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore UEAESKeyFinder.sln + + - name: Build Linux Binary + run: | + dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj \ + -c Release \ + -r linux-x64 \ + --self-contained true \ + -p:PublishSingleFile=true \ + -p:IncludeAllContentForSelfExtract=true \ + -p:PublishTrimmed=false \ + -o ./publish/linux + + - name: Prepare .deb package structure + run: | + mkdir -p ueaeskeyfinder_1.0.0/DEBIAN + mkdir -p ueaeskeyfinder_1.0.0/usr/local/bin + cp publish/linux/UEAESKeyFinder ueaeskeyfinder_1.0.0/usr/local/bin/ueaeskeyfinder + + echo "Package: ueaeskeyfinder + Version: 1.0.0 + Section: utils + Priority: optional + Architecture: amd64 + Maintainer: Your Name + Description: UEAESKeyFinder Linux version + A tool to find UE AES Keys." > ueaeskeyfinder_1.0.0/DEBIAN/control + + - name: Build .deb package + run: dpkg-deb --build ueaeskeyfinder_1.0.0 + + - name: Get DateTime Tashkent/Uzbekistan + id: datetime + shell: bash + run: echo "now=$(date -u -d '+5 hour' '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV + + - name: Create or Update Release + uses: softprops/action-gh-release@v2 + with: + tag_name: latest + name: "UEAESKeyFinder Linux .deb Build (${{ env.now }})" + body: "Build time: ${{ env.now }}" + files: ueaeskeyfinder_1.0.0.deb + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From ed8c2b9b9250f3ee8adb6d28a3792e910fe1ccc5 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 25 Aug 2025 15:12:37 +0500 Subject: [PATCH 26/38] Update linux.yml --- .github/workflows/linux.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index b490095..e15b527 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -37,21 +37,21 @@ jobs: - name: Prepare .deb package structure run: | - mkdir -p ueaeskeyfinder_1.0.0/DEBIAN - mkdir -p ueaeskeyfinder_1.0.0/usr/local/bin - cp publish/linux/UEAESKeyFinder ueaeskeyfinder_1.0.0/usr/local/bin/ueaeskeyfinder + mkdir -p ueaeskeyfinder/DEBIAN + mkdir -p ueaeskeyfinder/usr/local/bin + cp publish/linux/UEAESKeyFinder ueaeskeyfinder/usr/local/bin/ueaeskeyfinder echo "Package: ueaeskeyfinder - Version: 1.0.0 + Version: 1.0 Section: utils Priority: optional Architecture: amd64 Maintainer: Your Name Description: UEAESKeyFinder Linux version - A tool to find UE AES Keys." > ueaeskeyfinder_1.0.0/DEBIAN/control + A tool to find UE AES Keys." > ueaeskeyfinder/DEBIAN/control - name: Build .deb package - run: dpkg-deb --build ueaeskeyfinder_1.0.0 + run: dpkg-deb --build ueaeskeyfinder ueaeskeyfinder.deb - name: Get DateTime Tashkent/Uzbekistan id: datetime @@ -64,6 +64,6 @@ jobs: tag_name: latest name: "UEAESKeyFinder Linux .deb Build (${{ env.now }})" body: "Build time: ${{ env.now }}" - files: ueaeskeyfinder_1.0.0.deb + files: ueaeskeyfinder.deb env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From b5b46d9649ba94252e3c0978ab78675ed0822411 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 25 Aug 2025 16:09:03 +0500 Subject: [PATCH 27/38] Delete .github/workflows/linux.yml --- .github/workflows/linux.yml | 69 ------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 .github/workflows/linux.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index e15b527..0000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,69 +0,0 @@ -permissions: - contents: write -name: Build UEAESKeyFinder .deb - -on: - push: - branches: - - main - workflow_dispatch: - -jobs: - build-deb: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.x - - - name: Restore dependencies - run: dotnet restore UEAESKeyFinder.sln - - - name: Build Linux Binary - run: | - dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj \ - -c Release \ - -r linux-x64 \ - --self-contained true \ - -p:PublishSingleFile=true \ - -p:IncludeAllContentForSelfExtract=true \ - -p:PublishTrimmed=false \ - -o ./publish/linux - - - name: Prepare .deb package structure - run: | - mkdir -p ueaeskeyfinder/DEBIAN - mkdir -p ueaeskeyfinder/usr/local/bin - cp publish/linux/UEAESKeyFinder ueaeskeyfinder/usr/local/bin/ueaeskeyfinder - - echo "Package: ueaeskeyfinder - Version: 1.0 - Section: utils - Priority: optional - Architecture: amd64 - Maintainer: Your Name - Description: UEAESKeyFinder Linux version - A tool to find UE AES Keys." > ueaeskeyfinder/DEBIAN/control - - - name: Build .deb package - run: dpkg-deb --build ueaeskeyfinder ueaeskeyfinder.deb - - - name: Get DateTime Tashkent/Uzbekistan - id: datetime - shell: bash - run: echo "now=$(date -u -d '+5 hour' '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV - - - name: Create or Update Release - uses: softprops/action-gh-release@v2 - with: - tag_name: latest - name: "UEAESKeyFinder Linux .deb Build (${{ env.now }})" - body: "Build time: ${{ env.now }}" - files: ueaeskeyfinder.deb - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From fc78857f8140451a5ca2cd5e72639d32fb76f3d6 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:01:37 +0500 Subject: [PATCH 28/38] Update Searcher.cs --- UEAESKeyFinder/Searcher.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UEAESKeyFinder/Searcher.cs b/UEAESKeyFinder/Searcher.cs index dbb2b95..299491e 100644 --- a/UEAESKeyFinder/Searcher.cs +++ b/UEAESKeyFinder/Searcher.cs @@ -1,3 +1,4 @@ +/** using System; using System.Collections.Generic; using System.Diagnostics; @@ -353,4 +354,4 @@ public static class Win32 [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); } -} \ No newline at end of file +}*/ \ No newline at end of file From 15ffaafa4626fd02270c8bf4a8caf2d57d5bbd90 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:02:18 +0500 Subject: [PATCH 29/38] Update Searcher.cs --- UEAESKeyFinder/Searcher.cs | 398 ++++++++++++++++++++++++++++++++++++- 1 file changed, 397 insertions(+), 1 deletion(-) diff --git a/UEAESKeyFinder/Searcher.cs b/UEAESKeyFinder/Searcher.cs index 299491e..dc5d976 100644 --- a/UEAESKeyFinder/Searcher.cs +++ b/UEAESKeyFinder/Searcher.cs @@ -354,4 +354,400 @@ public static class Win32 [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); } -}*/ \ No newline at end of file +}*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Text.RegularExpressions; +using System.Runtime.InteropServices; + +public class Searcher +{ + private const int PAGE_SIZE = 4000; + + private bool useUE4Lib = false; + + private IntPtr hProcess; + private Process Process; + private ulong AllocationBase; + private byte[] ProcessMemory; + private string FilePath; + + public Searcher() { } + + public Searcher(Process p) + { + Process = p; + hProcess = p.Handle; + AllocationBase = (ulong)p.MainModule.BaseAddress; + ProcessMemory = new byte[p.MainModule.ModuleMemorySize]; + + // Читаем память кусками по 2048 байт (могут быть пустые регионы, поэтому по частям) + for (int i = 0; i < ProcessMemory.Length; i += 2048) + { + int bytesToRead = Math.Min(2048, ProcessMemory.Length - i); + byte[] bytes = new byte[bytesToRead]; + if (Win32.ReadProcessMemory(hProcess, AllocationBase + (ulong)i, bytes, bytesToRead)) + { + Array.Copy(bytes, 0, ProcessMemory, i, bytesToRead); + } + else + { + // Если чтение не удалось — просто продолжаем, можно логировать при необходимости + } + } + } + + public Searcher(byte[] bytes) + { + AllocationBase = 0; + ProcessMemory = bytes; + } + + public Searcher(byte[] bytes, bool useAndroid, bool isAPK = false) + { + if (isAPK) + { + // Поиск "APK Sig Block" (ищем подпись APK) + int libUE4Offset = 0; + byte[] apkSigBlock = Encoding.ASCII.GetBytes("APK Sig Block"); + + for (int i = bytes.Length - apkSigBlock.Length - 1; i >= 0; i--) + { + bool matched = true; + for (int j = 0; j < apkSigBlock.Length; j++) + { + if (bytes[i + j] != apkSigBlock[j]) + { + matched = false; + break; + } + } + if (matched) + { + libUE4Offset = i; + break; + } + } + + if (libUE4Offset == 0) + throw new Exception("Failed to read LibUE4.so, APK Sig Block not found!"); + + // Поиск оффсета libUE4.so в блоке + byte[] libUE4 = Encoding.ASCII.GetBytes("lib/arm64-v8a/libUE4.so"); + + int foundOffset = 0; + for (int i = libUE4Offset; i < bytes.Length - libUE4.Length - 4; i++) + { + if (bytes[i] != libUE4[0]) continue; + bool c = false; + for (int ii = 0; ii < libUE4.Length; ii++) + { + if (bytes[i + ii] != libUE4[ii]) + { + c = true; + break; + } + } + if (c) continue; + + // Считаем offset 4 байта перед этим местом (int32 little-endian) + foundOffset = BitConverter.ToInt32(bytes, i - 4); + break; + } + + if (foundOffset == 0) + throw new Exception("Failed to read LibUE4.so, pattern not found!"); + + int compressed = BitConverter.ToInt32(bytes, foundOffset + 18); + int uncompressed = BitConverter.ToInt32(bytes, foundOffset + 22); + int headerSize = 53; + int dataStart = foundOffset + headerSize; + + using (var compressedStream = new MemoryStream(bytes, dataStart, compressed)) + using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) + using (var uncompressedLibUE4 = new MemoryStream()) + { + deflateStream.CopyTo(uncompressedLibUE4); + if (uncompressedLibUE4.Length != uncompressed) + throw new Exception("Failed to decompress LibUE4.so, size mismatch!"); + + ProcessMemory = uncompressedLibUE4.ToArray(); + } + } + else + { + ProcessMemory = bytes; + } + + useUE4Lib = useAndroid; + } + + public void SetFilePath(string path) => FilePath = path; + + public string SearchEngineVersion() + { + if (FilePath != null) + return FileVersionInfo.GetVersionInfo(FilePath).FileVersion; + + // Паттерн ProductVersion в юникоде (бэкап) + byte[] ProductVersion = new byte[] + { + 0x01, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, + 0x64, 0x00, 0x75, 0x00, 0x63, 0x00, 0x74, 0x00, + 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, + 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00 + }; + + for (int i = ProcessMemory.Length - ProductVersion.Length - 1; i >= 0; i--) + { + bool matched = true; + for (int j = 0; j < ProductVersion.Length; j++) + { + if (ProcessMemory[i + j] != ProductVersion[j]) + { + matched = false; + break; + } + } + if (!matched) continue; + + var unicodeEncoding = new UnicodeEncoding(); + return unicodeEncoding.GetString(ProcessMemory, i + ProductVersion.Length - 2, 12); // 6 символов юникода (12 байт) + } + + return ""; + } + + public int FollowJMP(int addr) + { + int offset = BitConverter.ToInt32(ProcessMemory, addr + 1); + int newAddr = addr + offset + 5; + if (ProcessMemory[newAddr] == 0x0F && ProcessMemory[newAddr + 4] == 0xE9) + return FollowJMP(newAddr + 4); + return newAddr; + } + + public ulong DecodeADRP(int adrp) + { + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + + int imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); + int msbt = (imm >> 20) & 1; + int value = imm << 12; + + // Поддержка знакового расширения для 64-битного значения + long signedValue = (long)value; + if (msbt == 1) + signedValue |= -1L << 33; + + return (ulong)signedValue; + } + + public ulong DecodeADD(int add) + { + var imm12 = (add & 0x3ffc00) >> 10; + if ((imm12 & 0xc00000) != 0) + imm12 <<= 12; + return (ulong)imm12; + } + + public int GetADRLAddress(int ADRPLoc) + { + ulong ADRP = DecodeADRP(BitConverter.ToInt32(ProcessMemory, ADRPLoc)); + ulong ADD = DecodeADD(BitConverter.ToInt32(ProcessMemory, ADRPLoc + 4)); + + return (int)((((ulong)ADRPLoc & 0xFFFFF000) + ADRP + ADD) & 0xFFFFFFFF); + } + + public Dictionary FindAllPattern(out long elapsedMilliseconds) + { + Stopwatch timer = Stopwatch.StartNew(); + var offsets = new Dictionary(); + + if (useUE4Lib) + { + // Android UE4 key search pattern + for (int i = 0; i < ProcessMemory.Length - 12; i++) + { + if (ProcessMemory[i] != 0x01) continue; + if (ProcessMemory[i + 1] != 0x01) continue; + if (ProcessMemory[i + 2] != 0x40) continue; + if (ProcessMemory[i + 3] != 0xAD) continue; + if (ProcessMemory[i + 4] != 0x01) continue; + if (ProcessMemory[i + 5] != 0x00) continue; + if (ProcessMemory[i + 6] != 0x00) continue; + if (ProcessMemory[i + 7] != 0xAD) continue; + if (ProcessMemory[i + 8] != 0xC0) continue; + if (ProcessMemory[i + 9] != 0x03) continue; + if (ProcessMemory[i + 10] != 0x5F) continue; + if (ProcessMemory[i + 11] != 0xD6) continue; + + int aesKeyAddr = GetADRLAddress(i - 8); + if (aesKeyAddr < 0 || aesKeyAddr + 32 > ProcessMemory.Length) continue; + + string aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + + aesKeyAddr += 0x1000; // Необходимо проверить корректность смещения +0x1000 для разных игр + if (aesKeyAddr + 32 > ProcessMemory.Length) continue; + + aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + } + } + else + { + string EngineVersionStr = SearchEngineVersion(); + int EngineVersion = 17; + if (!string.IsNullOrEmpty(EngineVersionStr)) + { + string[] parts = EngineVersionStr.Split('.'); + if (parts.Length > 1 && int.TryParse(parts[1], out int ver)) + EngineVersion = ver; + } + + if (EngineVersion < 18) + { + // Старый способ поиска ключа + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + if (ProcessMemory[i] != 0x00 || ProcessMemory[i + 1] != 0x30 || ProcessMemory[i + 2] != 0x78) continue; + + int start = i; + while (start > 0 && ProcessMemory[start - 1] == 0x00) + start--; + + if (start - 65 < 0 || ProcessMemory[start - 65] != 0x00) continue; + + string aesKey = Encoding.Default.GetString(ProcessMemory, start - 64, 64); + + if (Regex.IsMatch(aesKey, @"^[a-zA-Z0-9]+$")) + { + offsets.Add(AllocationBase + (ulong)(start - 64), aesKey); + break; + } + } + } + + // Новый способ поиска ключа (например, для Fortnite и новых версий UE4) + int verify_1 = 0xC7; + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + try + { + if (i < 3) continue; + + if (ProcessMemory[i - 3] == 0x00 && ProcessMemory[i - 2] == 0x00 && ProcessMemory[i - 1] == 0x00) + continue; + + if (ProcessMemory[i] != verify_1 || (ProcessMemory[i + 1] != 0x45 && ProcessMemory[i + 1] != 0x01)) + continue; + + int verify_2 = ProcessMemory[i + 1] == 0x01 ? 0x41 : 0x45; + int verify_3 = ProcessMemory[i + 1] == 0x01 ? 0 : 0xD0; + + if (ProcessMemory[i + 1] == 0x45 && ProcessMemory[i + 2] != verify_3) + continue; + + if (ProcessMemory[i - 7] == verify_1 && ProcessMemory[i - 6] == verify_2) + continue; + + verify_3 += 0x04; + bool invalid = false; + int addr = i + 4 + 2 + (ProcessMemory[i + 1] == 0x01 ? 0 : 1); + string aesKey = BitConverter.ToString(ProcessMemory, addr - 4, 4).Replace("-", ""); + + while (aesKey.Length != 64) + { + if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr] != 0xE9) + { + if (ProcessMemory[addr] == 0x0F && ProcessMemory[addr + 4] == 0xE9) + { + addr += 4; + addr = FollowJMP(addr); + if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr + 1] != verify_2 && ProcessMemory[addr + 2] != verify_3) + invalid = true; + } + else if (ProcessMemory[addr + 4] != verify_1 && ProcessMemory[addr + 5] != verify_2 && ProcessMemory[addr + 6] != verify_3) + { + invalid = true; + } + else + { + addr += 4; + } + } + + if (ProcessMemory[addr] == 0xE9) + addr = FollowJMP(addr); + else + { + if (ProcessMemory[addr + 1] != verify_2 || ProcessMemory[addr + 2] != verify_3) + invalid = true; + + aesKey += BitConverter.ToString(ProcessMemory, addr + 3, 4).Replace("-", ""); + addr += 7; // 4 + 3 + verify_3 += 0x04; + } + + if (aesKey.Length == 64) + { + if (ProcessMemory[addr] == 0xE9) + addr = FollowJMP(addr); + + if (ProcessMemory[addr] != 0xC3 && ProcessMemory[addr] != 0x48) + { + if (ProcessMemory[addr] != 0x0F) + invalid = true; + + bool found = false; + for (int xx = 0; xx < 30; xx++) + { + int checkAddr = addr + xx; + if (checkAddr >= ProcessMemory.Length) break; + if (ProcessMemory[checkAddr] == 0x48 && ProcessMemory[checkAddr + 1] == 0x8D) + { + found = true; + break; + } + } + if (!found) + invalid = true; + } + } + + if (invalid) + break; + } + + if (invalid) continue; + + offsets.Add(AllocationBase + (ulong)i, $"0x{aesKey}"); + } + catch + { + // Игнорируем ошибки парсинга + } + } + } + + timer.Stop(); + elapsedMilliseconds = timer.ElapsedMilliseconds; + return offsets; + } + + public static class Win32 + { + [DllImport("kernel32.dll")] + public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); + + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + } +} \ No newline at end of file From 90b7ad7a1ac93d1d68600bccb47f8c50629f24c3 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:14:22 +0500 Subject: [PATCH 30/38] Update Searcher.cs --- UEAESKeyFinder/Searcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UEAESKeyFinder/Searcher.cs b/UEAESKeyFinder/Searcher.cs index dc5d976..d918e4c 100644 --- a/UEAESKeyFinder/Searcher.cs +++ b/UEAESKeyFinder/Searcher.cs @@ -744,8 +744,8 @@ public Dictionary FindAllPattern(out long elapsedMilliseconds) public static class Win32 { - [DllImport("kernel32.dll")] - public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); + [DllImport("kernel32.dll", SetLastError = true)] +public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); From b37d84e85f12d89f56a29c8bb446eb58ad5468de Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:19:29 +0500 Subject: [PATCH 31/38] Refactor Searcher class and update ReadProcessMemory --- UEAESKeyFinder/Searcher.cs | 797 +++++++++++++++++++------------------ 1 file changed, 399 insertions(+), 398 deletions(-) diff --git a/UEAESKeyFinder/Searcher.cs b/UEAESKeyFinder/Searcher.cs index d918e4c..eee5de0 100644 --- a/UEAESKeyFinder/Searcher.cs +++ b/UEAESKeyFinder/Searcher.cs @@ -1,4 +1,4 @@ -/** +/** using System; using System.Collections.Generic; using System.Diagnostics; @@ -354,400 +354,401 @@ public static class Win32 [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); } -}*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Text; -using System.Text.RegularExpressions; -using System.Runtime.InteropServices; - -public class Searcher -{ - private const int PAGE_SIZE = 4000; - - private bool useUE4Lib = false; - - private IntPtr hProcess; - private Process Process; - private ulong AllocationBase; - private byte[] ProcessMemory; - private string FilePath; - - public Searcher() { } - - public Searcher(Process p) - { - Process = p; - hProcess = p.Handle; - AllocationBase = (ulong)p.MainModule.BaseAddress; - ProcessMemory = new byte[p.MainModule.ModuleMemorySize]; - - // Читаем память кусками по 2048 байт (могут быть пустые регионы, поэтому по частям) - for (int i = 0; i < ProcessMemory.Length; i += 2048) - { - int bytesToRead = Math.Min(2048, ProcessMemory.Length - i); - byte[] bytes = new byte[bytesToRead]; - if (Win32.ReadProcessMemory(hProcess, AllocationBase + (ulong)i, bytes, bytesToRead)) - { - Array.Copy(bytes, 0, ProcessMemory, i, bytesToRead); - } - else - { - // Если чтение не удалось — просто продолжаем, можно логировать при необходимости - } - } - } - - public Searcher(byte[] bytes) - { - AllocationBase = 0; - ProcessMemory = bytes; - } - - public Searcher(byte[] bytes, bool useAndroid, bool isAPK = false) - { - if (isAPK) - { - // Поиск "APK Sig Block" (ищем подпись APK) - int libUE4Offset = 0; - byte[] apkSigBlock = Encoding.ASCII.GetBytes("APK Sig Block"); - - for (int i = bytes.Length - apkSigBlock.Length - 1; i >= 0; i--) - { - bool matched = true; - for (int j = 0; j < apkSigBlock.Length; j++) - { - if (bytes[i + j] != apkSigBlock[j]) - { - matched = false; - break; - } - } - if (matched) - { - libUE4Offset = i; - break; - } - } - - if (libUE4Offset == 0) - throw new Exception("Failed to read LibUE4.so, APK Sig Block not found!"); - - // Поиск оффсета libUE4.so в блоке - byte[] libUE4 = Encoding.ASCII.GetBytes("lib/arm64-v8a/libUE4.so"); - - int foundOffset = 0; - for (int i = libUE4Offset; i < bytes.Length - libUE4.Length - 4; i++) - { - if (bytes[i] != libUE4[0]) continue; - bool c = false; - for (int ii = 0; ii < libUE4.Length; ii++) - { - if (bytes[i + ii] != libUE4[ii]) - { - c = true; - break; - } - } - if (c) continue; - - // Считаем offset 4 байта перед этим местом (int32 little-endian) - foundOffset = BitConverter.ToInt32(bytes, i - 4); - break; - } - - if (foundOffset == 0) - throw new Exception("Failed to read LibUE4.so, pattern not found!"); - - int compressed = BitConverter.ToInt32(bytes, foundOffset + 18); - int uncompressed = BitConverter.ToInt32(bytes, foundOffset + 22); - int headerSize = 53; - int dataStart = foundOffset + headerSize; - - using (var compressedStream = new MemoryStream(bytes, dataStart, compressed)) - using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) - using (var uncompressedLibUE4 = new MemoryStream()) - { - deflateStream.CopyTo(uncompressedLibUE4); - if (uncompressedLibUE4.Length != uncompressed) - throw new Exception("Failed to decompress LibUE4.so, size mismatch!"); - - ProcessMemory = uncompressedLibUE4.ToArray(); - } - } - else - { - ProcessMemory = bytes; - } - - useUE4Lib = useAndroid; - } - - public void SetFilePath(string path) => FilePath = path; - - public string SearchEngineVersion() - { - if (FilePath != null) - return FileVersionInfo.GetVersionInfo(FilePath).FileVersion; - - // Паттерн ProductVersion в юникоде (бэкап) - byte[] ProductVersion = new byte[] - { - 0x01, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, - 0x64, 0x00, 0x75, 0x00, 0x63, 0x00, 0x74, 0x00, - 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, - 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00 - }; - - for (int i = ProcessMemory.Length - ProductVersion.Length - 1; i >= 0; i--) - { - bool matched = true; - for (int j = 0; j < ProductVersion.Length; j++) - { - if (ProcessMemory[i + j] != ProductVersion[j]) - { - matched = false; - break; - } - } - if (!matched) continue; - - var unicodeEncoding = new UnicodeEncoding(); - return unicodeEncoding.GetString(ProcessMemory, i + ProductVersion.Length - 2, 12); // 6 символов юникода (12 байт) - } - - return ""; - } - - public int FollowJMP(int addr) - { - int offset = BitConverter.ToInt32(ProcessMemory, addr + 1); - int newAddr = addr + offset + 5; - if (ProcessMemory[newAddr] == 0x0F && ProcessMemory[newAddr + 4] == 0xE9) - return FollowJMP(newAddr + 4); - return newAddr; - } - - public ulong DecodeADRP(int adrp) - { - const int mask19 = (1 << 19) - 1; - const int mask2 = 3; - - int imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); - int msbt = (imm >> 20) & 1; - int value = imm << 12; - - // Поддержка знакового расширения для 64-битного значения - long signedValue = (long)value; - if (msbt == 1) - signedValue |= -1L << 33; - - return (ulong)signedValue; - } - - public ulong DecodeADD(int add) - { - var imm12 = (add & 0x3ffc00) >> 10; - if ((imm12 & 0xc00000) != 0) - imm12 <<= 12; - return (ulong)imm12; - } - - public int GetADRLAddress(int ADRPLoc) - { - ulong ADRP = DecodeADRP(BitConverter.ToInt32(ProcessMemory, ADRPLoc)); - ulong ADD = DecodeADD(BitConverter.ToInt32(ProcessMemory, ADRPLoc + 4)); - - return (int)((((ulong)ADRPLoc & 0xFFFFF000) + ADRP + ADD) & 0xFFFFFFFF); - } - - public Dictionary FindAllPattern(out long elapsedMilliseconds) - { - Stopwatch timer = Stopwatch.StartNew(); - var offsets = new Dictionary(); - - if (useUE4Lib) - { - // Android UE4 key search pattern - for (int i = 0; i < ProcessMemory.Length - 12; i++) - { - if (ProcessMemory[i] != 0x01) continue; - if (ProcessMemory[i + 1] != 0x01) continue; - if (ProcessMemory[i + 2] != 0x40) continue; - if (ProcessMemory[i + 3] != 0xAD) continue; - if (ProcessMemory[i + 4] != 0x01) continue; - if (ProcessMemory[i + 5] != 0x00) continue; - if (ProcessMemory[i + 6] != 0x00) continue; - if (ProcessMemory[i + 7] != 0xAD) continue; - if (ProcessMemory[i + 8] != 0xC0) continue; - if (ProcessMemory[i + 9] != 0x03) continue; - if (ProcessMemory[i + 10] != 0x5F) continue; - if (ProcessMemory[i + 11] != 0xD6) continue; - - int aesKeyAddr = GetADRLAddress(i - 8); - if (aesKeyAddr < 0 || aesKeyAddr + 32 > ProcessMemory.Length) continue; - - string aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); - offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); - - aesKeyAddr += 0x1000; // Необходимо проверить корректность смещения +0x1000 для разных игр - if (aesKeyAddr + 32 > ProcessMemory.Length) continue; - - aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); - offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); - } - } - else - { - string EngineVersionStr = SearchEngineVersion(); - int EngineVersion = 17; - if (!string.IsNullOrEmpty(EngineVersionStr)) - { - string[] parts = EngineVersionStr.Split('.'); - if (parts.Length > 1 && int.TryParse(parts[1], out int ver)) - EngineVersion = ver; - } - - if (EngineVersion < 18) - { - // Старый способ поиска ключа - for (int i = 0; i < ProcessMemory.Length - 10; i++) - { - if (ProcessMemory[i] != 0x00 || ProcessMemory[i + 1] != 0x30 || ProcessMemory[i + 2] != 0x78) continue; - - int start = i; - while (start > 0 && ProcessMemory[start - 1] == 0x00) - start--; - - if (start - 65 < 0 || ProcessMemory[start - 65] != 0x00) continue; - - string aesKey = Encoding.Default.GetString(ProcessMemory, start - 64, 64); - - if (Regex.IsMatch(aesKey, @"^[a-zA-Z0-9]+$")) - { - offsets.Add(AllocationBase + (ulong)(start - 64), aesKey); - break; - } - } - } - - // Новый способ поиска ключа (например, для Fortnite и новых версий UE4) - int verify_1 = 0xC7; - for (int i = 0; i < ProcessMemory.Length - 10; i++) - { - try - { - if (i < 3) continue; - - if (ProcessMemory[i - 3] == 0x00 && ProcessMemory[i - 2] == 0x00 && ProcessMemory[i - 1] == 0x00) - continue; - - if (ProcessMemory[i] != verify_1 || (ProcessMemory[i + 1] != 0x45 && ProcessMemory[i + 1] != 0x01)) - continue; - - int verify_2 = ProcessMemory[i + 1] == 0x01 ? 0x41 : 0x45; - int verify_3 = ProcessMemory[i + 1] == 0x01 ? 0 : 0xD0; - - if (ProcessMemory[i + 1] == 0x45 && ProcessMemory[i + 2] != verify_3) - continue; - - if (ProcessMemory[i - 7] == verify_1 && ProcessMemory[i - 6] == verify_2) - continue; - - verify_3 += 0x04; - bool invalid = false; - int addr = i + 4 + 2 + (ProcessMemory[i + 1] == 0x01 ? 0 : 1); - string aesKey = BitConverter.ToString(ProcessMemory, addr - 4, 4).Replace("-", ""); - - while (aesKey.Length != 64) - { - if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr] != 0xE9) - { - if (ProcessMemory[addr] == 0x0F && ProcessMemory[addr + 4] == 0xE9) - { - addr += 4; - addr = FollowJMP(addr); - if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr + 1] != verify_2 && ProcessMemory[addr + 2] != verify_3) - invalid = true; - } - else if (ProcessMemory[addr + 4] != verify_1 && ProcessMemory[addr + 5] != verify_2 && ProcessMemory[addr + 6] != verify_3) - { - invalid = true; - } - else - { - addr += 4; - } - } - - if (ProcessMemory[addr] == 0xE9) - addr = FollowJMP(addr); - else - { - if (ProcessMemory[addr + 1] != verify_2 || ProcessMemory[addr + 2] != verify_3) - invalid = true; - - aesKey += BitConverter.ToString(ProcessMemory, addr + 3, 4).Replace("-", ""); - addr += 7; // 4 + 3 - verify_3 += 0x04; - } - - if (aesKey.Length == 64) - { - if (ProcessMemory[addr] == 0xE9) - addr = FollowJMP(addr); - - if (ProcessMemory[addr] != 0xC3 && ProcessMemory[addr] != 0x48) - { - if (ProcessMemory[addr] != 0x0F) - invalid = true; - - bool found = false; - for (int xx = 0; xx < 30; xx++) - { - int checkAddr = addr + xx; - if (checkAddr >= ProcessMemory.Length) break; - if (ProcessMemory[checkAddr] == 0x48 && ProcessMemory[checkAddr + 1] == 0x8D) - { - found = true; - break; - } - } - if (!found) - invalid = true; - } - } - - if (invalid) - break; - } - - if (invalid) continue; - - offsets.Add(AllocationBase + (ulong)i, $"0x{aesKey}"); - } - catch - { - // Игнорируем ошибки парсинга - } - } - } - - timer.Stop(); - elapsedMilliseconds = timer.ElapsedMilliseconds; - return offsets; - } - - public static class Win32 - { - [DllImport("kernel32.dll", SetLastError = true)] -public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); - - [DllImport("kernel32.dll")] - public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); - } -} \ No newline at end of file + +}*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Text.RegularExpressions; +using System.Runtime.InteropServices; + +public class Searcher +{ + private const int PAGE_SIZE = 4000; + + private bool useUE4Lib = false; + + private IntPtr hProcess; + private Process Process; + private ulong AllocationBase; + private byte[] ProcessMemory; + private string FilePath; + + public Searcher() { } + + public Searcher(Process p) + { + Process = p; + hProcess = p.Handle; + AllocationBase = (ulong)p.MainModule.BaseAddress; + ProcessMemory = new byte[p.MainModule.ModuleMemorySize]; + + // Читаем память кусками по 2048 байт (могут быть пустые регионы, поэтому по частям) + for (int i = 0; i < ProcessMemory.Length; i += 2048) + { + int bytesToRead = Math.Min(2048, ProcessMemory.Length - i); + byte[] bytes = new byte[bytesToRead]; + if (Win32.ReadProcessMemory(hProcess, AllocationBase + (ulong)i, bytes, bytesToRead)) + { + Array.Copy(bytes, 0, ProcessMemory, i, bytesToRead); + } + else + { + // Если чтение не удалось — просто продолжаем, можно логировать при необходимости + } + } + } + + public Searcher(byte[] bytes) + { + AllocationBase = 0; + ProcessMemory = bytes; + } + + public Searcher(byte[] bytes, bool useAndroid, bool isAPK = false) + { + if (isAPK) + { + // Поиск "APK Sig Block" (ищем подпись APK) + int libUE4Offset = 0; + byte[] apkSigBlock = Encoding.ASCII.GetBytes("APK Sig Block"); + + for (int i = bytes.Length - apkSigBlock.Length - 1; i >= 0; i--) + { + bool matched = true; + for (int j = 0; j < apkSigBlock.Length; j++) + { + if (bytes[i + j] != apkSigBlock[j]) + { + matched = false; + break; + } + } + if (matched) + { + libUE4Offset = i; + break; + } + } + + if (libUE4Offset == 0) + throw new Exception("Failed to read LibUE4.so, APK Sig Block not found!"); + + // Поиск оффсета libUE4.so в блоке + byte[] libUE4 = Encoding.ASCII.GetBytes("lib/arm64-v8a/libUE4.so"); + + int foundOffset = 0; + for (int i = libUE4Offset; i < bytes.Length - libUE4.Length - 4; i++) + { + if (bytes[i] != libUE4[0]) continue; + bool c = false; + for (int ii = 0; ii < libUE4.Length; ii++) + { + if (bytes[i + ii] != libUE4[ii]) + { + c = true; + break; + } + } + if (c) continue; + + // Считаем offset 4 байта перед этим местом (int32 little-endian) + foundOffset = BitConverter.ToInt32(bytes, i - 4); + break; + } + + if (foundOffset == 0) + throw new Exception("Failed to read LibUE4.so, pattern not found!"); + + int compressed = BitConverter.ToInt32(bytes, foundOffset + 18); + int uncompressed = BitConverter.ToInt32(bytes, foundOffset + 22); + int headerSize = 53; + int dataStart = foundOffset + headerSize; + + using (var compressedStream = new MemoryStream(bytes, dataStart, compressed)) + using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) + using (var uncompressedLibUE4 = new MemoryStream()) + { + deflateStream.CopyTo(uncompressedLibUE4); + if (uncompressedLibUE4.Length != uncompressed) + throw new Exception("Failed to decompress LibUE4.so, size mismatch!"); + + ProcessMemory = uncompressedLibUE4.ToArray(); + } + } + else + { + ProcessMemory = bytes; + } + + useUE4Lib = useAndroid; + } + + public void SetFilePath(string path) => FilePath = path; + + public string SearchEngineVersion() + { + if (FilePath != null) + return FileVersionInfo.GetVersionInfo(FilePath).FileVersion; + + // Паттерн ProductVersion в юникоде (бэкап) + byte[] ProductVersion = new byte[] + { + 0x01, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6F, 0x00, + 0x64, 0x00, 0x75, 0x00, 0x63, 0x00, 0x74, 0x00, + 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, + 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00 + }; + + for (int i = ProcessMemory.Length - ProductVersion.Length - 1; i >= 0; i--) + { + bool matched = true; + for (int j = 0; j < ProductVersion.Length; j++) + { + if (ProcessMemory[i + j] != ProductVersion[j]) + { + matched = false; + break; + } + } + if (!matched) continue; + + var unicodeEncoding = new UnicodeEncoding(); + return unicodeEncoding.GetString(ProcessMemory, i + ProductVersion.Length - 2, 12); // 6 символов юникода (12 байт) + } + + return ""; + } + + public int FollowJMP(int addr) + { + int offset = BitConverter.ToInt32(ProcessMemory, addr + 1); + int newAddr = addr + offset + 5; + if (ProcessMemory[newAddr] == 0x0F && ProcessMemory[newAddr + 4] == 0xE9) + return FollowJMP(newAddr + 4); + return newAddr; + } + + public ulong DecodeADRP(int adrp) + { + const int mask19 = (1 << 19) - 1; + const int mask2 = 3; + + int imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2); + int msbt = (imm >> 20) & 1; + int value = imm << 12; + + // Поддержка знакового расширения для 64-битного значения + long signedValue = (long)value; + if (msbt == 1) + signedValue |= -1L << 33; + + return (ulong)signedValue; + } + + public ulong DecodeADD(int add) + { + var imm12 = (add & 0x3ffc00) >> 10; + if ((imm12 & 0xc00000) != 0) + imm12 <<= 12; + return (ulong)imm12; + } + + public int GetADRLAddress(int ADRPLoc) + { + ulong ADRP = DecodeADRP(BitConverter.ToInt32(ProcessMemory, ADRPLoc)); + ulong ADD = DecodeADD(BitConverter.ToInt32(ProcessMemory, ADRPLoc + 4)); + + return (int)((((ulong)ADRPLoc & 0xFFFFF000) + ADRP + ADD) & 0xFFFFFFFF); + } + + public Dictionary FindAllPattern(out long elapsedMilliseconds) + { + Stopwatch timer = Stopwatch.StartNew(); + var offsets = new Dictionary(); + + if (useUE4Lib) + { + // Android UE4 key search pattern + for (int i = 0; i < ProcessMemory.Length - 12; i++) + { + if (ProcessMemory[i] != 0x01) continue; + if (ProcessMemory[i + 1] != 0x01) continue; + if (ProcessMemory[i + 2] != 0x40) continue; + if (ProcessMemory[i + 3] != 0xAD) continue; + if (ProcessMemory[i + 4] != 0x01) continue; + if (ProcessMemory[i + 5] != 0x00) continue; + if (ProcessMemory[i + 6] != 0x00) continue; + if (ProcessMemory[i + 7] != 0xAD) continue; + if (ProcessMemory[i + 8] != 0xC0) continue; + if (ProcessMemory[i + 9] != 0x03) continue; + if (ProcessMemory[i + 10] != 0x5F) continue; + if (ProcessMemory[i + 11] != 0xD6) continue; + + int aesKeyAddr = GetADRLAddress(i - 8); + if (aesKeyAddr < 0 || aesKeyAddr + 32 > ProcessMemory.Length) continue; + + string aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + + aesKeyAddr += 0x1000; // Необходимо проверить корректность смещения +0x1000 для разных игр + if (aesKeyAddr + 32 > ProcessMemory.Length) continue; + + aesKey = BitConverter.ToString(ProcessMemory, aesKeyAddr, 32).Replace("-", ""); + offsets.Add(AllocationBase + (ulong)aesKeyAddr, $"0x{aesKey}"); + } + } + else + { + string EngineVersionStr = SearchEngineVersion(); + int EngineVersion = 17; + if (!string.IsNullOrEmpty(EngineVersionStr)) + { + string[] parts = EngineVersionStr.Split('.'); + if (parts.Length > 1 && int.TryParse(parts[1], out int ver)) + EngineVersion = ver; + } + + if (EngineVersion < 18) + { + // Старый способ поиска ключа + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + if (ProcessMemory[i] != 0x00 || ProcessMemory[i + 1] != 0x30 || ProcessMemory[i + 2] != 0x78) continue; + + int start = i; + while (start > 0 && ProcessMemory[start - 1] == 0x00) + start--; + + if (start - 65 < 0 || ProcessMemory[start - 65] != 0x00) continue; + + string aesKey = Encoding.Default.GetString(ProcessMemory, start - 64, 64); + + if (Regex.IsMatch(aesKey, @"^[a-zA-Z0-9]+$")) + { + offsets.Add(AllocationBase + (ulong)(start - 64), aesKey); + break; + } + } + } + + // Новый способ поиска ключа (например, для Fortnite и новых версий UE4) + int verify_1 = 0xC7; + for (int i = 0; i < ProcessMemory.Length - 10; i++) + { + try + { + if (i < 3) continue; + + if (ProcessMemory[i - 3] == 0x00 && ProcessMemory[i - 2] == 0x00 && ProcessMemory[i - 1] == 0x00) + continue; + + if (ProcessMemory[i] != verify_1 || (ProcessMemory[i + 1] != 0x45 && ProcessMemory[i + 1] != 0x01)) + continue; + + int verify_2 = ProcessMemory[i + 1] == 0x01 ? 0x41 : 0x45; + int verify_3 = ProcessMemory[i + 1] == 0x01 ? 0 : 0xD0; + + if (ProcessMemory[i + 1] == 0x45 && ProcessMemory[i + 2] != verify_3) + continue; + + if (ProcessMemory[i - 7] == verify_1 && ProcessMemory[i - 6] == verify_2) + continue; + + verify_3 += 0x04; + bool invalid = false; + int addr = i + 4 + 2 + (ProcessMemory[i + 1] == 0x01 ? 0 : 1); + string aesKey = BitConverter.ToString(ProcessMemory, addr - 4, 4).Replace("-", ""); + + while (aesKey.Length != 64) + { + if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr] != 0xE9) + { + if (ProcessMemory[addr] == 0x0F && ProcessMemory[addr + 4] == 0xE9) + { + addr += 4; + addr = FollowJMP(addr); + if (ProcessMemory[addr] != verify_1 && ProcessMemory[addr + 1] != verify_2 && ProcessMemory[addr + 2] != verify_3) + invalid = true; + } + else if (ProcessMemory[addr + 4] != verify_1 && ProcessMemory[addr + 5] != verify_2 && ProcessMemory[addr + 6] != verify_3) + { + invalid = true; + } + else + { + addr += 4; + } + } + + if (ProcessMemory[addr] == 0xE9) + addr = FollowJMP(addr); + else + { + if (ProcessMemory[addr + 1] != verify_2 || ProcessMemory[addr + 2] != verify_3) + invalid = true; + + aesKey += BitConverter.ToString(ProcessMemory, addr + 3, 4).Replace("-", ""); + addr += 7; // 4 + 3 + verify_3 += 0x04; + } + + if (aesKey.Length == 64) + { + if (ProcessMemory[addr] == 0xE9) + addr = FollowJMP(addr); + + if (ProcessMemory[addr] != 0xC3 && ProcessMemory[addr] != 0x48) + { + if (ProcessMemory[addr] != 0x0F) + invalid = true; + + bool found = false; + for (int xx = 0; xx < 30; xx++) + { + int checkAddr = addr + xx; + if (checkAddr >= ProcessMemory.Length) break; + if (ProcessMemory[checkAddr] == 0x48 && ProcessMemory[checkAddr + 1] == 0x8D) + { + found = true; + break; + } + } + if (!found) + invalid = true; + } + } + + if (invalid) + break; + } + + if (invalid) continue; + + offsets.Add(AllocationBase + (ulong)i, $"0x{aesKey}"); + } + catch + { + // Игнорируем ошибки парсинга + } + } + } + + timer.Stop(); + elapsedMilliseconds = timer.ElapsedMilliseconds; + return offsets; + } + + public static class Win32 + { + [DllImport("kernel32.dll")] +public static extern bool ReadProcessMemory(IntPtr hProcess, ulong lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, int lpNumberOfBytesRead = 0); + + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); + } +} From e7ae0a28bdb8511b1d1bf3a2791ed33b23aee28c Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:24:19 +0500 Subject: [PATCH 32/38] Create dependabot.yml --- .github/dependabot.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..29dbfa6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + # Enable version updates for npm + - package-ecosystem: 'npm' + # Look for `package.json` and `lock` files in the `root` directory + directory: '/' + # Check the npm registry for updates every day (weekdays) + schedule: + interval: 'weekly' + + # Enable version updates for GitHub Actions + - package-ecosystem: 'github-actions' + # Workflow files stored in the default location of `.github/workflows` + # You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`. + directory: '/' + schedule: + interval: 'weekly' \ No newline at end of file From 373d71309c7ea3a67c04d79f5cd13446553431a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Nov 2025 15:29:45 +0000 Subject: [PATCH 33/38] Bump actions/setup-dotnet from 4 to 5 Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03e977d..925cc9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: uses: actions/checkout@v5 - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: | 8.0.x From 802cecbf3bfc944e1ebfa924b092f49de9d0bf0b Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 20:50:07 +0500 Subject: [PATCH 34/38] Update .NET versions in build workflow --- .github/workflows/build.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 925cc9c..bcaa779 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,12 @@ jobs: uses: actions/setup-dotnet@v5 with: dotnet-version: | - 8.0.x + 3.1.x + 6.0.x + 7.0.x + 8.0.x + 9.0.x + 10.0.x - name: Restore dependencies run: dotnet restore UEAESKeyFinder.sln @@ -41,4 +46,4 @@ jobs: body: "Build time: ${{ env.now }}" files: ./publish/** env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 211eb575bff8cb41b7009b6befb2c606f57794d4 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 21:01:24 +0500 Subject: [PATCH 35/38] Update build.yml --- .github/workflows/build.yml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bcaa779..504f3f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,3 @@ -permissions: - contents: write name: Build UEAESKeyFinder on: @@ -8,30 +6,30 @@ on: - main workflow_dispatch: +permissions: + contents: write + jobs: build: runs-on: windows-latest + strategy: + matrix: + dotnet-version: [3.1.x, 6.0.x, 7.0.x, 8.0.x, 9.0.x, 10.0.x] steps: - name: Checkout uses: actions/checkout@v5 - - name: Setup .NET + - name: Setup .NET SDK uses: actions/setup-dotnet@v5 with: - dotnet-version: | - 3.1.x - 6.0.x - 7.0.x - 8.0.x - 9.0.x - 10.0.x + dotnet-version: ${{ matrix.dotnet-version }} - name: Restore dependencies run: dotnet restore UEAESKeyFinder.sln - name: Build Publish Binary - run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish + run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish/${{ matrix.dotnet-version }} - name: Get DateTime Tashkent/Uzbekistan id: datetime @@ -42,8 +40,8 @@ jobs: uses: softprops/action-gh-release@v2 with: tag_name: latest - name: "UEAESKeyFinder Build (${{ env.now }})" - body: "Build time: ${{ env.now }}" - files: ./publish/** + name: "UEAESKeyFinder Build (${{ env.now }}) - ${{ matrix.dotnet-version }}" + body: "Build time: ${{ env.now }} - .NET ${{ matrix.dotnet-version }}" + files: ./publish/${{ matrix.dotnet-version }}/** env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file From 4bb988ae84b35226b81a8d0291441e2042d36319 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Sat, 15 Nov 2025 21:08:23 +0500 Subject: [PATCH 36/38] Refactor build workflow for .NET SDK and publishing Updated the .NET SDK setup and adjusted the publish output path. --- .github/workflows/build.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 504f3f2..bf97677 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,24 +12,26 @@ permissions: jobs: build: runs-on: windows-latest - strategy: - matrix: - dotnet-version: [3.1.x, 6.0.x, 7.0.x, 8.0.x, 9.0.x, 10.0.x] steps: - name: Checkout uses: actions/checkout@v5 - - name: Setup .NET SDK + - name: Setup .NET uses: actions/setup-dotnet@v5 with: - dotnet-version: ${{ matrix.dotnet-version }} - + dotnet-version: | + 3.1.x + 6.0.x + 7.0.x + 8.0.x + 9.0.x + 10.0.x - name: Restore dependencies run: dotnet restore UEAESKeyFinder.sln - name: Build Publish Binary - run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish/${{ matrix.dotnet-version }} + run: dotnet publish ./UEAESKeyFinder/UEAESKeyFinder.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./publish - name: Get DateTime Tashkent/Uzbekistan id: datetime @@ -40,8 +42,8 @@ jobs: uses: softprops/action-gh-release@v2 with: tag_name: latest - name: "UEAESKeyFinder Build (${{ env.now }}) - ${{ matrix.dotnet-version }}" - body: "Build time: ${{ env.now }} - .NET ${{ matrix.dotnet-version }}" - files: ./publish/${{ matrix.dotnet-version }}/** + name: "UEAESKeyFinder Build (${{ env.now }})" + body: "Build time: ${{ env.now }}" + files: ./publish/** env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 86aec88b3947d14375877fd11c55c00bd8755fad Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Thu, 20 Nov 2025 23:57:23 +0500 Subject: [PATCH 37/38] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf97677..1b2f700 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup .NET uses: actions/setup-dotnet@v5 From cf3063187bfdd5775689dd4fab4e91cf54c9cf47 Mon Sep 17 00:00:00 2001 From: tojik_proof_93 Date: Mon, 9 Feb 2026 12:29:03 +0500 Subject: [PATCH 38/38] Update SpecialForcesGroup2.md --- AESKeys/SpecialForcesGroup2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AESKeys/SpecialForcesGroup2.md b/AESKeys/SpecialForcesGroup2.md index 4a12286..bd97d4c 100644 --- a/AESKeys/SpecialForcesGroup2.md +++ b/AESKeys/SpecialForcesGroup2.md @@ -3,4 +3,4 @@ ## Closed Alpha | Version | Key | | ----------------- | --------------------------------------------------------------------- | -| 4.21 | 0x78E155ECC391708269C2759E867B7D6C01F12B6DB51AE021A4E7B9A4F8A00000 | +| 4.21 | 0xB96978E155ECC391708269C2759E867B7D6C01F12B6DB51AE021A4E7B9A4F8A0 |