├── .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(); 106 | 107 | foreach (var local in originalMethod.Body.Variables) { 108 | var newLocal = new Local(ctx.Import(local.Type)); 109 | newMethod.Body.Variables.Add(newLocal); 110 | newLocal.Name = local.Name; 111 | newLocal.PdbAttributes = local.PdbAttributes; 112 | 113 | bodyMap[local] = newLocal; 114 | } 115 | 116 | foreach (var instr in originalMethod.Body.Instructions) { 117 | var newInstr = new Instruction(instr.OpCode, instr.Operand) { SequencePoint = instr.SequencePoint }; 118 | 119 | if (newInstr.Operand is IType) 120 | newInstr.Operand = ctx.Import((IType)newInstr.Operand); 121 | 122 | else if (newInstr.Operand is IMethod) 123 | newInstr.Operand = ctx.Import((IMethod)newInstr.Operand); 124 | 125 | else if (newInstr.Operand is IField) 126 | newInstr.Operand = ctx.Import((IField)newInstr.Operand); 127 | 128 | newMethod.Body.Instructions.Add(newInstr); 129 | bodyMap[instr] = newInstr; 130 | } 131 | 132 | foreach (var instr in newMethod.Body.Instructions) { 133 | if (instr.Operand != null && bodyMap.ContainsKey(instr.Operand)) 134 | instr.Operand = bodyMap[instr.Operand]; 135 | 136 | else if (instr.Operand is Instruction[]) 137 | instr.Operand = ((Instruction[])instr.Operand).Select(target => (Instruction)bodyMap[target]).ToArray(); 138 | } 139 | 140 | foreach (var eh in originalMethod.Body.ExceptionHandlers) 141 | newMethod.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType) { 142 | CatchType = eh.CatchType == null ? null : (ITypeDefOrRef)ctx.Import(eh.CatchType), 143 | TryStart = (Instruction)bodyMap[eh.TryStart], 144 | TryEnd = (Instruction)bodyMap[eh.TryEnd], 145 | HandlerStart = (Instruction)bodyMap[eh.HandlerStart], 146 | HandlerEnd = (Instruction)bodyMap[eh.HandlerEnd], 147 | FilterStart = eh.FilterStart == null ? null : (Instruction)bodyMap[eh.FilterStart] 148 | }); 149 | 150 | newMethod.Body.SimplifyMacros(newMethod.Parameters); 151 | } 152 | 153 | static void CopyFieldDef(FieldDef originalField, TypeDef newType, Importer ctx) { 154 | var newField = newType.FindField(originalField.Name); 155 | 156 | // I don't know why but if declaring type is a nested type the dnlib can't found them. :/ 157 | // Then we go to do it manually 158 | // Equals methods 159 | if (newField == null) { 160 | foreach (var type in newType.GetTypes()) { 161 | foreach (var field in type.Fields) { 162 | if (field.Name == originalField.Name) 163 | newField = field; 164 | } 165 | } 166 | } 167 | 168 | newField.Signature = ctx.Import(originalField.Signature); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Deobfuscator/Utils.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | 4 | namespace NoFuserEx.Deobfuscator { 5 | internal static class Utils { 6 | internal static int FindInstructionsNumber(this MethodDef method, OpCode opCode, object operand) { 7 | var num = 0; 8 | foreach (var instruction in method.Body.Instructions) { 9 | if (instruction.OpCode != opCode) 10 | continue; 11 | if (operand is int) { 12 | var value = instruction.GetLdcI4Value(); 13 | if (value == (int)operand) 14 | num++; 15 | } 16 | else if (operand is string) { 17 | var value = instruction.Operand.ToString(); 18 | if (value.Contains(operand.ToString())) 19 | num++; 20 | } 21 | } 22 | return num; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace NoFuserEx { 5 | internal class Logger { 6 | internal static void Information() { 7 | Console.Title = "NoFuserEx v1.1"; 8 | Console.ForegroundColor = ConsoleColor.Red; 9 | const string text = "_____ __ __________ __________ "; 10 | const string text1 = "___ | / /________ ____/___ _______________________ ____/___ __ "; 11 | const string text2 = @"__ |/ /_ __ \_ /_ _ / / /_ ___/ _ \_ ___/_ __/ __ |/_/"; 12 | const string text3 = "_ /| / / /_/ / __/ / /_/ /_(__ )/ __/ / _ /___ __> < "; 13 | const string text4 = @"/_/ |_/ \____//_/ \__,_/ /____/ \___//_/ /_____/ /_/|_| "; 14 | const string text5 = "[ NoFuserEx - v1.1 ]"; 15 | const string text6 = "- By CodeShark -"; 16 | CenterWrite(text); 17 | CenterWrite(text1); 18 | CenterWrite(text2); 19 | CenterWrite(text3); 20 | CenterWrite(text4); 21 | CenterWrite(text5); 22 | CenterWrite(text6); 23 | WriteLine(string.Empty); 24 | Console.ForegroundColor = ConsoleColor.White; 25 | } 26 | 27 | internal static void Help() { 28 | WriteLine(@" 29 | For deobfuscate an assembly protected with any version of ConfuserEx (and some modded too) you just have to drag and drop the file in this .exe. 30 | 31 | Some options that you can use: 32 | * --force-deob for force the deobfuscation. 33 | * --dont-unpack for don't unpack the assembly. 34 | * --dont-tamper for don't remove anti-tamper. 35 | * --dont-constants for don't decrypt the constants. 36 | * --dont-cflow for don't deobfuscate the control flow. 37 | * --dont-proxy-calls for don't replace the proxy calls. 38 | * --dont-remove-junk-methods for don't remove the junk methods. 39 | * --dont-resources for don't decrypt the protected resources. 40 | * --dont-rename for don't rename the obfuscated names. 41 | * -v for verbose information. 42 | * -vv for very verbose information. 43 | 44 | If something doesn't work properly, you can notify me or fix it yourself. 45 | This is an open-source, if you paid for this, you got ripped off :P"); 46 | WriteLine(string.Empty); 47 | } 48 | 49 | internal static void CenterWrite(string text) { 50 | Write(new string(' ', (Console.WindowWidth - text.Length) / 2)); 51 | WriteLine(text); 52 | } 53 | 54 | internal static void Info(string text) { 55 | Console.ForegroundColor = ConsoleColor.Cyan; 56 | Write("[~] "); 57 | Console.ForegroundColor = ConsoleColor.White; 58 | WriteLine(text); 59 | } 60 | 61 | internal static void Error(string text) { 62 | Console.ForegroundColor = ConsoleColor.Red; 63 | Write(" [-] "); 64 | Console.ForegroundColor = ConsoleColor.White; 65 | WriteLine(text); 66 | } 67 | 68 | internal static void Exclamation(string text) { 69 | Console.ForegroundColor = ConsoleColor.Yellow; 70 | Write(" [!] "); 71 | Console.ForegroundColor = ConsoleColor.White; 72 | WriteLine(text); 73 | } 74 | 75 | internal static void Success(string message) { 76 | Console.ForegroundColor = ConsoleColor.Green; 77 | Write(" [+] "); 78 | Console.ForegroundColor = ConsoleColor.White; 79 | WriteLine(message); 80 | } 81 | 82 | internal static void Exception(Exception exception) { 83 | WriteLine(string.Empty); 84 | WriteLine($"Error message: {exception.Message}"); 85 | if (Options.Verbose) 86 | WriteLine($"Error stack trace: {exception.StackTrace}"); 87 | WriteLine(string.Empty); 88 | throw exception; 89 | } 90 | 91 | internal static void Verbose(string text) { 92 | if (Options.Verbose) 93 | WriteLine(text); 94 | } 95 | 96 | internal static void VeryVerbose(string text) { 97 | if (Options.VeryVerbose) 98 | Verbose(text); 99 | } 100 | 101 | internal static void Write(string text) { 102 | Console.Write(text); 103 | } 104 | 105 | internal static void WriteLine(string text) { 106 | Console.WriteLine(text); 107 | } 108 | 109 | internal static void Exit(bool info = true) { 110 | const string exitMessage = "Press any key to exit..."; 111 | if (IsN00bUser()) { 112 | if (info) 113 | Info(exitMessage); 114 | else 115 | WriteLine(exitMessage); 116 | Console.ReadKey(true); 117 | } 118 | Environment.Exit(0); 119 | } 120 | 121 | // Thanks to 0xd4d 122 | static bool IsN00bUser() { 123 | if (HasEnv("VisualStudioDir")) 124 | return false; 125 | if (HasEnv("SHELL")) 126 | return false; 127 | return HasEnv("windir") && !HasEnv("PROMPT"); 128 | } 129 | 130 | static bool HasEnv(string name) { 131 | return 132 | Environment.GetEnvironmentVariables() 133 | .Keys.OfType() 134 | .Any(env => string.Equals(env, name, StringComparison.OrdinalIgnoreCase)); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/NoFuserEx.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6E8B8F61-E5C3-4ABD-9B8A-8F4FA5777EBB} 8 | Exe 9 | Properties 10 | NoFuserEx 11 | NoFuserEx 12 | v4.0 13 | 512 14 | true 15 | 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | nofuserex icon.ico 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {fdfc1237-143f-4919-8318-4926901f4639} 87 | dnlib 88 | 89 | 90 | 91 | 92 | 93 | 94 | 101 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Options.cs: -------------------------------------------------------------------------------- 1 | namespace NoFuserEx { 2 | internal class Options { 3 | internal static bool ForceDeobfuscation; 4 | internal static bool NoUnpack; 5 | internal static bool NoTamper; 6 | internal static bool NoConstants; 7 | internal static bool NoControlFlow; 8 | internal static bool NoProxyCalls; 9 | internal static bool NoRemoveJunkMethods; 10 | internal static bool NoResources; 11 | internal static bool NoRename; 12 | internal static bool Verbose; 13 | internal static bool VeryVerbose; 14 | 15 | /* Unused at this moment 16 | internal static void RestoreOptions() { 17 | ForceDeobfuscation = false; 18 | NoUnpack = false; 19 | NoTamper = false; 20 | NoConstants = false; 21 | NoControlFlow = false; 22 | NoProxyCalls = false; 23 | NoRemoveJunkMethods = false; 24 | NoResources = false; 25 | NoRename = false; 26 | Verbose = false; 27 | VeryVerbose = false; 28 | }*/ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | 6 | namespace NoFuserEx { 7 | class Program { 8 | static void Main(string[] args) { 9 | Logger.Information(); 10 | 11 | if (args.Length == 0) { 12 | Logger.Help(); 13 | Logger.Exit(false); 14 | } 15 | 16 | var files = GetOptions(args); 17 | foreach (var file in files) { 18 | var stopWatch = new Stopwatch(); 19 | stopWatch.Start(); 20 | 21 | var assemblyManager = new AssemblyManager(file); 22 | assemblyManager.LoadAssembly(); 23 | 24 | Logger.Info($"File queue: {files.IndexOf(file) + 1}/{files.Count}"); 25 | Logger.WriteLine(string.Empty); 26 | 27 | var deobfuscator = new Deobfuscator.DeobfuscatorManager(assemblyManager); 28 | deobfuscator.Start(); 29 | assemblyManager.SaveAssembly(); 30 | 31 | stopWatch.Stop(); 32 | Logger.Info( 33 | $"Elapsed time: {stopWatch.Elapsed.Minutes}:{stopWatch.Elapsed.Seconds}:{stopWatch.Elapsed.Milliseconds}"); 34 | Logger.WriteLine(string.Empty); 35 | } 36 | 37 | Logger.Exit(); 38 | } 39 | 40 | static List GetOptions(IEnumerable args) { 41 | var files = new List(); 42 | Logger.Verbose("Checking options..."); 43 | foreach (var arg in args) { 44 | switch (arg) { 45 | case "--force-deob": 46 | Logger.VeryVerbose("Force deobfuscation option detected."); 47 | Options.ForceDeobfuscation = true; 48 | break; 49 | case "--dont-unpack": 50 | Logger.VeryVerbose("Don't unpack module option detected."); 51 | Options.NoUnpack = true; 52 | break; 53 | case "--dont-tamper": 54 | Logger.VeryVerbose("Don't decrypt anti-tampering option detected."); 55 | Options.NoTamper = true; 56 | break; 57 | case "--dont-constants": 58 | Logger.VeryVerbose("Don't decrypt constants option detected."); 59 | Options.NoConstants = true; 60 | break; 61 | case "--dont-cflow": 62 | Logger.VeryVerbose("Don't deobfuscate control flow option detected."); 63 | Options.NoControlFlow = true; 64 | break; 65 | case "--dont-proxy-calls": 66 | Logger.VeryVerbose("Don't fix proxy calls option detected."); 67 | Options.NoProxyCalls = true; 68 | break; 69 | case "--dont-remove-junk-methods": 70 | Logger.VeryVerbose("Don't remove junk methods option detected."); 71 | Options.NoRemoveJunkMethods = true; 72 | break; 73 | case "--dont-resources": 74 | Logger.VeryVerbose("Don't decrypt resouces option detected."); 75 | Options.NoResources = true; 76 | break; 77 | case "--dont-rename": 78 | Logger.VeryVerbose("Don't rename option detected."); 79 | Options.NoRename = true; 80 | break; 81 | case "-v": 82 | Options.Verbose = true; 83 | break; 84 | case "-vv": 85 | Options.Verbose = true; 86 | Options.VeryVerbose = true; 87 | break; 88 | default: 89 | if (!File.Exists(arg)) 90 | break; 91 | var extension = Path.GetExtension(arg); 92 | switch (extension) { 93 | case ".exe": 94 | case ".dll": 95 | case ".netmodule": 96 | Logger.VeryVerbose($"Extension file: {extension}"); 97 | files.Add(arg); 98 | break; 99 | default: 100 | throw new Exception("Invalid file extension!"); 101 | } 102 | break; 103 | } 104 | } 105 | return files; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // La información general de un ensamblado se controla mediante el siguiente 5 | // conjunto de atributos. Cambie estos valores de atributo para modificar la información 6 | // asociada con un ensamblado. 7 | [assembly: AssemblyTitle("NoFuserEx")] 8 | [assembly: AssemblyDescription("ConfuserEx deobfuscator")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("NoFuserEx")] 12 | [assembly: AssemblyCopyright("Copyright © CodeShark 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Si establece ComVisible en false, los tipos de este ensamblado no estarán visibles 17 | // para los componentes COM. Si necesita obtener acceso a un tipo de este ensamblado desde 18 | // COM, establezca el atributo ComVisible en true en este tipo. 19 | [assembly: ComVisible(false)] 20 | 21 | // El siguiente GUID sirve como id. de typelib si este proyecto se expone a COM. 22 | [assembly: Guid("6e8b8f61-e5c3-4abd-9b8a-8f4fa5777ebb")] 23 | 24 | // La información de versión de un ensamblado consta de los cuatro valores siguientes: 25 | // 26 | // Versión principal 27 | // Versión secundaria 28 | // Número de compilación 29 | // Revisión 30 | // 31 | // Puede especificar todos los valores o usar los valores predeterminados de número de compilación y de revisión 32 | // mediante el carácter '*', como se muestra a continuación: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.1.0")] 35 | [assembly: AssemblyFileVersion("1.1.0")] 36 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace NoFuserEx { 5 | internal static class Utils { 6 | internal static bool CreateDirectory(string directory) { 7 | if (Directory.Exists(directory)) 8 | return true; 9 | try { 10 | Directory.CreateDirectory(directory); 11 | return true; 12 | } 13 | catch (Exception ex){ 14 | Logger.Exception(ex); 15 | } 16 | return false; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /NoFuserEx/NoFuserEx/nofuserex icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/undebel/NoFuserEx/84a27e5f60695ab6b841fdb5500b3372263a7a1a/NoFuserEx/NoFuserEx/nofuserex icon.ico -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NoFuserEx 2 | NoFuserEx is an open-source deobfuscator for ConfuserEx. 3 | License: MIT. 4 | 5 | ## Usage 6 | Just drag and drop any file(s) onto NoFuserEx.exe. 7 | 8 | ## Supported protections 9 | * Compressor 10 | * Anti-tamper 11 | * Anti-dumper 12 | * Anti-debugger 13 | * Resources 14 | * Constants 15 | * Proxy calls 16 | * Working on more 17 | 18 | ## Special thanks 19 | * 0xd4d - dnlib 20 | * yck1509 - some code 21 | * Alcatraz3222 - because yes :P 22 | --------------------------------------------------------------------------------