From a191156402b07a194d5e0417195ce4c7d3d8bbd3 Mon Sep 17 00:00:00 2001 From: ShiningLea <49339966+AnErrupTion@users.noreply.github.com> Date: Fri, 27 Dec 2019 10:50:49 +0100 Subject: [PATCH] Add files via upload --- App.config | 6 ++ LoGiC.NET.csproj | 77 +++++++++++++++++++ Program.cs | 60 +++++++++++++++ Properties/AssemblyInfo.cs | 36 +++++++++ Protections/IntEncoding.cs | 61 +++++++++++++++ Protections/JunkMethods.cs | 65 ++++++++++++++++ Protections/ProxyAdder.cs | 89 +++++++++++++++++++++ Protections/Renamer.cs | 115 ++++++++++++++++++++++++++++ Protections/StringEncryption.cs | 64 ++++++++++++++++ Utils/Analyzer/DefAnalyzer.cs | 10 +++ Utils/Analyzer/EventDefAnalyzer.cs | 18 +++++ Utils/Analyzer/FieldDefAnalyzer.cs | 20 +++++ Utils/Analyzer/MethodDefAnalyzer.cs | 22 ++++++ Utils/Analyzer/ParameterAnalyzer.cs | 18 +++++ Utils/Analyzer/TypeDefAnalyzer.cs | 22 ++++++ Utils/InjectContext.cs | 77 +++++++++++++++++++ Utils/ProxyExtension.cs | 92 ++++++++++++++++++++++ Utils/Randomizer.cs | 47 ++++++++++++ Utils/Reference.cs | 8 ++ Utils/Watermark.cs | 31 ++++++++ packages.config | 4 + 21 files changed, 942 insertions(+) create mode 100644 App.config create mode 100644 LoGiC.NET.csproj create mode 100644 Program.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 Protections/IntEncoding.cs create mode 100644 Protections/JunkMethods.cs create mode 100644 Protections/ProxyAdder.cs create mode 100644 Protections/Renamer.cs create mode 100644 Protections/StringEncryption.cs create mode 100644 Utils/Analyzer/DefAnalyzer.cs create mode 100644 Utils/Analyzer/EventDefAnalyzer.cs create mode 100644 Utils/Analyzer/FieldDefAnalyzer.cs create mode 100644 Utils/Analyzer/MethodDefAnalyzer.cs create mode 100644 Utils/Analyzer/ParameterAnalyzer.cs create mode 100644 Utils/Analyzer/TypeDefAnalyzer.cs create mode 100644 Utils/InjectContext.cs create mode 100644 Utils/ProxyExtension.cs create mode 100644 Utils/Randomizer.cs create mode 100644 Utils/Reference.cs create mode 100644 Utils/Watermark.cs create mode 100644 packages.config diff --git a/App.config b/App.config new file mode 100644 index 0000000..5754728 --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LoGiC.NET.csproj b/LoGiC.NET.csproj new file mode 100644 index 0000000..1d50679 --- /dev/null +++ b/LoGiC.NET.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {9C7A7E96-A9D9-4D5B-9F70-8B84D1C50B5D} + Exe + LoGiC.NET + LoGiC.NET + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\dnlib.3.3.1\lib\net45\dnlib.dll + + + ..\..\..\..\Desktop\My Projects\Goldfuscator\Goldfuscator Project\Goldfuscator\bin\Debug\SharpConfigParser.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..c3c9eb6 --- /dev/null +++ b/Program.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using dnlib.DotNet; +using dnlib.DotNet.Writer; +using LoGiC.NET.Protections; +using SharpConfigParser; +using LoGiC.NET.Utils; + +namespace LoGiC.NET +{ + class Program + { + public static ModuleDefMD Module { get; set; } + + public static string FileExtension { get; set; } + + public static bool DontRename { get; set; } + public static bool ForceWinForms { get; set; } + + static void Main(string[] args) + { + Console.WriteLine("Drag & drop your file : "); + string path = Console.ReadLine(); + + Console.WriteLine("Preparing obfuscation..."); + Parser p = new Parser() { ConfigFile = "config.txt" }; + ForceWinForms = bool.Parse(p.Read("ForceWinFormsCompatibility").ReadResponse().ReplaceSpaces()); + DontRename = bool.Parse(p.Read("DontRename").ReadResponse().ReplaceSpaces()); + + Module = ModuleDefMD.Load(path); + FileExtension = Path.GetExtension(path); + + Console.WriteLine("Renaming..."); + Renamer.Execute(); + + Console.WriteLine("Adding junk methods..."); + JunkMethods.Execute(); + + Console.WriteLine("Adding proxy calls..."); + ProxyAdder.Execute(); + + Console.WriteLine("Encoding ints..."); + IntEncoding.Execute(); + + Console.WriteLine("Encrypting strings..."); + StringEncryption.Execute(); + + Console.WriteLine("Watermarking..."); + Watermark.AddAttribute(); + + Console.WriteLine("Saving file..."); + ModuleWriterOptions opts = new ModuleWriterOptions(Module) { Logger = DummyLogger.NoThrowInstance }; + Module.Write(@"C:\Users\" + Environment.UserName + @"\Desktop\" + Path.GetFileNameWithoutExtension(path) + "_protected" + + FileExtension, opts); + + Console.WriteLine("Done! Press any key to exit..."); + Console.ReadKey(); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a8f9a2a --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Les informations générales relatives à un assembly dépendent de +// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations +// associées à un assembly. +[assembly: AssemblyTitle("LoGiC.NET")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LoGiC.NET")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly +// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de +// COM, affectez la valeur true à l'attribut ComVisible sur ce type. +[assembly: ComVisible(false)] + +// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM +[assembly: Guid("9c7a7e96-a9d9-4d5b-9f70-8b84d1c50b5d")] + +// Les informations de version pour un assembly se composent des quatre valeurs suivantes : +// +// Version principale +// Version secondaire +// Numéro de build +// Révision +// +// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut +// en utilisant '*', comme indiqué ci-dessous : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Protections/IntEncoding.cs b/Protections/IntEncoding.cs new file mode 100644 index 0000000..5f4f81e --- /dev/null +++ b/Protections/IntEncoding.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using LoGiC.NET.Utils; + +namespace LoGiC.NET.Protections +{ + public class IntEncoding : Randomizer + { + /// + /// The amount of encoded ints. + /// + private static int Amount { get; set; } + + /// + /// Execution of the 'IntEncoding' method. It'll encodes the integers within different methods. + /// Absolute : This method will add Math.Abs(int) before each integer. + /// StringLen : This method will replace each integer by their string equivalent. + /// + public static void Execute() + { + foreach (TypeDef type in Program.Module.Types) + foreach (MethodDef method in type.Methods) + { + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + if (operand <= 0) continue; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction( + Program.Module.Import(typeof(Math).GetMethod("Abs", new Type[] { typeof(int) })))); + ++Amount; + } + } + + foreach (TypeDef type in Program.Module.Types) + foreach (MethodDef method in type.Methods) + { + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + if (operand <= 0) continue; + method.Body.Instructions[i].OpCode = OpCodes.Ldstr; + method.Body.Instructions[i].Operand = GenerateRandomString(operand); + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction( + Program.Module.Import(typeof(string).GetMethod("get_Length")))); + ++Amount; + } + } + + Console.WriteLine($"Encoded {Amount} ints."); + } + } +} diff --git a/Protections/JunkMethods.cs b/Protections/JunkMethods.cs new file mode 100644 index 0000000..f654f51 --- /dev/null +++ b/Protections/JunkMethods.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LoGiC.NET.Utils; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace LoGiC.NET.Protections +{ + public class JunkMethods : Randomizer + { + /// + /// The amount of added junk methods. + /// + private static int Amount { get; set; } + + /// + /// This obfuscation will add random junk methods to make the code harder to decrypt to people if they think the junk methods are actually used. + /// + public static void Execute() + { + foreach (TypeDef type in Program.Module.Types) + { + if (type.IsGlobalModuleType) continue; + foreach (MethodDef _ in type.Methods.ToArray()) + { + MethodDef strings = CreateReturnMethodDef(GenerateRandomString(Next(700, 500)), Program.Module); + MethodDef ints = CreateReturnMethodDef(Next(500, 100), Program.Module); + type.Methods.Add(strings); + ++Amount; + type.Methods.Add(ints); + ++Amount; + } + } + Console.WriteLine($"Added {Amount} junk methods."); + } + + /// + /// The return value for the randomly generated method. It can be an integer or a string. + /// + private static MethodDef CreateReturnMethodDef(object value, ModuleDefMD module) + { + CorLibTypeSig corlib = null; + if (value is int) corlib = module.CorLibTypes.Int32; + else if (value is string) corlib = module.CorLibTypes.String; + + MethodDef newMethod = new MethodDefUser(GenerateRandomString(Next(700, 500)), + MethodSig.CreateStatic(corlib), + MethodImplAttributes.IL | MethodImplAttributes.Managed, + MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig) + { + Body = new CilBody() + }; + if (value is int) + newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, Convert.ToInt32(value))); + else if (value is string) + newMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldstr, value.ToString())); + newMethod.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); + + return newMethod; + } + } +} diff --git a/Protections/ProxyAdder.cs b/Protections/ProxyAdder.cs new file mode 100644 index 0000000..ae2641c --- /dev/null +++ b/Protections/ProxyAdder.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using LoGiC.NET.Utils; + +namespace LoGiC.NET.Protections +{ + public class ProxyAdder : Randomizer + { + /// + /// The intensity of the proxy calls. The more the intensity is, the more proxy calls will be added! + /// + private static int Intensity { get; set; } = 2; + + /// + /// The amount of added proxy calls. + /// + private static int Amount { get; set; } + + // Thanks to the BasicProxyObfuscator project by XenocodeRCE on GitHub! + + /// + /// Execution of the 'ProxyAdder' method. It'll add proxy calls, basically each proxy call will call another method that will call another method, etc. until it calls a real method (example : InitializeComponent). + /// + public static void Execute() + { + for (int o = 0; o < Intensity; o++) + { + foreach (TypeDef t in Program.Module.Types) + { + if (t.IsGlobalModuleType) continue; + foreach (MethodDef m in t.Methods.ToArray()) + { + if (!m.HasBody) continue; + for (int z = 0; z < m.Body.Instructions.Count; z++) + { + if (m.Body.Instructions[z].OpCode == OpCodes.Call) + { + try + { + MethodDef targetMethod = m.Body.Instructions[z].Operand as MethodDef; + if (!targetMethod.FullName.Contains(Program.Module.Assembly.Name)) continue; + if (targetMethod.Parameters.Count == 0 || targetMethod.Parameters.Count > 4) continue; + + MethodDef newMeth = targetMethod.CopyMethod(Program.Module); + targetMethod.DeclaringType.Methods.Add(newMeth); + targetMethod.CloneSignature(newMeth); + + CilBody body = new CilBody(); + body.Instructions.Add(OpCodes.Nop.ToInstruction()); + for (int x = 0; x < targetMethod.Parameters.Count; x++) + { + switch (x) + { + case 0: + body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction()); + break; + case 1: + body.Instructions.Add(OpCodes.Ldarg_1.ToInstruction()); + break; + case 2: + body.Instructions.Add(OpCodes.Ldarg_2.ToInstruction()); + break; + case 3: + body.Instructions.Add(OpCodes.Ldarg_3.ToInstruction()); + break; + } + } + body.Instructions.Add(OpCodes.Call.ToInstruction(newMeth)); + body.Instructions.Add(OpCodes.Ret.ToInstruction()); + + targetMethod.Body = body; + ++Amount; + } + catch { continue; } + } + } + } + } + } + + Console.WriteLine($"Added {Amount} proxy calls."); + } + } +} diff --git a/Protections/Renamer.cs b/Protections/Renamer.cs new file mode 100644 index 0000000..c0c94b9 --- /dev/null +++ b/Protections/Renamer.cs @@ -0,0 +1,115 @@ +using System; +using dnlib.DotNet; +using LoGiC.NET.Utils; +using LoGiC.NET.Utils.Analyzer; + +namespace LoGiC.NET.Protections +{ + public class Renamer : Randomizer + { + private static int TypeAmount { get; set; } + + private static int MethodAmount { get; set; } + + private static int ParameterAmount { get; set; } + + private static int PropertyAmount { get; set; } + + private static int FieldAmount { get; set; } + + private static int EventAmount { get; set; } + + /// + /// Execution of the 'Renamer' method. It'll rename types, methods and their parameters, properties, fields and events to random strings. But before they get renamed, they get analyzed to see if they are good to be renamed. (That prevents the program being broken) + /// + public static void Execute() + { + if (Program.DontRename) return; + + Program.Module.Mvid = Guid.NewGuid(); + Program.Module.Name = GenerateRandomString(Next(700, 500)); + Program.Module.EntryPoint.Name = GenerateRandomString(Next(700, 500)); + + foreach (TypeDef type in Program.Module.Types) + { + if (CanRename(type) && !Program.FileExtension.Contains("dll") && !Program.ForceWinForms && !Program.Module.HasResources) + { + type.Name = GenerateRandomString(Next(700, 500)); + type.Namespace = GenerateRandomString(Next(700, 500)); + ++TypeAmount; + } + + foreach (MethodDef m in type.Methods) + { + if (CanRename(m) && !Program.ForceWinForms && !Program.FileExtension.Contains("dll")) + { + m.Name = GenerateRandomString(Next(700, 500)); + ++MethodAmount; + } + + foreach (Parameter para in m.Parameters) + { + if (CanRename(para)) + { + para.Name = GenerateRandomString(Next(700, 500)); + ++ParameterAmount; + } + } + } + + foreach (PropertyDef p in type.Properties) + { + if (CanRename(p)) + { + p.Name = GenerateRandomString(Next(700, 500)); + ++PropertyAmount; + } + } + + foreach (FieldDef field in type.Fields) + { + if (CanRename(field)) + { + field.Name = GenerateRandomString(Next(700, 500)); + ++FieldAmount; + } + } + + foreach (EventDef e in type.Events) + { + if (CanRename(e)) + { + e.Name = GenerateRandomString(Next(700, 500)); + ++EventAmount; + } + } + } + + Console.WriteLine($"Renamed {TypeAmount} types.\nRenamed {MethodAmount} methods.\nRenamed {ParameterAmount} parameters.\n" + + $"Renamed {PropertyAmount} properties.\nRenamed {FieldAmount} fields.\nRenamed {EventAmount} events."); + } + + /// + /// This will check with some Analyzers if it's possible to rename a determinate { TypeDef, MethodDef, EventDef, FieldDef }. + /// + /// The determinate to check. + /// If the determinate can be renamed. + public static bool CanRename(object obj) + { + DefAnalyzer analyze = null; + if (obj is TypeDef) + analyze = new TypeDefAnalyzer(); + else if (obj is MethodDef) + analyze = new MethodDefAnalyzer(); + else if (obj is EventDef) + analyze = new EventDefAnalyzer(); + else if (obj is FieldDef) + analyze = new FieldDefAnalyzer(); + else if (obj is Parameter) + analyze = new ParameterAnalyzer(); + if (analyze == null) + return false; + return analyze.Execute(obj); + } + } +} diff --git a/Protections/StringEncryption.cs b/Protections/StringEncryption.cs new file mode 100644 index 0000000..a17c054 --- /dev/null +++ b/Protections/StringEncryption.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using LoGiC.NET.Utils; + +namespace LoGiC.NET.Protections +{ + public class StringEncryption : Randomizer + { + private static int Amount { get; set; } + + public static void Execute() + { + MethodDef strings = CreateReturnMethodDef(); + Program.Module.GlobalType.Methods.Add(strings); + + foreach (TypeDef type in Program.Module.Types) + { + if (type.IsGlobalModuleType) continue; + foreach (MethodDef method in type.Methods) + { + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) + if (method.Body.Instructions[i].OpCode == OpCodes.Ldstr) + { + string operand = method.Body.Instructions[i].Operand.ToString(); + method.Body.Instructions[i].Operand = Convert.ToBase64String(Encoding.UTF8.GetBytes(operand)); + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(strings)); + ++Amount; + } + } + } + + Console.WriteLine($"Encrypted {Amount} strings."); + } + + private static MethodDef CreateReturnMethodDef() + { + MethodDef newMethod = new MethodDefUser(GenerateRandomString(Next(700, 500)), + MethodSig.CreateStatic(Program.Module.CorLibTypes.String, Program.Module.CorLibTypes.String), + MethodImplAttributes.IL | MethodImplAttributes.Managed, + MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig + | MethodAttributes.ReuseSlot) + { Body = new CilBody() }; + + newMethod.Body.Instructions.Add(OpCodes.Nop.ToInstruction()); + newMethod.Body.Instructions.Add( + OpCodes.Call.ToInstruction(Program.Module.Import(typeof(Encoding).GetMethod("get_UTF8")))); + newMethod.Body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction()); + newMethod.Body.Instructions.Add( + OpCodes.Call.ToInstruction(Program.Module.Import(typeof(Convert).GetMethod("FromBase64String", + new Type[] { typeof(string) })))); + newMethod.Body.Instructions.Add( + OpCodes.Callvirt.ToInstruction(Program.Module.Import(typeof(Encoding).GetMethod("GetString", + new Type[] { typeof(byte[]) })))); + newMethod.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); + return newMethod; + } + } +} diff --git a/Utils/Analyzer/DefAnalyzer.cs b/Utils/Analyzer/DefAnalyzer.cs new file mode 100644 index 0000000..41685d0 --- /dev/null +++ b/Utils/Analyzer/DefAnalyzer.cs @@ -0,0 +1,10 @@ +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class is the one that is inherited in mostly all def analyzers. + /// + public abstract class DefAnalyzer + { + public abstract bool Execute(object context); + } +} \ No newline at end of file diff --git a/Utils/Analyzer/EventDefAnalyzer.cs b/Utils/Analyzer/EventDefAnalyzer.cs new file mode 100644 index 0000000..6bd63ee --- /dev/null +++ b/Utils/Analyzer/EventDefAnalyzer.cs @@ -0,0 +1,18 @@ +using dnlib.DotNet; + +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class will analyze an event def. + /// + public class EventDefAnalyzer : DefAnalyzer + { + public override bool Execute(object context) + { + EventDef ev = (EventDef)context; + if (ev.IsRuntimeSpecialName) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/Utils/Analyzer/FieldDefAnalyzer.cs b/Utils/Analyzer/FieldDefAnalyzer.cs new file mode 100644 index 0000000..2cf9af2 --- /dev/null +++ b/Utils/Analyzer/FieldDefAnalyzer.cs @@ -0,0 +1,20 @@ +using dnlib.DotNet; + +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class will analyze a field def. + /// + public class FieldDefAnalyzer : DefAnalyzer + { + public override bool Execute(object context) + { + FieldDef field = (FieldDef)context; + if (field.IsRuntimeSpecialName) + return false; + if (field.IsLiteral && field.DeclaringType.IsEnum) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/Utils/Analyzer/MethodDefAnalyzer.cs b/Utils/Analyzer/MethodDefAnalyzer.cs new file mode 100644 index 0000000..98a4c6d --- /dev/null +++ b/Utils/Analyzer/MethodDefAnalyzer.cs @@ -0,0 +1,22 @@ +using dnlib.DotNet; + +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class will analyze a method def. + /// + public class MethodDefAnalyzer : DefAnalyzer + { + public override bool Execute(object context) + { + MethodDef method = (MethodDef)context; + if (method.IsRuntimeSpecialName) + return false; + if (method.DeclaringType.IsForwarder) + return false; + if (method.IsConstructor || method.IsStaticConstructor) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/Utils/Analyzer/ParameterAnalyzer.cs b/Utils/Analyzer/ParameterAnalyzer.cs new file mode 100644 index 0000000..30eac40 --- /dev/null +++ b/Utils/Analyzer/ParameterAnalyzer.cs @@ -0,0 +1,18 @@ +using dnlib.DotNet; + +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class will analyze a parameter (NOT def). + /// + public class ParameterAnalyzer : DefAnalyzer + { + public override bool Execute(object context) + { + Parameter param = (Parameter)context; + if (param.Name == string.Empty) + return false; + return true; + } + } +} diff --git a/Utils/Analyzer/TypeDefAnalyzer.cs b/Utils/Analyzer/TypeDefAnalyzer.cs new file mode 100644 index 0000000..d2802b2 --- /dev/null +++ b/Utils/Analyzer/TypeDefAnalyzer.cs @@ -0,0 +1,22 @@ +using dnlib.DotNet; + +namespace LoGiC.NET.Utils.Analyzer +{ + /// + /// This class will analyze a type def. + /// + public class TypeDefAnalyzer : DefAnalyzer + { + public override bool Execute(object context) + { + TypeDef type = (TypeDef)context; + if (type.IsRuntimeSpecialName) + return false; + if (type.IsGlobalModuleType) + return false; + if (type.IsWindowsRuntime) + return false; + return true; + } + } +} \ No newline at end of file diff --git a/Utils/InjectContext.cs b/Utils/InjectContext.cs new file mode 100644 index 0000000..fa3325f --- /dev/null +++ b/Utils/InjectContext.cs @@ -0,0 +1,77 @@ +using dnlib.DotNet; +using System.Collections.Generic; + +namespace LoGiC.NET.Utils +{ + /// + /// The context of an injection process. + /// + public class InjectContext + { + /// + /// The mapping of origin definitions to injected definitions. + /// + public readonly Dictionary Map = new Dictionary(); + + /// + /// The module which source type originated from. + /// + public readonly ModuleDef OriginModule; + + /// + /// The module which source type is being injected to. + /// + public readonly ModuleDef TargetModule; + + /// + /// Initializes a new instance of the class. + /// + /// The origin module. + /// The target module. + public InjectContext(ModuleDef module, ModuleDef target) + { + OriginModule = module; + TargetModule = target; + Importer = new Importer(target, ImporterOptions.TryToUseTypeDefs); + } + + /// + /// Gets the importer. + /// + /// The importer. + public Importer Importer { get; } + + /// + /// Resolves a choosed TypeDef from the Map. + /// + /// The TypeDef that will be searched. + /// A TypeDef from the Map or null if it cannot find it. + public TypeDef Resolve(TypeDef typeDef) + { + if (Map.ContainsKey(typeDef)) return (TypeDef)Map[typeDef]; + return null; + } + + /// + /// Resolves a choosed MethodDef from the Map. + /// + /// The MethodDef that will be searched. + /// A MethodDef from the Map or null if it cannot find it. + public MethodDef Resolve(MethodDef methodDef) + { + if (Map.ContainsKey(methodDef)) return (MethodDef)Map[methodDef]; + return null; + } + + /// + /// Resolves a choosed FieldDef from the Map. + /// + /// The FieldDef that will be searched. + /// A FieldDef from the Map or null if it cannot find it. + public FieldDef Resolve(FieldDef fieldDef) + { + if (Map.ContainsKey(fieldDef)) return (FieldDef)Map[fieldDef]; + return null; + } + } +} diff --git a/Utils/ProxyExtension.cs b/Utils/ProxyExtension.cs new file mode 100644 index 0000000..4244515 --- /dev/null +++ b/Utils/ProxyExtension.cs @@ -0,0 +1,92 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System.Collections.Generic; +using System.Linq; + +namespace LoGiC.NET.Utils +{ + /// + /// The class that contains extensions for MethodDefs. It's used for the 'ProxyAdder' method. + /// + public static class ProxyExtension + { + public static MethodDef CloneSignature(this MethodDef from, MethodDef to) + { + to.Attributes = from.Attributes; + if (from.IsHideBySig) to.IsHideBySig = true; + return to; + } + + public static MethodDef CopyMethod(this MethodDef originMethod, ModuleDef mod) + { + InjectContext ctx = new InjectContext(mod, mod); + + MethodDefUser newMethodDef = new MethodDefUser + { + Signature = ctx.Importer.Import(originMethod.Signature), + Name = Randomizer.GenerateRandomString(Randomizer.Next(700, 500)) + }; + newMethodDef.Parameters.UpdateParameterTypes(); + + if (originMethod.ImplMap != null) newMethodDef.ImplMap = new ImplMapUser(new ModuleRefUser(ctx.TargetModule, + originMethod.ImplMap.Module.Name), originMethod.ImplMap.Name, originMethod.ImplMap.Attributes); + + foreach (CustomAttribute ca in originMethod.CustomAttributes) + newMethodDef.CustomAttributes.Add(new CustomAttribute((ICustomAttributeType) + ctx.Importer.Import(ca.Constructor))); + + if (originMethod.HasBody) + { + newMethodDef.Body = new CilBody() + { + InitLocals = originMethod.Body.InitLocals, + MaxStack = originMethod.Body.MaxStack + }; + + Dictionary bodyMap = new Dictionary(); + + foreach (Local local in originMethod.Body.Variables) + { + Local newLocal = new Local(ctx.Importer.Import(local.Type)); + newMethodDef.Body.Variables.Add(newLocal); + newLocal.Name = local.Name; + + bodyMap[local] = newLocal; + } + + foreach (Instruction instr in originMethod.Body.Instructions) + { + Instruction newInstr = new Instruction(instr.OpCode, instr.Operand) + { SequencePoint = instr.SequencePoint }; + + if (newInstr.Operand is IType) newInstr.Operand = ctx.Importer.Import((IType)newInstr.Operand); + else if (newInstr.Operand is IMethod) newInstr.Operand = ctx.Importer.Import((IMethod)newInstr.Operand); + else if (newInstr.Operand is IField) newInstr.Operand = ctx.Importer.Import((IField)newInstr.Operand); + + newMethodDef.Body.Instructions.Add(newInstr); + bodyMap[instr] = newInstr; + } + + foreach (Instruction instr in newMethodDef.Body.Instructions) + if (instr.Operand != null && bodyMap.ContainsKey(instr.Operand)) instr.Operand = bodyMap[instr.Operand]; + else if (instr.Operand is Instruction[]) instr.Operand = ((Instruction[])instr.Operand).Select( + target => (Instruction)bodyMap[target]).ToArray(); + + foreach (ExceptionHandler eh in originMethod.Body.ExceptionHandlers) + newMethodDef.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType) + { + CatchType = eh.CatchType == null ? null : ctx.Importer.Import(eh.CatchType), + TryStart = (Instruction)bodyMap[eh.TryStart], + TryEnd = (Instruction)bodyMap[eh.TryEnd], + HandlerStart = (Instruction)bodyMap[eh.HandlerStart], + HandlerEnd = (Instruction)bodyMap[eh.HandlerEnd], + FilterStart = eh.FilterStart == null ? null : (Instruction)bodyMap[eh.FilterStart] + }); + + newMethodDef.Body.SimplifyMacros(newMethodDef.Parameters); + } + + return newMethodDef; + } + } +} diff --git a/Utils/Randomizer.cs b/Utils/Randomizer.cs new file mode 100644 index 0000000..c2c4c87 --- /dev/null +++ b/Utils/Randomizer.cs @@ -0,0 +1,47 @@ +using System; +using System.Security.Cryptography; +using System.Text; + +namespace LoGiC.NET.Utils +{ + /// + /// This class is the one that generates random integers and strings. + /// + public class Randomizer + { + private static readonly RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider(); + private static readonly char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); + + public static int Next(int maxValue, int minValue = 0) + { + if (minValue >= maxValue) throw new ArgumentOutOfRangeException(nameof(minValue)); + long diff = (long)maxValue - minValue; + long upperBound = uint.MaxValue / diff * diff; + uint ui; + do { ui = RandomUInt(); } while (ui >= upperBound); + return (int)(minValue + (ui % diff)); + } + + public static string GenerateRandomString(int size) + { + byte[] data = new byte[4 * size]; + csp.GetBytes(data); + StringBuilder sb = new StringBuilder(size); + for (int i = 0; i < size; i++) sb.Append(chars[BitConverter.ToUInt32(data, i * 4) % chars.Length]); + return sb.ToString(); + } + + private static uint RandomUInt() + { + var randomBytes = RandomBytes(sizeof(uint)); + return BitConverter.ToUInt32(randomBytes, 0); + } + + private static byte[] RandomBytes(int bytesNumber) + { + byte[] buffer = new byte[bytesNumber]; + csp.GetBytes(buffer); + return buffer; + } + } +} diff --git a/Utils/Reference.cs b/Utils/Reference.cs new file mode 100644 index 0000000..6298d49 --- /dev/null +++ b/Utils/Reference.cs @@ -0,0 +1,8 @@ +namespace LoGiC.NET.Utils +{ + public class Reference + { + public static string Name = "LoGiC.NET"; + public static string Version = "1.0"; + } +} diff --git a/Utils/Watermark.cs b/Utils/Watermark.cs new file mode 100644 index 0000000..1c28245 --- /dev/null +++ b/Utils/Watermark.cs @@ -0,0 +1,31 @@ +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace LoGiC.NET.Utils +{ + public class Watermark + { + public static void AddAttribute() + { + TypeRef attrRef = Program.Module.CorLibTypes.GetTypeRef("System", "Attribute"); + TypeDefUser attrType = new TypeDefUser(string.Empty, "LoGiCdotNetAttribute", attrRef); + Program.Module.Types.Add(attrType); + MethodDefUser ctor = new MethodDefUser(".ctor", MethodSig.CreateInstance(Program.Module.CorLibTypes.Void, + Program.Module.CorLibTypes.String), MethodImplAttributes.Managed, MethodAttributes.HideBySig | MethodAttributes.Public + | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName) + { + Body = new CilBody { MaxStack = 1 } + }; + ctor.Body.Instructions.Add(OpCodes.Ldarg_0.ToInstruction()); + ctor.Body.Instructions.Add(OpCodes.Call.ToInstruction(new MemberRefUser(Program.Module, ".ctor", MethodSig.CreateInstance( + Program.Module.CorLibTypes.Void), attrRef))); + ctor.Body.Instructions.Add(OpCodes.Ret.ToInstruction()); + attrType.Methods.Add(ctor); + + CustomAttribute attr = new CustomAttribute(ctor); + attr.ConstructorArguments.Add(new CAArgument(Program.Module.CorLibTypes.String, $"Obfuscated with {Reference.Name}" + + $" version {Reference.Version}.")); + Program.Module.CustomAttributes.Add(attr); + } + } +} diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..e4b41b4 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file