├── 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 | }
--------------------------------------------------------------------------------