├── .gitattributes
├── .gitignore
├── .gitmodules
├── LICENSE
├── NoFuserEx
├── NoFuserEx.sln
└── NoFuserEx
│ ├── App.config
│ ├── AssemblyManager.cs
│ ├── Deobfuscator
│ ├── AssemblyCreator.cs
│ ├── DeobfuscatorManager.cs
│ ├── Deobfuscators
│ │ ├── AntiDebuggerDeobfuscator.cs
│ │ ├── AntiDumperDeobfuscator.cs
│ │ ├── AntiTamperDeobfuscator.cs
│ │ ├── CompressorDeobfuscator.cs
│ │ ├── Constants
│ │ │ ├── ByteArrayDecrypter.cs
│ │ │ ├── CharArrayDecrypter.cs
│ │ │ ├── ConstantsDeobfuscator.cs
│ │ │ ├── DecrypterBase.cs
│ │ │ ├── DoubleArrayDecrypter.cs
│ │ │ ├── FloatArrayDecrypter.cs
│ │ │ ├── IntArrayDecrypter.cs
│ │ │ ├── LongArrayDecrypter.cs
│ │ │ ├── SByteArrayDecrypter.cs
│ │ │ ├── ShortArrayDecrypter.cs
│ │ │ ├── StringDecrypter.cs
│ │ │ ├── UIntArrayDecrypter.cs
│ │ │ ├── ULongArrayDecrypter.cs
│ │ │ └── UShortArrayDecrypter.cs
│ │ ├── ProxyDeobfuscator.cs
│ │ └── ResourcesDeobfuscator.cs
│ ├── IDeobfuscator.cs
│ ├── MemberCloner.cs
│ └── Utils.cs
│ ├── Logger.cs
│ ├── NoFuserEx.csproj
│ ├── Options.cs
│ ├── Program.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Utils.cs
│ └── nofuserex icon.ico
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "dnlib"]
2 | path = dnlib
3 | url = https://github.com/CodeShark-Dev/dnlib
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 CodeShark
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 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoFuserEx", "NoFuserEx\NoFuserEx.csproj", "{6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dnlib", "..\dnlib\src\dnlib.csproj", "{FDFC1237-143F-4919-8318-4926901F4639}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|Mixed Platforms = Debug|Mixed Platforms
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|Mixed Platforms = Release|Mixed Platforms
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
23 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
24 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|x86.ActiveCfg = Debug|Any CPU
25 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Debug|x86.Build.0 = Debug|Any CPU
26 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
29 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
30 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|x86.ActiveCfg = Release|Any CPU
31 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB}.Release|x86.Build.0 = Release|Any CPU
32 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
35 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
36 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|x86.ActiveCfg = Debug|Any CPU
37 | {FDFC1237-143F-4919-8318-4926901F4639}.Debug|x86.Build.0 = Debug|Any CPU
38 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
41 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|Mixed Platforms.Build.0 = Release|Any CPU
42 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|x86.ActiveCfg = Release|Any CPU
43 | {FDFC1237-143F-4919-8318-4926901F4639}.Release|x86.Build.0 = Release|Any CPU
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/AssemblyManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.IO;
4 | using dnlib.DotNet;
5 | using dnlib.DotNet.Writer;
6 |
7 | namespace NoFuserEx {
8 | internal class AssemblyManager {
9 | readonly string inputFile;
10 | readonly string outputFile;
11 |
12 | internal AssemblyManager(string inputFile) {
13 | this.inputFile = inputFile;
14 | outputFile =
15 | $"{Path.GetDirectoryName(inputFile)}\\NoFuserEx_Output\\{Path.GetFileName(inputFile)}";
16 | Logger.VeryVerbose($"Output assembly: {outputFile}.");
17 |
18 | if (Utils.CreateDirectory(Path.GetDirectoryName(outputFile)))
19 | Logger.VeryVerbose("Created output directory.");
20 | else
21 | Logger.Exception(new Exception("Error creating directory..."));
22 | }
23 |
24 | internal ModuleDefMD Module { get; set; }
25 | internal ModuleWriterOptions ModuleWriterOptions { get; private set; }
26 | internal NativeModuleWriterOptions NativeModuleWriterOptions { get; private set; }
27 |
28 | void ShowAssemblyInfo() {
29 | Logger.Info($"Module Name: {Module.Name}");
30 | using (var stream = Module.MetaData.PEImage.CreateFullStream())
31 | Logger.Info($"Module Size: {GetSize(stream.Length)}");
32 | Logger.Info($"CLR Version: {Module.RuntimeVersion.Substring(0, 4)}");
33 | }
34 |
35 | static string GetSize(long size) {
36 | string[] sizeType = { " B", " KB", " MB", " GB", " TB", " PB", " EB" };
37 | if (size == 0)
38 | return "0 B";
39 | var bytes = Math.Abs(size);
40 | var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
41 | var num = Math.Round(bytes / Math.Pow(1024, place), 1);
42 | return (Math.Sign(size) * num).ToString(CultureInfo.InvariantCulture) + sizeType[place];
43 | }
44 |
45 | internal void LoadAssembly() {
46 | try {
47 | Logger.Verbose("Loading module...");
48 | Module = ModuleDefMD.Load(inputFile);
49 | ModuleWriterOptions = new ModuleWriterOptions(Module);
50 | NativeModuleWriterOptions = new NativeModuleWriterOptions(Module);
51 | ShowAssemblyInfo();
52 | }
53 | catch (Exception ex) {
54 | Logger.Exception(ex);
55 | }
56 | }
57 |
58 | internal void SaveAssembly() {
59 | Logger.Verbose($"Module IsILOnly: {Module.IsILOnly}");
60 | try {
61 | if (Module.IsILOnly)
62 | Module.Write(outputFile);
63 | else
64 | Module.NativeWrite(outputFile);
65 | Logger.Info($"Saved successfully in {outputFile}");
66 | }
67 | catch (ModuleWriterException) {
68 | Logger.Verbose("Trying with \"DummyLogger.NoThrowInstance\"...");
69 | ModuleWriterOptions.Logger = DummyLogger.NoThrowInstance;
70 | NativeModuleWriterOptions.Logger = DummyLogger.NoThrowInstance;
71 |
72 | if (Module.IsILOnly)
73 | Module.Write(outputFile, ModuleWriterOptions);
74 | else
75 | Module.NativeWrite(outputFile, NativeModuleWriterOptions);
76 | Logger.Exclamation($"Saved with errors in {outputFile}");
77 | }
78 | catch (Exception ex) {
79 | Logger.Error("Error saving assembly.");
80 | Logger.Exception(ex);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/AssemblyCreator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using dnlib.DotNet;
5 | using dnlib.DotNet.Writer;
6 |
7 | namespace NoFuserEx.Deobfuscator {
8 | class AssemblyCreator {
9 | readonly TypeDef typeDef;
10 | readonly MethodDef methodDef;
11 | int methodToInvoke;
12 |
13 | internal AssemblyCreator(TypeDef typeDef, MethodDef methodDef) {
14 | Logger.Verbose($"Cloning type {typeDef.Name}");
15 | this.typeDef = MemberCloner.CloneTypeDef(typeDef);
16 | this.methodDef = methodDef;
17 | }
18 |
19 | internal object Invoke(object[] parameters) {
20 | var assemblyDef = new AssemblyDefUser("NoFuserExAssembly");
21 | Logger.Verbose($"Assembly created: {assemblyDef.Name}");
22 | var moduleDef = new ModuleDefUser("NoFuserExModule");
23 | Logger.Verbose($"Module created: {moduleDef.Name}");
24 | assemblyDef.Modules.Add(moduleDef);
25 | Logger.VeryVerbose("Module added to the assembly.");
26 |
27 | moduleDef.Types.Add(typeDef);
28 | Logger.VeryVerbose("Type injected to module.");
29 |
30 | foreach (var type in moduleDef.GetTypes()) {
31 | foreach (var method in type.Methods) {
32 | if (method.DeclaringType.Name != methodDef.DeclaringType.Name)
33 | continue;
34 | if (method.Name != methodDef.Name)
35 | continue;
36 | methodToInvoke = method.MDToken.ToInt32();
37 | Logger.VeryVerbose($"Token found: {methodToInvoke}");
38 | }
39 | }
40 |
41 | if (methodToInvoke == 0)
42 | Logger.Exception(new Exception("Error searching the token."));
43 |
44 | using (var stream = new MemoryStream()) {
45 | assemblyDef.Write(stream, new ModuleWriterOptions { Logger = DummyLogger.NoThrowInstance });
46 | Logger.VeryVerbose("Assembly writed.");
47 |
48 | var assembly = Assembly.Load(stream.ToArray());
49 | Logger.VeryVerbose("Created assembly loaded.");
50 |
51 | var module = assembly.ManifestModule;
52 | var method = module.ResolveMethod(methodToInvoke);
53 | Logger.VeryVerbose($"Method to invoke: {method.Name}");
54 |
55 | if (method.IsStatic)
56 | return method.Invoke(null, parameters);
57 |
58 | Logger.Verbose("Method is not static, creating instance...");
59 | var instance = Activator.CreateInstance(method.DeclaringType);
60 | return method.Invoke(instance, parameters);
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/DeobfuscatorManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using NoFuserEx.Deobfuscator.Deobfuscators;
4 | using NoFuserEx.Deobfuscator.Deobfuscators.Constants;
5 |
6 | namespace NoFuserEx.Deobfuscator {
7 | internal class DeobfuscatorManager {
8 | readonly AssemblyManager assemblyManager;
9 |
10 | readonly List deobfuscators;
11 |
12 | internal DeobfuscatorManager(AssemblyManager assemblyManager) {
13 | this.assemblyManager = assemblyManager;
14 | deobfuscators = new List();
15 | }
16 |
17 | void SelectDeobfuscators() {
18 | Logger.Verbose("Adding deobfuscators...");
19 |
20 | if (!Options.NoUnpack) {
21 | deobfuscators.Add(new CompressorDeobfuscator());
22 | Logger.VeryVerbose("Added compressor deobfuscator.");
23 | }
24 |
25 | if (!Options.NoTamper) {
26 | deobfuscators.Add(new AntiTamperDeobfuscator());
27 | Logger.VeryVerbose("Added anti-tamper deobfuscator.");
28 | }
29 |
30 | if (!Options.NoResources) {
31 | deobfuscators.Add(new ResourcesDeobfuscator());
32 | Logger.VeryVerbose("Added resources deobfuscator.");
33 | }
34 |
35 | if (!Options.NoConstants) {
36 | deobfuscators.Add(new ConstantsDeobfuscator());
37 | Logger.VeryVerbose("Added constants deobfuscator.");
38 | }
39 |
40 | if (!Options.NoProxyCalls) {
41 | deobfuscators.Add(new ProxyDeobfuscator());
42 | Logger.VeryVerbose("Added proxy deobfuscator.");
43 | }
44 |
45 | deobfuscators.Add(new AntiDumperDeobfuscator());
46 | Logger.VeryVerbose("Added anti-dumper deobfuscator.");
47 |
48 | deobfuscators.Add(new AntiDebuggerDeobfuscator());
49 | Logger.VeryVerbose("Added anti-debugger deobfuscator.");
50 | }
51 |
52 | internal void Start() {
53 | SelectDeobfuscators();
54 | DetectConfuserVersion();
55 |
56 | foreach (var deobfuscator in deobfuscators) {
57 | var deobfuscated = deobfuscator.Deobfuscate(assemblyManager);
58 | if (deobfuscated)
59 | deobfuscator.Log();
60 | }
61 | Logger.WriteLine(string.Empty);
62 | }
63 |
64 | void DetectConfuserVersion() {
65 | Logger.Verbose("Detecting ConfuserEx version...");
66 | var versions = new List();
67 | var module = assemblyManager.Module;
68 | foreach (var attribute in module.CustomAttributes) {
69 | if (attribute.TypeFullName != "ConfusedByAttribute")
70 | continue;
71 | foreach (var argument in attribute.ConstructorArguments) {
72 | if (argument.Type.ElementType != ElementType.String)
73 | continue;
74 | var value = argument.Value.ToString();
75 | if (!value.Contains("ConfuserEx"))
76 | continue;
77 | Logger.Info($"Detected: {value}");
78 | versions.Add(value);
79 | }
80 | }
81 |
82 | if (versions.Count >= 1)
83 | return;
84 | if (Options.ForceDeobfuscation) {
85 | Logger.Info("Forced deobfuscation.");
86 | return;
87 | }
88 |
89 | Logger.Exclamation("ConfuserEx doesn't detected. Use de4dot.");
90 | Logger.Exit();
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/AntiDebuggerDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using dnlib.DotNet;
2 | using dnlib.DotNet.Emit;
3 |
4 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
5 | class AntiDebuggerDeobfuscator : IDeobfuscator {
6 | public void Log() {
7 | Logger.Success("Removed: Anti-debugger protection.");
8 | }
9 |
10 | public bool Deobfuscate(AssemblyManager assemblyManager) {
11 | var instructions = assemblyManager.Module.GlobalType.FindStaticConstructor().Body.Instructions;
12 |
13 | foreach (var instruction in instructions) {
14 | if (instruction.OpCode != OpCodes.Call)
15 | continue;
16 |
17 | var debuggerMethod = instruction.Operand as MethodDef;
18 | if (debuggerMethod == null)
19 | continue;
20 | if (!debuggerMethod.DeclaringType.IsGlobalModuleType)
21 | continue;
22 |
23 | if (debuggerMethod.FindInstructionsNumber(OpCodes.Ldstr, "ENABLE_PROFILING") != 1)
24 | continue;
25 | if (debuggerMethod.FindInstructionsNumber(OpCodes.Ldstr, "GetEnvironmentVariable") != 1)
26 | continue;
27 | if (debuggerMethod.FindInstructionsNumber(OpCodes.Ldstr, "COR") != 1)
28 | continue;
29 |
30 | if (debuggerMethod.FindInstructionsNumber(OpCodes.Call, "System.Environment::FailFast(System.String)") != 1)
31 | continue;
32 |
33 | instruction.OpCode = OpCodes.Nop;
34 | instruction.Operand = null;
35 | return true;
36 | }
37 | return false;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/AntiDumperDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using dnlib.DotNet;
2 | using dnlib.DotNet.Emit;
3 |
4 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
5 | internal class AntiDumperDeobfuscator : IDeobfuscator {
6 | public void Log() {
7 | Logger.Success("Removed: Anti-dumper protection.");
8 | }
9 |
10 | public bool Deobfuscate(AssemblyManager assemblyManager) {
11 | var instructions = assemblyManager.Module.GlobalType.FindStaticConstructor().Body.Instructions;
12 | foreach (var instr in instructions) {
13 | if (instr.OpCode != OpCodes.Call)
14 | continue;
15 |
16 | var dumperMethod = instr.Operand as MethodDef;
17 | if (dumperMethod == null)
18 | continue;
19 | if (!dumperMethod.DeclaringType.IsGlobalModuleType)
20 | continue;
21 |
22 | const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static |
23 | MethodAttributes.HideBySig;
24 | if (dumperMethod.Attributes != attributes)
25 | continue;
26 | if (dumperMethod.CodeType != MethodImplAttributes.IL)
27 | continue;
28 |
29 | if (dumperMethod.ReturnType.ElementType != ElementType.Void)
30 | continue;
31 |
32 | // Anti-dumper method have 14 calls to VirtualProtect
33 | if (dumperMethod.FindInstructionsNumber(OpCodes.Call, "(System.Byte*,System.Int32,System.UInt32,System.UInt32&)") != 14)
34 | continue;
35 | instr.OpCode = OpCodes.Nop;
36 | instr.Operand = null;
37 | Logger.Verbose("Anti-dumper call was removed from .cctor.");
38 | return true;
39 | }
40 | return false;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/AntiTamperDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using dnlib.DotNet;
6 | using dnlib.DotNet.Emit;
7 | using MethodAttributes = dnlib.DotNet.MethodAttributes;
8 | using MethodImplAttributes = dnlib.DotNet.MethodImplAttributes;
9 |
10 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
11 | internal class AntiTamperDeobfuscator : IDeobfuscator {
12 | public void Log() {
13 | Logger.Success("Removed: Anti-tamper protection.");
14 | }
15 |
16 | public bool Deobfuscate(AssemblyManager assemblyManager) {
17 | var module = assemblyManager.Module;
18 |
19 | var isTampered = IsTampered(module);
20 | if (isTampered == null)
21 | Logger.Exception(new Exception("Oh oh.. I can't check if the assembly has anti-tamper protection."));
22 |
23 | if (!(bool)isTampered)
24 | return false;
25 |
26 | using (var stream = module.MetaData.PEImage.CreateFullStream()) {
27 | var moduleArray = new byte[stream.Length];
28 | stream.Read(moduleArray, 0, moduleArray.Length);
29 | var assembly = Assembly.Load(moduleArray);
30 | var cctor =
31 | assembly.ManifestModule.ResolveMethod(module.GlobalType.FindStaticConstructor().MDToken.ToInt32());
32 |
33 | Logger.Verbose("Decrypting methods....");
34 | // Thanks alot to Alcatraz3222 for help me in load cctor without invoke :P
35 | RuntimeHelpers.PrepareMethod(cctor.MethodHandle);
36 |
37 | var hinstance = Marshal.GetHINSTANCE(assembly.ManifestModule);
38 | var tableDecrypted = new byte[stream.Length];
39 | Marshal.Copy(hinstance, tableDecrypted, 0, tableDecrypted.Length);
40 |
41 | var entryPoint = assemblyManager.Module.EntryPoint;
42 |
43 | uint realEntryPoint = 0;
44 | if (entryPoint != null)
45 | realEntryPoint = assemblyManager.Module.EntryPoint.MDToken.Rid;
46 |
47 | assemblyManager.Module = ModuleDefMD.Load(tableDecrypted);
48 | Logger.Verbose("Have been decrypted all methods.");
49 |
50 | if (realEntryPoint != 0)
51 | assemblyManager.Module.EntryPoint = assemblyManager.Module.ResolveMethod(realEntryPoint);
52 |
53 |
54 | RemoveCall(assemblyManager.Module.GlobalType.FindStaticConstructor());
55 | }
56 |
57 | return true;
58 | }
59 |
60 | static bool? IsTampered(ModuleDefMD module) {
61 | var sections = module.MetaData.PEImage.ImageSectionHeaders;
62 |
63 | if (sections.Count == 3) {
64 | Logger.Verbose("Anti-tamper not detected.");
65 | return false;
66 | }
67 |
68 | foreach (var section in sections) {
69 | switch (section.DisplayName) {
70 | case ".text":
71 | case ".rsrc":
72 | case ".reloc":
73 | continue;
74 | default:
75 | Logger.Verbose($"Anti-tamper detected in section: {section.DisplayName}.");
76 | return true;
77 | }
78 | }
79 | return null;
80 | }
81 |
82 | static void RemoveCall(MethodDef method) {
83 | var instructions = method.Body.Instructions;
84 | foreach (var instr in instructions) {
85 | if (instr.OpCode != OpCodes.Call)
86 | continue;
87 |
88 | var tamperMethod = instr.Operand as MethodDef;
89 | if (tamperMethod == null)
90 | continue;
91 | if (!tamperMethod.DeclaringType.IsGlobalModuleType)
92 | continue;
93 |
94 | const MethodAttributes attributes = MethodAttributes.Assembly | MethodAttributes.Static |
95 | MethodAttributes.HideBySig;
96 | if (tamperMethod.Attributes != attributes)
97 | continue;
98 | if (tamperMethod.CodeType != MethodImplAttributes.IL)
99 | continue;
100 |
101 | if (tamperMethod.ReturnType.ElementType != ElementType.Void)
102 | continue;
103 |
104 | // The decrypter method just have 1 call to VirtualProtect
105 | if (tamperMethod.FindInstructionsNumber(OpCodes.Call, "(System.IntPtr,System.UInt32,System.UInt32,System.UInt32&)") != 1)
106 | continue;
107 | instr.OpCode = OpCodes.Nop;
108 | instr.Operand = null;
109 | Logger.Verbose("Anti-tamper decrypter call was removed from .cctor.");
110 | return;
111 | }
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/CompressorDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using dnlib.DotNet;
6 | using dnlib.DotNet.Emit;
7 | using dnlib.DotNet.Writer;
8 |
9 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
10 | internal class CompressorDeobfuscator : IDeobfuscator {
11 | readonly List ModuleNames = new List();
12 |
13 | string moduleName;
14 |
15 | public void Log() {
16 | Logger.Success($"Unpacked: Module \"{moduleName}\".");
17 | }
18 |
19 | void PosibleModules() {
20 | // Add here all posible modules if you found a modded ConfuserEx
21 | var modules = new[] {
22 | "koi",
23 | "netmodule"
24 | };
25 | ModuleNames.AddRange(modules);
26 | }
27 |
28 | public bool Deobfuscate(AssemblyManager assemblyManager) {
29 | PosibleModules();
30 |
31 | var module = assemblyManager.Module;
32 |
33 | if (!IsPacked(module))
34 | return false;
35 |
36 | var resources = module.Resources;
37 |
38 | var newEntryPoint = ResolveEntryPoint(assemblyManager.Module);
39 | if (newEntryPoint == 0)
40 | Logger.Exception(
41 | new Exception(
42 | "Error searching entry point token, maybe the file is protected.\nOpen the NoFuserEx.exe without arguments for see all help."));
43 |
44 | ModifyMethod(module.EntryPoint);
45 |
46 | using (var stream = new MemoryStream()) {
47 | module.Write(stream, new ModuleWriterOptions { Logger = DummyLogger.NoThrowInstance });
48 | var asm = Assembly.Load(stream.ToArray());
49 | var method = asm.ManifestModule.ResolveMethod(module.EntryPoint.MDToken.ToInt32());
50 | var moduleDecrypted = (byte[])method.Invoke(null, new object[1]);
51 | assemblyManager.Module = ModuleDefMD.Load(moduleDecrypted);
52 | Logger.Verbose($"Module decrypted: {assemblyManager.Module.Name}.");
53 | }
54 |
55 | Logger.Verbose("Adding resources to new module...");
56 | foreach (var resource in resources) {
57 | assemblyManager.Module.Resources.Add(resource);
58 | Logger.VeryVerbose($"Resource \"{resource.Name}\" added to new module.");
59 | }
60 |
61 | Logger.Verbose("Setting new entry point...");
62 | assemblyManager.Module.EntryPoint = assemblyManager.Module.ResolveMethod(new MDToken(newEntryPoint).Rid);
63 |
64 | return true;
65 | }
66 |
67 | bool IsPacked(ModuleDefMD module) {
68 | // Thanks to 0xd4d https://github.com/0xd4d/dnlib/issues/72
69 | for (uint rid = 1; rid <= module.MetaData.TablesStream.FileTable.Rows; rid++) {
70 | var row = module.TablesStream.ReadFileRow(rid);
71 | var name = module.StringsStream.ReadNoNull(row.Name);
72 | if (!ModuleNames.Contains(name)) continue;
73 | moduleName = name;
74 | Logger.Verbose($"Is packed with ConfuserEx, module packed: {name}.");
75 | return true;
76 | }
77 | Logger.Verbose("Compressor not detected.");
78 | return false;
79 | }
80 |
81 | static uint ResolveEntryPoint(ModuleDefMD module) {
82 | Logger.Verbose("Resolving entry point of module encrypted...");
83 | var instructions = module.EntryPoint.Body.Instructions;
84 |
85 | for (var i = 0; i < instructions.Count; i++) {
86 | if (instructions[i].OpCode != OpCodes.Callvirt)
87 | continue;
88 |
89 | var operand = instructions[i].Operand.ToString();
90 | if (!operand.Contains("System.Reflection.Module::ResolveSignature(System.Int32)"))
91 | continue;
92 |
93 | for (var ii = i; ii >= 0; ii--) {
94 | if (!instructions[ii].IsLdcI4())
95 | continue;
96 | var signatureToken = (uint)instructions[ii].GetLdcI4Value();
97 | var signature = module.ReadBlob(signatureToken);
98 | var entryPoint = (uint)(signature[0] | signature[1] << 8 | signature[2] << 16 | signature[3] << 24);
99 | Logger.Verbose($"Entry point of module decrypted: {entryPoint}");
100 | return entryPoint;
101 | }
102 | }
103 | Logger.Exception(new Exception("Error resolving entry point."));
104 | return 0;
105 | }
106 |
107 | static void ModifyMethod(MethodDef method) {
108 | var corLib = method.Module.Import(typeof(byte[]));
109 |
110 | method.ReturnType = corLib.ToTypeSig();
111 |
112 | var instructions = method.Body.Instructions;
113 | for (var i = 0; i < instructions.Count; i++) {
114 | if (instructions[i].OpCode != OpCodes.Call)
115 | continue;
116 |
117 | var operand = instructions[i].Operand.ToString();
118 | if (!operand.Contains("System.Runtime.InteropServices.GCHandle::get_Target()"))
119 | continue;
120 |
121 | instructions.Insert(i + 1, Instruction.Create(OpCodes.Castclass, corLib));
122 | instructions.Insert(i + 2, Instruction.Create(OpCodes.Ret));
123 | }
124 | Logger.Verbose($"Method \"{method.Name}\" adjusted to invoke.");
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/ByteArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class ByteArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal ByteArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Byte array decrypted: {result.Length} bytes.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(byte[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Byte),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I1));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/CharArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class CharArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal CharArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Char array decrypted: {result.Length} chars.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(char[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Char),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I1));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/ConstantsDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using dnlib.DotNet;
4 | using dnlib.DotNet.Emit;
5 | using MethodAttributes = dnlib.DotNet.MethodAttributes;
6 |
7 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
8 | internal class ConstantsDeobfuscator : IDeobfuscator {
9 | readonly List decrypterMethods = new List();
10 | int decryptedConstants;
11 | int detectedConstants;
12 |
13 | public void Log() {
14 | Logger.Success($"Decrypted: {decryptedConstants}/{detectedConstants} constant(s).");
15 | }
16 |
17 | void FindDecrypterMethods(ModuleDef module) {
18 | foreach (var method in module.GlobalType.Methods) {
19 | const MethodAttributes attributes =
20 | MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig;
21 | if (method.Attributes != attributes)
22 | continue;
23 |
24 | if (method.GenericParameters.Count != 1)
25 | continue;
26 | if (method.Parameters.Count != 1)
27 | continue;
28 | if (method.Parameters[0].Type.ElementType != ElementType.U4)
29 | continue;
30 | if (method.FindInstructionsNumber(OpCodes.Call,
31 | "System.Buffer::BlockCopy(System.Array,System.Int32,System.Array,System.Int32,System.Int32)") != 2)
32 | continue;
33 | if (method.FindInstructionsNumber(OpCodes.Call,
34 | "System.Array::CreateInstance(System.Type,System.Int32)") != 1)
35 | continue;
36 | if (method.FindInstructionsNumber(OpCodes.Callvirt,
37 | "System.Text.Encoding::GetString(System.Byte[],System.Int32,System.Int32)") != 1)
38 | continue;
39 |
40 | decrypterMethods.Add(method);
41 | Logger.Verbose($"Constant decrypter method detected: {method.FullName}.");
42 | }
43 | Logger.Verbose($"Decrypter methods detected: {decrypterMethods.Count}.");
44 | }
45 |
46 | public bool Deobfuscate(AssemblyManager assemblyManager) {
47 | var module = assemblyManager.Module;
48 | FindDecrypterMethods(module);
49 |
50 | if (decrypterMethods.Count == 0) {
51 | Logger.Verbose("Constants protection not detected.");
52 | return false;
53 | }
54 |
55 | foreach (var type in module.GetTypes()) {
56 | foreach (var method in type.Methods) {
57 | if (!method.HasBody)
58 | continue;
59 |
60 | var instructions = method.Body.Instructions;
61 | for (var i = 0; i < instructions.Count; i++) {
62 | if (instructions[i].OpCode != OpCodes.Call)
63 | continue;
64 |
65 | var decrypterMethod = (instructions[i].Operand as MethodSpec).ResolveMethodDef();
66 | if (decrypterMethod == null)
67 | continue;
68 |
69 | if (!decrypterMethod.DeclaringType.IsGlobalModuleType)
70 | continue;
71 | if (!decrypterMethods.Contains(decrypterMethod))
72 | continue;
73 | detectedConstants++;
74 |
75 | DecrypterBase decrypter = null;
76 | if (instructions[i].Operand.ToString().Contains("System.String"))
77 | decrypter = new StringDecrypter(method, decrypterMethod, i);
78 |
79 | // I know that this is a shit but for now I not found another way :(
80 | else if (instructions[i].Operand.ToString().Contains("System.Byte[]"))
81 | decrypter = new ByteArrayDecrypter(method, decrypterMethod, i);
82 | else if (instructions[i].Operand.ToString().Contains("System.SByte[]"))
83 | decrypter = new SByteArrayDecrypter(method, decrypterMethod, i);
84 | else if (instructions[i].Operand.ToString().Contains("System.Char[]"))
85 | decrypter = new CharArrayDecrypter(method, decrypterMethod, i);
86 | else if (instructions[i].Operand.ToString().Contains("System.Int16[]"))
87 | decrypter = new ShortArrayDecrypter(method, decrypterMethod, i);
88 | else if (instructions[i].Operand.ToString().Contains("System.UInt16[]"))
89 | decrypter = new UShortArrayDecrypter(method, decrypterMethod, i);
90 | else if (instructions[i].Operand.ToString().Contains("System.Int32[]"))
91 | decrypter = new IntArrayDecrypter(method, decrypterMethod, i);
92 | else if (instructions[i].Operand.ToString().Contains("System.UInt32[]"))
93 | decrypter = new UIntArrayDecrypter(method, decrypterMethod, i);
94 | else if (instructions[i].Operand.ToString().Contains("System.Int64[]"))
95 | decrypter = new LongArrayDecrypter(method, decrypterMethod, i);
96 | else if (instructions[i].Operand.ToString().Contains("System.UInt64[]"))
97 | decrypter = new ULongArrayDecrypter(method, decrypterMethod, i);
98 | else if (instructions[i].Operand.ToString().Contains("System.Single[]"))
99 | decrypter = new FloatArrayDecrypter(method, decrypterMethod, i);
100 | else if (instructions[i].Operand.ToString().Contains("System.Double[]"))
101 | decrypter = new DoubleArrayDecrypter(method, decrypterMethod, i);
102 |
103 | if (decrypter != null && decrypter.Decrypt())
104 | Logger.Verbose($"Constants decrypted: {decryptedConstants++}");
105 |
106 | }
107 | }
108 | }
109 | if (detectedConstants == decryptedConstants)
110 | RemoveInitializeCall(module);
111 |
112 | return detectedConstants > 0;
113 | }
114 |
115 | void RemoveInitializeCall(ModuleDef module) {
116 | var cctor = module.GlobalType.FindStaticConstructor();
117 | var instructions = cctor.Body.Instructions;
118 | foreach (var instruction in instructions) {
119 | if (instruction.OpCode != OpCodes.Call)
120 | continue;
121 |
122 | var initializeMethod = instruction.Operand as MethodDef;
123 | if (initializeMethod == null)
124 | continue;
125 | if (!initializeMethod.DeclaringType.IsGlobalModuleType)
126 | continue;
127 |
128 | const MethodAttributes attributes =
129 | MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig;
130 | if (initializeMethod.Attributes != attributes)
131 | continue;
132 |
133 | if (initializeMethod.ReturnType.ElementType != ElementType.Void)
134 | continue;
135 | if (initializeMethod.HasParamDefs)
136 | continue;
137 |
138 | if (initializeMethod.FindInstructionsNumber(OpCodes.Call,
139 | "System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") != 1)
140 | continue;
141 |
142 | var field = FindArrayField(module);
143 | var operand = (from instr in initializeMethod.Body.Instructions
144 | where instr.OpCode == OpCodes.Stsfld
145 | let fieldArray = instr.Operand as FieldDef
146 | where fieldArray != null
147 | where field == fieldArray
148 | select instr.Operand.ToString()).FirstOrDefault();
149 |
150 | if (initializeMethod.FindInstructionsNumber(OpCodes.Stsfld, operand) != 1)
151 | continue;
152 |
153 | instruction.OpCode = OpCodes.Nop;
154 | instruction.Operand = null;
155 | Logger.Verbose("Removed constans initialize call.");
156 | }
157 | }
158 |
159 | static FieldDef FindArrayField(ModuleDef module) {
160 | foreach (var field in module.GlobalType.Fields) {
161 | const FieldAttributes attributes = FieldAttributes.Assembly | FieldAttributes.Static;
162 | if (field.Attributes != attributes)
163 | continue;
164 | if (!field.DeclaringType.IsGlobalModuleType)
165 | continue;
166 | if (field.FieldType.ElementType != ElementType.SZArray)
167 | continue;
168 | if (field.FieldType.FullName != "System.Byte[]")
169 | continue;
170 |
171 | return field;
172 | }
173 | return null;
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/DecrypterBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Reflection;
5 | using dnlib.DotNet;
6 | using dnlib.DotNet.Emit;
7 | using dnlib.DotNet.Writer;
8 |
9 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
10 | abstract class DecrypterBase {
11 | internal abstract bool Decrypt();
12 |
13 | static Assembly assembly;
14 | protected T MethodInvoker(MethodDef decrypterMethod, uint value) {
15 | if (assembly == null)
16 | LoadAssembly(decrypterMethod.Module);
17 | if (assembly.ManifestModule.ScopeName != decrypterMethod.Module.FullName)
18 | LoadAssembly(decrypterMethod.Module);
19 |
20 | if (assembly == null)
21 | Logger.Exception(new Exception("Error loading assembly."));
22 |
23 | var method = (MethodInfo)assembly.ManifestModule.ResolveMethod(decrypterMethod.MDToken.ToInt32());
24 |
25 | var result = method.MakeGenericMethod(typeof(T)).Invoke(null, new object[] { value });
26 | return (T)result;
27 | }
28 |
29 | static void LoadAssembly(ModuleDef module) {
30 | using (var stream = new MemoryStream()) {
31 | module.Write(stream, new ModuleWriterOptions { Logger = DummyLogger.NoThrowInstance });
32 | assembly = Assembly.Load(stream.ToArray());
33 | if (assembly == null)
34 | Logger.Exception(new Exception("Error loading assembly for invoke the constants."));
35 | }
36 | }
37 |
38 | protected static Instruction GetValueDecrypter(IList instructions, int index) {
39 | for (var i = index; i >= 0; i--) {
40 | if (!instructions[i].IsLdcI4())
41 | continue;
42 | return instructions[i];
43 | }
44 | return null;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/DoubleArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class DoubleArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal DoubleArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Double array decrypted: {result.Length} doubles.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(double[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Double),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.Create(OpCodes.Ldc_R8, array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_R8));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/FloatArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class FloatArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal FloatArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Float array decrypted: {result.Length} floats.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(float[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Single),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.Create(OpCodes.Ldc_R4, array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_R4));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/IntArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class IntArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal IntArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Int array decrypted: {result.Length} ints.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(int[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Int32),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I4));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/LongArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class LongArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal LongArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Long array decrypted: {result.Length} longs.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(long[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Int64),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.Create(OpCodes.Ldc_I8, array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I8));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/SByteArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class SByteArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal SByteArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"SByte array decrypted: {result.Length} sbytes.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(sbyte[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.SByte),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I1));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/ShortArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class ShortArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal ShortArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"Short array decrypted: {result.Length} shorts.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(short[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.Int16),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I2));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/StringDecrypter.cs:
--------------------------------------------------------------------------------
1 | using dnlib.DotNet;
2 | using dnlib.DotNet.Emit;
3 |
4 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
5 | class StringDecrypter : DecrypterBase {
6 | readonly MethodDef method;
7 | readonly MethodDef decrypterMethod;
8 | readonly int index;
9 | internal StringDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
10 | this.method = method;
11 | this.decrypterMethod = decrypterMethod;
12 | this.index = index;
13 | }
14 |
15 | internal override bool Decrypt() {
16 | var instructions = method.Body.Instructions;
17 | var valueDecrypter = GetValueDecrypter(instructions, index);
18 | var result = MethodInvoker(decrypterMethod, (uint)valueDecrypter.GetLdcI4Value());
19 |
20 | if (result == null)
21 | return false;
22 |
23 | Logger.VeryVerbose($"String decrypted: {result}");
24 |
25 | valueDecrypter.OpCode = OpCodes.Nop;
26 | valueDecrypter.Operand = null;
27 | instructions[index].OpCode = OpCodes.Ldstr;
28 | instructions[index].Operand = result;
29 | return true;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/UIntArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class UIntArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal UIntArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"UInt array decrypted: {result.Length} uints.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(uint[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.UInt32),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4((int)array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I4));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/ULongArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class ULongArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal ULongArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"ULong array decrypted: {result.Length} ulongs.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(ulong[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.UInt64),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.Create(OpCodes.Ldc_I8, array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I8));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/Constants/UShortArrayDecrypter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using dnlib.DotNet;
3 | using dnlib.DotNet.Emit;
4 |
5 | namespace NoFuserEx.Deobfuscator.Deobfuscators.Constants {
6 | class UShortArrayDecrypter : DecrypterBase {
7 | readonly MethodDef decrypterMethod;
8 | readonly MethodDef method;
9 | readonly int index;
10 |
11 | internal UShortArrayDecrypter(MethodDef method, MethodDef decrypterMethod, int index) {
12 | this.method = method;
13 | this.decrypterMethod = decrypterMethod;
14 | this.index = index;
15 | }
16 |
17 | internal override bool Decrypt() {
18 | var instructions = method.Body.Instructions;
19 | var valueDecrypter = GetValueDecrypter(instructions, index);
20 | var result = MethodInvoker(decrypterMethod,
21 | (uint)valueDecrypter.GetLdcI4Value());
22 | if (result == null)
23 | return false;
24 |
25 | Logger.VeryVerbose($"UShort array decrypted: {result.Length} ushorts.");
26 |
27 | valueDecrypter.OpCode = OpCodes.Nop;
28 | valueDecrypter.Operand = null;
29 | var decrypterInstruction = instructions[index];
30 | var local = CreateArray(method, index, result);
31 | decrypterInstruction.OpCode = OpCodes.Ldloc;
32 | decrypterInstruction.Operand = local;
33 | return true;
34 | }
35 |
36 | static Local CreateArray(MethodDef method, int index, IList array) {
37 | var corLib = method.Module.ImportAsTypeSig(typeof(ushort[]));
38 | var local = method.Body.Variables.Add(new Local(corLib));
39 | var instructions = method.Body.Instructions;
40 |
41 | var list = new List {
42 | Instruction.CreateLdcI4(array.Count),
43 | Instruction.Create(OpCodes.Newarr, method.Module.CorLibTypes.UInt16),
44 | Instruction.Create(OpCodes.Stloc, local)
45 | };
46 | for (var i = 0; i < array.Count; i++) {
47 | list.Add(Instruction.Create(OpCodes.Ldloc, local));
48 | list.Add(Instruction.CreateLdcI4(i));
49 | list.Add(Instruction.CreateLdcI4(array[i]));
50 | list.Add(Instruction.Create(OpCodes.Stelem_I2));
51 | }
52 |
53 | for (var i = 0; i < list.Count; i++) {
54 | instructions.Insert(index + i, list[i]);
55 | }
56 | return local;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/ProxyDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using dnlib.DotNet;
4 | using dnlib.DotNet.Emit;
5 |
6 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
7 | internal class ProxyDeobfuscator : IDeobfuscator {
8 | readonly List junkMethods = new List();
9 | int proxyFixed;
10 | int removedJunkMethods;
11 |
12 | public void Log() {
13 | Logger.Success($"Fixed: {proxyFixed} proxy(s).");
14 | if (removedJunkMethods > 0)
15 | Logger.Success($"Removed: {removedJunkMethods} junk method(s).");
16 | }
17 |
18 | public bool Deobfuscate(AssemblyManager assemblyManager) {
19 | foreach (var typeDef in assemblyManager.Module.GetTypes())
20 | foreach (var methodDef in typeDef.Methods) {
21 | if (!methodDef.HasBody)
22 | continue;
23 |
24 | var instructions = methodDef.Body.Instructions;
25 | foreach (var instruction in instructions) {
26 | if (!instruction.OpCode.Equals(OpCodes.Call))
27 | continue;
28 |
29 | var operandAsMethodDef = instruction.Operand as MethodDef;
30 | if (operandAsMethodDef == null)
31 | continue;
32 |
33 | const MethodAttributes attributes = MethodAttributes.PrivateScope | MethodAttributes.Static;
34 | if (operandAsMethodDef.Attributes != attributes)
35 | continue;
36 | if (operandAsMethodDef.DeclaringType != typeDef)
37 | continue;
38 |
39 | OpCode opCodeProxy;
40 | var operandProxy = GetProxyValues(operandAsMethodDef, out opCodeProxy);
41 | if (opCodeProxy == null || operandProxy == null)
42 | continue;
43 | instruction.OpCode = opCodeProxy;
44 | instruction.Operand = operandProxy;
45 | proxyFixed++;
46 | if (!junkMethods.Contains(operandAsMethodDef))
47 | junkMethods.Add(operandAsMethodDef);
48 | }
49 | }
50 | if (proxyFixed == 0)
51 | return false;
52 |
53 | if (!Options.NoRemoveJunkMethods)
54 | RemoveJunkMethods();
55 |
56 | return true;
57 | }
58 |
59 | static object GetProxyValues(MethodDef method, out OpCode opCode) {
60 | var instructions = method.Body.Instructions.ToArray();
61 | var validInstruction = instructions.Length - 2;
62 | opCode = null;
63 | if (!(instructions[validInstruction].OpCode.Equals(OpCodes.Newobj) ||
64 | instructions[validInstruction].OpCode.Equals(OpCodes.Call) ||
65 | instructions[validInstruction].OpCode.Equals(OpCodes.Callvirt)))
66 | return null;
67 | if (instructions[validInstruction + 1].OpCode.Code != Code.Ret)
68 | return null;
69 | if (instructions.Length != method.Parameters.Count + 2)
70 | return null;
71 | opCode = instructions[validInstruction].OpCode;
72 | return instructions[validInstruction].Operand;
73 | }
74 |
75 | void RemoveJunkMethods() {
76 | for (var i = 0; i < junkMethods.Count; i++) {
77 | junkMethods[i].DeclaringType.Remove(junkMethods[i]);
78 | removedJunkMethods++;
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/Deobfuscators/ResourcesDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Linq;
3 | using System.Reflection;
4 | using dnlib.DotNet;
5 | using dnlib.DotNet.Emit;
6 | using dnlib.DotNet.Writer;
7 | using FieldAttributes = dnlib.DotNet.FieldAttributes;
8 | using MethodAttributes = dnlib.DotNet.MethodAttributes;
9 |
10 | namespace NoFuserEx.Deobfuscator.Deobfuscators {
11 | internal class ResourcesDeobfuscator : IDeobfuscator {
12 | int resourcesDecrypted;
13 | int totalResources;
14 |
15 | public void Log() {
16 | Logger.Success($"Decrypted: {resourcesDecrypted}/{totalResources} resource(s).");
17 | }
18 |
19 | public bool Deobfuscate(AssemblyManager assemblyManager) {
20 | var module = assemblyManager.Module;
21 |
22 | var decrypterMethod = GetDecrypterMethod(module);
23 | if (decrypterMethod == null)
24 | return false;
25 | var cctor = module.GlobalType.FindStaticConstructor();
26 | foreach (var instr in cctor.Body.Instructions) {
27 | if (instr.OpCode != OpCodes.Call || instr.Operand as MethodDef != decrypterMethod)
28 | continue;
29 | instr.OpCode = OpCodes.Nop;
30 | instr.Operand = null;
31 | }
32 |
33 | ModifyMethod(decrypterMethod);
34 |
35 | using (var stream = new MemoryStream()) {
36 | module.Write(stream, new ModuleWriterOptions { Logger = DummyLogger.NoThrowInstance });
37 | var asm = Assembly.Load(stream.ToArray());
38 | var method = asm.ManifestModule.ResolveMethod(decrypterMethod.MDToken.ToInt32());
39 | var moduleDecrypted = (byte[])method.Invoke(null, null);
40 | var resources = ModuleDefMD.Load(moduleDecrypted).Resources;
41 |
42 | totalResources = module.Resources.Count;
43 |
44 | foreach (var resource in resources) {
45 | if (!module.Resources.Remove(module.Resources.Find(resource.Name)))
46 | continue;
47 | module.Resources.Add(resource);
48 | resourcesDecrypted++;
49 | }
50 |
51 | RemoveMethod(decrypterMethod);
52 | }
53 |
54 | return totalResources > 0;
55 | }
56 |
57 | static MethodDef GetDecrypterMethod(ModuleDef module) {
58 | var cctor = module.GlobalType.FindStaticConstructor();
59 | var instructions = cctor.Body.Instructions;
60 | foreach (var instruction in instructions) {
61 | if (instruction.OpCode != OpCodes.Call)
62 | continue;
63 |
64 | var initializeMethod = instruction.Operand as MethodDef;
65 | if (initializeMethod == null)
66 | continue;
67 | if (!initializeMethod.DeclaringType.IsGlobalModuleType)
68 | continue;
69 |
70 | const MethodAttributes attributes =
71 | MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig;
72 | if (initializeMethod.Attributes != attributes)
73 | continue;
74 |
75 | if (initializeMethod.ReturnType.ElementType != ElementType.Void)
76 | continue;
77 | if (initializeMethod.HasParamDefs)
78 | continue;
79 |
80 | if (initializeMethod.FindInstructionsNumber(OpCodes.Call,
81 | "System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") != 1)
82 | continue;
83 |
84 | var field = FindAssemblyField(module);
85 | var operand = (from instr in initializeMethod.Body.Instructions
86 | where instr.OpCode == OpCodes.Stsfld
87 | let fieldArray = instr.Operand as FieldDef
88 | where fieldArray != null
89 | where field == fieldArray
90 | select instr.Operand.ToString()).FirstOrDefault();
91 |
92 | if (initializeMethod.FindInstructionsNumber(OpCodes.Stsfld, operand) != 1)
93 | continue;
94 |
95 | return initializeMethod;
96 | }
97 | return null;
98 | }
99 |
100 | static FieldDef FindAssemblyField(ModuleDef module) {
101 | foreach (var field in module.GlobalType.Fields) {
102 | const FieldAttributes attributes = FieldAttributes.Assembly | FieldAttributes.Static;
103 | if (field.Attributes != attributes)
104 | continue;
105 | if (!field.DeclaringType.IsGlobalModuleType)
106 | continue;
107 | if (field.FieldType.ElementType != ElementType.Class)
108 | continue;
109 | if (field.FieldType.FullName != "System.Reflection.Assembly")
110 | continue;
111 |
112 | return field;
113 | }
114 | return null;
115 | }
116 |
117 | static void ModifyMethod(MethodDef method) {
118 | var corLib = method.Module.Import(typeof(byte[]));
119 |
120 | method.ReturnType = corLib.ToTypeSig();
121 |
122 | var instructions = method.Body.Instructions;
123 | foreach (var instruction in instructions) {
124 | if (instruction.OpCode != OpCodes.Call)
125 | continue;
126 |
127 | var operand = instruction.Operand.ToString();
128 | if (!operand.Contains("System.Reflection.Assembly::Load(System.Byte[])"))
129 | continue;
130 |
131 | instruction.OpCode = OpCodes.Ret;
132 | instruction.Operand = null;
133 | }
134 | Logger.Verbose($"Method \"{method.Name}\" adjusted to invoke.");
135 | }
136 |
137 | static void RemoveMethod(MethodDef method) {
138 | var body = new CilBody {
139 | Instructions = { Instruction.Create(OpCodes.Ldnull), Instruction.Create(OpCodes.Ret) }
140 | };
141 | method.Body = body;
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/IDeobfuscator.cs:
--------------------------------------------------------------------------------
1 | namespace NoFuserEx.Deobfuscator {
2 | internal interface IDeobfuscator {
3 | void Log();
4 | bool Deobfuscate(AssemblyManager assemblyManager);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/NoFuserEx/NoFuserEx/Deobfuscator/MemberCloner.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Thanks to yck1509
3 | */
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using dnlib.DotNet;
9 | using dnlib.DotNet.Emit;
10 |
11 | namespace NoFuserEx.Deobfuscator {
12 | class MemberCloner {
13 | internal static TypeDef CloneTypeDef(TypeDef originalType) {
14 | var importer = new Importer(originalType.Module, ImporterOptions.TryToUseTypeDefs);
15 | var newType = Clone(originalType);
16 | Copy(originalType, newType, importer, true);
17 | return newType;
18 | }
19 |
20 | static TypeDefUser Clone(TypeDef originalType) {
21 | var ret = new TypeDefUser(originalType.Namespace, originalType.Name) { Attributes = originalType.Attributes };
22 |
23 | if (originalType.ClassLayout != null)
24 | ret.ClassLayout = new ClassLayoutUser(originalType.ClassLayout.PackingSize, originalType.ClassSize);
25 |
26 | foreach (var genericParam in originalType.GenericParameters)
27 | ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-"));
28 |
29 | foreach (var nestedType in originalType.NestedTypes)
30 | ret.NestedTypes.Add(Clone(nestedType));
31 |
32 | foreach (var method in originalType.Methods)
33 | ret.Methods.Add(Clone(method));
34 |
35 | foreach (var field in originalType.Fields)
36 | ret.Fields.Add(Clone(field));
37 |
38 | return ret;
39 | }
40 |
41 | static MethodDefUser Clone(MethodDef originalMethod) {
42 | var ret = new MethodDefUser(originalMethod.Name, null, originalMethod.ImplAttributes, originalMethod.Attributes);
43 |
44 | foreach (var genericParam in originalMethod.GenericParameters)
45 | ret.GenericParameters.Add(new GenericParamUser(genericParam.Number, genericParam.Flags, "-"));
46 |
47 | return ret;
48 | }
49 |
50 | static FieldDefUser Clone(FieldDef originalField) {
51 | return new FieldDefUser(originalField.Name, null, originalField.Attributes);
52 | }
53 |
54 | static void Copy(TypeDef originalType, TypeDef newType, Importer ctx, bool copySelf) {
55 | if (copySelf)
56 | CopyTypeDef(originalType, newType, ctx);
57 |
58 | foreach (var nestedType in originalType.NestedTypes)
59 | Copy(nestedType, newType, ctx, true);
60 |
61 | foreach (var method in originalType.Methods) {
62 | CopyMethodDef(method, newType, ctx);
63 | }
64 |
65 | foreach (var field in originalType.Fields)
66 | CopyFieldDef(field, newType, ctx);
67 | }
68 |
69 | static void CopyTypeDef(TypeDef originalType, TypeDef newType, Importer ctx) {
70 | newType.BaseType = (ITypeDefOrRef)ctx.Import(originalType.BaseType);
71 | foreach (var iface in originalType.Interfaces)
72 | newType.Interfaces.Add(new InterfaceImplUser((ITypeDefOrRef)ctx.Import(iface.Interface)));
73 | }
74 |
75 | static void CopyMethodDef(MethodDef originalMethod, TypeDef newType, Importer ctx) {
76 | var newMethod = newType.FindMethod(originalMethod.Name);
77 |
78 | // I don't know why but if declaring type is a nested type the dnlib can't found them. :/
79 | // Then we go to do it manually
80 | if (newMethod == null) {
81 | foreach (var type in newType.GetTypes()) {
82 | foreach (var method in type.Methods) {
83 | if (method.Name == originalMethod.Name)
84 | newMethod = method;
85 | }
86 | }
87 | }
88 |
89 | if (newMethod == null)
90 | Logger.Exception(new Exception($"Error cloning the method: {originalMethod.Name}"));
91 |
92 | newMethod.Signature = ctx.Import(originalMethod.Signature);
93 | newMethod.Parameters.UpdateParameterTypes();
94 |
95 | if (originalMethod.ImplMap != null)
96 | newMethod.ImplMap = new ImplMapUser(new ModuleRefUser(originalMethod.Module, originalMethod.ImplMap.Module.Name), originalMethod.ImplMap.Name, originalMethod.ImplMap.Attributes);
97 |
98 | foreach (var ca in originalMethod.CustomAttributes)
99 | newMethod.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType)ctx.Import(ca.Constructor)));
100 |
101 | if (!originalMethod.HasBody) return;
102 | newMethod.Body = new CilBody(originalMethod.Body.InitLocals, new List(),
103 | new List(), new List()) { MaxStack = originalMethod.Body.MaxStack };
104 |
105 | var bodyMap = new Dictionary