├── global.json ├── .gitignore ├── README.md ├── Phoenix Protector Strings Decryptor ├── Dependencies │ └── dnlib.dll ├── Phoenix Protector Strings Decryptor.csproj ├── Program.cs └── StringsDecryptor.cs ├── Phoenix Protector Strings Decryptor.sln └── LICENSE /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "3.1.300" 4 | } 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phoenix-Protector-Strings-Decryptor 2 | A strings decryptor for Phoenix Protector using the stack thanks to https://github.com/MindSystemm/StackYenoDeobfuscator. 3 | -------------------------------------------------------------------------------- /Phoenix Protector Strings Decryptor/Dependencies/dnlib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illuZion9999/Phoenix-Protector-Strings-Decryptor/HEAD/Phoenix Protector Strings Decryptor/Dependencies/dnlib.dll -------------------------------------------------------------------------------- /Phoenix Protector Strings Decryptor/Phoenix Protector Strings Decryptor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | Phoenix_Protector_Strings_Decryptor 7 | 8 | 9 | 10 | 11 | Dependencies\dnlib.dll 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Phoenix Protector Strings Decryptor.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Phoenix Protector Strings Decryptor", "Phoenix Protector Strings Decryptor\Phoenix Protector Strings Decryptor.csproj", "{C72ED157-D445-4D9E-B969-D4CA570A9A7A}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {C72ED157-D445-4D9E-B969-D4CA570A9A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {C72ED157-D445-4D9E-B969-D4CA570A9A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {C72ED157-D445-4D9E-B969-D4CA570A9A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {C72ED157-D445-4D9E-B969-D4CA570A9A7A}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 illuZion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Phoenix Protector Strings Decryptor/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Net.Mime; 6 | using Colorful; 7 | using dnlib.DotNet; 8 | using dnlib.DotNet.Writer; 9 | using Console = Colorful.Console; 10 | 11 | namespace Phoenix_Protector_Strings_Decryptor 12 | { 13 | class Program 14 | { 15 | static void Main(string[] args) 16 | { 17 | Console.Title = "Phoenix Protector Strings Decryptor by illuZion"; 18 | Console.WriteAscii("Phoenix Protector", Color.Red); 19 | Console.WriteAscii("Strings Decryptor", Color.Orange); 20 | Console.WriteLine("v1.0 by illuZion ", Color.Blue); 21 | 22 | var targetFilePath = string.Empty; 23 | if (args.Length < 1) 24 | { 25 | while (targetFilePath == string.Empty || !File.Exists(targetFilePath)) 26 | { 27 | Console.Write("Path of the file: "); 28 | targetFilePath = Path.GetFullPath(Console.ReadLine().Replace("\"", string.Empty)); 29 | } 30 | } 31 | else 32 | targetFilePath = Path.GetFullPath(args[0]); 33 | 34 | ModuleDefMD module = null; 35 | try 36 | { 37 | module = ModuleDefMD.Load(targetFilePath); 38 | } 39 | catch (Exception ex) 40 | { 41 | throw new BadImageFormatException("Module couldn't have been loaded.", ex); 42 | } 43 | if (module == null) 44 | throw new BadImageFormatException("Module couldn't have been loaded."); 45 | 46 | var stopwatch = new Stopwatch(); 47 | stopwatch.Start(); 48 | 49 | int decryptedCount = StringsDecryptor.DecryptStrings(module); 50 | 51 | stopwatch.Stop(); 52 | Console.WriteLine($"\n[+] Decrypted {decryptedCount} strings ! Elapsed time: {stopwatch.Elapsed.TotalSeconds}", Color.Green); 53 | Console.WriteLine("[$] Saving the file...", Color.Aqua); 54 | 55 | string outputFilePath = $"{Path.GetDirectoryName(targetFilePath)}\\{Path.GetFileNameWithoutExtension(targetFilePath)}-decrypted{Path.GetExtension(targetFilePath)}"; 56 | ModuleWriterOptionsBase moduleWriterOptionsBase = module.IsILOnly 57 | ? new ModuleWriterOptions(module) 58 | : (ModuleWriterOptionsBase) new NativeModuleWriterOptions(module, true); 59 | 60 | moduleWriterOptionsBase.MetadataOptions.Flags |= MetadataFlags.PreserveAll; 61 | // Prevents dnlib from throwing non-important errors. 62 | moduleWriterOptionsBase.Logger = DummyLogger.NoThrowInstance; 63 | moduleWriterOptionsBase.MetadataLogger = DummyLogger.NoThrowInstance; 64 | 65 | // Saves the output (unpacked) module. 66 | if (moduleWriterOptionsBase is NativeModuleWriterOptions nativeModuleWriterOptions) 67 | module.NativeWrite(outputFilePath, nativeModuleWriterOptions); 68 | else 69 | module.Write(outputFilePath, moduleWriterOptionsBase as ModuleWriterOptions); 70 | 71 | Console.WriteLine($"[+] File saved at {outputFilePath}", Color.Green); 72 | 73 | Console.ReadKey(); 74 | Environment.Exit(0); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /Phoenix Protector Strings Decryptor/StringsDecryptor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Linq; 6 | using dnlib.DotNet; 7 | using dnlib.DotNet.Emit; 8 | using Console = Colorful.Console; 9 | 10 | namespace Phoenix_Protector_Strings_Decryptor 11 | { 12 | public static class StringsDecryptor 13 | { 14 | public static int DecryptStrings(ModuleDefMD module) 15 | { 16 | MethodDef decryptionMethod = FindDecryptionMethod(module); 17 | if (decryptionMethod == null) 18 | return 0; 19 | 20 | var decryptedCount = 0; 21 | var stack = new Stack(); 22 | foreach (TypeDef type in module.Types.Where(t => t.HasMethods)) 23 | { 24 | foreach (MethodDef method in type.Methods.Where(m => m.HasBody && m.Body.HasInstructions)) 25 | { 26 | IList instr = method.Body.Instructions; 27 | for (var i = 0; i < instr.Count; i++) 28 | { 29 | if (instr[i].OpCode == OpCodes.Ldstr) 30 | { 31 | var encryptedString = new Tuple((string) instr[i].Operand, i); 32 | stack.Push(encryptedString); 33 | } 34 | else if (instr[i].OpCode == OpCodes.Call && instr[i].Operand is MethodDef callMethod && 35 | callMethod == decryptionMethod) 36 | { 37 | (string encryptedString, int index) = (Tuple) stack.Pop(); 38 | string decryptedString = Decrypt(encryptedString); 39 | instr[index].OpCode = OpCodes.Nop; 40 | instr[i] = Instruction.Create(OpCodes.Ldstr, decryptedString); 41 | 42 | Console.WriteLine($"[$] Decrypted {decryptedString}", Color.Purple); 43 | decryptedCount++; 44 | } 45 | } 46 | } 47 | } 48 | 49 | return decryptedCount; 50 | } 51 | 52 | private static MethodDef FindDecryptionMethod(ModuleDef module) 53 | { 54 | foreach (TypeDef type in module.Types.Where(t => t.HasMethods)) 55 | { 56 | foreach (MethodDef method in type.Methods.Where(m => m.HasBody && m.Body.HasInstructions)) 57 | { 58 | if (!string.IsNullOrWhiteSpace(method.DeclaringType.Namespace) || 59 | method.ReturnType != module.CorLibTypes.String || method.GetParamCount() != 1 || 60 | method.Parameters[0].Type != module.CorLibTypes.String) continue; 61 | // Stores all the calls in a list to avoid loop. 62 | List callInstrs = method.Body.Instructions.Where(i => i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt).ToList(); 63 | List getLength = callInstrs.FindAll(o => o.Operand.ToString().Contains("get_Length") && 64 | o.Operand is MemberRef getLengthCall && 65 | getLengthCall.ReturnType == module.CorLibTypes.Int32 && 66 | !getLengthCall.HasParams()); 67 | List getChars = callInstrs.FindAll(o => o.Operand.ToString().Contains("get_Chars") && 68 | o.Operand is MemberRef getCharsCall && 69 | getCharsCall.ReturnType == module.CorLibTypes.Char && 70 | getCharsCall.HasParams() && 71 | getCharsCall.GetParamCount() == 1 && 72 | getCharsCall.GetParams()[0].ToTypeDefOrRefSig() == module.CorLibTypes.Int32); 73 | List intern = callInstrs.FindAll(o => o.Operand.ToString().Contains("Intern") && 74 | o.Operand is MemberRef internCall && 75 | internCall.ReturnType == module.CorLibTypes.String && 76 | internCall.HasParams() && 77 | internCall.GetParamCount() == 1 && 78 | internCall.GetParams()[0].ToTypeDefOrRefSig() == module.CorLibTypes.String); 79 | // If instruction found, then we're almost sure it's the correct decryption method. 80 | if (getLength.Count != 1 || getChars.Count != 1 || intern.Count != 1) continue; 81 | 82 | return method; 83 | } 84 | } 85 | 86 | return null; 87 | } 88 | 89 | private static string Decrypt(string encryptedString) 90 | { 91 | var array = new char[encryptedString.Length]; 92 | for (var i = 0; i < array.Length; i++) 93 | array[i] = (char)((byte)(encryptedString[i] >> 8 ^ i) << 8 | (byte)(encryptedString[i] ^ encryptedString.Length - i)); 94 | return string.Intern(new string(array)); 95 | } 96 | } 97 | } --------------------------------------------------------------------------------