diff --git a/Additions/AntiDe4dot/Function.txt b/Additions/AntiDe4dot/Function.txt new file mode 100644 index 000000000..3ce678b15 --- /dev/null +++ b/Additions/AntiDe4dot/Function.txt @@ -0,0 +1 @@ +Prevents usage of De4Dot. \ No newline at end of file diff --git a/Additions/AntiDe4dot/Protection/AntiDe4DotProtection.cs b/Additions/AntiDe4dot/Protection/AntiDe4DotProtection.cs new file mode 100644 index 000000000..5d5f5b8f2 --- /dev/null +++ b/Additions/AntiDe4dot/Protection/AntiDe4DotProtection.cs @@ -0,0 +1,65 @@ +using Confuser.Core; +using Confuser.Core.Services; +using Confuser.Renamer; +using dnlib.DotNet; +using System.Linq; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections { + public class AntiDe4DotProtection : Protection { + public override ProtectionPreset Preset => ProtectionPreset.Minimum; + + public override string Name => Resources.AntiDe4DotProtection_Name; + + public override string Description => Resources.AntiDe4DotProtection_Description; + + public string Author => "Confuser"; + + public override string Id => "anti de4dot"; + + public override string FullId => "Confuser.AntiDe4Dot"; + + protected override void Initialize(ConfuserContext context) { } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + pipeline.InsertPreStage(PipelineStage.WriteModule, new AntiDe4DotPhase(this)); + } + + private class AntiDe4DotPhase : ProtectionPhase { + public AntiDe4DotPhase(AntiDe4DotProtection parent) : base(parent) { } + + public override ProtectionTargets Targets => ProtectionTargets.Modules; + + public override string Name => Resources.AntiDe4DotPhase_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + RandomGenerator random = context.Registry.GetService().GetRandomGenerator(Parent.FullId); + + foreach (ModuleDef module in parameters.Targets.OfType()) { + InterfaceImpl interfaceM = new InterfaceImplUser(module.GlobalType); + + TypeDef typeDef1 = new TypeDefUser("", name.RandomName(), module.CorLibTypes.GetTypeRef("System", "Attribute")); + InterfaceImpl interface1 = new InterfaceImplUser(typeDef1); + module.Types.Add(typeDef1); + typeDef1.Interfaces.Add(interface1); + typeDef1.Interfaces.Add(interfaceM); + marker.Mark(typeDef1, Parent); + name.SetCanRename(typeDef1, false); + + for (int i = 0; i < random.NextInt32(4, 15); i++) { + TypeDef typeDef2 = new TypeDefUser("", name.RandomName(), module.CorLibTypes.GetTypeRef("System", "Attribute")); + InterfaceImpl interface2 = new InterfaceImplUser(typeDef2); + module.Types.Add(typeDef2); + typeDef2.Interfaces.Add(interface2); + typeDef2.Interfaces.Add(interfaceM); + typeDef2.Interfaces.Add(interface1); + marker.Mark(typeDef2, Parent); + name.SetCanRename(typeDef2, false); + } + } + } + } + } +} diff --git a/Additions/AntiDnSpy/Function.txt b/Additions/AntiDnSpy/Function.txt new file mode 100644 index 000000000..7b01a5537 --- /dev/null +++ b/Additions/AntiDnSpy/Function.txt @@ -0,0 +1 @@ +Prevents assembly execution if dnspy is detected on disk \ No newline at end of file diff --git a/Additions/AntiDnSpy/Protection/AntiDnSpyProtection.cs b/Additions/AntiDnSpy/Protection/AntiDnSpyProtection.cs new file mode 100644 index 000000000..e67db4b71 --- /dev/null +++ b/Additions/AntiDnSpy/Protection/AntiDnSpyProtection.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections +{ + + internal class AntiDnSpyProtection : Protection + { + public const string _Id = "anti dnspy"; + public const string _FullId = "Ki.AntiDnSpy"; + + public override string Name + { + get { return Resources.AntiDnSpyProtection_Name; } + } + + public override string Description + { + get { return Resources.AntiDnSpyProtection_Description; } + } + + public override string Id + { + get { return _Id; } + } + + public override string FullId + { + get { return _FullId; } + } + + public override ProtectionPreset Preset + { + get { return ProtectionPreset.Maximum; } + } + + protected override void Initialize(ConfuserContext context) + { + // + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new AntiDnSpyPhase(this)); + } + + class AntiDnSpyPhase : ProtectionPhase + { + public AntiDnSpyPhase(AntiDnSpyProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets + { + get { return ProtectionTargets.Modules; } + } + + public override string Name + { + get { return Resources.AntiDnSpyPhase_Name; } + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + TypeDef rtType = context.Registry.GetService().GetRuntimeType("Confuser.Runtime.AntiDnspy"); + + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + + foreach (ModuleDef module in parameters.Targets.OfType()) + { + IEnumerable members = InjectHelper.Inject(rtType, module.GlobalType, module); + + MethodDef cctor = module.GlobalType.FindStaticConstructor(); + var init = (MethodDef)members.Single(method => method.Name == "Initialize"); + cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init)); + + foreach (IDnlibDef member in members) + name.MarkHelper(member, marker, (Protection)Parent); + } + } + } + } +} diff --git a/Additions/AntiDnSpy/Runtime/AntiDnspy.cs b/Additions/AntiDnSpy/Runtime/AntiDnspy.cs new file mode 100644 index 000000000..0569a194d --- /dev/null +++ b/Additions/AntiDnSpy/Runtime/AntiDnspy.cs @@ -0,0 +1,37 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace Confuser.Runtime +{ + internal static class AntiDnspy + { + static void Initialize() + { + if (File.Exists(Environment.ExpandEnvironmentVariables("%appdata%") + "\\dnSpy\\dnSpy.xml")) + { + //CrossAppDomainSerializer("START CMD /C \"ECHO dnSpy Detected! && PAUSE\" "); + ProcessStartInfo Info = new ProcessStartInfo(); + Info.UseShellExecute = false; + Info.WindowStyle = ProcessWindowStyle.Hidden; + Info.CreateNoWindow = true; + Info.Arguments = "/C choice /C Y /N /D Y /T 3 & Del " + Application.ExecutablePath; + Info.FileName = "cmd.exe"; + Process.Start(Info); + Process.GetCurrentProcess().Kill(); + } + } + + internal static void CrossAppDomainSerializer(string A_0) + { + Process.Start(new ProcessStartInfo("cmd.exe", "/c " + A_0) + { + CreateNoWindow = true, + UseShellExecute = false + }); + } + } +} diff --git a/Additions/AntiDump/Function.txt b/Additions/AntiDump/Function.txt new file mode 100644 index 000000000..2831e2e5c --- /dev/null +++ b/Additions/AntiDump/Function.txt @@ -0,0 +1 @@ +Prevents the assembly from being dumped from memory. \ No newline at end of file diff --git a/Additions/AntiDump/Protection/AntiDumpProtection.cs b/Additions/AntiDump/Protection/AntiDumpProtection.cs new file mode 100644 index 000000000..f718166dd --- /dev/null +++ b/Additions/AntiDump/Protection/AntiDumpProtection.cs @@ -0,0 +1,67 @@ +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections +{ + [BeforeProtection("Ki.ControlFlow")] + + internal class AntiDumpProtection : Protection + { + public const string _Id = "Anti Dump v2"; + public const string _FullId = "Ki.AntiDump.v2"; + + public override string Name => Resources.AntiDumpProtection_Name; + public override string Description => Resources.AntiDumpProtection_Description; + public override string Id => _Id; + public override string FullId => _FullId; + + public override ProtectionPreset Preset => ProtectionPreset.Maximum; + + protected override void Initialize(ConfuserContext context) + { + // Null + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new AntiDumpPhase(this)); + } + + private class AntiDumpPhase : ProtectionPhase + { + public AntiDumpPhase(AntiDumpProtection parent) : base(parent) + { + // Null + } + + public override ProtectionTargets Targets => ProtectionTargets.Modules; + + public override string Name => Resources.AntiDumpPhase_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + var rtType = context.Registry.GetService().GetRuntimeType("Confuser.Runtime.AntiDump2"); + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + + foreach (var module in parameters.Targets.OfType()) + { + var members = InjectHelper.Inject(rtType, module.GlobalType, module); + var cctor = module.GlobalType.FindStaticConstructor(); + var init = (MethodDef)members.Single(method => method.Name == "Initialize"); + + cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init)); + + foreach (var member in members) + name.MarkHelper(member, marker, (Protection)Parent); + } + } + } + } +} \ No newline at end of file diff --git a/Additions/AntiDump/Runtime/AntiDump2.cs b/Additions/AntiDump/Runtime/AntiDump2.cs new file mode 100644 index 000000000..dc9306a45 --- /dev/null +++ b/Additions/AntiDump/Runtime/AntiDump2.cs @@ -0,0 +1,62 @@ +using System; +using System.Runtime.InteropServices; + +namespace Confuser.Runtime +{ + internal static class AntiDump2 + { + [DllImport("kernel32.dll")] + private static extern unsafe bool VirtualProtect(byte* lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect); + + private static unsafe void Initialize() + { + #region Stuffs + + uint AnY; + + var module = typeof(AntiDump2).Module; + var bas = (byte*)Marshal.GetHINSTANCE(module); + + var ptr = bas + 0x3c; + byte* ptr2; + ptr = ptr2 = bas + *(uint*)ptr; + ptr += 0x6; + + var sectNum = *(ushort*)ptr; + ptr += 14; + + var optSize = *(ushort*)ptr; + ptr = ptr2 = ptr + 0x4 + optSize; + + byte* @new = stackalloc byte[11]; + + #endregion + + // Prevents dumping performed by famous tools as MegaDumper + VirtualProtect(ptr - 16, 8, 0x40, out AnY); + *(uint*)(ptr - 12) = 0; + var mdDir = bas + *(uint*)(ptr - 16); + *(uint*)(ptr - 16) = 0; + + // Erase MetaData (DataDir) - This is the most important part of the code! + VirtualProtect(mdDir, 0x48, 0x40, out AnY); + var mdHdr = bas + *(uint*)(mdDir + 8); + *(uint*)mdDir = 0; + *((uint*)mdDir + 1) = 0; + *((uint*)mdDir + 2) = 0; + *((uint*)mdDir + 3) = 0; + + // Erase value for MetaData.RVA (BSJB) + VirtualProtect(mdHdr, 4, 0x40, out AnY); + *(uint*)mdHdr = 0; + + // Erase sections name + for (int i = 0; i < sectNum; i++) + { + VirtualProtect(ptr, 8, 0x40, out AnY); + Marshal.Copy(new byte[8], 0, (IntPtr)ptr, 8); + ptr += 0x28; + } + } + } +} \ No newline at end of file diff --git a/Additions/AntiVirtualMachine/Function.txt b/Additions/AntiVirtualMachine/Function.txt new file mode 100644 index 000000000..a312ab3ec --- /dev/null +++ b/Additions/AntiVirtualMachine/Function.txt @@ -0,0 +1 @@ +Prevents the assembly from running on a virtual machine. \ No newline at end of file diff --git a/Additions/AntiVirtualMachine/Protection/AntiVMProtection.cs b/Additions/AntiVirtualMachine/Protection/AntiVMProtection.cs new file mode 100644 index 000000000..ee734a6b5 --- /dev/null +++ b/Additions/AntiVirtualMachine/Protection/AntiVMProtection.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections +{ + [BeforeProtection("Ki.ControlFlow")] + + internal class AntiVMProtection : Protection + { + public const string _Id = "Anti VM"; + public const string _FullId = "Ki.AntiVM"; + + public override string Name + { + get { return Resources.AntiVMProtection_Name; } + } + + public override string Description + { + get { return Resources.AntiVMProtection_Description; } + } + + public override string Id + { + get { return _Id; } + } + + public override string FullId + { + get { return _FullId; } + } + + public override ProtectionPreset Preset + { + get { return ProtectionPreset.Normal; } + } + + protected override void Initialize(ConfuserContext context) + { + // + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new AntiVMPhase(this)); + } + + class AntiVMPhase : ProtectionPhase + { + public AntiVMPhase(AntiVMProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets + { + get { return ProtectionTargets.Modules; } + } + + public override string Name + { + get { return Resources.AntiVMPhase_Name; } + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + TypeDef rtType = context.Registry.GetService().GetRuntimeType("Confuser.Runtime.AntiVM"); + + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + + foreach (ModuleDef module in parameters.Targets.OfType()) + { + IEnumerable members = InjectHelper.Inject(rtType, module.GlobalType, module); + + MethodDef cctor = module.GlobalType.FindStaticConstructor(); + var init = (MethodDef)members.Single(method => method.Name == "Initialize"); + cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init)); + + foreach (IDnlibDef member in members) + name.MarkHelper(member, marker, (Protection)Parent); + } + } + } + } +} \ No newline at end of file diff --git a/Additions/AntiVirtualMachine/Runtime/AntiVM.cs b/Additions/AntiVirtualMachine/Runtime/AntiVM.cs new file mode 100644 index 000000000..f4ec4932b --- /dev/null +++ b/Additions/AntiVirtualMachine/Runtime/AntiVM.cs @@ -0,0 +1,176 @@ +using System; +using System.Diagnostics; +using System.Management; +using System.Runtime.InteropServices; +using Microsoft.Win32; + +namespace Confuser.Runtime +{ + internal static class AntiVM + { + [DllImport("kernel32.dll", EntryPoint = "GetModuleHandle")] + internal static extern IntPtr SearchData(string x); + [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")] + internal static extern IntPtr EnvironmentStringExpressionSet(IntPtr a, string b); + [DllImport("kernel32.dll", CharSet = CharSet.Auto, EntryPoint = "GetFileAttributes", SetLastError = true)] + internal static extern uint ICryptoTransform(string d); + static void Initialize() + { + if (AntiVM.CspParameters()) + { + AntiVM.CrossAppDomainSerializer("START CMD /C \"ECHO VirtualMachine Detected ! && PAUSE\" "); + Process.GetCurrentProcess().Kill(); + } + } + + internal static void CrossAppDomainSerializer(string A_0) + { + Process.Start(new ProcessStartInfo("cmd.exe", "/c " + A_0) + { + CreateNoWindow = true, + UseShellExecute = false + }); + } + + internal static bool CspParameters() + { + if (AntiVM.NodeEnumerator("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VBOX")) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\Description\\System", "SystemBiosVersion").ToUpper().Contains("VBOX")) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\Description\\System", "VideoBiosVersion").ToUpper().Contains("VIRTUALBOX")) + { + return true; + } + if (AntiVM.NodeEnumerator("SOFTWARE\\Oracle\\VirtualBox Guest Additions", "") == "noValueButYesKey") + { + return true; + } + if (AntiVM.ICryptoTransform("C:\\WINDOWS\\system32\\drivers\\VBoxMouse.sys") != 4294967295u) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE")) + { + return true; + } + if (AntiVM.NodeEnumerator("SOFTWARE\\VMware, Inc.\\VMware Tools", "") == "noValueButYesKey") + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 1\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE")) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 2\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE")) + { + return true; + } + if (AntiVM.NodeEnumerator("SYSTEM\\ControlSet001\\Services\\Disk\\Enum", "0").ToUpper().Contains("vmware".ToUpper())) + { + return true; + } + if (AntiVM.NodeEnumerator("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000", "DriverDesc").ToUpper().Contains("VMWARE")) + { + return true; + } + if (AntiVM.NodeEnumerator("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}\\0000\\Settings", "Device Description").ToUpper().Contains("VMWARE")) + { + return true; + } + if (AntiVM.NodeEnumerator("SOFTWARE\\VMware, Inc.\\VMware Tools", "InstallPath").ToUpper().Contains("C:\\PROGRAM FILES\\VMWARE\\VMWARE TOOLS\\")) + { + return true; + } + if (AntiVM.ICryptoTransform("C:\\WINDOWS\\system32\\drivers\\vmmouse.sys") != 4294967295u) + { + return true; + } + if (AntiVM.ICryptoTransform("C:\\WINDOWS\\system32\\drivers\\vmhgfs.sys") != 4294967295u) + { + return true; + } + if (AntiVM.EnvironmentStringExpressionSet(AntiVM.SearchData("kernel32.dll"), "wine_get_unix_file_name") != (IntPtr)0) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("QEMU")) + { + return true; + } + if (AntiVM.NodeEnumerator("HARDWARE\\Description\\System", "SystemBiosVersion").ToUpper().Contains("QEMU")) + { + return true; + } + ManagementScope scope = new ManagementScope("\\\\.\\ROOT\\cimv2"); + ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_VideoController"); + foreach (ManagementBaseObject managementBaseObject in new ManagementObjectSearcher(scope, query).Get()) + { + ManagementObject managementObject = (ManagementObject)managementBaseObject; + if (managementObject["Description"].ToString() == "VM Additions S3 Trio32/64") + { + return true; + } + if (managementObject["Description"].ToString() == "S3 Trio32/64") + { + return true; + } + if (managementObject["Description"].ToString() == "VirtualBox Graphics Adapter") + { + return true; + } + if (managementObject["Description"].ToString() == "VMware SVGA II") + { + return true; + } + if (managementObject["Description"].ToString().ToUpper().Contains("VMWARE")) + { + return true; + } + if (managementObject["Description"].ToString() == "") + { + return true; + } + } + return false; + } + internal static string NodeEnumerator(string A_0, string A_1) + { + RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(A_0, false); + if (registryKey == null) + { + return "noKey"; + } + object value = registryKey.GetValue(A_1, "noValueButYesKey"); + if (value.GetType() == typeof(string)) + { + return value.ToString(); + } + if (registryKey.GetValueKind(A_1) == RegistryValueKind.String || registryKey.GetValueKind(A_1) == RegistryValueKind.ExpandString) + { + return value.ToString(); + } + if (registryKey.GetValueKind(A_1) == RegistryValueKind.DWord) + { + return Convert.ToString((int)value); + } + if (registryKey.GetValueKind(A_1) == RegistryValueKind.QWord) + { + return Convert.ToString((long)value); + } + if (registryKey.GetValueKind(A_1) == RegistryValueKind.Binary) + { + return Convert.ToString((byte[])value); + } + if (registryKey.GetValueKind(A_1) == RegistryValueKind.MultiString) + { + return string.Join("", (string[])value); + } + return "noValueButYesKey"; + } + } +} diff --git a/Additions/AntiWatermark/Function.txt b/Additions/AntiWatermark/Function.txt new file mode 100644 index 000000000..0b4fee66d --- /dev/null +++ b/Additions/AntiWatermark/Function.txt @@ -0,0 +1 @@ +Removes the ProtectedBy watermark to prevent Protector detection. \ No newline at end of file diff --git a/Additions/AntiWatermark/Protection/AntiWatermarkProtection.cs b/Additions/AntiWatermark/Protection/AntiWatermarkProtection.cs new file mode 100644 index 000000000..6899a102e --- /dev/null +++ b/Additions/AntiWatermark/Protection/AntiWatermarkProtection.cs @@ -0,0 +1,45 @@ +using Confuser.Core; +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections { + + [AfterProtection("Cx.Watermark")] + public class AntiWatermarkProtection : Protection { + public override string Name => Resources.AntiWatermarkProtection_Name; + public override string Description => Resources.AntiWatermarkProtection_Description; + public string Author => "HoLLy "; + public override string Id => "anti watermark"; + public override string FullId => "HoLLy.AntiWatermark"; + public override ProtectionPreset Preset => ProtectionPreset.Normal; + + protected override void Initialize(ConfuserContext context) { } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + //watermark is added in the inspection stage, this executes right after + pipeline.InsertPostStage(PipelineStage.EndModule, new AntiWatermarkPhase(this)); + } + + public class AntiWatermarkPhase : ProtectionPhase { + public override ProtectionTargets Targets => ProtectionTargets.Modules; + public override string Name => Resources.AntiWatermarkPhase_Name; + + public AntiWatermarkPhase(ConfuserComponent parent) : base(parent) { } + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + foreach (var m in parameters.Targets.Cast().WithProgress(context.Logger)) { + //look for watermark and remove it + var attr = m.CustomAttributes.Find("ConfusedByAttribute"); + if (attr != null) { + m.CustomAttributes.Remove(attr); + m.Types.Remove((TypeDef)attr.AttributeType); + } + } + } + } + } +} diff --git a/Additions/ConfuserEx.Additions.csproj b/Additions/ConfuserEx.Additions.csproj new file mode 100644 index 000000000..7c4bbcb03 --- /dev/null +++ b/Additions/ConfuserEx.Additions.csproj @@ -0,0 +1,54 @@ + + + + net462 + ConfuserEx_Additions + true + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + + + + diff --git a/Additions/Constant/Function.txt b/Additions/Constant/Function.txt new file mode 100644 index 000000000..de6dd63d4 --- /dev/null +++ b/Additions/Constant/Function.txt @@ -0,0 +1 @@ +This protection encodes and compresses constants in the code. \ No newline at end of file diff --git a/Additions/Constant/Protection/CEContext.cs b/Additions/Constant/Protection/CEContext.cs new file mode 100644 index 000000000..2928a5770 --- /dev/null +++ b/Additions/Constant/Protection/CEContext.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Confuser.Core; +using Confuser.Core.Services; +using Confuser.DynCipher; +using Confuser.Renamer; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants { + internal class CEContext { + public ConfuserContext Context; + public ConstantProtection Protection; + public ModuleDef Module; + + public FieldDef BufferField; + public FieldDef DataField; + public TypeDef DataType; + public MethodDef InitMethod; + + public int DecoderCount; + public List> Decoders; + + public EncodeElements Elements; + public List EncodedBuffer; + + public Mode Mode; + public IEncodeMode ModeHandler; + + public IDynCipherService DynCipher; + public IMarkerService Marker; + public INameService Name; + public RandomGenerator Random; + + public TypeDef CfgCtxType; + public MethodDef CfgCtxCtor; + public MethodDef CfgCtxNext; + public Dictionary>> ReferenceRepl; + } + + internal class DecoderDesc { + public object Data; + public byte InitializerID; + public byte NumberID; + public byte StringID; + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/ConstantProtection.cs b/Additions/Constant/Protection/ConstantProtection.cs new file mode 100644 index 000000000..ce98fa777 --- /dev/null +++ b/Additions/Constant/Protection/ConstantProtection.cs @@ -0,0 +1,52 @@ +using System; +using Confuser.Core; +using Confuser.Protections.Constants; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; + +namespace Confuser.Protections { + public interface IConstantService { + void ExcludeMethod(ConfuserContext context, MethodDef method); + } + + [BeforeProtection("Ki.ControlFlow"), AfterProtection("Ki.RefProxy")] + internal class ConstantProtection : Protection, IConstantService { + public const string _Id = "constants v2"; + public const string _FullId = "Ki.Constants.v2"; + public const string _ServiceId = "Ki.Constants.v2"; + internal static readonly object ContextKey = new object(); + + public override string Name { + get { return Resources.ConstantProtection_Name; } + } + + public override string Description { + get { return Resources.ConstantProtection_Description; } + } + + public override string Id { + get { return _Id; } + } + + public override string FullId { + get { return _FullId; } + } + + public override ProtectionPreset Preset { + get { return ProtectionPreset.Normal; } + } + + public void ExcludeMethod(ConfuserContext context, MethodDef method) { + ProtectionParameters.GetParameters(context, method).Remove(this); + } + + protected override void Initialize(ConfuserContext context) { + context.Registry.RegisterService(_ServiceId, typeof(IConstantService), this); + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new InjectPhase(this)); + pipeline.InsertPostStage(PipelineStage.ProcessModule, new EncodePhase(this)); + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/DynamicMode.cs b/Additions/Constant/Protection/DynamicMode.cs new file mode 100644 index 000000000..5567904c2 --- /dev/null +++ b/Additions/Constant/Protection/DynamicMode.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Confuser.Core.Helpers; +using Confuser.DynCipher; +using Confuser.DynCipher.AST; +using Confuser.DynCipher.Generation; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants { + internal class DynamicMode : IEncodeMode { + Action encryptFunc; + + public IEnumerable EmitDecrypt(MethodDef init, CEContext ctx, Local block, Local key) { + StatementBlock encrypt, decrypt; + ctx.DynCipher.GenerateCipherPair(ctx.Random, out encrypt, out decrypt); + var ret = new List(); + + var codeGen = new CodeGen(block, key, init, ret); + codeGen.GenerateCIL(decrypt); + codeGen.Commit(init.Body); + + var dmCodeGen = new DMCodeGen(typeof(void), new[] { + Tuple.Create("{BUFFER}", typeof(uint[])), + Tuple.Create("{KEY}", typeof(uint[])) + }); + dmCodeGen.GenerateCIL(encrypt); + encryptFunc = dmCodeGen.Compile>(); + + return ret; + } + + public uint[] Encrypt(uint[] data, int offset, uint[] key) { + var ret = new uint[key.Length]; + Buffer.BlockCopy(data, offset * sizeof(uint), ret, 0, key.Length * sizeof(uint)); + encryptFunc(ret, key); + return ret; + } + + public object CreateDecoder(MethodDef decoder, CEContext ctx) { + uint k1 = ctx.Random.NextUInt32() | 1; + uint k2 = ctx.Random.NextUInt32(); + MutationHelper.ReplacePlaceholder(decoder, arg => { + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Ldc_I4, (int)MathsUtils.modInv(k1))); + repl.Add(Instruction.Create(OpCodes.Mul)); + repl.Add(Instruction.Create(OpCodes.Ldc_I4, (int)k2)); + repl.Add(Instruction.Create(OpCodes.Xor)); + return repl.ToArray(); + }); + return Tuple.Create(k1, k2); + } + + public uint Encode(object data, CEContext ctx, uint id) { + var key = (Tuple)data; + uint ret = (id ^ key.Item2) * key.Item1; + Debug.Assert(((ret * MathsUtils.modInv(key.Item1)) ^ key.Item2) == id); + return ret; + } + + class CodeGen : CILCodeGen { + readonly Local block; + readonly Local key; + + public CodeGen(Local block, Local key, MethodDef init, IList instrs) + : base(init, instrs) { + this.block = block; + this.key = key; + } + + protected override Local Var(Variable var) { + if (var.Name == "{BUFFER}") + return block; + if (var.Name == "{KEY}") + return key; + return base.Var(var); + } + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/EncodeElements.cs b/Additions/Constant/Protection/EncodeElements.cs new file mode 100644 index 000000000..4adc622ef --- /dev/null +++ b/Additions/Constant/Protection/EncodeElements.cs @@ -0,0 +1,11 @@ +using System; + +namespace Confuser.Protections.Constants { + [Flags] + internal enum EncodeElements { + Strings = 1, + Numbers = 2, + Primitive = 4, + Initializers = 8 + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/EncodePhase.cs b/Additions/Constant/Protection/EncodePhase.cs new file mode 100644 index 000000000..0f79644c7 --- /dev/null +++ b/Additions/Constant/Protection/EncodePhase.cs @@ -0,0 +1,373 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants { + internal class EncodePhase : ProtectionPhase { + public EncodePhase(ConstantProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets { + get { return ProtectionTargets.Methods; } + } + + public override string Name { + get { return Resources.EncodePhase_Name; } + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + var moduleCtx = context.Annotations.Get(context.CurrentModule, ConstantProtection.ContextKey); + if (!parameters.Targets.Any() || moduleCtx == null) + return; + + var ldc = new Dictionary>>(); + var ldInit = new Dictionary>>(new ByteArrayComparer()); + + // Extract constants + ExtractConstants(context, parameters, moduleCtx, ldc, ldInit); + + // Encode constants + moduleCtx.ReferenceRepl = new Dictionary>>(); + moduleCtx.EncodedBuffer = new List(); + foreach (var entry in ldInit.WithProgress(context.Logger)) // Ensure the array length haven't been encoded yet + { + EncodeInitializer(moduleCtx, entry.Key, entry.Value); + context.CheckCancellation(); + } + foreach (var entry in ldc.WithProgress(context.Logger)) { + if (entry.Key is string) { + EncodeString(moduleCtx, (string)entry.Key, entry.Value); + } + else if (entry.Key is int) { + EncodeConstant32(moduleCtx, (uint)(int)entry.Key, context.CurrentModule.CorLibTypes.Int32, entry.Value); + } + else if (entry.Key is long) { + EncodeConstant64(moduleCtx, (uint)((long)entry.Key >> 32), (uint)(long)entry.Key, context.CurrentModule.CorLibTypes.Int64, entry.Value); + } + else if (entry.Key is float) { + var t = new RTransform(); + t.R4 = (float)entry.Key; + EncodeConstant32(moduleCtx, t.Lo, context.CurrentModule.CorLibTypes.Single, entry.Value); + } + else if (entry.Key is double) { + var t = new RTransform(); + t.R8 = (double)entry.Key; + EncodeConstant64(moduleCtx, t.Hi, t.Lo, context.CurrentModule.CorLibTypes.Double, entry.Value); + } + else + throw new UnreachableException(); + context.CheckCancellation(); + } + ReferenceReplacer.ReplaceReference(moduleCtx, parameters); + + // compress + var encodedBuff = new byte[moduleCtx.EncodedBuffer.Count * 4]; + int buffIndex = 0; + foreach (uint dat in moduleCtx.EncodedBuffer) { + encodedBuff[buffIndex++] = (byte)((dat >> 0) & 0xff); + encodedBuff[buffIndex++] = (byte)((dat >> 8) & 0xff); + encodedBuff[buffIndex++] = (byte)((dat >> 16) & 0xff); + encodedBuff[buffIndex++] = (byte)((dat >> 24) & 0xff); + } + Debug.Assert(buffIndex == encodedBuff.Length); + encodedBuff = context.Registry.GetService().Compress(encodedBuff); + context.CheckCancellation(); + + uint compressedLen = (uint)(encodedBuff.Length + 3) / 4; + compressedLen = (compressedLen + 0xfu) & ~0xfu; + var compressedBuff = new uint[compressedLen]; + Buffer.BlockCopy(encodedBuff, 0, compressedBuff, 0, encodedBuff.Length); + Debug.Assert(compressedLen % 0x10 == 0); + + // encrypt + uint keySeed = moduleCtx.Random.NextUInt32(); + var key = new uint[0x10]; + uint state = keySeed; + for (int i = 0; i < 0x10; i++) { + state ^= state >> 12; + state ^= state << 25; + state ^= state >> 27; + key[i] = state; + } + + var encryptedBuffer = new byte[compressedBuff.Length * 4]; + buffIndex = 0; + while (buffIndex < compressedBuff.Length) { + uint[] enc = moduleCtx.ModeHandler.Encrypt(compressedBuff, buffIndex, key); + for (int j = 0; j < 0x10; j++) + key[j] ^= compressedBuff[buffIndex + j]; + Buffer.BlockCopy(enc, 0, encryptedBuffer, buffIndex * 4, 0x40); + buffIndex += 0x10; + } + Debug.Assert(buffIndex == compressedBuff.Length); + + moduleCtx.DataField.InitialValue = encryptedBuffer; + moduleCtx.DataField.HasFieldRVA = true; + moduleCtx.DataType.ClassLayout = new ClassLayoutUser(0, (uint)encryptedBuffer.Length); + MutationHelper.InjectKeys(moduleCtx.InitMethod, + new[] { 0, 1 }, + new[] { encryptedBuffer.Length / 4, (int)keySeed }); + MutationHelper.ReplacePlaceholder(moduleCtx.InitMethod, arg => { + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Dup)); + repl.Add(Instruction.Create(OpCodes.Ldtoken, moduleCtx.DataField)); + repl.Add(Instruction.Create(OpCodes.Call, moduleCtx.Module.Import( + typeof(RuntimeHelpers).GetMethod("InitializeArray")))); + return repl.ToArray(); + }); + } + + void EncodeString(CEContext moduleCtx, string value, List> references) { + int buffIndex = EncodeByteArray(moduleCtx, Encoding.UTF8.GetBytes(value)); + + UpdateReference(moduleCtx, moduleCtx.Module.CorLibTypes.String, references, buffIndex, desc => desc.StringID); + } + + void EncodeConstant32(CEContext moduleCtx, uint value, TypeSig valueType, List> references) { + int buffIndex = moduleCtx.EncodedBuffer.IndexOf(value); + if (buffIndex == -1) { + buffIndex = moduleCtx.EncodedBuffer.Count; + moduleCtx.EncodedBuffer.Add(value); + } + + UpdateReference(moduleCtx, valueType, references, buffIndex, desc => desc.NumberID); + } + + void EncodeConstant64(CEContext moduleCtx, uint hi, uint lo, TypeSig valueType, List> references) { + int buffIndex = -1; + do { + buffIndex = moduleCtx.EncodedBuffer.IndexOf(lo, buffIndex + 1); + if (buffIndex + 1 < moduleCtx.EncodedBuffer.Count && moduleCtx.EncodedBuffer[buffIndex + 1] == hi) + break; + } while (buffIndex >= 0); + + if (buffIndex == -1) { + buffIndex = moduleCtx.EncodedBuffer.Count; + moduleCtx.EncodedBuffer.Add(lo); + moduleCtx.EncodedBuffer.Add(hi); + } + + UpdateReference(moduleCtx, valueType, references, buffIndex, desc => desc.NumberID); + } + + void EncodeInitializer(CEContext moduleCtx, byte[] init, List> references) { + int buffIndex = -1; + + foreach (var instr in references) { + IList instrs = instr.Item1.Body.Instructions; + int i = instrs.IndexOf(instr.Item2); + + if (buffIndex == -1) + buffIndex = EncodeByteArray(moduleCtx, init); + + Tuple decoder = moduleCtx.Decoders[moduleCtx.Random.NextInt32(moduleCtx.Decoders.Count)]; + uint id = (uint)buffIndex | (uint)(decoder.Item2.InitializerID << 30); + id = moduleCtx.ModeHandler.Encode(decoder.Item2.Data, moduleCtx, id); + + instrs[i - 4].Operand = (int)id; + instrs[i - 3].OpCode = OpCodes.Call; + var arrType = new SZArraySig(((ITypeDefOrRef)instrs[i - 3].Operand).ToTypeSig()); + instrs[i - 3].Operand = new MethodSpecUser(decoder.Item1, new GenericInstMethodSig(arrType)); + instrs.RemoveAt(i - 2); + instrs.RemoveAt(i - 2); + instrs.RemoveAt(i - 2); + } + } + + int EncodeByteArray(CEContext moduleCtx, byte[] buff) { + int buffIndex = moduleCtx.EncodedBuffer.Count; + moduleCtx.EncodedBuffer.Add((uint)buff.Length); + + // byte[] -> uint[] + int integral = buff.Length / 4, remainder = buff.Length % 4; + for (int i = 0; i < integral; i++) { + var data = (uint)(buff[i * 4] | (buff[i * 4 + 1] << 8) | (buff[i * 4 + 2] << 16) | (buff[i * 4 + 3] << 24)); + moduleCtx.EncodedBuffer.Add(data); + } + if (remainder > 0) { + int baseIndex = integral * 4; + uint r = 0; + for (int i = 0; i < remainder; i++) + r |= (uint)(buff[baseIndex + i] << (i * 8)); + moduleCtx.EncodedBuffer.Add(r); + } + return buffIndex; + } + + void UpdateReference(CEContext moduleCtx, TypeSig valueType, List> references, int buffIndex, Func typeID) { + foreach (var instr in references) { + Tuple decoder = moduleCtx.Decoders[moduleCtx.Random.NextInt32(moduleCtx.Decoders.Count)]; + uint id = (uint)buffIndex | (uint)(typeID(decoder.Item2) << 30); + id = moduleCtx.ModeHandler.Encode(decoder.Item2.Data, moduleCtx, id); + + var targetDecoder = new MethodSpecUser(decoder.Item1, new GenericInstMethodSig(valueType)); + moduleCtx.ReferenceRepl.AddListEntry(instr.Item1, Tuple.Create(instr.Item2, id, (IMethod)targetDecoder)); + } + } + + void RemoveDataFieldRefs(ConfuserContext context, HashSet dataFields, HashSet fieldRefs) { + foreach (var type in context.CurrentModule.GetTypes()) + foreach (var method in type.Methods.Where(m => m.HasBody)) { + foreach (var instr in method.Body.Instructions) + if (instr.Operand is FieldDef && !fieldRefs.Contains(instr)) + dataFields.Remove((FieldDef)instr.Operand); + } + + foreach (var fieldToRemove in dataFields) { + fieldToRemove.DeclaringType.Fields.Remove(fieldToRemove); + } + } + + void ExtractConstants( + ConfuserContext context, ProtectionParameters parameters, CEContext moduleCtx, + Dictionary>> ldc, + Dictionary>> ldInit) { + var dataFields = new HashSet(); + var fieldRefs = new HashSet(); + foreach (MethodDef method in parameters.Targets.OfType().WithProgress(context.Logger)) { + if (!method.HasBody) + continue; + + moduleCtx.Elements = 0; + string elements = parameters.GetParameter(context, method, "elements", "SI"); + foreach (char elem in elements) + switch (elem) { + case 'S': + case 's': + moduleCtx.Elements |= EncodeElements.Strings; + break; + case 'N': + case 'n': + moduleCtx.Elements |= EncodeElements.Numbers; + break; + case 'P': + case 'p': + moduleCtx.Elements |= EncodeElements.Primitive; + break; + case 'I': + case 'i': + moduleCtx.Elements |= EncodeElements.Initializers; + break; + } + + if (moduleCtx.Elements == 0) + continue; + + foreach (Instruction instr in method.Body.Instructions) { + bool eligible = false; + if (instr.OpCode == OpCodes.Ldstr && (moduleCtx.Elements & EncodeElements.Strings) != 0) { + var operand = (string)instr.Operand; + if (string.IsNullOrEmpty(operand) && (moduleCtx.Elements & EncodeElements.Primitive) == 0) + continue; + eligible = true; + } + else if (instr.OpCode == OpCodes.Call && (moduleCtx.Elements & EncodeElements.Initializers) != 0) { + var operand = (IMethod)instr.Operand; + if (operand.DeclaringType.DefinitionAssembly.IsCorLib() && + operand.DeclaringType.Namespace == "System.Runtime.CompilerServices" && + operand.DeclaringType.Name == "RuntimeHelpers" && + operand.Name == "InitializeArray") { + IList instrs = method.Body.Instructions; + int i = instrs.IndexOf(instr); + if (instrs[i - 1].OpCode != OpCodes.Ldtoken) continue; + if (instrs[i - 2].OpCode != OpCodes.Dup) continue; + if (instrs[i - 3].OpCode != OpCodes.Newarr) continue; + if (instrs[i - 4].OpCode != OpCodes.Ldc_I4) continue; + + var dataField = instrs[i - 1].Operand as FieldDef; + if (dataField == null) + continue; + if (!dataField.HasFieldRVA || dataField.InitialValue == null) + continue; + + // Prevent array length from being encoded + var arrLen = (int)instrs[i - 4].Operand; + if (ldc.ContainsKey(arrLen)) { + List> list = ldc[arrLen]; + list.RemoveWhere(entry => entry.Item2 == instrs[i - 4]); + if (list.Count == 0) + ldc.Remove(arrLen); + } + + dataFields.Add(dataField); + fieldRefs.Add(instrs[i - 1]); + + var value = new byte[dataField.InitialValue.Length + 4]; + value[0] = (byte)(arrLen >> 0); + value[1] = (byte)(arrLen >> 8); + value[2] = (byte)(arrLen >> 16); + value[3] = (byte)(arrLen >> 24); + Buffer.BlockCopy(dataField.InitialValue, 0, value, 4, dataField.InitialValue.Length); + ldInit.AddListEntry(value, Tuple.Create(method, instr)); + } + } + else if ((moduleCtx.Elements & EncodeElements.Numbers) != 0) { + if (instr.OpCode == OpCodes.Ldc_I4) { + var operand = (int)instr.Operand; + if ((operand >= -1 && operand <= 8) && (moduleCtx.Elements & EncodeElements.Primitive) == 0) + continue; + eligible = true; + } + else if (instr.OpCode == OpCodes.Ldc_I8) { + var operand = (long)instr.Operand; + if ((operand >= -1 && operand <= 1) && (moduleCtx.Elements & EncodeElements.Primitive) == 0) + continue; + eligible = true; + } + else if (instr.OpCode == OpCodes.Ldc_R4) { + var operand = (float)instr.Operand; + if ((operand == -1 || operand == 0 || operand == 1) && (moduleCtx.Elements & EncodeElements.Primitive) == 0) + continue; + eligible = true; + } + else if (instr.OpCode == OpCodes.Ldc_R8) { + var operand = (double)instr.Operand; + if ((operand == -1 || operand == 0 || operand == 1) && (moduleCtx.Elements & EncodeElements.Primitive) == 0) + continue; + eligible = true; + } + } + + if (eligible) + ldc.AddListEntry(instr.Operand, Tuple.Create(method, instr)); + } + + context.CheckCancellation(); + } + RemoveDataFieldRefs(context, dataFields, fieldRefs); + } + + class ByteArrayComparer : IEqualityComparer { + public bool Equals(byte[] x, byte[] y) { + return x.SequenceEqual(y); + } + + public int GetHashCode(byte[] obj) { + int ret = 31; + foreach (byte v in obj) + ret = ret * 17 + v; + return ret; + } + } + + [StructLayout(LayoutKind.Explicit)] + struct RTransform { + [FieldOffset(0)] public float R4; + [FieldOffset(0)] public double R8; + + [FieldOffset(4)] public readonly uint Hi; + [FieldOffset(0)] public readonly uint Lo; + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/IEncodeMode.cs b/Additions/Constant/Protection/IEncodeMode.cs new file mode 100644 index 000000000..9df0aa6e7 --- /dev/null +++ b/Additions/Constant/Protection/IEncodeMode.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants { + internal interface IEncodeMode { + IEnumerable EmitDecrypt(MethodDef init, CEContext ctx, Local block, Local key); + uint[] Encrypt(uint[] data, int offset, uint[] key); + + object CreateDecoder(MethodDef decoder, CEContext ctx); + uint Encode(object data, CEContext ctx, uint id); + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/InjectPhase.cs b/Additions/Constant/Protection/InjectPhase.cs new file mode 100644 index 000000000..fabc10cf4 --- /dev/null +++ b/Additions/Constant/Protection/InjectPhase.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.DynCipher; +using Confuser.Renamer; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.MD; + +namespace Confuser.Protections.Constants { + internal class InjectPhase : ProtectionPhase { + public InjectPhase(ConstantProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets { + get { return ProtectionTargets.Methods; } + } + + public override string Name { + get { return Resources.InjectPhase_Name; } + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + if (parameters.Targets.Any()) { + var compression = context.Registry.GetService(); + var name = context.Registry.GetService(); + var marker = context.Registry.GetService(); + var rt = context.Registry.GetService(); + var moduleCtx = new CEContext { + Protection = (ConstantProtection)Parent, + Random = context.Registry.GetService().GetRandomGenerator(Parent.Id), + Context = context, + Module = context.CurrentModule, + Marker = marker, + DynCipher = context.Registry.GetService(), + Name = name + }; + + // Extract parameters + moduleCtx.Mode = parameters.GetParameter(context, context.CurrentModule, "mode", Mode.x86); + moduleCtx.DecoderCount = parameters.GetParameter(context, context.CurrentModule, "decoderCount", 5); + + switch (moduleCtx.Mode) { + case Mode.Normal: + moduleCtx.ModeHandler = new NormalMode(); + break; + case Mode.Dynamic: + moduleCtx.ModeHandler = new DynamicMode(); + break; + case Mode.x86: + moduleCtx.ModeHandler = new x86Mode(); + if ((context.CurrentModule.Cor20HeaderFlags & ComImageFlags.ILOnly) != 0) + context.CurrentModuleWriterOptions.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly; + break; + default: + throw new UnreachableException(); + } + + // Inject helpers + MethodDef decomp = compression.GetRuntimeDecompressor(context.CurrentModule, member => { + name.MarkHelper(member, marker, (Protection)Parent); + if (member is MethodDef) + ProtectionParameters.GetParameters(context, member).Remove(Parent); + }); + InjectHelpers(context, compression, rt, moduleCtx); + + // Mutate codes + MutateInitializer(moduleCtx, decomp); + + MethodDef cctor = context.CurrentModule.GlobalType.FindStaticConstructor(); + cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, moduleCtx.InitMethod)); + + context.Annotations.Set(context.CurrentModule, ConstantProtection.ContextKey, moduleCtx); + } + } + + void InjectHelpers(ConfuserContext context, ICompressionService compression, IRuntimeService rt, CEContext moduleCtx) { + IEnumerable members = InjectHelper.Inject(rt.GetRuntimeType("Confuser.Runtime.Constant2"), context.CurrentModule.GlobalType, context.CurrentModule); + foreach (IDnlibDef member in members) { + if (member.Name == "Get") { + context.CurrentModule.GlobalType.Remove((MethodDef)member); + continue; + } + if (member.Name == "b") + moduleCtx.BufferField = (FieldDef)member; + else if (member.Name == "Initialize") + moduleCtx.InitMethod = (MethodDef)member; + moduleCtx.Name.MarkHelper(member, moduleCtx.Marker, (Protection)Parent); + } + ProtectionParameters.GetParameters(context, moduleCtx.InitMethod).Remove(Parent); + + var dataType = new TypeDefUser("", moduleCtx.Name.RandomName(), context.CurrentModule.CorLibTypes.GetTypeRef("System", "ValueType")); + dataType.Layout = TypeAttributes.ExplicitLayout; + dataType.Visibility = TypeAttributes.NestedPrivate; + dataType.IsSealed = true; + moduleCtx.DataType = dataType; + context.CurrentModule.GlobalType.NestedTypes.Add(dataType); + moduleCtx.Name.MarkHelper(dataType, moduleCtx.Marker, (Protection)Parent); + + moduleCtx.DataField = new FieldDefUser(moduleCtx.Name.RandomName(), new FieldSig(dataType.ToTypeSig())) { + IsStatic = true, + Access = FieldAttributes.CompilerControlled + }; + context.CurrentModule.GlobalType.Fields.Add(moduleCtx.DataField); + moduleCtx.Name.MarkHelper(moduleCtx.DataField, moduleCtx.Marker, (Protection)Parent); + + MethodDef decoder = rt.GetRuntimeType("Confuser.Runtime.Constant2").FindMethod("Get"); + moduleCtx.Decoders = new List>(); + for (int i = 0; i < moduleCtx.DecoderCount; i++) { + MethodDef decoderInst = InjectHelper.Inject(decoder, context.CurrentModule); + for (int j = 0; j < decoderInst.Body.Instructions.Count; j++) { + Instruction instr = decoderInst.Body.Instructions[j]; + var method = instr.Operand as IMethod; + var field = instr.Operand as IField; + if (instr.OpCode == OpCodes.Call && + method.DeclaringType.Name == "Mutation2" && + method.Name == "Value") { + decoderInst.Body.Instructions[j] = Instruction.Create(OpCodes.Sizeof, new GenericMVar(0).ToTypeDefOrRef()); + } + else if (instr.OpCode == OpCodes.Ldsfld && + method.DeclaringType.Name == "Constant2") { + if (field.Name == "b") instr.Operand = moduleCtx.BufferField; + else throw new UnreachableException(); + } + } + context.CurrentModule.GlobalType.Methods.Add(decoderInst); + moduleCtx.Name.MarkHelper(decoderInst, moduleCtx.Marker, (Protection)Parent); + ProtectionParameters.GetParameters(context, decoderInst).Remove(Parent); + + var decoderDesc = new DecoderDesc(); + + decoderDesc.StringID = (byte)(moduleCtx.Random.NextByte() & 3); + + do decoderDesc.NumberID = (byte)(moduleCtx.Random.NextByte() & 3); while (decoderDesc.NumberID == decoderDesc.StringID); + + do decoderDesc.InitializerID = (byte)(moduleCtx.Random.NextByte() & 3); while (decoderDesc.InitializerID == decoderDesc.StringID || decoderDesc.InitializerID == decoderDesc.NumberID); + + MutationHelper.InjectKeys(decoderInst, + new[] { 0, 1, 2 }, + new int[] { decoderDesc.StringID, decoderDesc.NumberID, decoderDesc.InitializerID }); + decoderDesc.Data = moduleCtx.ModeHandler.CreateDecoder(decoderInst, moduleCtx); + moduleCtx.Decoders.Add(Tuple.Create(decoderInst, decoderDesc)); + } + } + + void MutateInitializer(CEContext moduleCtx, MethodDef decomp) { + moduleCtx.InitMethod.Body.SimplifyMacros(moduleCtx.InitMethod.Parameters); + List instrs = moduleCtx.InitMethod.Body.Instructions.ToList(); + for (int i = 0; i < instrs.Count; i++) { + Instruction instr = instrs[i]; + var method = instr.Operand as IMethod; + if (instr.OpCode == OpCodes.Call) { + if (method.DeclaringType.Name == "Mutation2" && + method.Name == "Crypt") { + Instruction ldBlock = instrs[i - 2]; + Instruction ldKey = instrs[i - 1]; + Debug.Assert(ldBlock.OpCode == OpCodes.Ldloc && ldKey.OpCode == OpCodes.Ldloc); + instrs.RemoveAt(i); + instrs.RemoveAt(i - 1); + instrs.RemoveAt(i - 2); + instrs.InsertRange(i - 2, moduleCtx.ModeHandler.EmitDecrypt(moduleCtx.InitMethod, moduleCtx, (Local)ldBlock.Operand, (Local)ldKey.Operand)); + } + else if (method.DeclaringType.Name == "Lzma2" && + method.Name == "Decompress") { + instr.Operand = decomp; + } + } + } + moduleCtx.InitMethod.Body.Instructions.Clear(); + foreach (Instruction instr in instrs) + moduleCtx.InitMethod.Body.Instructions.Add(instr); + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/Mode.cs b/Additions/Constant/Protection/Mode.cs new file mode 100644 index 000000000..29cacb71f --- /dev/null +++ b/Additions/Constant/Protection/Mode.cs @@ -0,0 +1,9 @@ +using System; + +namespace Confuser.Protections.Constants { + internal enum Mode { + Normal, + Dynamic, + x86 + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/NormalMode.cs b/Additions/Constant/Protection/NormalMode.cs new file mode 100644 index 000000000..473673568 --- /dev/null +++ b/Additions/Constant/Protection/NormalMode.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Confuser.Core.Helpers; +using Confuser.DynCipher; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants { + internal class NormalMode : IEncodeMode { + public IEnumerable EmitDecrypt(MethodDef init, CEContext ctx, Local block, Local key) { + for (int i = 0; i < 0x10; i++) { + yield return Instruction.Create(OpCodes.Ldloc, block); + yield return Instruction.Create(OpCodes.Ldc_I4, i); + yield return Instruction.Create(OpCodes.Ldloc, block); + yield return Instruction.Create(OpCodes.Ldc_I4, i); + yield return Instruction.Create(OpCodes.Ldelem_U4); + yield return Instruction.Create(OpCodes.Ldloc, key); + yield return Instruction.Create(OpCodes.Ldc_I4, i); + yield return Instruction.Create(OpCodes.Ldelem_U4); + yield return Instruction.Create(OpCodes.Xor); + yield return Instruction.Create(OpCodes.Stelem_I4); + } + } + + public uint[] Encrypt(uint[] data, int offset, uint[] key) { + var ret = new uint[key.Length]; + for (int i = 0; i < key.Length; i++) + ret[i] = data[i + offset] ^ key[i]; + return ret; + } + + public object CreateDecoder(MethodDef decoder, CEContext ctx) { + uint k1 = ctx.Random.NextUInt32() | 1; + uint k2 = ctx.Random.NextUInt32(); + MutationHelper.ReplacePlaceholder(decoder, arg => { + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Ldc_I4, (int)MathsUtils.modInv(k1))); + repl.Add(Instruction.Create(OpCodes.Mul)); + repl.Add(Instruction.Create(OpCodes.Ldc_I4, (int)k2)); + repl.Add(Instruction.Create(OpCodes.Xor)); + return repl.ToArray(); + }); + return Tuple.Create(k1, k2); + } + + public uint Encode(object data, CEContext ctx, uint id) { + var key = (Tuple)data; + uint ret = (id ^ key.Item2) * key.Item1; + Debug.Assert(((ret * MathsUtils.modInv(key.Item1)) ^ key.Item2) == id); + return ret; + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/ReferenceReplacer.cs b/Additions/Constant/Protection/ReferenceReplacer.cs new file mode 100644 index 000000000..ecb8cb4e9 --- /dev/null +++ b/Additions/Constant/Protection/ReferenceReplacer.cs @@ -0,0 +1,1025 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.Constants +{ + internal class ReferenceReplacer + { + public static void ReplaceReference(CEContext ctx, ProtectionParameters parameters) + { + foreach (var entry in ctx.ReferenceRepl) + { + if (parameters.GetParameter(ctx.Context, entry.Key, "cfg")) + ReplaceCFG(entry.Key, entry.Value, ctx); + else + ReplaceNormal(entry.Key, entry.Value); + //Brs(entry.Key); + //Calc(entry.Key); + //Mutation2(entry.Key); + //Calc(entry.Key); + //resarm(entry.Key, ctx); + //IfInliner(entry.Key); + //InlineInteger(entry.Key); + //Calc(entry.Key); + //Calc(entry.Key); + //Mutation2(entry.Key); + } + } + private static Random rnd = new Random(); + public static List instr = new List(); + public static bool CanObfuscateLDCI4(IList instructions, int i) + { + if (instructions[i + 1].GetOperand() != null) + if (instructions[i + 1].Operand.ToString().Contains("bool")) + return false; + if (instructions[i + 1].OpCode == OpCodes.Newobj) + return false; + if (instructions[i].GetLdcI4Value() == 0 || instructions[i].GetLdcI4Value() == 1) + return false; + + + return true; + } + + public static void EmptyType(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + method.Body.Instructions[i].Operand = operand - Type.EmptyTypes.Length; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldsfld.ToInstruction(method.Module.Import(typeof(Type).GetField("EmptyTypes")))); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Ldlen)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Add)); + } + } + public static void DoubleParse(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + double n = RandomDouble(1.0, 1000.0); + string converter = Convert.ToString(n); + double nEw = double.Parse(converter); + int conta = operand - (int)nEw; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Ldstr, converter)); + method.Body.Instructions.Insert(i + 2, OpCodes.Call.ToInstruction(method.Module.Import(typeof(double).GetMethod("Parse", new Type[] { typeof(string) })))); + method.Body.Instructions.Insert(i + 3, OpCodes.Conv_I4.ToInstruction()); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Add)); + } + } + + public static void Brs(MethodDef method) + { + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + Instruction instr = method.Body.Instructions[i]; + if (instr.IsLdcI4()) + { + int operand = instr.GetLdcI4Value(); + instr.OpCode = OpCodes.Ldc_I4; + instr.Operand = operand - 1; + int valor = rnd.Next(100, 500); + int valor2 = rnd.Next(1000, 5000); + method.Body.Instructions.Insert(i + 1, Instruction.CreateLdcI4(valor)); + method.Body.Instructions.Insert(i + 2, Instruction.CreateLdcI4(valor2)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Clt)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Conv_I4)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Add)); + i += 5; + } + } + } + public static string RandomString(int length, string chars) + { + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[rnd.Next(s.Length)]).ToArray()); + } + + private static void Calc(MethodDef method) + { + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int op = method.Body.Instructions[i].GetLdcI4Value(); + int newvalue = rnd.Next(-100, 10000); + switch (rnd.Next(1, 4)) + { + case 1: + method.Body.Instructions[i].Operand = op - newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Add.ToInstruction()); + i += 2; + break; + case 2: + method.Body.Instructions[i].Operand = op + newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Sub.ToInstruction()); + i += 2; + break; + case 3: + method.Body.Instructions[i].Operand = op ^ newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Xor.ToInstruction()); + i += 2; + break; + case 4: + int operand = method.Body.Instructions[i].GetLdcI4Value(); + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions[i].Operand = operand - 1; + int valor = rnd.Next(100, 500); + int valor2 = rnd.Next(1000, 5000); + method.Body.Instructions.Insert(i + 1, Instruction.CreateLdcI4(valor)); + method.Body.Instructions.Insert(i + 2, Instruction.CreateLdcI4(valor2)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Clt)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Conv_I4)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Add)); + i += 5; + break; + } + } + } + } + private static double RandomDouble(double min, double max) + { + return new Random().NextDouble() * (max - min) + min; + } + private static void Mutation(MethodDef method) + { + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int op = method.Body.Instructions[i].GetLdcI4Value(); + int newvalue = rnd.Next(3, 12); + switch (rnd.Next(1, 11)) + { + case 1: + method.Body.Instructions[i].OpCode = OpCodes.Ldstr; + method.Body.Instructions[i].Operand = Convert.ToString(op); + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Int32).GetMethod("Parse", new Type[] { typeof(string) })))); + i += 1; + break; + case 2: + method.Body.Instructions[i].Operand = op - newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldstr.ToInstruction(RandomString(newvalue, "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁"))); + method.Body.Instructions.Insert(i + 2, OpCodes.Ldlen.ToInstruction()); + method.Body.Instructions.Insert(i + 3, OpCodes.Add.ToInstruction()); + i += 3; + break; + case 3: + method.Body.Instructions[i].Operand = op + 4; + switch (rnd.Next(1, 4)) + { + case 1: + method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Sizeof, method.Module.Import(typeof(System.Security.SecurityZone)))); + break; + case 2: + method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Sizeof, method.Module.Import(typeof(System.Security.SecurityCriticalScope)))); + break; + case 3: + method.Body.Instructions.Insert(i + 1, new Instruction(OpCodes.Sizeof, method.Module.Import(typeof(System.Security.HostSecurityManagerOptions)))); + break; + + } + method.Body.Instructions.Insert(i + 2, OpCodes.Sub.ToInstruction()); + i += 2; + break; + case 4: + FloorReplacer(method, method.Body.Instructions[i], ref i); + i += 2; + break; + case 5: + CeilingReplacer(method, method.Body.Instructions[i], ref i); + i += 2; + break; + case 6: + RoundReplacer(method, method.Body.Instructions[i], ref i); + i += 2; + break; + case 7: + SqrtReplacer(method, method.Body.Instructions[i], ref i); + i += 2; + break; + case 8: + StructGenerator(method, ref i); + i += 3; + break; + case 9: + EmptyType(method, ref i); + i += 3; + break; + case 10: + DoubleParse(method, ref i); + i += 4; + break; + } + } + } + } + public static int[] rndsizevalues = new int[] { 1, 2, 4, 8, 12, 16 }; + public static Dictionary> Dick = new Dictionary>(); + static int abc = 0; + public static void StructGenerator(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + ITypeDefOrRef valueTypeRef = new Importer(method.Module).Import(typeof(System.ValueType)); + TypeDef structDef = new TypeDefUser(RandomString(rnd.Next(10, 30), "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁abcdefghijlmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01"), valueTypeRef); + Tuple outTuple; + structDef.ClassLayout = new ClassLayoutUser(1, 0); + structDef.Attributes |= TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Public; + List retList = new List(); + int rand = rndsizevalues[rnd.Next(0, 6)]; + retList.Add(GetType(rand)); + retList.ForEach(x => structDef.Fields.Add(new FieldDefUser(RandomString(rnd.Next(10, 30), "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁abcdefghijlmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), new FieldSig(new Importer(method.Module).Import(x).ToTypeSig()), FieldAttributes.Public))); + int operand = method.Body.Instructions[i].GetLdcI4Value(); + if (abc < 25) + { + method.Module.Types.Add(structDef); + Dick.Add(abc++, new Tuple(structDef, rand)); + int conta = operand - rand; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, structDef)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + else + { + Dick.TryGetValue(rnd.Next(1, 24), out outTuple); + int conta = operand - outTuple.Item2; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, outTuple.Item1)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + } + } + private static Type GetType(int operand) + { + switch (operand) + { + case 1: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Boolean); + case 1: return typeof(SByte); + case 2: return typeof(Byte); + } + break; + case 2: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Int16); + case 1: return typeof(UInt16); + case 2: return typeof(Char); + } + break; + case 4: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Int32); + case 1: return typeof(Single); + case 2: return typeof(UInt32); + } + break; + case 8: + switch (rnd.Next(0, 5)) + { + case 0: return typeof(DateTime); + case 1: return typeof(TimeSpan); + case 2: return typeof(Int64); + case 3: return typeof(Double); + case 4: return typeof(UInt64); + } + break; + + case 12: return typeof(ConsoleKeyInfo); + + case 16: + switch (rnd.Next(0, 2)) + { + case 0: return typeof(Guid); + case 1: return typeof(Decimal); + } + break; + } + + return null; + } + public static List CreateTypeList(int size, out int total) + { + List retList = new List(); + int t = 0; + while (size != 0) + { + if (16 <= size) + { + size -= 16; + t += 16; + retList.Add(GetType(16)); + } + else if (12 <= size) + { + size -= 12; + t += 12; + retList.Add(GetType(12)); + } + else if (8 <= size) + { + size -= 8; + t += 8; + retList.Add(GetType(8)); + } + else if (4 <= size) + { + size -= 4; + t += 4; + + retList.Add(GetType(4)); + } + else if (2 <= size) + { + size -= 2; + t += 2; + retList.Add(GetType(2)); + } + else if (1 <= size) + { + size -= 1; + t += 1; + retList.Add(GetType(1)); + } + } + + total = t; + return retList; + } + public static string RandomOrNo() + { + string[] charsc = { "CausalityTraceLevel", "BitConverter", "UnhandledExceptionEventHandler", "PinnedBufferMemoryStream", "RichTextBoxScrollBars", "RichTextBoxSelectionAttribute", "RichTextBoxSelectionTypes", "RichTextBoxStreamType", "RichTextBoxWordPunctuations", "RightToLeft", "RTLAwareMessageBox", "SafeNativeMethods", "SaveFileDialog", "Screen", "ScreenOrientation", "ScrollableControl", "ScrollBar", "ScrollBarRenderer", "ScrollBars", "ScrollButton", "ScrollEventArgs", "ScrollEventHandler", "ScrollEventType", "ScrollOrientation", "ScrollProperties", "SearchDirectionHint", "SearchForVirtualItemEventArgs", "SearchForVirtualItemEventHandler", "SecurityIDType", "SelectedGridItemChangedEventArgs", "SelectedGridItemChangedEventHandler", "SelectionMode", "SelectionRange", "SelectionRangeConverter", "SendKeys", "Shortcut", "SizeGripStyle", "SortOrder", "SpecialFolderEnumConverter", "SplitContainer", "Splitter", "SplitterCancelEventArgs", "SplitterCancelEventHandler", "SplitterEventArgs", "SplitterEventHandler", "SplitterPanel", "StatusBar", "StatusBarDrawItemEventArgs", "StatusBarDrawItemEventHandler", "StatusBarPanel", "StatusBarPanelAutoSize", "StatusBarPanelBorderStyle", "StatusBarPanelClickEventArgs", "StatusBarPanelClickEventHandler", "StatusBarPanelStyle", "StatusStrip", "StringSorter", "StringSource", "StructFormat", "SystemInformation", "SystemParameter", "TabAlignment", "TabAppearance", "TabControl", "TabControlAction", "TabControlCancelEventArgs", "TabControlCancelEventHandler", "TabControlEventArgs", "TabControlEventHandler", "TabDrawMode", "TableLayoutPanel", "TableLayoutControlCollection", "TableLayoutPanelCellBorderStyle", "TableLayoutPanelCellPosition", "TableLayoutPanelCellPositionTypeConverter", "TableLayoutPanelGrowStyle", "TableLayoutSettings", "SizeType", "ColumnStyle", "RowStyle", "TableLayoutStyle", "TableLayoutStyleCollection", "TableLayoutCellPaintEventArgs", "TableLayoutCellPaintEventHandler", "TableLayoutColumnStyleCollection", "TableLayoutRowStyleCollection", "TabPage", "TabRenderer", "TabSizeMode", "TextBox", "TextBoxAutoCompleteSourceConverter", "TextBoxBase", "TextBoxRenderer", "TextDataFormat", "TextImageRelation", "ThreadExceptionDialog", "TickStyle", "ToolBar", "ToolBarAppearance", "ToolBarButton", "ToolBarButtonClickEventArgs", "ToolBarButtonClickEventHandler", "ToolBarButtonStyle", "ToolBarTextAlign", "ToolStrip", "CachedItemHdcInfo", "MouseHoverTimer", "ToolStripSplitStackDragDropHandler", "ToolStripArrowRenderEventArgs", "ToolStripArrowRenderEventHandler", "ToolStripButton", "ToolStripComboBox", "ToolStripControlHost", "ToolStripDropDown", "ToolStripDropDownCloseReason", "ToolStripDropDownClosedEventArgs", "ToolStripDropDownClosedEventHandler", "ToolStripDropDownClosingEventArgs", "ToolStripDropDownClosingEventHandler", "ToolStripDropDownDirection", "ToolStripDropDownButton", "ToolStripDropDownItem", "ToolStripDropDownItemAccessibleObject", "ToolStripDropDownMenu", "ToolStripDropTargetManager", "ToolStripHighContrastRenderer", "ToolStripGrip", "ToolStripGripDisplayStyle", "ToolStripGripRenderEventArgs", "ToolStripGripRenderEventHandler", "ToolStripGripStyle", "ToolStripItem", "ToolStripItemImageIndexer", "ToolStripItemInternalLayout", "ToolStripItemAlignment", "ToolStripItemClickedEventArgs", "ToolStripItemClickedEventHandler", "ToolStripItemCollection", "ToolStripItemDisplayStyle", "ToolStripItemEventArgs", "ToolStripItemEventHandler", "ToolStripItemEventType", "ToolStripItemImageRenderEventArgs", "ToolStripItemImageRenderEventHandler", "ToolStripItemImageScaling", "ToolStripItemOverflow", "ToolStripItemPlacement", "ToolStripItemRenderEventArgs", "ToolStripItemRenderEventHandler", "ToolStripItemStates", "ToolStripItemTextRenderEventArgs", "ToolStripItemTextRenderEventHandler", "ToolStripLabel", "ToolStripLayoutStyle", "ToolStripManager", "ToolStripCustomIComparer", "MergeHistory", "MergeHistoryItem", "ToolStripManagerRenderMode", "ToolStripMenuItem", "MenuTimer", "ToolStripMenuItemInternalLayout", "ToolStripOverflow", "ToolStripOverflowButton", "ToolStripContainer", "ToolStripContentPanel", "ToolStripPanel", "ToolStripPanelCell", "ToolStripPanelRenderEventArgs", "ToolStripPanelRenderEventHandler", "ToolStripContentPanelRenderEventArgs", "ToolStripContentPanelRenderEventHandler", "ToolStripPanelRow", "ToolStripPointType", "ToolStripProfessionalRenderer", "ToolStripProfessionalLowResolutionRenderer", "ToolStripProgressBar", "ToolStripRenderer", "ToolStripRendererSwitcher", "ToolStripRenderEventArgs", "ToolStripRenderEventHandler", "ToolStripRenderMode", "ToolStripScrollButton", "ToolStripSeparator", "ToolStripSeparatorRenderEventArgs", "ToolStripSeparatorRenderEventHandler", "ToolStripSettings", "ToolStripSettingsManager", "ToolStripSplitButton", "ToolStripSplitStackLayout", "ToolStripStatusLabel", "ToolStripStatusLabelBorderSides", "ToolStripSystemRenderer", "ToolStripTextBox", "ToolStripTextDirection", "ToolStripLocationCancelEventArgs", "ToolStripLocationCancelEventHandler", "ToolTip", "ToolTipIcon", "TrackBar", "TrackBarRenderer", "TreeNode", "TreeNodeMouseClickEventArgs", "TreeNodeMouseClickEventHandler", "TreeNodeCollection", "TreeNodeConverter", "TreeNodeMouseHoverEventArgs", "TreeNodeMouseHoverEventHandler", "TreeNodeStates", "TreeView", "TreeViewAction", "TreeViewCancelEventArgs", "TreeViewCancelEventHandler", "TreeViewDrawMode", "TreeViewEventArgs", "TreeViewEventHandler", "TreeViewHitTestInfo", "TreeViewHitTestLocations", "TreeViewImageIndexConverter", "TreeViewImageKeyConverter", "Triangle", "TriangleDirection", "TypeValidationEventArgs", "TypeValidationEventHandler", "UICues", "UICuesEventArgs", "UICuesEventHandler", "UpDownBase", "UpDownEventArgs", "UpDownEventHandler", "UserControl", "ValidationConstraints", "View", "VScrollBar", "VScrollProperties", "WebBrowser", "WebBrowserEncryptionLevel", "WebBrowserReadyState", "WebBrowserRefreshOption", "WebBrowserBase", "WebBrowserContainer", "WebBrowserDocumentCompletedEventHandler", "WebBrowserDocumentCompletedEventArgs", "WebBrowserHelper", "WebBrowserNavigatedEventHandler", "WebBrowserNavigatedEventArgs", "WebBrowserNavigatingEventHandler", "WebBrowserNavigatingEventArgs", "WebBrowserProgressChangedEventHandler", "WebBrowserProgressChangedEventArgs", "WebBrowserSiteBase", "WebBrowserUriTypeConverter", "WinCategoryAttribute", "WindowsFormsSection", "WindowsFormsSynchronizationContext", "IntSecurity", "WindowsFormsUtils", "IComponentEditorPageSite", "LayoutSettings", "PageSetupDialog", "PrintControllerWithStatusDialog", "PrintDialog", "PrintPreviewControl", "PrintPreviewDialog", "TextFormatFlags", "TextRenderer", "WindowsGraphicsWrapper", "SRDescriptionAttribute", "SRCategoryAttribute", "SR", "VisualStyleElement", "VisualStyleInformation", "VisualStyleRenderer", "VisualStyleState", "ComboBoxState", "CheckBoxState", "GroupBoxState", "HeaderItemState", "PushButtonState", "RadioButtonState", "ScrollBarArrowButtonState", "ScrollBarState", "ScrollBarSizeBoxState", "TabItemState", "TextBoxState", "ToolBarState", "TrackBarThumbState", "BackgroundType", "BorderType", "ImageOrientation", "SizingType", "FillType", "HorizontalAlign", "ContentAlignment", "VerticalAlignment", "OffsetType", "IconEffect", "TextShadowType", "GlyphType", "ImageSelectType", "TrueSizeScalingType", "GlyphFontSizingType", "ColorProperty", "EnumProperty", "FilenameProperty", "FontProperty", "IntegerProperty", "PointProperty", "MarginProperty", "StringProperty", "BooleanProperty", "Edges", "EdgeStyle", "EdgeEffects", "TextMetrics", "TextMetricsPitchAndFamilyValues", "TextMetricsCharacterSet", "HitTestOptions", "HitTestCode", "ThemeSizeType", "VisualStyleDocProperty", "VisualStyleSystemProperty", "ArrayElementGridEntry", "CategoryGridEntry", "DocComment", "DropDownButton", "DropDownButtonAdapter", "GridEntry", "AttributeTypeSorter", "GridEntryRecreateChildrenEventHandler", "GridEntryRecreateChildrenEventArgs", "GridEntryCollection", "GridErrorDlg", "GridToolTip", "HotCommands", "ImmutablePropertyDescriptorGridEntry", "IRootGridEntry", "MergePropertyDescriptor", "MultiPropertyDescriptorGridEntry", "MultiSelectRootGridEntry", "PropertiesTab", "PropertyDescriptorGridEntry", "PropertyGridCommands", "PropertyGridView", "SingleSelectRootGridEntry", "ComponentEditorForm", "ComponentEditorPage", "EventsTab", "IUIService", "IWindowsFormsEditorService", "PropertyTab", "ToolStripItemDesignerAvailability", "ToolStripItemDesignerAvailabilityAttribute", "WindowsFormsComponentEditor", "BaseCAMarshaler", "Com2AboutBoxPropertyDescriptor", "Com2ColorConverter", "Com2ComponentEditor", "Com2DataTypeToManagedDataTypeConverter", "Com2Enum", "Com2EnumConverter", "Com2ExtendedBrowsingHandler", "Com2ExtendedTypeConverter", "Com2FontConverter", "Com2ICategorizePropertiesHandler", "Com2IDispatchConverter", "Com2IManagedPerPropertyBrowsingHandler", "Com2IPerPropertyBrowsingHandler", "Com2IProvidePropertyBuilderHandler", "Com2IVsPerPropertyBrowsingHandler", "Com2PictureConverter", "Com2Properties", "Com2PropertyBuilderUITypeEditor", "Com2PropertyDescriptor", "GetAttributesEvent", "Com2EventHandler", "GetAttributesEventHandler", "GetNameItemEvent", "GetNameItemEventHandler", "DynamicMetaObjectProviderDebugView", "ExpressionTreeCallRewriter", "ICSharpInvokeOrInvokeMemberBinder", "ResetBindException", "RuntimeBinder", "RuntimeBinderController", "RuntimeBinderException", "RuntimeBinderInternalCompilerException", "SpecialNames", "SymbolTable", "RuntimeBinderExtensions", "NameManager", "Name", "NameTable", "OperatorKind", "PredefinedName", "PredefinedType", "TokenFacts", "TokenKind", "OutputContext", "UNSAFESTATES", "CheckedContext", "BindingFlag", "ExpressionBinder", "BinOpKind", "BinOpMask", "CandidateFunctionMember", "ConstValKind", "CONSTVAL", "ConstValFactory", "ConvKind", "CONVERTTYPE", "BetterType", "ListExtensions", "CConversions", "Operators", "UdConvInfo", "ArgInfos", "BodyType", "ConstCastResult", "AggCastResult", "UnaryOperatorSignatureFindResult", "UnaOpKind", "UnaOpMask", "OpSigFlags", "LiftFlags", "CheckLvalueKind", "BinOpFuncKind", "UnaOpFuncKind", "ExpressionKind", "ExpressionKindExtensions", "EXPRExtensions", "ExprFactory", "EXPRFLAG", "FileRecord", "FUNDTYPE", "GlobalSymbolContext", "InputFile", "LangCompiler", "MemLookFlags", "MemberLookup", "CMemberLookupResults", "mdToken", "CorAttributeTargets", "MethodKindEnum", "MethodTypeInferrer", "NameGenerator", "CNullable", "NullableCallLiftKind", "CONSTRESKIND", "LambdaParams", "TypeOrSimpleNameResolution", "InitializerKind", "ConstantStringConcatenation", "ForeachKind", "PREDEFATTR", "PREDEFMETH", "PREDEFPROP", "MethodRequiredEnum", "MethodCallingConventionEnum", "MethodSignatureEnum", "PredefinedMethodInfo", "PredefinedPropertyInfo", "PredefinedMembers", "ACCESSERROR", "CSemanticChecker", "SubstTypeFlags", "SubstContext", "CheckConstraintsFlags", "TypeBind", "UtilityTypeExtensions", "SymWithType", "MethPropWithType", "MethWithType", "PropWithType", "EventWithType", "FieldWithType", "MethPropWithInst", "MethWithInst", "AggregateDeclaration", "Declaration", "GlobalAttributeDeclaration", "ITypeOrNamespace", "AggregateSymbol", "AssemblyQualifiedNamespaceSymbol", "EventSymbol", "FieldSymbol", "IndexerSymbol", "LabelSymbol", "LocalVariableSymbol", "MethodOrPropertySymbol", "MethodSymbol", "InterfaceImplementationMethodSymbol", "IteratorFinallyMethodSymbol", "MiscSymFactory", "NamespaceOrAggregateSymbol", "NamespaceSymbol", "ParentSymbol", "PropertySymbol", "Scope", "KAID", "ACCESS", "AggKindEnum", "ARRAYMETHOD", "SpecCons", "Symbol", "SymbolExtensions", "SymFactory", "SymFactoryBase", "SYMKIND", "SynthAggKind", "SymbolLoader", "AidContainer", "BSYMMGR", "symbmask_t", "SYMTBL", "TransparentIdentifierMemberSymbol", "TypeParameterSymbol", "UnresolvedAggregateSymbol", "VariableSymbol", "EXPRARRAYINDEX", "EXPRARRINIT", "EXPRARRAYLENGTH", "EXPRASSIGNMENT", "EXPRBINOP", "EXPRBLOCK", "EXPRBOUNDLAMBDA", "EXPRCALL", "EXPRCAST", "EXPRCLASS", "EXPRMULTIGET", "EXPRMULTI", "EXPRCONCAT", "EXPRQUESTIONMARK", "EXPRCONSTANT", "EXPREVENT", "EXPR", "ExpressionIterator", "EXPRFIELD", "EXPRFIELDINFO", "EXPRHOISTEDLOCALEXPR", "EXPRLIST", "EXPRLOCAL", "EXPRMEMGRP", "EXPRMETHODINFO", "EXPRFUNCPTR", "EXPRNamedArgumentSpecification", "EXPRPROP", "EXPRPropertyInfo", "EXPRRETURN", "EXPRSTMT", "EXPRWRAP", "EXPRTHISPOINTER", "EXPRTYPEARGUMENTS", "EXPRTYPEOF", "EXPRTYPEORNAMESPACE", "EXPRUNARYOP", "EXPRUNBOUNDLAMBDA", "EXPRUSERDEFINEDCONVERSION", "EXPRUSERLOGOP", "EXPRZEROINIT", "ExpressionTreeRewriter", "ExprVisitorBase", "AggregateType", "ArgumentListType", "ArrayType", "BoundLambdaType", "ErrorType", "MethodGroupType", "NullableType", "NullType", "OpenTypePlaceholderType", "ParameterModifierType", "PointerType", "PredefinedTypes", "PredefinedTypeFacts", "CType", "TypeArray", "TypeFactory", "TypeManager", "TypeParameterType", "KeyPair`2", "TypeTable", "VoidType", "CError", "CParameterizedError", "CErrorFactory", "ErrorFacts", "ErrArgKind", "ErrArgFlags", "SymWithTypeMemo", "MethPropWithInstMemo", "ErrArg", "ErrArgRef", "ErrArgRefOnly", "ErrArgNoRef", "ErrArgIds", "ErrArgSymKind", "ErrorHandling", "IErrorSink", "MessageID", "UserStringBuilder", "CController", "d__10`1", "d__11`1", "DynamicProperty", "DynamicDebugViewEmptyException", "<>c__DisplayClass20_0", "ExpressionEXPR", "ArgumentObject", "NameHashKey", "<>c__DisplayClass18_0", "<>c__DisplayClass18_1", "<>c__DisplayClass43_0", "<>c__DisplayClass45_0", "KnownName", "BinOpArgInfo", "BinOpSig", "BinOpFullSig", "ConversionFunc", "ExplicitConversion", "PfnBindBinOp", "PfnBindUnaOp", "GroupToArgsBinder", "GroupToArgsBinderResult", "ImplicitConversion", "UnaOpSig", "UnaOpFullSig", "OPINFO", "d__1", "CMethodIterator", "NewInferenceResult", "Dependency", "d__0", "d__1", "d__2", "d__3", "d__4", "d__0", "Kind", "TypeArrayKey", "Key", "PredefinedTypeInfo", "StdTypeVarColl", "<>c__DisplayClass71_0", "__StaticArrayInitTypeSize=104", "__StaticArrayInitTypeSize=169", "SNINativeMethodWrapper", "QTypes", "ProviderEnum", "IOType", "ConsumerNumber", "SqlAsyncCallbackDelegate", "ConsumerInfo", "SNI_Error", "Win32NativeMethods", "NativeOledbWrapper", "AdalException", "ADALNativeWrapper", "Sni_Consumer_Info", "SNI_ConnWrapper", "SNI_Packet_IOType", "ConsumerNum", "$ArrayType$$$BY08$$CBG", "_GUID", "SNI_CLIENT_CONSUMER_INFO", "IUnknown", "__s_GUID", "IChapteredRowset", "_FILETIME", "ProviderNum", "ITransactionLocal", "SNI_ERROR", "$ArrayType$$$BY08G", "BOID", "ModuleLoadException", "ModuleLoadExceptionHandlerException", "ModuleUninitializer", "LanguageSupport", "gcroot", "$ArrayType$$$BY00Q6MPBXXZ", "Progress", "$ArrayType$$$BY0A@P6AXXZ", "$ArrayType$$$BY0A@P6AHXZ", "__enative_startup_state", "TriBool", "ICLRRuntimeHost", "ThisModule", "_EXCEPTION_POINTERS", "Bid", "SqlDependencyProcessDispatcher", "BidIdentityAttribute", "BidMetaTextAttribute", "BidMethodAttribute", "BidArgumentTypeAttribute", "ExtendedClrTypeCode", "ITypedGetters", "ITypedGettersV3", "ITypedSetters", "ITypedSettersV3", "MetaDataUtilsSmi", "SmiConnection", "SmiContext", "SmiContextFactory", "SmiEventSink", "SmiEventSink_Default", "SmiEventSink_DeferedProcessing", "SmiEventStream", "SmiExecuteType", "SmiGettersStream", "SmiLink", "SmiMetaData", "SmiExtendedMetaData", "SmiParameterMetaData", "SmiStorageMetaData", "SmiQueryMetaData", "SmiRecordBuffer", "SmiRequestExecutor", "SmiSettersStream", "SmiStream", "SmiXetterAccessMap", "SmiXetterTypeCode", "SqlContext", "SqlDataRecord", "SqlPipe", "SqlTriggerContext", "ValueUtilsSmi", "SqlClientWrapperSmiStream", "SqlClientWrapperSmiStreamChars", "IBinarySerialize", "InvalidUdtException", "SqlFacetAttribute", "DataAccessKind", "SystemDataAccessKind", "SqlFunctionAttribute", "SqlMetaData", "SqlMethodAttribute", "FieldInfoEx", "BinaryOrderedUdtNormalizer", "Normalizer", "BooleanNormalizer", "SByteNormalizer", "ByteNormalizer", "ShortNormalizer", "UShortNormalizer", "IntNormalizer", "UIntNormalizer", "LongNormalizer", "ULongNormalizer", "FloatNormalizer", "DoubleNormalizer", "SqlProcedureAttribute", "SerializationHelperSql9", "Serializer", "NormalizedSerializer", "BinarySerializeSerializer", "DummyStream", "SqlTriggerAttribute", "SqlUserDefinedAggregateAttribute", "SqlUserDefinedTypeAttribute", "TriggerAction", "MemoryRecordBuffer", "SmiPropertySelector", "SmiMetaDataPropertyCollection", "SmiMetaDataProperty", "SmiUniqueKeyProperty", "SmiOrderProperty", "SmiDefaultFieldsProperty", "SmiTypedGetterSetter", "SqlRecordBuffer", "BaseTreeIterator", "DataDocumentXPathNavigator", "DataPointer", "DataSetMapper", "IXmlDataVirtualNode", "BaseRegionIterator", "RegionIterator", "TreeIterator", "ElementState", "XmlBoundElement", "XmlDataDocument", "XmlDataImplementation", "XPathNodePointer", "AcceptRejectRule", "InternalDataCollectionBase", "TypedDataSetGenerator", "StrongTypingException", "TypedDataSetGeneratorException", "ColumnTypeConverter", "CommandBehavior", "CommandType", "KeyRestrictionBehavior", "ConflictOption", "ConnectionState", "Constraint", "ConstraintCollection", "ConstraintConverter", "ConstraintEnumerator", "ForeignKeyConstraintEnumerator", "ChildForeignKeyConstraintEnumerator", "ParentForeignKeyConstraintEnumerator", "DataColumn", "AutoIncrementValue", "AutoIncrementInt64", "AutoIncrementBigInteger", "DataColumnChangeEventArgs", "DataColumnChangeEventHandler", "DataColumnCollection", "DataColumnPropertyDescriptor", "DataError", "DataException", "ConstraintException", "DeletedRowInaccessibleException", "DuplicateNameException", "InRowChangingEventException", "InvalidConstraintException", "MissingPrimaryKeyException", "NoNullAllowedException", "ReadOnlyException", "RowNotInTableException", "VersionNotFoundException", "ExceptionBuilder", "DataKey", "DataRelation", "DataRelationCollection", "DataRelationPropertyDescriptor", "DataRow", "DataRowBuilder", "DataRowAction", "DataRowChangeEventArgs", "DataRowChangeEventHandler", "DataRowCollection", "DataRowCreatedEventHandler", "DataSetClearEventhandler", "DataRowState", "DataRowVersion", "DataRowView", "SerializationFormat", "DataSet", "DataSetSchemaImporterExtension", "DataSetDateTime", "DataSysDescriptionAttribute", "DataTable", "DataTableClearEventArgs", "DataTableClearEventHandler", "DataTableCollection", "DataTableNewRowEventArgs", "DataTableNewRowEventHandler", "DataTablePropertyDescriptor", "DataTableReader", "DataTableReaderListener", "DataTableTypeConverter", "DataView", "DataViewListener", "DataViewManager", "DataViewManagerListItemTypeDescriptor", "DataViewRowState", "DataViewSetting", "DataViewSettingCollection", "DBConcurrencyException", "DbType", "DefaultValueTypeConverter", "FillErrorEventArgs", "FillErrorEventHandler", "AggregateNode", "BinaryNode", "LikeNode", "ConstNode", "DataExpression", "ExpressionNode", "ExpressionParser", "Tokens", "OperatorInfo", "InvalidExpressionException", "EvaluateException", "SyntaxErrorException", "ExprException", "FunctionNode", "FunctionId", "Function", "IFilter", "LookupNode", "NameNode", "UnaryNode", "ZeroOpNode", "ForeignKeyConstraint", "IColumnMapping", "IColumnMappingCollection", "IDataAdapter", "IDataParameter", "IDataParameterCollection", "IDataReader", "IDataRecord", "IDbCommand", "IDbConnection", "IDbDataAdapter", "IDbDataParameter", "IDbTransaction", "IsolationLevel", "ITableMapping", "ITableMappingCollection", "LoadOption", "MappingType", "MergeFailedEventArgs", "MergeFailedEventHandler", "Merger", "MissingMappingAction", "MissingSchemaAction", "OperationAbortedException", "ParameterDirection", "PrimaryKeyTypeConverter", "PropertyCollection", "RBTreeError", "TreeAccessMethod", "RBTree`1", "RecordManager", "StatementCompletedEventArgs", "StatementCompletedEventHandler", "RelatedView", "RelationshipConverter", "Rule", "SchemaSerializationMode", "SchemaType", "IndexField", "Index", "Listeners`1", "SimpleType", "LocalDBAPI", "LocalDBInstanceElement", "LocalDBInstancesCollection", "LocalDBConfigurationSection", "SqlDbType", "StateChangeEventArgs", "StateChangeEventHandler", "StatementType", "UniqueConstraint", "UpdateRowSource", "UpdateStatus", "XDRSchema", "XmlDataLoader", "XMLDiffLoader", "XmlReadMode", "SchemaFormat", "XmlTreeGen", "NewDiffgramGen", "XmlDataTreeWriter", "DataTextWriter", "DataTextReader", "XMLSchema", "ConstraintTable", "XSDSchema", "XmlIgnoreNamespaceReader", "XmlToDatasetMap", "XmlWriteMode", "SqlEventSource", "SqlDataSourceEnumerator", "SqlGenericUtil", "SqlNotificationRequest", "INullable", "SqlBinary", "SqlBoolean", "SqlByte", "SqlBytesCharsState", "SqlBytes", "StreamOnSqlBytes", "SqlChars", "StreamOnSqlChars", "SqlStreamChars", "SqlDateTime", "SqlDecimal", "SqlDouble", "SqlFileStream", "UnicodeString", "SecurityQualityOfService", "FileFullEaInformation", "SqlGuid", "SqlInt16", "SqlInt32", "SqlInt64", "SqlMoney", "SQLResource", "SqlSingle", "SqlCompareOptions", "SqlString", "SqlTypesSchemaImporterExtensionHelper", "TypeCharSchemaImporterExtension", "TypeNCharSchemaImporterExtension", "TypeVarCharSchemaImporterExtension", "TypeNVarCharSchemaImporterExtension", "TypeTextSchemaImporterExtension", "TypeNTextSchemaImporterExtension", "TypeVarBinarySchemaImporterExtension", "TypeBinarySchemaImporterExtension", "TypeVarImageSchemaImporterExtension", "TypeDecimalSchemaImporterExtension", "TypeNumericSchemaImporterExtension", "TypeBigIntSchemaImporterExtension", "TypeIntSchemaImporterExtension", "TypeSmallIntSchemaImporterExtension", "TypeTinyIntSchemaImporterExtension", "TypeBitSchemaImporterExtension", "TypeFloatSchemaImporterExtension", "TypeRealSchemaImporterExtension", "TypeDateTimeSchemaImporterExtension", "TypeSmallDateTimeSchemaImporterExtension", "TypeMoneySchemaImporterExtension", "TypeSmallMoneySchemaImporterExtension", "TypeUniqueIdentifierSchemaImporterExtension", "EComparison", "StorageState", "SqlTypeException", "SqlNullValueException", "SqlTruncateException", "SqlNotFilledException", "SqlAlreadyFilledException", "SQLDebug", "SqlXml", "SqlXmlStreamWrapper", "SqlClientEncryptionAlgorithmFactoryList", "SqlSymmetricKeyCache", "SqlColumnEncryptionKeyStoreProvider", "SqlColumnEncryptionCertificateStoreProvider", "SqlColumnEncryptionCngProvider", "SqlColumnEncryptionCspProvider", "SqlAeadAes256CbcHmac256Algorithm", "SqlAeadAes256CbcHmac256Factory", "SqlAeadAes256CbcHmac256EncryptionKey", "SqlAes256CbcAlgorithm", "SqlAes256CbcFactory", "SqlClientEncryptionAlgorithm", "SqlClientEncryptionAlgorithmFactory", "SqlClientEncryptionType", "SqlClientSymmetricKey", "SqlSecurityUtility", "SqlQueryMetadataCache", "ApplicationIntent", "SqlCredential", "SqlConnectionPoolKey", "AssemblyCache", "OnChangeEventHandler", "SqlRowsCopiedEventArgs", "SqlRowsCopiedEventHandler", "SqlBuffer", "_ColumnMapping", "Row", "BulkCopySimpleResultSet", "SqlBulkCopy", "SqlBulkCopyColumnMapping", "SqlBulkCopyColumnMappingCollection", "SqlBulkCopyOptions", "SqlCachedBuffer", "SqlClientFactory", "SqlClientMetaDataCollectionNames", "SqlClientPermission", "SqlClientPermissionAttribute", "SqlCommand", "SqlCommandBuilder", "SqlCommandSet", "SqlConnection", "SQLDebugging", "ISQLDebug", "SqlDebugContext", "MEMMAP", "SqlConnectionFactory", "SqlPerformanceCounters", "SqlConnectionPoolGroupProviderInfo", "SqlConnectionPoolProviderInfo", "SqlConnectionString", "SqlConnectionStringBuilder", "SqlConnectionTimeoutErrorPhase", "SqlConnectionInternalSourceType", "SqlConnectionTimeoutPhaseDuration", "SqlConnectionTimeoutErrorInternal", "SqlDataAdapter", "SqlDataReader", "SqlDataReaderSmi", "SqlDelegatedTransaction", "SqlDependency", "SqlDependencyPerAppDomainDispatcher", "SqlNotification", "MetaType", "TdsDateTime", "SqlError", "SqlErrorCollection", "SqlException", "SqlInfoMessageEventArgs", "SqlInfoMessageEventHandler", "SqlInternalConnection", "SqlInternalConnectionSmi", "SessionStateRecord", "SessionData", "SqlInternalConnectionTds", "ServerInfo", "TransactionState", "TransactionType", "SqlInternalTransaction", "SqlMetaDataFactory", "SqlNotificationEventArgs", "SqlNotificationInfo", "SqlNotificationSource", "SqlNotificationType", "DataFeed", "StreamDataFeed", "TextDataFeed", "XmlDataFeed", "SqlParameter", "SqlParameterCollection", "SqlReferenceCollection", "SqlRowUpdatedEventArgs", "SqlRowUpdatedEventHandler", "SqlRowUpdatingEventArgs", "SqlRowUpdatingEventHandler", "SqlSequentialStream", "SqlSequentialStreamSmi", "System.Diagnostics.DebuggableAttribute", "System.Diagnostics", "System.Net.WebClient", "System", "System.Specialized.Protection" }; + return charsc[rnd.Next(charsc.Length)]; + } + private static void FloorReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig + RandomDouble(0.01, 0.99); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Floor", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + public static void IfInliner(MethodDef method) + { + Local local = new Local(method.Module.ImportAsTypeSig(typeof(int))); + method.Body.Variables.Add(local); + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + if (CanObfuscateLDCI4(method.Body.Instructions, i)) + { + int numorig = rnd.Next(); + int div = rnd.Next(); + int num = numorig ^ div; + + Instruction nop = OpCodes.Nop.ToInstruction(); + method.Body.Instructions.Insert(i + 1, OpCodes.Stloc_S.ToInstruction(local)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Ldc_I4, method.Body.Instructions[i].GetLdcI4Value() - sizeof(float))); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Ldc_I4, num)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Ldc_I4, div)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Xor)); + method.Body.Instructions.Insert(i + 6, Instruction.Create(OpCodes.Ldc_I4, numorig)); + method.Body.Instructions.Insert(i + 7, Instruction.Create(OpCodes.Bne_Un, nop)); + method.Body.Instructions.Insert(i + 8, Instruction.Create(OpCodes.Ldc_I4, 2)); + method.Body.Instructions.Insert(i + 9, OpCodes.Stloc_S.ToInstruction(local)); + method.Body.Instructions.Insert(i + 10, Instruction.Create(OpCodes.Sizeof, method.Module.Import(typeof(float)))); + method.Body.Instructions.Insert(i + 11, Instruction.Create(OpCodes.Add)); + method.Body.Instructions.Insert(i + 12, nop); + i += 12; + } + } + } + } + public static void InlineInteger(MethodDef method) + { + Local new_local = new Local(method.Module.CorLibTypes.String); + method.Body.Variables.Add(new_local); + Local new_local2 = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(new_local2); + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + if (CanObfuscateLDCI4(method.Body.Instructions, i)) + { + if (method.DeclaringType.IsGlobalModuleType) return; + if (!method.HasBody) return; + var instr = method.Body.Instructions; + if ((i - 1) > 0) + try + { + + if (instr[i - 1].OpCode == OpCodes.Callvirt) + { + if (instr[i + 1].OpCode == OpCodes.Call) + { + return; + } + } + } + catch { } + bool is_valid_inline = true; + switch (rnd.Next(0, 2)) + { + case 0: + is_valid_inline = true; + break; + case 1: + is_valid_inline = false; + break; + } + + + var value = instr[i].GetLdcI4Value(); + var first_ldstr = RandomString(5, "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁"); + + instr.Insert(i, Instruction.Create(OpCodes.Ldloc_S, new_local2)); + + instr.Insert(i, Instruction.Create(OpCodes.Stloc_S, new_local2)); + if (is_valid_inline) + { + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value)); + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value + 1)); + } + else + { + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value + 1)); + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value)); + } + instr.Insert(i, + Instruction.Create(OpCodes.Call, + method.Module.Import(typeof(System.String).GetMethod("op_Equality", + new Type[] { typeof(string), typeof(string) })))); + instr.Insert(i, Instruction.Create(OpCodes.Ldstr, first_ldstr)); + instr.Insert(i, Instruction.Create(OpCodes.Ldloc_S, new_local)); + instr.Insert(i, Instruction.Create(OpCodes.Stloc_S, new_local)); + if (is_valid_inline) + { + instr.Insert(i, Instruction.Create(OpCodes.Ldstr, first_ldstr)); + } + else + { + instr.Insert(i, + Instruction.Create(OpCodes.Ldstr, + RandomString(7, "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁"))); + } + instr.Insert(i + 5, Instruction.Create(OpCodes.Brtrue_S, instr[i + 6])); + instr.Insert(i + 7, Instruction.Create(OpCodes.Br_S, instr[i + 8])); + instr.RemoveAt(i + 10); + i += 10; + } + } + } + } + private static void RoundReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig + RandomDouble(0.01, 0.5); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Round", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + private static void SqrtReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + if ((int)instruction.Operand > 1) + { + int orig = (int)instruction.Operand; + double m = (double)orig * orig; + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + } + catch { } + } + private static void CeilingReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig - 1 + RandomDouble(0.01, 0.99); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Ceiling", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + static void ReplaceNormal(MethodDef method, List> instrs) + { + foreach (var instr in instrs) + { + int i = method.Body.Instructions.IndexOf(instr.Item1); + instr.Item1.OpCode = OpCodes.Ldc_I4; + instr.Item1.Operand = (int)instr.Item2; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Call, instr.Item3)); + } + } + + struct CFGContext + { + public CEContext Ctx; + public ControlFlowGraph Graph; + public BlockKey[] Keys; + public RandomGenerator Random; + public Dictionary StatesMap; + public Local StateVariable; + } + + struct CFGState + { + public uint A; + public uint B; + public uint C; + public uint D; + + public CFGState(uint seed) + { + A = seed *= 0x21412321; + B = seed *= 0x21412321; + C = seed *= 0x21412321; + D = seed *= 0x21412321; + } + + public void UpdateExplicit(int id, uint value) + { + switch (id) + { + case 0: + A = value; + break; + case 1: + B = value; + break; + case 2: + C = value; + break; + case 3: + D = value; + break; + } + } + + public void UpdateIncremental(int id, uint value) + { + switch (id) + { + case 0: + A *= value; + break; + case 1: + B += value; + break; + case 2: + C ^= value; + break; + case 3: + D -= value; + break; + } + } + + public uint GetIncrementalUpdate(int id, uint target) + { + switch (id) + { + case 0: + return A ^ target; + case 1: + return target - B; + case 2: + return C ^ target; + case 3: + return D - target; + } + throw new UnreachableException(); + } + + public uint Get(int id) + { + switch (id) + { + case 0: + return A; + case 1: + return B; + case 2: + return C; + case 3: + return D; + } + throw new UnreachableException(); + } + + public static byte EncodeFlag(bool exp, int updateId, int getId) + { + byte fl = (byte)(exp ? 0x80 : 0); + fl |= (byte)updateId; + fl |= (byte)(getId << 2); + return fl; + } + } + + static void InjectStateType(CEContext ctx) + { + if (ctx.CfgCtxType == null) + { + var type = ctx.Context.Registry.GetService().GetRuntimeType("Confuser.Runtime.CFGCtx"); + ctx.CfgCtxType = InjectHelper.Inject(type, ctx.Module); + ctx.Module.Types.Add(ctx.CfgCtxType); + ctx.CfgCtxCtor = ctx.CfgCtxType.FindMethod(".ctor"); + ctx.CfgCtxNext = ctx.CfgCtxType.FindMethod("Next"); + + ctx.Name.MarkHelper(ctx.CfgCtxType, ctx.Marker, ctx.Protection); + foreach (var def in ctx.CfgCtxType.Fields) + ctx.Name.MarkHelper(def, ctx.Marker, ctx.Protection); + foreach (var def in ctx.CfgCtxType.Methods) + ctx.Name.MarkHelper(def, ctx.Marker, ctx.Protection); + } + } + + static void InsertEmptyStateUpdate(CFGContext ctx, ControlFlowBlock block) + { + var body = ctx.Graph.Body; + var key = ctx.Keys[block.Id]; + if (key.EntryState == key.ExitState) + return; + + Instruction first = null; + // Cannot use graph.IndexOf because instructions has been modified. + int targetIndex = body.Instructions.IndexOf(block.Header); + + CFGState entry; + if (!ctx.StatesMap.TryGetValue(key.EntryState, out entry)) + { + key.Type = BlockKeyType.Explicit; + } + + + if (key.Type == BlockKeyType.Incremental) + { + // Incremental + + CFGState exit; + if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) + { + // Create new exit state + // Update one of the entry states to be exit state + exit = entry; + int updateId = ctx.Random.NextInt32(3); + uint targetValue = ctx.Random.NextUInt32(); + exit.UpdateExplicit(updateId, targetValue); + + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(false, updateId, getId); + var incr = entry.GetIncrementalUpdate(updateId, targetValue); + + body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); + + ctx.StatesMap[key.ExitState] = exit; + } + else + { + // Scan for updated state + var headerIndex = targetIndex; + for (int stateId = 0; stateId < 4; stateId++) + { + if (entry.Get(stateId) == exit.Get(stateId)) + continue; + + uint targetValue = exit.Get(stateId); + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(false, stateId, getId); + var incr = entry.GetIncrementalUpdate(stateId, targetValue); + + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); + } + first = body.Instructions[headerIndex]; + } + } + else + { + // Explicit + + CFGState exit; + if (!ctx.StatesMap.TryGetValue(key.ExitState, out exit)) + { + // Create new exit state from random seed + var seed = ctx.Random.NextUInt32(); + exit = new CFGState(seed); + body.Instructions.Insert(targetIndex++, first = Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)seed)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor)); + + ctx.StatesMap[key.ExitState] = exit; + } + else + { + // Scan for updated state + var headerIndex = targetIndex; + for (int stateId = 0; stateId < 4; stateId++) + { + uint targetValue = exit.Get(stateId); + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(true, stateId, getId); + + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + body.Instructions.Insert(targetIndex++, Instruction.Create(OpCodes.Pop)); + } + first = body.Instructions[headerIndex]; + } + } + + ctx.Graph.Body.ReplaceReference(block.Header, first); + } + + static uint InsertStateGetAndUpdate(CFGContext ctx, ref int index, BlockKeyType type, ref CFGState currentState, CFGState? targetState) + { + var body = ctx.Graph.Body; + + if (type == BlockKeyType.Incremental) + { + // Incremental + + if (targetState == null) + { + // Randomly update and get state + int updateId = ctx.Random.NextInt32(3); + uint targetValue = ctx.Random.NextUInt32(); + + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(false, updateId, getId); + var incr = currentState.GetIncrementalUpdate(updateId, targetValue); + currentState.UpdateExplicit(updateId, targetValue); + + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + + return currentState.Get(getId); + } + // Scan for updated state + int[] stateIds = { 0, 1, 2, 3 }; + ctx.Random.Shuffle(stateIds); + int i = 0; + uint getValue = 0; + foreach (var stateId in stateIds) + { + // There must be at least one update&get + if (currentState.Get(stateId) == targetState.Value.Get(stateId) && + i != stateIds.Length - 1) + { + i++; + continue; + } + + uint targetValue = targetState.Value.Get(stateId); + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(false, stateId, getId); + var incr = currentState.GetIncrementalUpdate(stateId, targetValue); + currentState.UpdateExplicit(stateId, targetValue); + + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + + i++; + if (i == stateIds.Length) + getValue = currentState.Get(getId); + else + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop)); + } + return getValue; + } + else + { + // Explicit + + if (targetState == null) + { + // Create new exit state from random seed + var seed = ctx.Random.NextUInt32(); + currentState = new CFGState(seed); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Dup)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)seed)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxCtor)); + + // Randomly get state + int updateId = ctx.Random.NextInt32(3); + uint targetValue = ctx.Random.NextUInt32(); + + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(false, updateId, getId); + var incr = currentState.GetIncrementalUpdate(updateId, targetValue); + currentState.UpdateExplicit(updateId, targetValue); + + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)incr)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + + return currentState.Get(getId); + } + else + { + // Scan for updated state + int[] stateIds = { 0, 1, 2, 3 }; + ctx.Random.Shuffle(stateIds); + int i = 0; + uint getValue = 0; + foreach (var stateId in stateIds) + { + uint targetValue = targetState.Value.Get(stateId); + int getId = ctx.Random.NextInt32(3); + var fl = CFGState.EncodeFlag(true, stateId, getId); + currentState.UpdateExplicit(stateId, targetValue); + + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldloca, ctx.StateVariable)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4_S, (sbyte)fl)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)targetValue)); + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.Ctx.CfgCtxNext)); + + i++; + if (i == stateIds.Length) + getValue = targetState.Value.Get(getId); + else + body.Instructions.Insert(index++, Instruction.Create(OpCodes.Pop)); + } + return getValue; + } + } + } + + static void ReplaceCFG(MethodDef method, List> instrs, CEContext ctx) + { + InjectStateType(ctx); + + var graph = ControlFlowGraph.Construct(method.Body); + var sequence = KeySequence.ComputeKeys(graph, null); + + var cfgCtx = new CFGContext + { + Ctx = ctx, + Graph = graph, + Keys = sequence, + StatesMap = new Dictionary(), + Random = ctx.Random + }; + + cfgCtx.StateVariable = new Local(ctx.CfgCtxType.ToTypeSig()); + method.Body.Variables.Add(cfgCtx.StateVariable); + method.Body.InitLocals = true; + + var blockReferences = new Dictionary>>(); + foreach (var instr in instrs) + { + var index = graph.IndexOf(instr.Item1); + var block = graph.GetContainingBlock(index); + + SortedList> list; + if (!blockReferences.TryGetValue(block.Id, out list)) + list = blockReferences[block.Id] = new SortedList>(); + + list.Add(index, instr); + } + + // Update state for blocks not in use + for (int i = 0; i < graph.Count; i++) + { + var block = graph[i]; + if (blockReferences.ContainsKey(block.Id)) + continue; + InsertEmptyStateUpdate(cfgCtx, block); + } + + // Update references + foreach (var blockRef in blockReferences) + { + var key = sequence[blockRef.Key]; + CFGState currentState; + if (!cfgCtx.StatesMap.TryGetValue(key.EntryState, out currentState)) + { + Debug.Assert((graph[blockRef.Key].Type & ControlFlowBlockType.Entry) != 0); + Debug.Assert(key.Type == BlockKeyType.Explicit); + + // Create new entry state + uint blockSeed = ctx.Random.NextUInt32(); + currentState = new CFGState(blockSeed); + cfgCtx.StatesMap[key.EntryState] = currentState; + + var index = graph.Body.Instructions.IndexOf(graph[blockRef.Key].Header); + Instruction newHeader; + method.Body.Instructions.Insert(index++, newHeader = Instruction.Create(OpCodes.Ldloca, cfgCtx.StateVariable)); + method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Ldc_I4, (int)blockSeed)); + method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Call, ctx.CfgCtxCtor)); + method.Body.ReplaceReference(graph[blockRef.Key].Header, newHeader); + key.Type = BlockKeyType.Incremental; + } + var type = key.Type; + + for (int i = 0; i < blockRef.Value.Count; i++) + { + var refEntry = blockRef.Value.Values[i]; + + CFGState? targetState = null; + if (i == blockRef.Value.Count - 1) + { + CFGState exitState; + if (cfgCtx.StatesMap.TryGetValue(key.ExitState, out exitState)) + targetState = exitState; + } + + var index = graph.Body.Instructions.IndexOf(refEntry.Item1) + 1; + var value = InsertStateGetAndUpdate(cfgCtx, ref index, type, ref currentState, targetState); + + refEntry.Item1.OpCode = OpCodes.Ldc_I4; + refEntry.Item1.Operand = (int)(refEntry.Item2 ^ value); + method.Body.Instructions.Insert(index++, Instruction.Create(OpCodes.Xor)); + method.Body.Instructions.Insert(index, Instruction.Create(OpCodes.Call, refEntry.Item3)); + + if (i == blockRef.Value.Count - 1 && targetState == null) + { + cfgCtx.StatesMap[key.ExitState] = currentState; + } + + type = BlockKeyType.Incremental; + } + } + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Protection/a.cs b/Additions/Constant/Protection/a.cs new file mode 100644 index 000000000..5fc633fa9 --- /dev/null +++ b/Additions/Constant/Protection/a.cs @@ -0,0 +1,38 @@ + public static int[] rndsizevalues = new int[] { 1, 2, 4, 8, 12, 16 }; + public static Dictionary> Dick = new Dictionary>(); + static int abc = 0; + public static void StructGenerator(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + ITypeDefOrRef valueTypeRef = new Importer(method.Module).Import(typeof(System.ValueType)); + TypeDef structDef = new TypeDefUser(RandomString(rnd.Next(10, 30), ""), valueTypeRef); + Tuple outTuple; + structDef.ClassLayout = new ClassLayoutUser(1, 0); + structDef.Attributes |= TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Public; + List retList = new List(); + int rand = rndsizevalues[rnd.Next(0, 6)]; + retList.Add(GetType(rand)); + retList.ForEach(x => structDef.Fields.Add(new FieldDefUser(RandomString(rnd.Next(10, 30), ""), new FieldSig(new Importer(method.Module).Import(x).ToTypeSig()), FieldAttributes.Public))); + int operand = method.Body.Instructions[i].GetLdcI4Value(); + if (abc < 25) + { + method.Module.Types.Add(structDef); + Dick.Add(abc++, new Tuple(structDef, rand)); + int conta = operand - rand; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, structDef)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + else + { + Dick.TryGetValue(rnd.Next(1, 24), out outTuple); + int conta = operand - outTuple.Item2; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, outTuple.Item1)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + } + } \ No newline at end of file diff --git a/Additions/Constant/Protection/x86Mode.cs b/Additions/Constant/Protection/x86Mode.cs new file mode 100644 index 000000000..511bb6e3d --- /dev/null +++ b/Additions/Constant/Protection/x86Mode.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.DynCipher; +using Confuser.DynCipher.AST; +using Confuser.DynCipher.Generation; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.MD; +using dnlib.DotNet.Writer; +using MethodBody = dnlib.DotNet.Writer.MethodBody; + +namespace Confuser.Protections.Constants { + internal class x86Mode : IEncodeMode { + Action encryptFunc; + + public IEnumerable EmitDecrypt(MethodDef init, CEContext ctx, Local block, Local key) { + StatementBlock encrypt, decrypt; + ctx.DynCipher.GenerateCipherPair(ctx.Random, out encrypt, out decrypt); + var ret = new List(); + + var codeGen = new CipherCodeGen(block, key, init, ret); + codeGen.GenerateCIL(decrypt); + codeGen.Commit(init.Body); + + var dmCodeGen = new DMCodeGen(typeof(void), new[] { + Tuple.Create("{BUFFER}", typeof(uint[])), + Tuple.Create("{KEY}", typeof(uint[])) + }); + dmCodeGen.GenerateCIL(encrypt); + encryptFunc = dmCodeGen.Compile>(); + + return ret; + } + + public uint[] Encrypt(uint[] data, int offset, uint[] key) { + var ret = new uint[key.Length]; + Buffer.BlockCopy(data, offset * sizeof(uint), ret, 0, key.Length * sizeof(uint)); + encryptFunc(ret, key); + return ret; + } + + public object CreateDecoder(MethodDef decoder, CEContext ctx) { + var encoding = new x86Encoding(); + encoding.Compile(ctx); + MutationHelper.ReplacePlaceholder(decoder, arg => { + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Call, encoding.native)); + return repl.ToArray(); + }); + return encoding; + } + + public uint Encode(object data, CEContext ctx, uint id) { + var encoding = (x86Encoding)data; + return (uint)encoding.expCompiled((int)id); + } + + class CipherCodeGen : CILCodeGen { + readonly Local block; + readonly Local key; + + public CipherCodeGen(Local block, Local key, MethodDef init, IList instrs) + : base(init, instrs) { + this.block = block; + this.key = key; + } + + protected override Local Var(Variable var) { + if (var.Name == "{BUFFER}") + return block; + if (var.Name == "{KEY}") + return key; + return base.Var(var); + } + } + + class x86Encoding { + byte[] code; + MethodBody codeChunk; + + public Func expCompiled; + Expression expression; + Expression inverse; + public MethodDef native; + + public void Compile(CEContext ctx) { + var var = new Variable("{VAR}"); + var result = new Variable("{RESULT}"); + + CorLibTypeSig int32 = ctx.Module.CorLibTypes.Int32; + native = new MethodDefUser("", MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static); + native.ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig; + // Attempt to improve performance --- failed with StackOverflowException... :/ + //var suppressAttr = ctx.Method.Module.CorLibTypes.GetTypeRef("System.Security", "SuppressUnmanagedCodeSecurityAttribute").ResolveThrow(); + //native.CustomAttributes.Add(new CustomAttribute((MemberRef)ctx.Method.Module.Import(suppressAttr.FindDefaultConstructor()))); + //native.HasSecurity = true; + ctx.Module.GlobalType.Methods.Add(native); + + ctx.Name.MarkHelper(native, ctx.Marker, ctx.Protection); + + x86Register? reg; + var codeGen = new x86CodeGen(); + do { + ctx.DynCipher.GenerateExpressionPair( + ctx.Random, + new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, + 4, out expression, out inverse); + + reg = codeGen.GenerateX86(inverse, (v, r) => { return new[] { x86Instruction.Create(x86OpCode.POP, new x86RegisterOperand(r)) }; }); + } while (reg == null); + + code = CodeGenUtils.AssembleCode(codeGen, reg.Value); + + expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) + .GenerateCIL(expression) + .Compile>(); + + + ctx.Context.CurrentModuleWriterOptions.WriterEvent += InjectNativeCode; + } + + void InjectNativeCode(object sender, ModuleWriterEventArgs e) { + var writer = e.Writer; + switch (e.Event) + { + case ModuleWriterEvent.MDEndWriteMethodBodies: + codeChunk = writer.MethodBodies.Add(new MethodBody(code)); + break; + case ModuleWriterEvent.EndCalculateRvasAndFileOffsets: + uint rid = writer.Metadata.GetRid(native); + var methodRow = writer.Metadata.TablesHeap.MethodTable[rid]; + writer.Metadata.TablesHeap.MethodTable[rid] = new RawMethodRow( + (uint)codeChunk.RVA, + methodRow.ImplFlags, + methodRow.Flags, + methodRow.Name, + methodRow.Signature, + methodRow.ParamList); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Runtime/Constant2.cs b/Additions/Constant/Runtime/Constant2.cs new file mode 100644 index 000000000..56d0eee24 --- /dev/null +++ b/Additions/Constant/Runtime/Constant2.cs @@ -0,0 +1,134 @@ +using System; +using System.Text; +using System.Reflection; +using System.Diagnostics; + +namespace Confuser.Runtime { + internal static class Constant2 { + static byte[] b; + + static void Initialize() { + var l = (uint)Mutation2.KeyI0; + uint[] q = Mutation2.Placeholder(new uint[Mutation2.KeyI0]); + + var k = new uint[0x10]; + var n = (uint)Mutation2.KeyI1; + for (int i = 0; i < 0x10; i++) { + n ^= n >> 12; + n ^= n << 25; + n ^= n >> 27; + k[i] = n; + } + + int s = 0, d = 0; + var w = new uint[0x10]; + var o = new byte[l * 4]; + while (s < l) { + for (int j = 0; j < 0x10; j++) + w[j] = q[s + j]; + Mutation2.Crypt(w, k); + for (int j = 0; j < 0x10; j++) { + uint e = w[j]; + o[d++] = (byte)e; + o[d++] = (byte)(e >> 8); + o[d++] = (byte)(e >> 16); + o[d++] = (byte)(e >> 24); + k[j] ^= e; + } + s += 0x10; + } + + b = Lzma2.Decompress(o); + } + + static T Get(uint id) { + id = (uint)Mutation2.Placeholder((int)id); + uint t = id >> 30; + + T ret = default(T); + id &= 0x3fffffff; + id <<= 2; + + if (t == Mutation2.KeyI0) + { + int l = b[id++] | (b[id++] << 8) | (b[id++] << 16) | (b[id++] << 24); + ret = (T)(object)string.Intern(Encoding.UTF8.GetString(b, (int)id, l)); + } + // NOTE: Assume little-endian + else if (t == Mutation2.KeyI1) + { + var v = new T[1]; + Buffer.BlockCopy(b, (int)id, v, 0, Mutation2.Value()); + ret = v[0]; + } + else if (t == Mutation2.KeyI2) + { + int s = b[id++] | (b[id++] << 8) | (b[id++] << 16) | (b[id++] << 24); + int l = b[id++] | (b[id++] << 8) | (b[id++] << 16) | (b[id++] << 24); + Array v = Array.CreateInstance(typeof(T).GetElementType(), l); + Buffer.BlockCopy(b, (int)id, v, 0, s - 4); + ret = (T)(object)v; + } + return ret; + } + } + + internal struct CFGCtx { + uint A; + uint B; + uint C; + uint D; + + public CFGCtx(uint seed) { + A = seed *= 0x21412321; + B = seed *= 0x21412321; + C = seed *= 0x21412321; + D = seed *= 0x21412321; + } + + public uint Next(byte f, uint q) { + if ((f & 0x80) != 0) { + switch (f & 0x3) { + case 0: + A = q; + break; + case 1: + B = q; + break; + case 2: + C = q; + break; + case 3: + D = q; + break; + } + } + else { + switch (f & 0x3) { + case 0: + A ^= q; + break; + case 1: + B += q; + break; + case 2: + C ^= q; + break; + case 3: + D -= q; + break; + } + } + + switch ((f >> 2) & 0x3) { + case 0: + return A; + case 1: + return B; + case 2: + return C; + } + return D; + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Runtime/Lzma2.cs b/Additions/Constant/Runtime/Lzma2.cs new file mode 100644 index 000000000..01afbac22 --- /dev/null +++ b/Additions/Constant/Runtime/Lzma2.cs @@ -0,0 +1,597 @@ +using System; +using System.IO; + +namespace Confuser.Runtime { + internal static class Lzma2 { + const uint kNumStates = 12; + + const int kNumPosSlotBits = 6; + + const uint kNumLenToPosStates = 4; + + const uint kMatchMinLen = 2; + + const int kNumAlignBits = 4; + const uint kAlignTableSize = 1 << kNumAlignBits; + + const uint kStartPosModelIndex = 4; + const uint kEndPosModelIndex = 14; + + const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2); + + const int kNumPosStatesBitsMax = 4; + const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax); + + const int kNumLowLenBits = 3; + const int kNumMidLenBits = 3; + const int kNumHighLenBits = 8; + const uint kNumLowLenSymbols = 1 << kNumLowLenBits; + const uint kNumMidLenSymbols = 1 << kNumMidLenBits; + + public static byte[] Decompress(byte[] data) { + var s = new MemoryStream(data); + var decoder = new LzmaDecoder(); + var prop = new byte[5]; + s.Read(prop, 0, 5); + decoder.SetDecoderProperties(prop); + long outSize = 0; + for (int i = 0; i < 8; i++) { + int v = s.ReadByte(); + outSize |= ((long)(byte)v) << (8 * i); + } + var b = new byte[(int)outSize]; + var z = new MemoryStream(b, true); + long compressedSize = s.Length - 13; + decoder.Code(s, z, compressedSize, outSize); + return b; + } + + struct BitDecoder { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + const int kNumMoveBits = 5; + + uint Prob; + + public void Init() { + Prob = kBitModelTotal >> 1; + } + + public uint Decode(Decoder rangeDecoder) { + uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob; + if (rangeDecoder.Code < newBound) { + rangeDecoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 0; + } + rangeDecoder.Range -= newBound; + rangeDecoder.Code -= newBound; + Prob -= (Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 1; + } + } + + struct BitTreeDecoder { + readonly BitDecoder[] Models; + readonly int NumBitLevels; + + public BitTreeDecoder(int numBitLevels) { + NumBitLevels = numBitLevels; + Models = new BitDecoder[1 << numBitLevels]; + } + + public void Init() { + for (uint i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + + public uint Decode(Decoder rangeDecoder) { + uint m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--) + m = (m << 1) + Models[m].Decode(rangeDecoder); + return m - ((uint)1 << NumBitLevels); + } + + public uint ReverseDecode(Decoder rangeDecoder) { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) { + uint bit = Models[m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + + public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex, + Decoder rangeDecoder, int NumBitLevels) { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) { + uint bit = Models[startIndex + m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + } + + class Decoder { + public const uint kTopValue = (1 << 24); + public uint Code; + public uint Range; + public Stream Stream; + + public void Init(Stream stream) { + // Stream.Init(stream); + Stream = stream; + + Code = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 5; i++) + Code = (Code << 8) | (byte)Stream.ReadByte(); + } + + public void ReleaseStream() { + Stream = null; + } + + public void Normalize() { + while (Range < kTopValue) { + Code = (Code << 8) | (byte)Stream.ReadByte(); + Range <<= 8; + } + } + + public uint DecodeDirectBits(int numTotalBits) { + uint range = Range; + uint code = Code; + uint result = 0; + for (int i = numTotalBits; i > 0; i--) { + range >>= 1; + /* + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + */ + uint t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < kTopValue) { + code = (code << 8) | (byte)Stream.ReadByte(); + range <<= 8; + } + } + Range = range; + Code = code; + return result; + } + } + + class LzmaDecoder { + readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[kNumStates << kNumPosStatesBitsMax]; + readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[kNumStates << kNumPosStatesBitsMax]; + readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[kNumStates]; + readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[kNumStates]; + readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[kNumStates]; + readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[kNumStates]; + + readonly LenDecoder m_LenDecoder = new LenDecoder(); + + readonly LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); + readonly OutWindow m_OutWindow = new OutWindow(); + readonly BitDecoder[] m_PosDecoders = new BitDecoder[kNumFullDistances - kEndPosModelIndex]; + readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[kNumLenToPosStates]; + readonly Decoder m_RangeDecoder = new Decoder(); + readonly LenDecoder m_RepLenDecoder = new LenDecoder(); + bool _solid = false; + + uint m_DictionarySize; + uint m_DictionarySizeCheck; + BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(kNumAlignBits); + + uint m_PosStateMask; + + public LzmaDecoder() { + m_DictionarySize = 0xFFFFFFFF; + for (int i = 0; i < kNumLenToPosStates; i++) + m_PosSlotDecoder[i] = new BitTreeDecoder(kNumPosSlotBits); + } + + void SetDictionarySize(uint dictionarySize) { + if (m_DictionarySize != dictionarySize) { + m_DictionarySize = dictionarySize; + m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1); + uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12)); + m_OutWindow.Create(blockSize); + } + } + + void SetLiteralProperties(int lp, int lc) { + m_LiteralDecoder.Create(lp, lc); + } + + void SetPosBitsProperties(int pb) { + uint numPosStates = (uint)1 << pb; + m_LenDecoder.Create(numPosStates); + m_RepLenDecoder.Create(numPosStates); + m_PosStateMask = numPosStates - 1; + } + + void Init(Stream inStream, Stream outStream) { + m_RangeDecoder.Init(inStream); + m_OutWindow.Init(outStream, _solid); + + uint i; + for (i = 0; i < kNumStates; i++) { + for (uint j = 0; j <= m_PosStateMask; j++) { + uint index = (i << kNumPosStatesBitsMax) + j; + m_IsMatchDecoders[index].Init(); + m_IsRep0LongDecoders[index].Init(); + } + m_IsRepDecoders[i].Init(); + m_IsRepG0Decoders[i].Init(); + m_IsRepG1Decoders[i].Init(); + m_IsRepG2Decoders[i].Init(); + } + + m_LiteralDecoder.Init(); + for (i = 0; i < kNumLenToPosStates; i++) + m_PosSlotDecoder[i].Init(); + // m_PosSpecDecoder.Init(); + for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + m_PosDecoders[i].Init(); + + m_LenDecoder.Init(); + m_RepLenDecoder.Init(); + m_PosAlignDecoder.Init(); + } + + public void Code(Stream inStream, Stream outStream, + Int64 inSize, Int64 outSize) { + Init(inStream, outStream); + + var state = new State(); + state.Init(); + uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; + + UInt64 nowPos64 = 0; + var outSize64 = (UInt64)outSize; + if (nowPos64 < outSize64) { + m_IsMatchDecoders[state.Index << kNumPosStatesBitsMax].Decode(m_RangeDecoder); + state.UpdateChar(); + byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0); + m_OutWindow.PutByte(b); + nowPos64++; + } + while (nowPos64 < outSize64) { + // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); + // while(nowPos64 < next) + { + uint posState = (uint)nowPos64 & m_PosStateMask; + if (m_IsMatchDecoders[(state.Index << kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) { + byte b; + byte prevByte = m_OutWindow.GetByte(0); + if (!state.IsCharState()) + b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, + (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0)); + else + b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte); + m_OutWindow.PutByte(b); + state.UpdateChar(); + nowPos64++; + } + else { + uint len; + if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1) { + if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0) { + if (m_IsRep0LongDecoders[(state.Index << kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) { + state.UpdateShortRep(); + m_OutWindow.PutByte(m_OutWindow.GetByte(rep0)); + nowPos64++; + continue; + } + } + else { + UInt32 distance; + if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0) { + distance = rep1; + } + else { + if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0) + distance = rep2; + else { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + kMatchMinLen; + state.UpdateRep(); + } + else { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); + state.UpdateMatch(); + uint posSlot = m_PosSlotDecoder[GetLenToPosState(len)].Decode(m_RangeDecoder); + if (posSlot >= kStartPosModelIndex) { + var numDirectBits = (int)((posSlot >> 1) - 1); + rep0 = ((2 | (posSlot & 1)) << numDirectBits); + if (posSlot < kEndPosModelIndex) + rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders, + rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); + else { + rep0 += (m_RangeDecoder.DecodeDirectBits( + numDirectBits - kNumAlignBits) << kNumAlignBits); + rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); + } + } + else + rep0 = posSlot; + } + if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck) { + if (rep0 == 0xFFFFFFFF) + break; + } + m_OutWindow.CopyBlock(rep0, len); + nowPos64 += len; + } + } + } + m_OutWindow.Flush(); + m_OutWindow.ReleaseStream(); + m_RangeDecoder.ReleaseStream(); + } + + public void SetDecoderProperties(byte[] properties) { + int lc = properties[0] % 9; + int remainder = properties[0] / 9; + int lp = remainder % 5; + int pb = remainder / 5; + UInt32 dictionarySize = 0; + for (int i = 0; i < 4; i++) + dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); + SetDictionarySize(dictionarySize); + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + } + + static uint GetLenToPosState(uint len) { + len -= kMatchMinLen; + if (len < kNumLenToPosStates) + return len; + return unchecked((kNumLenToPosStates - 1)); + } + + class LenDecoder { + readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[kNumPosStatesMax]; + readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[kNumPosStatesMax]; + BitDecoder m_Choice = new BitDecoder(); + BitDecoder m_Choice2 = new BitDecoder(); + BitTreeDecoder m_HighCoder = new BitTreeDecoder(kNumHighLenBits); + uint m_NumPosStates; + + public void Create(uint numPosStates) { + for (uint posState = m_NumPosStates; posState < numPosStates; posState++) { + m_LowCoder[posState] = new BitTreeDecoder(kNumLowLenBits); + m_MidCoder[posState] = new BitTreeDecoder(kNumMidLenBits); + } + m_NumPosStates = numPosStates; + } + + public void Init() { + m_Choice.Init(); + for (uint posState = 0; posState < m_NumPosStates; posState++) { + m_LowCoder[posState].Init(); + m_MidCoder[posState].Init(); + } + m_Choice2.Init(); + m_HighCoder.Init(); + } + + public uint Decode(Decoder rangeDecoder, uint posState) { + if (m_Choice.Decode(rangeDecoder) == 0) + return m_LowCoder[posState].Decode(rangeDecoder); + uint symbol = kNumLowLenSymbols; + if (m_Choice2.Decode(rangeDecoder) == 0) + symbol += m_MidCoder[posState].Decode(rangeDecoder); + else { + symbol += kNumMidLenSymbols; + symbol += m_HighCoder.Decode(rangeDecoder); + } + return symbol; + } + } + + class LiteralDecoder { + Decoder2[] m_Coders; + int m_NumPosBits; + int m_NumPrevBits; + uint m_PosMask; + + public void Create(int numPosBits, int numPrevBits) { + if (m_Coders != null && m_NumPrevBits == numPrevBits && + m_NumPosBits == numPosBits) + return; + m_NumPosBits = numPosBits; + m_PosMask = ((uint)1 << numPosBits) - 1; + m_NumPrevBits = numPrevBits; + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new Decoder2[numStates]; + for (uint i = 0; i < numStates; i++) + m_Coders[i].Create(); + } + + public void Init() { + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + for (uint i = 0; i < numStates; i++) + m_Coders[i].Init(); + } + + uint GetState(uint pos, byte prevByte) { + return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); + } + + public byte DecodeNormal(Decoder rangeDecoder, uint pos, byte prevByte) { + return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); + } + + public byte DecodeWithMatchByte(Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) { + return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); + } + + struct Decoder2 { + BitDecoder[] m_Decoders; + + public void Create() { + m_Decoders = new BitDecoder[0x300]; + } + + public void Init() { + for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); + } + + public byte DecodeNormal(Decoder rangeDecoder) { + uint symbol = 1; + do + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); while (symbol < 0x100); + return (byte)symbol; + } + + public byte DecodeWithMatchByte(Decoder rangeDecoder, byte matchByte) { + uint symbol = 1; + do { + uint matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + if (matchBit != bit) { + while (symbol < 0x100) + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); + break; + } + } while (symbol < 0x100); + return (byte)symbol; + } + } + }; + } + + class OutWindow { + byte[] _buffer; + uint _pos; + Stream _stream; + uint _streamPos; + uint _windowSize; + + public void Create(uint windowSize) { + if (_windowSize != windowSize) { + _buffer = new byte[windowSize]; + } + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + } + + public void Init(Stream stream, bool solid) { + ReleaseStream(); + _stream = stream; + if (!solid) { + _streamPos = 0; + _pos = 0; + } + } + + public void ReleaseStream() { + Flush(); + _stream = null; + Buffer.BlockCopy(new byte[_buffer.Length], 0, _buffer, 0, _buffer.Length); + } + + public void Flush() { + uint size = _pos - _streamPos; + if (size == 0) + return; + _stream.Write(_buffer, (int)_streamPos, (int)size); + if (_pos >= _windowSize) + _pos = 0; + _streamPos = _pos; + } + + public void CopyBlock(uint distance, uint len) { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + for (; len > 0; len--) { + if (pos >= _windowSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + if (_pos >= _windowSize) + Flush(); + } + } + + public void PutByte(byte b) { + _buffer[_pos++] = b; + if (_pos >= _windowSize) + Flush(); + } + + public byte GetByte(uint distance) { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + return _buffer[pos]; + } + } + + struct State { + public uint Index; + + public void Init() { + Index = 0; + } + + public void UpdateChar() { + if (Index < 4) Index = 0; + else if (Index < 10) Index -= 3; + else Index -= 6; + } + + public void UpdateMatch() { + Index = (uint)(Index < 7 ? 7 : 10); + } + + public void UpdateRep() { + Index = (uint)(Index < 7 ? 8 : 11); + } + + public void UpdateShortRep() { + Index = (uint)(Index < 7 ? 9 : 11); + } + + public bool IsCharState() { + return Index < 7; + } + } + } +} \ No newline at end of file diff --git a/Additions/Constant/Runtime/Mutation2.cs b/Additions/Constant/Runtime/Mutation2.cs new file mode 100644 index 000000000..45f1445f6 --- /dev/null +++ b/Additions/Constant/Runtime/Mutation2.cs @@ -0,0 +1,531 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Protections.Constants; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Runtime +{ + internal class Mutation2 + { + public static readonly int KeyI0 = 0; + public static readonly int KeyI1 = 1; + public static readonly int KeyI2 = 2; + public static readonly int KeyI3 = 3; + public static readonly int KeyI4 = 4; + public static readonly int KeyI5 = 5; + public static readonly int KeyI6 = 6; + public static readonly int KeyI7 = 7; + public static readonly int KeyI8 = 8; + public static readonly int KeyI9 = 9; + public static readonly int KeyI10 = 10; + public static readonly int KeyI11 = 11; + public static readonly int KeyI12 = 12; + public static readonly int KeyI13 = 13; + public static readonly int KeyI14 = 14; + public static readonly int KeyI15 = 15; + + public static T Placeholder(T val) + { + return val; + } + + public static T Value() + { + return default(T); + } + + public static T Value(Arg0 arg0) + { + return default(T); + } + + public static void Crypt(uint[] data, uint[] key) + { + } + + + private static Random rnd = new Random(); + public static List instr = new List(); + public static bool CanObfuscateLDCI4(IList instructions, int i) + { + if (instructions[i + 1].GetOperand() != null) + if (instructions[i + 1].Operand.ToString().Contains("bool")) + return false; + if (instructions[i + 1].OpCode == OpCodes.Newobj) + return false; + if (instructions[i].GetLdcI4Value() == 0 || instructions[i].GetLdcI4Value() == 1) + return false; + + + return true; + } + + public static void EmptyType(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + method.Body.Instructions[i].Operand = operand - Type.EmptyTypes.Length; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, + OpCodes.Ldsfld.ToInstruction(method.Module.Import(typeof(Type).GetField("EmptyTypes")))); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Ldlen)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Add)); + } + } + public static void DoubleParse(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int operand = method.Body.Instructions[i].GetLdcI4Value(); + double n = RandomDouble(1.0, 1000.0); + string converter = Convert.ToString(n); + double nEw = double.Parse(converter); + int conta = operand - (int)nEw; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Ldstr, converter)); + method.Body.Instructions.Insert(i + 2, + OpCodes.Call.ToInstruction( + method.Module.Import(typeof(double).GetMethod("Parse", new Type[] { typeof(string) })))); + method.Body.Instructions.Insert(i + 3, OpCodes.Conv_I4.ToInstruction()); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Add)); + } + } + + public static void Brs(MethodDef method) + { + for (int i = 0; i < method.Body.Instructions.Count; + i++) + { + Instruction instr = method.Body.Instructions[i]; + if (instr.IsLdcI4()) + { + int operand = instr.GetLdcI4Value(); + instr.OpCode = OpCodes.Ldc_I4; + instr.Operand = operand - 1; + int valor = rnd.Next(100, 500); + int valor2 = rnd.Next(1000, 5000); + method.Body.Instructions.Insert(i + 1, Instruction.CreateLdcI4(valor)); + method.Body.Instructions.Insert(i + 2, Instruction.CreateLdcI4(valor2)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Clt)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Conv_I4)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Add)); + i += 5; + } + } + } + public static string RandomString(int length, string chars) + { + return new string(Enumerable.Repeat(chars, length) + .Select(s => s[rnd.Next(s.Length)]).ToArray()); + } + + private static void Calc(MethodDef method) + { + for (int i = 0; i < method.Body.Instructions.Count; + i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + int op = method.Body.Instructions[i].GetLdcI4Value(); + int newvalue = rnd.Next(-100, 10000); + switch (rnd.Next(1, 4)) + { + case 1: + method.Body.Instructions[i].Operand = op - newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Add.ToInstruction()); + i += 2; + break; + case 2: + method.Body.Instructions[i].Operand = op + newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Sub.ToInstruction()); + i += 2; + break; + case 3: + method.Body.Instructions[i].Operand = op ^ newvalue; + method.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + method.Body.Instructions.Insert(i + 2, OpCodes.Xor.ToInstruction()); + i += 2; + break; + case 4: + int operand = method.Body.Instructions[i].GetLdcI4Value(); + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions[i].Operand = operand - 1; + int valor = rnd.Next(100, 500); + int valor2 = rnd.Next(1000, 5000); + method.Body.Instructions.Insert(i + 1, Instruction.CreateLdcI4(valor)); + method.Body.Instructions.Insert(i + 2, Instruction.CreateLdcI4(valor2)); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Clt)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Conv_I4)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Add)); + i += 5; + break; + } + } + } + } + private static double RandomDouble(double min, double max) + { + return new Random().NextDouble() * (max - min) + min; + } + + public static int[] rndsizevalues = new int[] { + 1, 2, 4, 8, 12, 16 + }; + public static Dictionary> Dick = new Dictionary>(); + static int abc = 0; + public static void StructGenerator(MethodDef method, ref int i) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + ITypeDefOrRef valueTypeRef = new Importer(method.Module).Import(typeof(System.ValueType)); + TypeDef structDef = + new TypeDefUser( + RandomString(rnd.Next(10, 30), + "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁abcdefghijlmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01"), valueTypeRef); + Tuple outTuple; + structDef.ClassLayout = new ClassLayoutUser(1, 0); + structDef.Attributes |= TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Public; + List retList = new List(); + int rand = rndsizevalues[rnd.Next(0, 6)]; + retList.Add(GetType(rand)); + retList.ForEach(x => structDef.Fields.Add(new FieldDefUser( + RandomString(rnd.Next(10, 30), + "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁abcdefghijlmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), + new FieldSig(new Importer(method.Module).Import(x).ToTypeSig()), FieldAttributes.Public))); + int operand = method.Body.Instructions[i].GetLdcI4Value(); + if (abc < 25) + { + method.Module.Types.Add(structDef); + Dick.Add(abc++, new Tuple(structDef, rand)); + int conta = operand - rand; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, structDef)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + else + { + Dick.TryGetValue(rnd.Next(1, 24), out outTuple); + int conta = operand - outTuple.Item2; + method.Body.Instructions[i].Operand = conta; + method.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + method.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, outTuple.Item1)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + } + } + } + + private static Type GetType(int operand) + { + switch (operand) + { + case 1: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Boolean); + case 1: return typeof(SByte); + case 2: return typeof(Byte); + } + break; + case 2: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Int16); + case 1: return typeof(UInt16); + case 2: return typeof(Char); + } + break; + case 4: + switch (rnd.Next(0, 3)) + { + case 0: return typeof(Int32); + case 1: return typeof(Single); + case 2: return typeof(UInt32); + } + break; + case 8: + switch (rnd.Next(0, 5)) + { + case 0: return typeof(DateTime); + case 1: return typeof(TimeSpan); + case 2: return typeof(Int64); + case 3: return typeof(Double); + case 4: return typeof(UInt64); + } + break; + + case 12: return typeof(ConsoleKeyInfo); + + case 16: + switch (rnd.Next(0, 2)) + { + case 0: return typeof(Guid); + case 1: return typeof(Decimal); + } + break; + } + + return null; + } + public static List CreateTypeList(int size, out int total) + { + List retList = new List(); + int t = 0; + while (size != 0) + { + if (16 <= size) + { + size -= 16; + t += 16; + retList.Add(GetType(16)); + } + else if (12 <= size) + { + size -= 12; + t += 12; + retList.Add(GetType(12)); + } + else if (8 <= size) + { + size -= 8; + t += 8; + retList.Add(GetType(8)); + } + else if (4 <= size) + { + size -= 4; + t += 4; + + retList.Add(GetType(4)); + } + else if (2 <= size) + { + size -= 2; + t += 2; + retList.Add(GetType(2)); + } + else if (1 <= size) + { + size -= 1; + t += 1; + retList.Add(GetType(1)); + } + } + + total = t; + return retList; + } + public static string RandomOrNo() + { + string[] charsc = { "CausalityTraceLevel", "BitConverter", "UnhandledExceptionEventHandler", "PinnedBufferMemoryStream", "RichTextBoxScrollBars", "RichTextBoxSelectionAttribute", "RichTextBoxSelectionTypes", "RichTextBoxStreamType", "RichTextBoxWordPunctuations", "RightToLeft", "RTLAwareMessageBox", "SafeNativeMethods", "SaveFileDialog", "Screen", "ScreenOrientation", "ScrollableControl", "ScrollBar", "ScrollBarRenderer", "ScrollBars", "ScrollButton", "ScrollEventArgs", "ScrollEventHandler", "ScrollEventType", "ScrollOrientation", "ScrollProperties", "SearchDirectionHint", "SearchForVirtualItemEventArgs", "SearchForVirtualItemEventHandler", "SecurityIDType", "SelectedGridItemChangedEventArgs", "SelectedGridItemChangedEventHandler", "SelectionMode", "SelectionRange", "SelectionRangeConverter", "SendKeys", "Shortcut", "SizeGripStyle", "SortOrder", "SpecialFolderEnumConverter", "SplitContainer", "Splitter", "SplitterCancelEventArgs", "SplitterCancelEventHandler", "SplitterEventArgs", "SplitterEventHandler", "SplitterPanel", "StatusBar", "StatusBarDrawItemEventArgs", "StatusBarDrawItemEventHandler", "StatusBarPanel", "StatusBarPanelAutoSize", "StatusBarPanelBorderStyle", "StatusBarPanelClickEventArgs", "StatusBarPanelClickEventHandler", "StatusBarPanelStyle", "StatusStrip", "StringSorter", "StringSource", "StructFormat", "SystemInformation", "SystemParameter", "TabAlignment", "TabAppearance", "TabControl", "TabControlAction", "TabControlCancelEventArgs", "TabControlCancelEventHandler", "TabControlEventArgs", "TabControlEventHandler", "TabDrawMode", "TableLayoutPanel", "TableLayoutControlCollection", "TableLayoutPanelCellBorderStyle", "TableLayoutPanelCellPosition", "TableLayoutPanelCellPositionTypeConverter", "TableLayoutPanelGrowStyle", "TableLayoutSettings", "SizeType", "ColumnStyle", "RowStyle", "TableLayoutStyle", "TableLayoutStyleCollection", "TableLayoutCellPaintEventArgs", "TableLayoutCellPaintEventHandler", "TableLayoutColumnStyleCollection", "TableLayoutRowStyleCollection", "TabPage", "TabRenderer", "TabSizeMode", "TextBox", "TextBoxAutoCompleteSourceConverter", "TextBoxBase", "TextBoxRenderer", "TextDataFormat", "TextImageRelation", "ThreadExceptionDialog", "TickStyle", "ToolBar", "ToolBarAppearance", "ToolBarButton", "ToolBarButtonClickEventArgs", "ToolBarButtonClickEventHandler", "ToolBarButtonStyle", "ToolBarTextAlign", "ToolStrip", "CachedItemHdcInfo", "MouseHoverTimer", "ToolStripSplitStackDragDropHandler", "ToolStripArrowRenderEventArgs", "ToolStripArrowRenderEventHandler", "ToolStripButton", "ToolStripComboBox", "ToolStripControlHost", "ToolStripDropDown", "ToolStripDropDownCloseReason", "ToolStripDropDownClosedEventArgs", "ToolStripDropDownClosedEventHandler", "ToolStripDropDownClosingEventArgs", "ToolStripDropDownClosingEventHandler", "ToolStripDropDownDirection", "ToolStripDropDownButton", "ToolStripDropDownItem", "ToolStripDropDownItemAccessibleObject", "ToolStripDropDownMenu", "ToolStripDropTargetManager", "ToolStripHighContrastRenderer", "ToolStripGrip", "ToolStripGripDisplayStyle", "ToolStripGripRenderEventArgs", "ToolStripGripRenderEventHandler", "ToolStripGripStyle", "ToolStripItem", "ToolStripItemImageIndexer", "ToolStripItemInternalLayout", "ToolStripItemAlignment", "ToolStripItemClickedEventArgs", "ToolStripItemClickedEventHandler", "ToolStripItemCollection", "ToolStripItemDisplayStyle", "ToolStripItemEventArgs", "ToolStripItemEventHandler", "ToolStripItemEventType", "ToolStripItemImageRenderEventArgs", "ToolStripItemImageRenderEventHandler", "ToolStripItemImageScaling", "ToolStripItemOverflow", "ToolStripItemPlacement", "ToolStripItemRenderEventArgs", "ToolStripItemRenderEventHandler", "ToolStripItemStates", "ToolStripItemTextRenderEventArgs", "ToolStripItemTextRenderEventHandler", "ToolStripLabel", "ToolStripLayoutStyle", "ToolStripManager", "ToolStripCustomIComparer", "MergeHistory", "MergeHistoryItem", "ToolStripManagerRenderMode", "ToolStripMenuItem", "MenuTimer", "ToolStripMenuItemInternalLayout", "ToolStripOverflow", "ToolStripOverflowButton", "ToolStripContainer", "ToolStripContentPanel", "ToolStripPanel", "ToolStripPanelCell", "ToolStripPanelRenderEventArgs", "ToolStripPanelRenderEventHandler", "ToolStripContentPanelRenderEventArgs", "ToolStripContentPanelRenderEventHandler", "ToolStripPanelRow", "ToolStripPointType", "ToolStripProfessionalRenderer", "ToolStripProfessionalLowResolutionRenderer", "ToolStripProgressBar", "ToolStripRenderer", "ToolStripRendererSwitcher", "ToolStripRenderEventArgs", "ToolStripRenderEventHandler", "ToolStripRenderMode", "ToolStripScrollButton", "ToolStripSeparator", "ToolStripSeparatorRenderEventArgs", "ToolStripSeparatorRenderEventHandler", "ToolStripSettings", "ToolStripSettingsManager", "ToolStripSplitButton", "ToolStripSplitStackLayout", "ToolStripStatusLabel", "ToolStripStatusLabelBorderSides", "ToolStripSystemRenderer", "ToolStripTextBox", "ToolStripTextDirection", "ToolStripLocationCancelEventArgs", "ToolStripLocationCancelEventHandler", "ToolTip", "ToolTipIcon", "TrackBar", "TrackBarRenderer", "TreeNode", "TreeNodeMouseClickEventArgs", "TreeNodeMouseClickEventHandler", "TreeNodeCollection", "TreeNodeConverter", "TreeNodeMouseHoverEventArgs", "TreeNodeMouseHoverEventHandler", "TreeNodeStates", "TreeView", "TreeViewAction", "TreeViewCancelEventArgs", "TreeViewCancelEventHandler", "TreeViewDrawMode", "TreeViewEventArgs", "TreeViewEventHandler", "TreeViewHitTestInfo", "TreeViewHitTestLocations", "TreeViewImageIndexConverter", "TreeViewImageKeyConverter", "Triangle", "TriangleDirection", "TypeValidationEventArgs", "TypeValidationEventHandler", "UICues", "UICuesEventArgs", "UICuesEventHandler", "UpDownBase", "UpDownEventArgs", "UpDownEventHandler", "UserControl", "ValidationConstraints", "View", "VScrollBar", "VScrollProperties", "WebBrowser", "WebBrowserEncryptionLevel", "WebBrowserReadyState", "WebBrowserRefreshOption", "WebBrowserBase", "WebBrowserContainer", "WebBrowserDocumentCompletedEventHandler", "WebBrowserDocumentCompletedEventArgs", "WebBrowserHelper", "WebBrowserNavigatedEventHandler", "WebBrowserNavigatedEventArgs", "WebBrowserNavigatingEventHandler", "WebBrowserNavigatingEventArgs", "WebBrowserProgressChangedEventHandler", "WebBrowserProgressChangedEventArgs", "WebBrowserSiteBase", "WebBrowserUriTypeConverter", "WinCategoryAttribute", "WindowsFormsSection", "WindowsFormsSynchronizationContext", "IntSecurity", "WindowsFormsUtils", "IComponentEditorPageSite", "LayoutSettings", "PageSetupDialog", "PrintControllerWithStatusDialog", "PrintDialog", "PrintPreviewControl", "PrintPreviewDialog", "TextFormatFlags", "TextRenderer", "WindowsGraphicsWrapper", "SRDescriptionAttribute", "SRCategoryAttribute", "SR", "VisualStyleElement", "VisualStyleInformation", "VisualStyleRenderer", "VisualStyleState", "ComboBoxState", "CheckBoxState", "GroupBoxState", "HeaderItemState", "PushButtonState", "RadioButtonState", "ScrollBarArrowButtonState", "ScrollBarState", "ScrollBarSizeBoxState", "TabItemState", "TextBoxState", "ToolBarState", "TrackBarThumbState", "BackgroundType", "BorderType", "ImageOrientation", "SizingType", "FillType", "HorizontalAlign", "ContentAlignment", "VerticalAlignment", "OffsetType", "IconEffect", "TextShadowType", "GlyphType", "ImageSelectType", "TrueSizeScalingType", "GlyphFontSizingType", "ColorProperty", "EnumProperty", "FilenameProperty", "FontProperty", "IntegerProperty", "PointProperty", "MarginProperty", "StringProperty", "BooleanProperty", "Edges", "EdgeStyle", "EdgeEffects", "TextMetrics", "TextMetricsPitchAndFamilyValues", "TextMetricsCharacterSet", "HitTestOptions", "HitTestCode", "ThemeSizeType", "VisualStyleDocProperty", "VisualStyleSystemProperty", "ArrayElementGridEntry", "CategoryGridEntry", "DocComment", "DropDownButton", "DropDownButtonAdapter", "GridEntry", "AttributeTypeSorter", "GridEntryRecreateChildrenEventHandler", "GridEntryRecreateChildrenEventArgs", "GridEntryCollection", "GridErrorDlg", "GridToolTip", "HotCommands", "ImmutablePropertyDescriptorGridEntry", "IRootGridEntry", "MergePropertyDescriptor", "MultiPropertyDescriptorGridEntry", "MultiSelectRootGridEntry", "PropertiesTab", "PropertyDescriptorGridEntry", "PropertyGridCommands", "PropertyGridView", "SingleSelectRootGridEntry", "ComponentEditorForm", "ComponentEditorPage", "EventsTab", "IUIService", "IWindowsFormsEditorService", "PropertyTab", "ToolStripItemDesignerAvailability", "ToolStripItemDesignerAvailabilityAttribute", "WindowsFormsComponentEditor", "BaseCAMarshaler", "Com2AboutBoxPropertyDescriptor", "Com2ColorConverter", "Com2ComponentEditor", "Com2DataTypeToManagedDataTypeConverter", "Com2Enum", "Com2EnumConverter", "Com2ExtendedBrowsingHandler", "Com2ExtendedTypeConverter", "Com2FontConverter", "Com2ICategorizePropertiesHandler", "Com2IDispatchConverter", "Com2IManagedPerPropertyBrowsingHandler", "Com2IPerPropertyBrowsingHandler", "Com2IProvidePropertyBuilderHandler", "Com2IVsPerPropertyBrowsingHandler", "Com2PictureConverter", "Com2Properties", "Com2PropertyBuilderUITypeEditor", "Com2PropertyDescriptor", "GetAttributesEvent", "Com2EventHandler", "GetAttributesEventHandler", "GetNameItemEvent", "GetNameItemEventHandler", "DynamicMetaObjectProviderDebugView", "ExpressionTreeCallRewriter", "ICSharpInvokeOrInvokeMemberBinder", "ResetBindException", "RuntimeBinder", "RuntimeBinderController", "RuntimeBinderException", "RuntimeBinderInternalCompilerException", "SpecialNames", "SymbolTable", "RuntimeBinderExtensions", "NameManager", "Name", "NameTable", "OperatorKind", "PredefinedName", "PredefinedType", "TokenFacts", "TokenKind", "OutputContext", "UNSAFESTATES", "CheckedContext", "BindingFlag", "ExpressionBinder", "BinOpKind", "BinOpMask", "CandidateFunctionMember", "ConstValKind", "CONSTVAL", "ConstValFactory", "ConvKind", "CONVERTTYPE", "BetterType", "ListExtensions", "CConversions", "Operators", "UdConvInfo", "ArgInfos", "BodyType", "ConstCastResult", "AggCastResult", "UnaryOperatorSignatureFindResult", "UnaOpKind", "UnaOpMask", "OpSigFlags", "LiftFlags", "CheckLvalueKind", "BinOpFuncKind", "UnaOpFuncKind", "ExpressionKind", "ExpressionKindExtensions", "EXPRExtensions", "ExprFactory", "EXPRFLAG", "FileRecord", "FUNDTYPE", "GlobalSymbolContext", "InputFile", "LangCompiler", "MemLookFlags", "MemberLookup", "CMemberLookupResults", "mdToken", "CorAttributeTargets", "MethodKindEnum", "MethodTypeInferrer", "NameGenerator", "CNullable", "NullableCallLiftKind", "CONSTRESKIND", "LambdaParams", "TypeOrSimpleNameResolution", "InitializerKind", "ConstantStringConcatenation", "ForeachKind", "PREDEFATTR", "PREDEFMETH", "PREDEFPROP", "MethodRequiredEnum", "MethodCallingConventionEnum", "MethodSignatureEnum", "PredefinedMethodInfo", "PredefinedPropertyInfo", "PredefinedMembers", "ACCESSERROR", "CSemanticChecker", "SubstTypeFlags", "SubstContext", "CheckConstraintsFlags", "TypeBind", "UtilityTypeExtensions", "SymWithType", "MethPropWithType", "MethWithType", "PropWithType", "EventWithType", "FieldWithType", "MethPropWithInst", "MethWithInst", "AggregateDeclaration", "Declaration", "GlobalAttributeDeclaration", "ITypeOrNamespace", "AggregateSymbol", "AssemblyQualifiedNamespaceSymbol", "EventSymbol", "FieldSymbol", "IndexerSymbol", "LabelSymbol", "LocalVariableSymbol", "MethodOrPropertySymbol", "MethodSymbol", "InterfaceImplementationMethodSymbol", "IteratorFinallyMethodSymbol", "MiscSymFactory", "NamespaceOrAggregateSymbol", "NamespaceSymbol", "ParentSymbol", "PropertySymbol", "Scope", "KAID", "ACCESS", "AggKindEnum", "ARRAYMETHOD", "SpecCons", "Symbol", "SymbolExtensions", "SymFactory", "SymFactoryBase", "SYMKIND", "SynthAggKind", "SymbolLoader", "AidContainer", "BSYMMGR", "symbmask_t", "SYMTBL", "TransparentIdentifierMemberSymbol", "TypeParameterSymbol", "UnresolvedAggregateSymbol", "VariableSymbol", "EXPRARRAYINDEX", "EXPRARRINIT", "EXPRARRAYLENGTH", "EXPRASSIGNMENT", "EXPRBINOP", "EXPRBLOCK", "EXPRBOUNDLAMBDA", "EXPRCALL", "EXPRCAST", "EXPRCLASS", "EXPRMULTIGET", "EXPRMULTI", "EXPRCONCAT", "EXPRQUESTIONMARK", "EXPRCONSTANT", "EXPREVENT", "EXPR", "ExpressionIterator", "EXPRFIELD", "EXPRFIELDINFO", "EXPRHOISTEDLOCALEXPR", "EXPRLIST", "EXPRLOCAL", "EXPRMEMGRP", "EXPRMETHODINFO", "EXPRFUNCPTR", "EXPRNamedArgumentSpecification", "EXPRPROP", "EXPRPropertyInfo", "EXPRRETURN", "EXPRSTMT", "EXPRWRAP", "EXPRTHISPOINTER", "EXPRTYPEARGUMENTS", "EXPRTYPEOF", "EXPRTYPEORNAMESPACE", "EXPRUNARYOP", "EXPRUNBOUNDLAMBDA", "EXPRUSERDEFINEDCONVERSION", "EXPRUSERLOGOP", "EXPRZEROINIT", "ExpressionTreeRewriter", "ExprVisitorBase", "AggregateType", "ArgumentListType", "ArrayType", "BoundLambdaType", "ErrorType", "MethodGroupType", "NullableType", "NullType", "OpenTypePlaceholderType", "ParameterModifierType", "PointerType", "PredefinedTypes", "PredefinedTypeFacts", "CType", "TypeArray", "TypeFactory", "TypeManager", "TypeParameterType", "KeyPair`2", "TypeTable", "VoidType", "CError", "CParameterizedError", "CErrorFactory", "ErrorFacts", "ErrArgKind", "ErrArgFlags", "SymWithTypeMemo", "MethPropWithInstMemo", "ErrArg", "ErrArgRef", "ErrArgRefOnly", "ErrArgNoRef", "ErrArgIds", "ErrArgSymKind", "ErrorHandling", "IErrorSink", "MessageID", "UserStringBuilder", "CController", "d__10`1", "d__11`1", "DynamicProperty", "DynamicDebugViewEmptyException", "<>c__DisplayClass20_0", "ExpressionEXPR", "ArgumentObject", "NameHashKey", "<>c__DisplayClass18_0", "<>c__DisplayClass18_1", "<>c__DisplayClass43_0", "<>c__DisplayClass45_0", "KnownName", "BinOpArgInfo", "BinOpSig", "BinOpFullSig", "ConversionFunc", "ExplicitConversion", "PfnBindBinOp", "PfnBindUnaOp", "GroupToArgsBinder", "GroupToArgsBinderResult", "ImplicitConversion", "UnaOpSig", "UnaOpFullSig", "OPINFO", "d__1", "CMethodIterator", "NewInferenceResult", "Dependency", "d__0", "d__1", "d__2", "d__3", "d__4", "d__0", "Kind", "TypeArrayKey", "Key", "PredefinedTypeInfo", "StdTypeVarColl", "<>c__DisplayClass71_0", "__StaticArrayInitTypeSize=104", "__StaticArrayInitTypeSize=169", "SNINativeMethodWrapper", "QTypes", "ProviderEnum", "IOType", "ConsumerNumber", "SqlAsyncCallbackDelegate", "ConsumerInfo", "SNI_Error", "Win32NativeMethods", "NativeOledbWrapper", "AdalException", "ADALNativeWrapper", "Sni_Consumer_Info", "SNI_ConnWrapper", "SNI_Packet_IOType", "ConsumerNum", "$ArrayType$$$BY08$$CBG", "_GUID", "SNI_CLIENT_CONSUMER_INFO", "IUnknown", "__s_GUID", "IChapteredRowset", "_FILETIME", "ProviderNum", "ITransactionLocal", "SNI_ERROR", "$ArrayType$$$BY08G", "BOID", "ModuleLoadException", "ModuleLoadExceptionHandlerException", "ModuleUninitializer", "LanguageSupport", "gcroot", "$ArrayType$$$BY00Q6MPBXXZ", "Progress", "$ArrayType$$$BY0A@P6AXXZ", "$ArrayType$$$BY0A@P6AHXZ", "__enative_startup_state", "TriBool", "ICLRRuntimeHost", "ThisModule", "_EXCEPTION_POINTERS", "Bid", "SqlDependencyProcessDispatcher", "BidIdentityAttribute", "BidMetaTextAttribute", "BidMethodAttribute", "BidArgumentTypeAttribute", "ExtendedClrTypeCode", "ITypedGetters", "ITypedGettersV3", "ITypedSetters", "ITypedSettersV3", "MetaDataUtilsSmi", "SmiConnection", "SmiContext", "SmiContextFactory", "SmiEventSink", "SmiEventSink_Default", "SmiEventSink_DeferedProcessing", "SmiEventStream", "SmiExecuteType", "SmiGettersStream", "SmiLink", "SmiMetaData", "SmiExtendedMetaData", "SmiParameterMetaData", "SmiStorageMetaData", "SmiQueryMetaData", "SmiRecordBuffer", "SmiRequestExecutor", "SmiSettersStream", "SmiStream", "SmiXetterAccessMap", "SmiXetterTypeCode", "SqlContext", "SqlDataRecord", "SqlPipe", "SqlTriggerContext", "ValueUtilsSmi", "SqlClientWrapperSmiStream", "SqlClientWrapperSmiStreamChars", "IBinarySerialize", "InvalidUdtException", "SqlFacetAttribute", "DataAccessKind", "SystemDataAccessKind", "SqlFunctionAttribute", "SqlMetaData", "SqlMethodAttribute", "FieldInfoEx", "BinaryOrderedUdtNormalizer", "Normalizer", "BooleanNormalizer", "SByteNormalizer", "ByteNormalizer", "ShortNormalizer", "UShortNormalizer", "IntNormalizer", "UIntNormalizer", "LongNormalizer", "ULongNormalizer", "FloatNormalizer", "DoubleNormalizer", "SqlProcedureAttribute", "SerializationHelperSql9", "Serializer", "NormalizedSerializer", "BinarySerializeSerializer", "DummyStream", "SqlTriggerAttribute", "SqlUserDefinedAggregateAttribute", "SqlUserDefinedTypeAttribute", "TriggerAction", "MemoryRecordBuffer", "SmiPropertySelector", "SmiMetaDataPropertyCollection", "SmiMetaDataProperty", "SmiUniqueKeyProperty", "SmiOrderProperty", "SmiDefaultFieldsProperty", "SmiTypedGetterSetter", "SqlRecordBuffer", "BaseTreeIterator", "DataDocumentXPathNavigator", "DataPointer", "DataSetMapper", "IXmlDataVirtualNode", "BaseRegionIterator", "RegionIterator", "TreeIterator", "ElementState", "XmlBoundElement", "XmlDataDocument", "XmlDataImplementation", "XPathNodePointer", "AcceptRejectRule", "InternalDataCollectionBase", "TypedDataSetGenerator", "StrongTypingException", "TypedDataSetGeneratorException", "ColumnTypeConverter", "CommandBehavior", "CommandType", "KeyRestrictionBehavior", "ConflictOption", "ConnectionState", "Constraint", "ConstraintCollection", "ConstraintConverter", "ConstraintEnumerator", "ForeignKeyConstraintEnumerator", "ChildForeignKeyConstraintEnumerator", "ParentForeignKeyConstraintEnumerator", "DataColumn", "AutoIncrementValue", "AutoIncrementInt64", "AutoIncrementBigInteger", "DataColumnChangeEventArgs", "DataColumnChangeEventHandler", "DataColumnCollection", "DataColumnPropertyDescriptor", "DataError", "DataException", "ConstraintException", "DeletedRowInaccessibleException", "DuplicateNameException", "InRowChangingEventException", "InvalidConstraintException", "MissingPrimaryKeyException", "NoNullAllowedException", "ReadOnlyException", "RowNotInTableException", "VersionNotFoundException", "ExceptionBuilder", "DataKey", "DataRelation", "DataRelationCollection", "DataRelationPropertyDescriptor", "DataRow", "DataRowBuilder", "DataRowAction", "DataRowChangeEventArgs", "DataRowChangeEventHandler", "DataRowCollection", "DataRowCreatedEventHandler", "DataSetClearEventhandler", "DataRowState", "DataRowVersion", "DataRowView", "SerializationFormat", "DataSet", "DataSetSchemaImporterExtension", "DataSetDateTime", "DataSysDescriptionAttribute", "DataTable", "DataTableClearEventArgs", "DataTableClearEventHandler", "DataTableCollection", "DataTableNewRowEventArgs", "DataTableNewRowEventHandler", "DataTablePropertyDescriptor", "DataTableReader", "DataTableReaderListener", "DataTableTypeConverter", "DataView", "DataViewListener", "DataViewManager", "DataViewManagerListItemTypeDescriptor", "DataViewRowState", "DataViewSetting", "DataViewSettingCollection", "DBConcurrencyException", "DbType", "DefaultValueTypeConverter", "FillErrorEventArgs", "FillErrorEventHandler", "AggregateNode", "BinaryNode", "LikeNode", "ConstNode", "DataExpression", "ExpressionNode", "ExpressionParser", "Tokens", "OperatorInfo", "InvalidExpressionException", "EvaluateException", "SyntaxErrorException", "ExprException", "FunctionNode", "FunctionId", "Function", "IFilter", "LookupNode", "NameNode", "UnaryNode", "ZeroOpNode", "ForeignKeyConstraint", "IColumnMapping", "IColumnMappingCollection", "IDataAdapter", "IDataParameter", "IDataParameterCollection", "IDataReader", "IDataRecord", "IDbCommand", "IDbConnection", "IDbDataAdapter", "IDbDataParameter", "IDbTransaction", "IsolationLevel", "ITableMapping", "ITableMappingCollection", "LoadOption", "MappingType", "MergeFailedEventArgs", "MergeFailedEventHandler", "Merger", "MissingMappingAction", "MissingSchemaAction", "OperationAbortedException", "ParameterDirection", "PrimaryKeyTypeConverter", "PropertyCollection", "RBTreeError", "TreeAccessMethod", "RBTree`1", "RecordManager", "StatementCompletedEventArgs", "StatementCompletedEventHandler", "RelatedView", "RelationshipConverter", "Rule", "SchemaSerializationMode", "SchemaType", "IndexField", "Index", "Listeners`1", "SimpleType", "LocalDBAPI", "LocalDBInstanceElement", "LocalDBInstancesCollection", "LocalDBConfigurationSection", "SqlDbType", "StateChangeEventArgs", "StateChangeEventHandler", "StatementType", "UniqueConstraint", "UpdateRowSource", "UpdateStatus", "XDRSchema", "XmlDataLoader", "XMLDiffLoader", "XmlReadMode", "SchemaFormat", "XmlTreeGen", "NewDiffgramGen", "XmlDataTreeWriter", "DataTextWriter", "DataTextReader", "XMLSchema", "ConstraintTable", "XSDSchema", "XmlIgnoreNamespaceReader", "XmlToDatasetMap", "XmlWriteMode", "SqlEventSource", "SqlDataSourceEnumerator", "SqlGenericUtil", "SqlNotificationRequest", "INullable", "SqlBinary", "SqlBoolean", "SqlByte", "SqlBytesCharsState", "SqlBytes", "StreamOnSqlBytes", "SqlChars", "StreamOnSqlChars", "SqlStreamChars", "SqlDateTime", "SqlDecimal", "SqlDouble", "SqlFileStream", "UnicodeString", "SecurityQualityOfService", "FileFullEaInformation", "SqlGuid", "SqlInt16", "SqlInt32", "SqlInt64", "SqlMoney", "SQLResource", "SqlSingle", "SqlCompareOptions", "SqlString", "SqlTypesSchemaImporterExtensionHelper", "TypeCharSchemaImporterExtension", "TypeNCharSchemaImporterExtension", "TypeVarCharSchemaImporterExtension", "TypeNVarCharSchemaImporterExtension", "TypeTextSchemaImporterExtension", "TypeNTextSchemaImporterExtension", "TypeVarBinarySchemaImporterExtension", "TypeBinarySchemaImporterExtension", "TypeVarImageSchemaImporterExtension", "TypeDecimalSchemaImporterExtension", "TypeNumericSchemaImporterExtension", "TypeBigIntSchemaImporterExtension", "TypeIntSchemaImporterExtension", "TypeSmallIntSchemaImporterExtension", "TypeTinyIntSchemaImporterExtension", "TypeBitSchemaImporterExtension", "TypeFloatSchemaImporterExtension", "TypeRealSchemaImporterExtension", "TypeDateTimeSchemaImporterExtension", "TypeSmallDateTimeSchemaImporterExtension", "TypeMoneySchemaImporterExtension", "TypeSmallMoneySchemaImporterExtension", "TypeUniqueIdentifierSchemaImporterExtension", "EComparison", "StorageState", "SqlTypeException", "SqlNullValueException", "SqlTruncateException", "SqlNotFilledException", "SqlAlreadyFilledException", "SQLDebug", "SqlXml", "SqlXmlStreamWrapper", "SqlClientEncryptionAlgorithmFactoryList", "SqlSymmetricKeyCache", "SqlColumnEncryptionKeyStoreProvider", "SqlColumnEncryptionCertificateStoreProvider", "SqlColumnEncryptionCngProvider", "SqlColumnEncryptionCspProvider", "SqlAeadAes256CbcHmac256Algorithm", "SqlAeadAes256CbcHmac256Factory", "SqlAeadAes256CbcHmac256EncryptionKey", "SqlAes256CbcAlgorithm", "SqlAes256CbcFactory", "SqlClientEncryptionAlgorithm", "SqlClientEncryptionAlgorithmFactory", "SqlClientEncryptionType", "SqlClientSymmetricKey", "SqlSecurityUtility", "SqlQueryMetadataCache", "ApplicationIntent", "SqlCredential", "SqlConnectionPoolKey", "AssemblyCache", "OnChangeEventHandler", "SqlRowsCopiedEventArgs", "SqlRowsCopiedEventHandler", "SqlBuffer", "_ColumnMapping", "Row", "BulkCopySimpleResultSet", "SqlBulkCopy", "SqlBulkCopyColumnMapping", "SqlBulkCopyColumnMappingCollection", "SqlBulkCopyOptions", "SqlCachedBuffer", "SqlClientFactory", "SqlClientMetaDataCollectionNames", "SqlClientPermission", "SqlClientPermissionAttribute", "SqlCommand", "SqlCommandBuilder", "SqlCommandSet", "SqlConnection", "SQLDebugging", "ISQLDebug", "SqlDebugContext", "MEMMAP", "SqlConnectionFactory", "SqlPerformanceCounters", "SqlConnectionPoolGroupProviderInfo", "SqlConnectionPoolProviderInfo", "SqlConnectionString", "SqlConnectionStringBuilder", "SqlConnectionTimeoutErrorPhase", "SqlConnectionInternalSourceType", "SqlConnectionTimeoutPhaseDuration", "SqlConnectionTimeoutErrorInternal", "SqlDataAdapter", "SqlDataReader", "SqlDataReaderSmi", "SqlDelegatedTransaction", "SqlDependency", "SqlDependencyPerAppDomainDispatcher", "SqlNotification", "MetaType", "TdsDateTime", "SqlError", "SqlErrorCollection", "SqlException", "SqlInfoMessageEventArgs", "SqlInfoMessageEventHandler", "SqlInternalConnection", "SqlInternalConnectionSmi", "SessionStateRecord", "SessionData", "SqlInternalConnectionTds", "ServerInfo", "TransactionState", "TransactionType", "SqlInternalTransaction", "SqlMetaDataFactory", "SqlNotificationEventArgs", "SqlNotificationInfo", "SqlNotificationSource", "SqlNotificationType", "DataFeed", "StreamDataFeed", "TextDataFeed", "XmlDataFeed", "SqlParameter", "SqlParameterCollection", "SqlReferenceCollection", "SqlRowUpdatedEventArgs", "SqlRowUpdatedEventHandler", "SqlRowUpdatingEventArgs", "SqlRowUpdatingEventHandler", "SqlSequentialStream", "SqlSequentialStreamSmi", "System.Diagnostics.DebuggableAttribute", "System.Diagnostics", "System.Net.WebClient", "System", "System.Specialized.Protection" }; + return charsc[rnd.Next(charsc.Length)]; + } + private static void FloorReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig + RandomDouble(0.01, 0.99); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Floor", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + + //https://github.com/GabTeix + public static void IfInliner(MethodDef method) + { + Local local = new Local(method.Module.ImportAsTypeSig(typeof(int))); + method.Body.Variables.Add(local); + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + if (CanObfuscateLDCI4(method.Body.Instructions, i)) + { + int numorig = rnd.Next(); + int div = rnd.Next(); + int num = numorig ^ div; + + Instruction nop = OpCodes.Nop.ToInstruction(); + method.Body.Instructions.Insert(i + 1, OpCodes.Stloc_S.ToInstruction(local)); + method.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Ldc_I4, method.Body.Instructions[i].GetLdcI4Value() - sizeof(float))); + method.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Ldc_I4, num)); + method.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Ldc_I4, div)); + method.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Xor)); + method.Body.Instructions.Insert(i + 6, Instruction.Create(OpCodes.Ldc_I4, numorig)); + method.Body.Instructions.Insert(i + 7, Instruction.Create(OpCodes.Bne_Un, nop)); + method.Body.Instructions.Insert(i + 8, Instruction.Create(OpCodes.Ldc_I4, 2)); + method.Body.Instructions.Insert(i + 9, OpCodes.Stloc_S.ToInstruction(local)); + method.Body.Instructions.Insert(i + 10, Instruction.Create(OpCodes.Sizeof, method.Module.Import(typeof(float)))); + method.Body.Instructions.Insert(i + 11, Instruction.Create(OpCodes.Add)); + method.Body.Instructions.Insert(i + 12, nop); + i += 12; + } + } + } + } + + public static void InlineInteger(MethodDef method) + { + Local new_local = new Local(method.Module.CorLibTypes.String); + method.Body.Variables.Add(new_local); + Local new_local2 = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(new_local2); + for (int i = 0; i < method.Body.Instructions.Count; i++) + { + if (method.Body.Instructions[i].IsLdcI4()) + { + if (CanObfuscateLDCI4(method.Body.Instructions, i)) + { + if (method.DeclaringType.IsGlobalModuleType) return; + if (!method.HasBody) return; + var instr = method.Body.Instructions; + if ((i - 1) > 0) + try + { + + if (instr[i - 1].OpCode == OpCodes.Callvirt) + { + if (instr[i + 1].OpCode == OpCodes.Call) + { + return; + } + } + } + catch { } + bool is_valid_inline = true; + switch (rnd.Next(0, 2)) + { + case 0: + is_valid_inline = true; + break; + case 1: + is_valid_inline = false; + break; + } + + + var value = instr[i].GetLdcI4Value(); + var first_ldstr = RandomString(5, "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁"); + + instr.Insert(i, Instruction.Create(OpCodes.Ldloc_S, new_local2)); + + instr.Insert(i, Instruction.Create(OpCodes.Stloc_S, new_local2)); + if (is_valid_inline) + { + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value)); + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value + 1)); + } + else + { + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value + 1)); + instr.Insert(i, Instruction.Create(OpCodes.Ldc_I4, value)); + } + instr.Insert(i, + Instruction.Create(OpCodes.Call, + method.Module.Import(typeof(System.String).GetMethod("op_Equality", + new Type[] { typeof(string), typeof(string) })))); + instr.Insert(i, Instruction.Create(OpCodes.Ldstr, first_ldstr)); + instr.Insert(i, Instruction.Create(OpCodes.Ldloc_S, new_local)); + instr.Insert(i, Instruction.Create(OpCodes.Stloc_S, new_local)); + if (is_valid_inline) + { + instr.Insert(i, Instruction.Create(OpCodes.Ldstr, first_ldstr)); + } + else + { + instr.Insert(i, + Instruction.Create(OpCodes.Ldstr, + RandomString(7, "畹畞疲疷疹痲痹痹瘕番畐畞畵畵畲畲蘽蘐藴虜蘞虢謊謁"))); + } + instr.Insert(i + 5, Instruction.Create(OpCodes.Brtrue_S, instr[i + 6])); + instr.Insert(i + 7, Instruction.Create(OpCodes.Br_S, instr[i + 8])); + instr.RemoveAt(i + 10); + i += 10; + } + } + } + } + private static void RoundReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig + RandomDouble(0.01, 0.5); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Round", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + private static void SqrtReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + if ((int)instruction.Operand > 1) + { + int orig = (int)instruction.Operand; + double m = (double)orig * orig; + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + } + catch { } + } + private static void CeilingReplacer(MethodDef method, Instruction instruction, ref int i) + { + try + { + if (instruction.Operand != null) + if (instruction.IsLdcI4()) + { + if (instruction.GetLdcI4Value() < int.MaxValue) + { + int orig = (int)instruction.Operand; + double m = (double)orig - 1 + RandomDouble(0.01, 0.99); + instruction.OpCode = OpCodes.Ldc_R8; + instruction.Operand = m; + method.Body.Instructions.Insert(i + 1, OpCodes.Call.ToInstruction(method.Module.Import(typeof(Math).GetMethod("Ceiling", new Type[] { typeof(double) })))); + method.Body.Instructions.Insert(i + 2, OpCodes.Conv_I4.ToInstruction()); + } + } + } + catch { } + } + } +} diff --git a/Additions/ControlFlow-v2/BlockParser.cs b/Additions/ControlFlow-v2/BlockParser.cs new file mode 100644 index 000000000..6a4dafd63 --- /dev/null +++ b/Additions/ControlFlow-v2/BlockParser.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal static class BlockParser { + public static ScopeBlock ParseBody(CilBody body) { + var ehScopes = new Dictionary>(); + foreach (ExceptionHandler eh in body.ExceptionHandlers) { + var tryBlock = new ScopeBlock(BlockType.Try, eh); + + var handlerType = BlockType.Handler; + + if (eh.HandlerType == ExceptionHandlerType.Finally) + handlerType = BlockType.Finally; + else if (eh.HandlerType == ExceptionHandlerType.Fault) + handlerType = BlockType.Fault; + + var handlerBlock = new ScopeBlock(handlerType, eh); + + if (eh.FilterStart != null) { + var filterBlock = new ScopeBlock(BlockType.Filter, eh); + ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, filterBlock); + } + else + ehScopes[eh] = Tuple.Create(tryBlock, handlerBlock, (ScopeBlock)null); + } + + var root = new ScopeBlock(BlockType.Normal, null); + var scopeStack = new Stack(); + + scopeStack.Push(root); + foreach (Instruction instr in body.Instructions) { + foreach (ExceptionHandler eh in body.ExceptionHandlers) { + Tuple ehScope = ehScopes[eh]; + + if (instr == eh.TryEnd) + scopeStack.Pop(); + + if (instr == eh.HandlerEnd) + scopeStack.Pop(); + + if (eh.FilterStart != null && instr == eh.HandlerStart) { + // Filter must precede handler immediately + Debug.Assert(scopeStack.Peek().Type == BlockType.Filter); + scopeStack.Pop(); + } + } + foreach (ExceptionHandler eh in body.ExceptionHandlers.Reverse()) { + Tuple ehScope = ehScopes[eh]; + ScopeBlock parent = scopeStack.Count > 0 ? scopeStack.Peek() : null; + + if (instr == eh.TryStart) { + if (parent != null) + parent.Children.Add(ehScope.Item1); + scopeStack.Push(ehScope.Item1); + } + + if (instr == eh.HandlerStart) { + if (parent != null) + parent.Children.Add(ehScope.Item2); + scopeStack.Push(ehScope.Item2); + } + + if (instr == eh.FilterStart) { + if (parent != null) + parent.Children.Add(ehScope.Item3); + scopeStack.Push(ehScope.Item3); + } + } + + ScopeBlock scope = scopeStack.Peek(); + var block = scope.Children.LastOrDefault() as InstrBlock; + if (block == null) + scope.Children.Add(block = new InstrBlock()); + block.Instructions.Add(instr); + } + foreach (ExceptionHandler eh in body.ExceptionHandlers) { + if (eh.TryEnd == null) + scopeStack.Pop(); + if (eh.HandlerEnd == null) + scopeStack.Pop(); + } + Debug.Assert(scopeStack.Count == 1); + return root; + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/Blocks.cs b/Additions/ControlFlow-v2/Blocks.cs new file mode 100644 index 000000000..38a35dea9 --- /dev/null +++ b/Additions/ControlFlow-v2/Blocks.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal abstract class BlockBase { + public BlockBase(BlockType type) { + Type = type; + } + + public ScopeBlock Parent { get; private set; } + + public BlockType Type { get; private set; } + public abstract void ToBody(CilBody body); + } + + internal enum BlockType { + Normal, + Try, + Handler, + Finally, + Filter, + Fault + } + + internal class ScopeBlock : BlockBase { + public ScopeBlock(BlockType type, ExceptionHandler handler) + : base(type) { + Handler = handler; + Children = new List(); + } + + public ExceptionHandler Handler { get; private set; } + + public List Children { get; set; } + + public override string ToString() { + var ret = new StringBuilder(); + if (Type == BlockType.Try) + ret.Append("try "); + else if (Type == BlockType.Handler) + ret.Append("handler "); + else if (Type == BlockType.Finally) + ret.Append("finally "); + else if (Type == BlockType.Fault) + ret.Append("fault "); + ret.AppendLine("{"); + foreach (BlockBase child in Children) + ret.Append(child); + ret.AppendLine("}"); + return ret.ToString(); + } + + public Instruction GetFirstInstr() { + BlockBase firstBlock = Children.First(); + if (firstBlock is ScopeBlock) + return ((ScopeBlock)firstBlock).GetFirstInstr(); + return ((InstrBlock)firstBlock).Instructions.First(); + } + + public Instruction GetLastInstr() { + BlockBase firstBlock = Children.Last(); + if (firstBlock is ScopeBlock) + return ((ScopeBlock)firstBlock).GetLastInstr(); + return ((InstrBlock)firstBlock).Instructions.Last(); + } + + public override void ToBody(CilBody body) { + if (Type != BlockType.Normal) { + if (Type == BlockType.Try) { + Handler.TryStart = GetFirstInstr(); + Handler.TryEnd = GetLastInstr(); + } + else if (Type == BlockType.Filter) { + Handler.FilterStart = GetFirstInstr(); + } + else { + Handler.HandlerStart = GetFirstInstr(); + Handler.HandlerEnd = GetLastInstr(); + } + } + + foreach (BlockBase block in Children) + block.ToBody(body); + } + } + + internal class InstrBlock : BlockBase { + public InstrBlock() + : base(BlockType.Normal) { + Instructions = new List(); + } + + public List Instructions { get; set; } + + public override string ToString() { + var ret = new StringBuilder(); + foreach (Instruction instr in Instructions) + ret.AppendLine(instr.ToString()); + return ret.ToString(); + } + + public override void ToBody(CilBody body) { + foreach (Instruction instr in Instructions) + body.Instructions.Add(instr); + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/CFContext.cs b/Additions/ControlFlow-v2/CFContext.cs new file mode 100644 index 000000000..28f4c5dfd --- /dev/null +++ b/Additions/ControlFlow-v2/CFContext.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using Confuser.Core; +using Confuser.Core.Services; +using Confuser.DynCipher; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal enum CFType { + Switch, + Jump + } + + internal enum PredicateType { + Normal, + Expression, + x86 + } + + internal class CFContext { + public ConfuserContext Context; + public ControlFlowProtection Protection; + public int Depth; + public IDynCipherService DynCipher; + + public double Intensity; + public bool JunkCode; + public MethodDef Method; + public PredicateType Predicate; + public RandomGenerator Random; + public CFType Type; + + public void AddJump(IList instrs, Instruction target) { + if (!Method.Module.IsClr40 && JunkCode && + !Method.DeclaringType.HasGenericParameters && !Method.HasGenericParameters && + (instrs[0].OpCode.FlowControl == FlowControl.Call || instrs[0].OpCode.FlowControl == FlowControl.Next)) { + switch (Random.NextInt32(3)) { + case 0: + instrs.Add(Instruction.Create(OpCodes.Ldc_I4_0)); + instrs.Add(Instruction.Create(OpCodes.Brtrue, instrs[0])); + break; + + case 1: + instrs.Add(Instruction.Create(OpCodes.Ldc_I4_1)); + instrs.Add(Instruction.Create(OpCodes.Brfalse, instrs[0])); + break; + + case 2: // Take that, de4dot + ILSpy :) + bool addDefOk = false; + if (Random.NextBoolean()) { + TypeDef randomType; + randomType = Method.Module.Types[Random.NextInt32(Method.Module.Types.Count)]; + + if (randomType.HasMethods) { + instrs.Add(Instruction.Create(OpCodes.Ldtoken, randomType.Methods[Random.NextInt32(randomType.Methods.Count)])); + instrs.Add(Instruction.Create(OpCodes.Box, Method.Module.CorLibTypes.GetTypeRef("System", "RuntimeMethodHandle"))); + addDefOk = true; + } + } + + if (!addDefOk) { + instrs.Add(Instruction.Create(OpCodes.Ldc_I4, Random.NextBoolean() ? 0 : 1)); + instrs.Add(Instruction.Create(OpCodes.Box, Method.Module.CorLibTypes.Int32.TypeDefOrRef)); + } + Instruction pop = Instruction.Create(OpCodes.Pop); + instrs.Add(Instruction.Create(OpCodes.Brfalse, instrs[0])); + instrs.Add(Instruction.Create(OpCodes.Ldc_I4, Random.NextBoolean() ? 0 : 1)); + instrs.Add(pop); + break; + } + } + + instrs.Add(Instruction.Create(OpCodes.Br, target)); + } + + public void AddJunk(IList instrs) { + if (Method.Module.IsClr40 || !JunkCode) + return; + + switch (Random.NextInt32(6)) { + case 0: + instrs.Add(Instruction.Create(OpCodes.Pop)); + break; + case 1: + instrs.Add(Instruction.Create(OpCodes.Dup)); + break; + case 2: + instrs.Add(Instruction.Create(OpCodes.Throw)); + break; + case 3: + instrs.Add(Instruction.Create(OpCodes.Ldarg, new Parameter(0xff))); + break; + case 4: + instrs.Add(Instruction.Create(OpCodes.Ldloc, new Local(null, null, 0xff))); + break; + case 5: + instrs.Add(Instruction.Create(OpCodes.Ldtoken, Method)); + break; + } + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/ControlFlowPhase.cs b/Additions/ControlFlow-v2/ControlFlowPhase.cs new file mode 100644 index 000000000..3a5dc69bc --- /dev/null +++ b/Additions/ControlFlow-v2/ControlFlowPhase.cs @@ -0,0 +1,112 @@ +using System; +using System.Diagnostics; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Services; +using Confuser.DynCipher; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.MD; +using dnlib.DotNet.Writer; + +namespace Confuser.Protections.ControlFlow { + internal class ControlFlowPhase : ProtectionPhase { + static readonly JumpMangler Jump = new JumpMangler(); + static readonly SwitchMangler Switch = new SwitchMangler(); + + public ControlFlowPhase(ControlFlowProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets { + get { return ProtectionTargets.Methods; } + } + + public override string Name { + get { return Resources.ControlFlowPhase_Name; } + } + + CFContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RandomGenerator random, bool disableOpti) { + var ret = new CFContext(); + ret.Type = parameters.GetParameter(context, method, "type", CFType.Switch); + ret.Predicate = parameters.GetParameter(context, method, "predicate", PredicateType.x86); + + int rawIntensity = parameters.GetParameter(context, method, "intensity", 60); + ret.Intensity = rawIntensity / 100.0; + ret.Depth = parameters.GetParameter(context, method, "depth", 4); + + ret.JunkCode = parameters.GetParameter(context, method, "junk", false) && !disableOpti; + + ret.Protection = (ControlFlowProtection)Parent; + ret.Random = random; + ret.Method = method; + ret.Context = context; + ret.DynCipher = context.Registry.GetService(); + + if (ret.Predicate == PredicateType.x86) { + if ((context.CurrentModule.Cor20HeaderFlags & ComImageFlags.ILOnly) != 0) + context.CurrentModuleWriterOptions.Cor20HeaderOptions.Flags &= ~ComImageFlags.ILOnly; + } + + return ret; + } + + static bool DisabledOptimization(ModuleDef module) { + bool disableOpti = false; + CustomAttribute debugAttr = module.Assembly.CustomAttributes.Find("System.Diagnostics.DebuggableAttribute"); + if (debugAttr != null) { + if (debugAttr.ConstructorArguments.Count == 1) + disableOpti |= ((DebuggableAttribute.DebuggingModes)(int)debugAttr.ConstructorArguments[0].Value & DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0; + else + disableOpti |= (bool)debugAttr.ConstructorArguments[1].Value; + } + debugAttr = module.CustomAttributes.Find("System.Diagnostics.DebuggableAttribute"); + if (debugAttr != null) { + if (debugAttr.ConstructorArguments.Count == 1) + disableOpti |= ((DebuggableAttribute.DebuggingModes)(int)debugAttr.ConstructorArguments[0].Value & DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0; + else + disableOpti |= (bool)debugAttr.ConstructorArguments[1].Value; + } + return disableOpti; + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + bool disabledOpti = DisabledOptimization(context.CurrentModule); + RandomGenerator random = context.Registry.GetService().GetRandomGenerator(ControlFlowProtection._FullId); + + foreach (MethodDef method in parameters.Targets.OfType().WithProgress(context.Logger)) + if (method.HasBody && method.Body.Instructions.Count > 0) { + ProcessMethod(method.Body, ParseParameters(method, context, parameters, random, disabledOpti)); + context.CheckCancellation(); + } + } + + static ManglerBase GetMangler(CFType type) { + if (type == CFType.Switch) + return Switch; + return Jump; + } + + void ProcessMethod(CilBody body, CFContext ctx) { + uint maxStack; + if (!MaxStackCalculator.GetMaxStack(body.Instructions, body.ExceptionHandlers, out maxStack)) { + ctx.Context.Logger.Error(Resources.ControlFlowPhase_ProcessMethod_Failed); + throw new ConfuserException(null); + } + body.MaxStack = (ushort)maxStack; + ScopeBlock root = BlockParser.ParseBody(body); + + GetMangler(ctx.Type).Mangle(body, root, ctx); + + body.Instructions.Clear(); + root.ToBody(body); + foreach (ExceptionHandler eh in body.ExceptionHandlers) { + var index = body.Instructions.IndexOf(eh.TryEnd) + 1; + eh.TryEnd = index < body.Instructions.Count ? body.Instructions[index] : null; + index = body.Instructions.IndexOf(eh.HandlerEnd) + 1; + eh.HandlerEnd = index < body.Instructions.Count ? body.Instructions[index] : null; + } + body.KeepOldMaxStack = true; + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/ControlFlowProtection.cs b/Additions/ControlFlow-v2/ControlFlowProtection.cs new file mode 100644 index 000000000..9d9988c27 --- /dev/null +++ b/Additions/ControlFlow-v2/ControlFlowProtection.cs @@ -0,0 +1,49 @@ +using System; +using Confuser.Core; +using Confuser.Protections.ControlFlow; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; + +namespace Confuser.Protections { + public interface IControlFlowService { + void ExcludeMethod(ConfuserContext context, MethodDef method); + } + + internal class ControlFlowProtection : Protection, IControlFlowService { + public const string _Id = "ctrl flow v2"; + public const string _FullId = "Ki.ControlFlow.v2"; + public const string _ServiceId = "Ki.ControlFlow.v2"; + + public override string Name { + get { return Resources.ControlFlowProtection_Name; } + } + + public override string Description { + get { return Resources.ControlFlowProtection_Description; } + } + + public override string Id { + get { return _Id; } + } + + public override string FullId { + get { return _FullId; } + } + + public override ProtectionPreset Preset { + get { return ProtectionPreset.Normal; } + } + + public void ExcludeMethod(ConfuserContext context, MethodDef method) { + ProtectionParameters.GetParameters(context, method).Remove(this); + } + + protected override void Initialize(ConfuserContext context) { + context.Registry.RegisterService(_ServiceId, typeof(IControlFlowService), this); + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new ControlFlowPhase(this)); + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/ExpressionPredicate.cs b/Additions/ControlFlow-v2/ExpressionPredicate.cs new file mode 100644 index 000000000..d9c7d68c5 --- /dev/null +++ b/Additions/ControlFlow-v2/ExpressionPredicate.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using Confuser.DynCipher.AST; +using Confuser.DynCipher.Generation; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal class ExpressionPredicate : IPredicate { + readonly CFContext ctx; + Func expCompiled; + Expression expression; + + bool inited; + List invCompiled; + Expression inverse; + Local stateVar; + + public ExpressionPredicate(CFContext ctx) { + this.ctx = ctx; + } + + public void Init(CilBody body) { + if (inited) + return; + stateVar = new Local(ctx.Method.Module.CorLibTypes.Int32); + body.Variables.Add(stateVar); + body.InitLocals = true; + Compile(body); + inited = true; + } + + public void EmitSwitchLoad(IList instrs) { + instrs.Add(Instruction.Create(OpCodes.Stloc, stateVar)); + foreach (Instruction instr in invCompiled) + instrs.Add(instr.Clone()); + } + + public int GetSwitchKey(int key) { + return expCompiled(key); + } + + void Compile(CilBody body) { + var var = new Variable("{VAR}"); + var result = new Variable("{RESULT}"); + + ctx.DynCipher.GenerateExpressionPair( + ctx.Random, + new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, + ctx.Depth, out expression, out inverse); + + expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) + .GenerateCIL(expression) + .Compile>(); + + invCompiled = new List(); + new CodeGen(stateVar, ctx, invCompiled).GenerateCIL(inverse); + body.MaxStack += (ushort)ctx.Depth; + } + + class CodeGen : CILCodeGen { + readonly Local state; + + public CodeGen(Local state, CFContext ctx, IList instrs) + : base(ctx.Method, instrs) { + this.state = state; + } + + protected override Local Var(Variable var) { + if (var.Name == "{RESULT}") + return state; + return base.Var(var); + } + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/IPredicate.cs b/Additions/ControlFlow-v2/IPredicate.cs new file mode 100644 index 000000000..4dc1152fe --- /dev/null +++ b/Additions/ControlFlow-v2/IPredicate.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal interface IPredicate { + void Init(CilBody body); + void EmitSwitchLoad(IList instrs); + int GetSwitchKey(int key); + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/JumpMangler.cs b/Additions/ControlFlow-v2/JumpMangler.cs new file mode 100644 index 000000000..dbb72112a --- /dev/null +++ b/Additions/ControlFlow-v2/JumpMangler.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal class JumpMangler : ManglerBase { + LinkedList SpiltFragments(InstrBlock block, CFContext ctx) { + var fragments = new LinkedList(); + var currentFragment = new List(); + + int skipCount = -1; + for (int i = 0; i < block.Instructions.Count; i++) { + if (skipCount != -1) { + if (skipCount > 0) { + currentFragment.Add(block.Instructions[i]); + skipCount--; + continue; + } + fragments.AddLast(currentFragment.ToArray()); + currentFragment.Clear(); + + skipCount = -1; + } + + if (block.Instructions[i].OpCode.OpCodeType == OpCodeType.Prefix) { + skipCount = 1; + currentFragment.Add(block.Instructions[i]); + } + if (i + 2 < block.Instructions.Count && + block.Instructions[i + 0].OpCode.Code == Code.Dup && + block.Instructions[i + 1].OpCode.Code == Code.Ldvirtftn && + block.Instructions[i + 2].OpCode.Code == Code.Newobj) { + skipCount = 2; + currentFragment.Add(block.Instructions[i]); + } + if (i + 4 < block.Instructions.Count && + block.Instructions[i + 0].OpCode.Code == Code.Ldc_I4 && + block.Instructions[i + 1].OpCode.Code == Code.Newarr && + block.Instructions[i + 2].OpCode.Code == Code.Dup && + block.Instructions[i + 3].OpCode.Code == Code.Ldtoken && + block.Instructions[i + 4].OpCode.Code == Code.Call) // Array initializer + { + skipCount = 4; + currentFragment.Add(block.Instructions[i]); + } + if (i + 1 < block.Instructions.Count && + block.Instructions[i + 0].OpCode.Code == Code.Ldftn && + block.Instructions[i + 1].OpCode.Code == Code.Newobj) { + skipCount = 1; + currentFragment.Add(block.Instructions[i]); + } + currentFragment.Add(block.Instructions[i]); + + if (ctx.Intensity > ctx.Random.NextDouble()) { + fragments.AddLast(currentFragment.ToArray()); + currentFragment.Clear(); + } + } + + if (currentFragment.Count > 0) + fragments.AddLast(currentFragment.ToArray()); + + return fragments; + } + + public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { + body.MaxStack++; + foreach (InstrBlock block in GetAllBlocks(root)) { + LinkedList fragments = SpiltFragments(block, ctx); + if (fragments.Count < 4) continue; + + LinkedListNode current = fragments.First; + while (current.Next != null) { + var newFragment = new List(current.Value); + ctx.AddJump(newFragment, current.Next.Value[0]); + ctx.AddJunk(newFragment); + current.Value = newFragment.ToArray(); + current = current.Next; + } + Instruction[] first = fragments.First.Value; + fragments.RemoveFirst(); + Instruction[] last = fragments.Last.Value; + fragments.RemoveLast(); + + List newFragments = fragments.ToList(); + ctx.Random.Shuffle(newFragments); + + block.Instructions = first + .Concat(newFragments.SelectMany(fragment => fragment)) + .Concat(last).ToList(); + } + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/ManglerBase.cs b/Additions/ControlFlow-v2/ManglerBase.cs new file mode 100644 index 000000000..8e42e29f3 --- /dev/null +++ b/Additions/ControlFlow-v2/ManglerBase.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal abstract class ManglerBase { + protected static IEnumerable GetAllBlocks(ScopeBlock scope) { + foreach (BlockBase child in scope.Children) { + if (child is InstrBlock) + yield return (InstrBlock)child; + else { + foreach (InstrBlock block in GetAllBlocks((ScopeBlock)child)) + yield return block; + } + } + } + + public abstract void Mangle(CilBody body, ScopeBlock root, CFContext ctx); + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/NormalPredicate.cs b/Additions/ControlFlow-v2/NormalPredicate.cs new file mode 100644 index 000000000..84b808e62 --- /dev/null +++ b/Additions/ControlFlow-v2/NormalPredicate.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal class NormalPredicate : IPredicate { + readonly CFContext ctx; + bool inited; + int xorKey; + + public NormalPredicate(CFContext ctx) { + this.ctx = ctx; + } + + public void Init(CilBody body) { + if (inited) + return; + + xorKey = ctx.Random.NextInt32(); + inited = true; + } + + public void EmitSwitchLoad(IList instrs) { + instrs.Add(Instruction.Create(OpCodes.Ldc_I4, xorKey)); + instrs.Add(Instruction.Create(OpCodes.Xor)); + } + + public int GetSwitchKey(int key) { + return key ^ xorKey; + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/SwitchMangler.cs b/Additions/ControlFlow-v2/SwitchMangler.cs new file mode 100644 index 000000000..916b23e3c --- /dev/null +++ b/Additions/ControlFlow-v2/SwitchMangler.cs @@ -0,0 +1,434 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Confuser.Core; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections.ControlFlow { + internal class SwitchMangler : ManglerBase { + struct Trace { + public Dictionary RefCount; + public Dictionary> BrRefs; + public Dictionary BeforeStack; + public Dictionary AfterStack; + + static void Increment(Dictionary counts, uint key) { + int value; + if (!counts.TryGetValue(key, out value)) + value = 0; + counts[key] = value + 1; + } + + public Trace(CilBody body, bool hasReturnValue) { + RefCount = new Dictionary(); + BrRefs = new Dictionary>(); + BeforeStack = new Dictionary(); + AfterStack = new Dictionary(); + + body.UpdateInstructionOffsets(); + + foreach (ExceptionHandler eh in body.ExceptionHandlers) { + BeforeStack[eh.TryStart.Offset] = 0; + BeforeStack[eh.HandlerStart.Offset] = (eh.HandlerType != ExceptionHandlerType.Finally ? 1 : 0); + if (eh.FilterStart != null) + BeforeStack[eh.FilterStart.Offset] = 1; + } + + int currentStack = 0; + for (int i = 0; i < body.Instructions.Count; i++) { + var instr = body.Instructions[i]; + + if (BeforeStack.ContainsKey(instr.Offset)) + currentStack = BeforeStack[instr.Offset]; + + BeforeStack[instr.Offset] = currentStack; + instr.UpdateStack(ref currentStack, hasReturnValue); + AfterStack[instr.Offset] = currentStack; + + uint offset; + switch (instr.OpCode.FlowControl) { + case FlowControl.Branch: + offset = ((Instruction)instr.Operand).Offset; + if (!BeforeStack.ContainsKey(offset)) + BeforeStack[offset] = currentStack; + + Increment(RefCount, offset); + BrRefs.AddListEntry(offset, instr); + + currentStack = 0; + continue; + case FlowControl.Call: + if (instr.OpCode.Code == Code.Jmp) + currentStack = 0; + break; + case FlowControl.Cond_Branch: + if (instr.OpCode.Code == Code.Switch) { + foreach (Instruction target in (Instruction[])instr.Operand) { + if (!BeforeStack.ContainsKey(target.Offset)) + BeforeStack[target.Offset] = currentStack; + + Increment(RefCount, target.Offset); + BrRefs.AddListEntry(target.Offset, instr); + } + } + else { + offset = ((Instruction)instr.Operand).Offset; + if (!BeforeStack.ContainsKey(offset)) + BeforeStack[offset] = currentStack; + + Increment(RefCount, offset); + BrRefs.AddListEntry(offset, instr); + } + break; + case FlowControl.Meta: + case FlowControl.Next: + case FlowControl.Break: + break; + case FlowControl.Return: + case FlowControl.Throw: + continue; + default: + throw new UnreachableException(); + } + + if (i + 1 < body.Instructions.Count) { + offset = body.Instructions[i + 1].Offset; + Increment(RefCount, offset); + } + } + } + + public bool IsBranchTarget(uint offset) { + List src; + if (BrRefs.TryGetValue(offset, out src)) + return src.Count > 0; + return false; + } + + public bool HasMultipleSources(uint offset) { + int src; + if (RefCount.TryGetValue(offset, out src)) + return src > 1; + return false; + } + } + + LinkedList SpiltStatements(InstrBlock block, Trace trace, CFContext ctx) { + var statements = new LinkedList(); + var currentStatement = new List(); + + // Instructions that must be included in the ccurrent statement to ensure all outgoing + // branches have stack = 0 + var requiredInstr = new HashSet(); + + for (int i = 0; i < block.Instructions.Count; i++) { + Instruction instr = block.Instructions[i]; + currentStatement.Add(instr); + + bool shouldSpilt = i + 1 < block.Instructions.Count && trace.HasMultipleSources(block.Instructions[i + 1].Offset); + switch (instr.OpCode.FlowControl) { + case FlowControl.Branch: + case FlowControl.Cond_Branch: + case FlowControl.Return: + case FlowControl.Throw: + shouldSpilt = true; + if (trace.AfterStack[instr.Offset] != 0) { + if (instr.Operand is Instruction) + requiredInstr.Add((Instruction)instr.Operand); + else if (instr.Operand is Instruction[]) { + foreach (var target in (Instruction[])instr.Operand) + requiredInstr.Add(target); + } + } + break; + } + requiredInstr.Remove(instr); + if ((instr.OpCode.OpCodeType != OpCodeType.Prefix && trace.AfterStack[instr.Offset] == 0 && + requiredInstr.Count == 0) && + (shouldSpilt || ctx.Intensity > ctx.Random.NextDouble())) { + statements.AddLast(currentStatement.ToArray()); + currentStatement.Clear(); + } + } + + if (currentStatement.Count > 0) + statements.AddLast(currentStatement.ToArray()); + + return statements; + } + + static OpCode InverseBranch(OpCode opCode) { + switch (opCode.Code) { + case Code.Bge: + return OpCodes.Blt; + case Code.Bge_Un: + return OpCodes.Blt_Un; + case Code.Blt: + return OpCodes.Bge; + case Code.Blt_Un: + return OpCodes.Bge_Un; + case Code.Bgt: + return OpCodes.Ble; + case Code.Bgt_Un: + return OpCodes.Ble_Un; + case Code.Ble: + return OpCodes.Bgt; + case Code.Ble_Un: + return OpCodes.Bgt_Un; + case Code.Brfalse: + return OpCodes.Brtrue; + case Code.Brtrue: + return OpCodes.Brfalse; + case Code.Beq: + return OpCodes.Bne_Un; + case Code.Bne_Un: + return OpCodes.Beq; + } + throw new NotSupportedException(); + } + + public override void Mangle(CilBody body, ScopeBlock root, CFContext ctx) { + Trace trace = new Trace(body, ctx.Method.ReturnType.RemoveModifiers().ElementType != ElementType.Void); + var local = new Local(ctx.Method.Module.CorLibTypes.UInt32); + body.Variables.Add(local); + body.InitLocals = true; + + body.MaxStack += 2; + IPredicate predicate = null; + if (ctx.Predicate == PredicateType.Normal) { + predicate = new NormalPredicate(ctx); + } + else if (ctx.Predicate == PredicateType.Expression) { + predicate = new ExpressionPredicate(ctx); + } + else if (ctx.Predicate == PredicateType.x86) { + predicate = new x86Predicate(ctx); + } + + foreach (InstrBlock block in GetAllBlocks(root)) { + LinkedList statements = SpiltStatements(block, trace, ctx); + + // Make sure .ctor is executed before switch + if (ctx.Method.IsInstanceConstructor) { + var newStatement = new List(); + while (statements.First != null) { + newStatement.AddRange(statements.First.Value); + Instruction lastInstr = statements.First.Value.Last(); + statements.RemoveFirst(); + if (lastInstr.OpCode == OpCodes.Call && ((IMethod)lastInstr.Operand).Name == ".ctor") + break; + } + statements.AddFirst(newStatement.ToArray()); + } + + if (statements.Count < 3) continue; + + int i; + + var keyId = Enumerable.Range(0, statements.Count).ToArray(); + ctx.Random.Shuffle(keyId); + var key = new int[keyId.Length]; + for (i = 0; i < key.Length; i++) { + var q = ctx.Random.NextInt32() & 0x7fffffff; + key[i] = q - q % statements.Count + keyId[i]; + } + + var statementKeys = new Dictionary(); + LinkedListNode current = statements.First; + i = 0; + while (current != null) { + if (i != 0) + statementKeys[current.Value[0]] = key[i]; + i++; + current = current.Next; + } + + var statementLast = new HashSet(statements.Select(st => st.Last())); + + Func, bool> hasUnknownSource; + hasUnknownSource = instrs => instrs.Any(instr => { + if (trace.HasMultipleSources(instr.Offset)) + return true; + if (trace.BrRefs.TryGetValue(instr.Offset, out var srcs)) { + // Target of switch => assume unknown + if (srcs.Any(src => src.Operand is Instruction[])) + return true; + + // Not within current instruction block / targeted in first statement + if (srcs.Any(src => src.Offset <= statements.First.Value.Last().Offset || + src.Offset >= block.Instructions.Last().Offset)) + return true; + + // Not targeted by the last of statements + if (srcs.Any(src => statementLast.Contains(src))) + return true; + } + return false; + }); + + var switchInstr = new Instruction(OpCodes.Switch); + var switchHdr = new List(); + + if (predicate != null) { + predicate.Init(body); + switchHdr.Add(Instruction.CreateLdcI4(predicate.GetSwitchKey(key[1]))); + predicate.EmitSwitchLoad(switchHdr); + } + else { + switchHdr.Add(Instruction.CreateLdcI4(key[1])); + } + + switchHdr.Add(Instruction.Create(OpCodes.Dup)); + switchHdr.Add(Instruction.Create(OpCodes.Stloc, local)); + switchHdr.Add(Instruction.Create(OpCodes.Ldc_I4, statements.Count)); + switchHdr.Add(Instruction.Create(OpCodes.Rem_Un)); + switchHdr.Add(switchInstr); + + ctx.AddJump(switchHdr, statements.Last.Value[0]); + ctx.AddJunk(switchHdr); + + var operands = new Instruction[statements.Count]; + current = statements.First; + i = 0; + while (current.Next != null) { + var newStatement = new List(current.Value); + + if (i != 0) { + // Convert to switch + bool converted = false; + + if (newStatement.Last().IsBr()) { + // Unconditional + + var target = (Instruction)newStatement.Last().Operand; + int brKey; + if (!trace.IsBranchTarget(newStatement.Last().Offset) && + statementKeys.TryGetValue(target, out brKey)) { + var targetKey = predicate != null ? predicate.GetSwitchKey(brKey) : brKey; + var unkSrc = hasUnknownSource(newStatement); + + newStatement.RemoveAt(newStatement.Count - 1); + + if (unkSrc) { + newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); + } + else { + var thisKey = key[i]; + var r = ctx.Random.NextInt32(); + newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); + newStatement.Add(Instruction.CreateLdcI4(r)); + newStatement.Add(Instruction.Create(OpCodes.Mul)); + newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, (thisKey * r) ^ targetKey)); + newStatement.Add(Instruction.Create(OpCodes.Xor)); + } + + ctx.AddJump(newStatement, switchHdr[1]); + ctx.AddJunk(newStatement); + operands[keyId[i]] = newStatement[0]; + converted = true; + } + } + else if (newStatement.Last().IsConditionalBranch()) { + // Conditional + + var target = (Instruction)newStatement.Last().Operand; + int brKey; + if (!trace.IsBranchTarget(newStatement.Last().Offset) && + statementKeys.TryGetValue(target, out brKey)) { + bool unkSrc = hasUnknownSource(newStatement); + int nextKey = key[i + 1]; + OpCode condBr = newStatement.Last().OpCode; + newStatement.RemoveAt(newStatement.Count - 1); + + if (ctx.Random.NextBoolean()) { + condBr = InverseBranch(condBr); + int tmp = brKey; + brKey = nextKey; + nextKey = tmp; + } + + var thisKey = key[i]; + int r = 0, xorKey = 0; + if (!unkSrc) { + r = ctx.Random.NextInt32(); + xorKey = thisKey * r; + } + + Instruction brKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(brKey) : brKey)); + Instruction nextKeyInstr = Instruction.CreateLdcI4(xorKey ^ (predicate != null ? predicate.GetSwitchKey(nextKey) : nextKey)); + Instruction pop = Instruction.Create(OpCodes.Pop); + + newStatement.Add(Instruction.Create(condBr, brKeyInstr)); + newStatement.Add(nextKeyInstr); + newStatement.Add(Instruction.Create(OpCodes.Dup)); + newStatement.Add(Instruction.Create(OpCodes.Br, pop)); + newStatement.Add(brKeyInstr); + newStatement.Add(Instruction.Create(OpCodes.Dup)); + newStatement.Add(pop); + + if (!unkSrc) { + newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); + newStatement.Add(Instruction.CreateLdcI4(r)); + newStatement.Add(Instruction.Create(OpCodes.Mul)); + newStatement.Add(Instruction.Create(OpCodes.Xor)); + } + + ctx.AddJump(newStatement, switchHdr[1]); + ctx.AddJunk(newStatement); + operands[keyId[i]] = newStatement[0]; + converted = true; + } + } + + if (!converted) { + // Normal + + var targetKey = predicate != null ? predicate.GetSwitchKey(key[i + 1]) : key[i + 1]; + if (!hasUnknownSource(newStatement)) { + var thisKey = key[i]; + var r = ctx.Random.NextInt32(); + newStatement.Add(Instruction.Create(OpCodes.Ldloc, local)); + newStatement.Add(Instruction.CreateLdcI4(r)); + newStatement.Add(Instruction.Create(OpCodes.Mul)); + newStatement.Add(Instruction.Create(OpCodes.Ldstr, Convert.ToString((thisKey * r) - targetKey))); + newStatement.Add(Instruction.Create(OpCodes.Call, ctx.Method.Module.Import(typeof(System.Int32).GetMethod("Parse", new Type[] { typeof(string) })))); + newStatement.Add(Instruction.Create(OpCodes.Sub)); + } + else { + newStatement.Add(Instruction.Create(OpCodes.Ldc_I4, targetKey)); + } + + ctx.AddJump(newStatement, switchHdr[1]); + ctx.AddJunk(newStatement); + operands[keyId[i]] = newStatement[0]; + } + } + else + operands[keyId[i]] = switchHdr[0]; + + current.Value = newStatement.ToArray(); + current = current.Next; + i++; + } + operands[keyId[i]] = current.Value[0]; + switchInstr.Operand = operands; + + Instruction[] first = statements.First.Value; + statements.RemoveFirst(); + Instruction[] last = statements.Last.Value; + statements.RemoveLast(); + + List newStatements = statements.ToList(); + ctx.Random.Shuffle(newStatements); + + block.Instructions.Clear(); + block.Instructions.AddRange(first); + block.Instructions.AddRange(switchHdr); + foreach (var statement in newStatements) + block.Instructions.AddRange(statement); + block.Instructions.AddRange(last); + } + } + } +} \ No newline at end of file diff --git a/Additions/ControlFlow-v2/x86Predicate.cs b/Additions/ControlFlow-v2/x86Predicate.cs new file mode 100644 index 000000000..a4fb5c7ea --- /dev/null +++ b/Additions/ControlFlow-v2/x86Predicate.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using Confuser.Core; +using Confuser.Core.Services; +using Confuser.DynCipher; +using Confuser.DynCipher.AST; +using Confuser.DynCipher.Generation; +using Confuser.Renamer; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.MD; +using dnlib.DotNet.Writer; +using MethodBody = dnlib.DotNet.Writer.MethodBody; + +namespace Confuser.Protections.ControlFlow { + internal class x86Predicate : IPredicate { + static readonly object Encoding = new object(); + readonly CFContext ctx; + x86Encoding encoding; + + bool inited; + + public x86Predicate(CFContext ctx) { + this.ctx = ctx; + } + + public void Init(CilBody body) { + if (inited) + return; + + encoding = ctx.Context.Annotations.Get(ctx.Method.DeclaringType, Encoding, null); + if (encoding == null) { + encoding = new x86Encoding(); + encoding.Compile(ctx); + ctx.Context.Annotations.Set(ctx.Method.DeclaringType, Encoding, encoding); + } + + inited = true; + } + + public void EmitSwitchLoad(IList instrs) { + instrs.Add(Instruction.Create(OpCodes.Call, encoding.native)); + } + + public int GetSwitchKey(int key) { + return encoding.expCompiled(key); + } + + class x86Encoding { + byte[] code; + MethodBody codeChunk; + + public Func expCompiled; + Expression expression; + Expression inverse; + public MethodDef native; + + public void Compile(CFContext ctx) { + var var = new Variable("{VAR}"); + var result = new Variable("{RESULT}"); + + CorLibTypeSig int32 = ctx.Method.Module.CorLibTypes.Int32; + native = new MethodDefUser(ctx.Context.Registry.GetService().RandomName(), MethodSig.CreateStatic(int32, int32), MethodAttributes.PinvokeImpl | MethodAttributes.PrivateScope | MethodAttributes.Static); + native.ImplAttributes = MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.PreserveSig; + // Attempt to improve performance --- failed with StackOverflowException... :/ + //var suppressAttr = ctx.Method.Module.CorLibTypes.GetTypeRef("System.Security", "SuppressUnmanagedCodeSecurityAttribute").ResolveThrow(); + //native.CustomAttributes.Add(new CustomAttribute((MemberRef)ctx.Method.Module.Import(suppressAttr.FindDefaultConstructor()))); + //native.HasSecurity = true; + ctx.Method.Module.GlobalType.Methods.Add(native); + + ctx.Context.Registry.GetService().Mark(native, ctx.Protection); + ctx.Context.Registry.GetService().SetCanRename(native, false); + + x86Register? reg; + var codeGen = new x86CodeGen(); + do { + ctx.DynCipher.GenerateExpressionPair( + ctx.Random, + new VariableExpression { Variable = var }, new VariableExpression { Variable = result }, + ctx.Depth, out expression, out inverse); + + reg = codeGen.GenerateX86(inverse, (v, r) => { return new[] { x86Instruction.Create(x86OpCode.POP, new x86RegisterOperand(r)) }; }); + } while (reg == null); + + code = CodeGenUtils.AssembleCode(codeGen, reg.Value); + + expCompiled = new DMCodeGen(typeof(int), new[] { Tuple.Create("{VAR}", typeof(int)) }) + .GenerateCIL(expression) + .Compile>(); + + + ctx.Context.CurrentModuleWriterOptions.WriterEvent += InjectNativeCode; + } + + void InjectNativeCode(object sender, ModuleWriterEventArgs e) { + var writer = e.Writer; + switch (e.Event) + { + case ModuleWriterEvent.MDEndWriteMethodBodies: + codeChunk = writer.MethodBodies.Add(new MethodBody(code)); + break; + case ModuleWriterEvent.EndCalculateRvasAndFileOffsets: + uint rid = writer.Metadata.GetRid(native); + + var methodRow = writer.Metadata.TablesHeap.MethodTable[rid]; + writer.Metadata.TablesHeap.MethodTable[rid] = new RawMethodRow( + (uint)codeChunk.RVA, + methodRow.ImplFlags, + methodRow.Flags, + methodRow.Name, + methodRow.Signature, + methodRow.ParamList); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Additions/EreaseHeader/Function.txt b/Additions/EreaseHeader/Function.txt new file mode 100644 index 000000000..fff13e68e --- /dev/null +++ b/Additions/EreaseHeader/Function.txt @@ -0,0 +1 @@ +Overwrites the whole PE Header. \ No newline at end of file diff --git a/Additions/EreaseHeader/Protection/EreaseHeader.cs b/Additions/EreaseHeader/Protection/EreaseHeader.cs new file mode 100644 index 000000000..c372a7dc0 --- /dev/null +++ b/Additions/EreaseHeader/Protection/EreaseHeader.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections +{ + // Token: 0x02000074 RID: 116 + + + internal class EraseHeadersProtection : Protection + { + // Token: 0x060001E9 RID: 489 RVA: 0x00011C8C File Offset: 0x0000FE8C + protected override void Initialize(ConfuserContext context) + { + } + + // Token: 0x060001EA RID: 490 RVA: 0x00011C8E File Offset: 0x0000FE8E + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + + pipeline.InsertPreStage(PipelineStage.EndModule, new EraseHeadersProtection.ErasePhase(this)); + + + + } + public static bool first; + // Token: 0x17000053 RID: 83 + public override string Description + { + // Token: 0x060001E5 RID: 485 RVA: 0x00011C74 File Offset: 0x0000FE74 + get + { + return Resources.EraseHeadersProtection_Description; + } + } + + // Token: 0x17000055 RID: 85 + public override string FullId + { + // Token: 0x060001E7 RID: 487 RVA: 0x00011C82 File Offset: 0x0000FE82 + get + { + return "Ki.EraseHeaders"; + } + } + + // Token: 0x17000054 RID: 84 + public override string Id + { + // Token: 0x060001E6 RID: 486 RVA: 0x00011C7B File Offset: 0x0000FE7B + get + { + return "erase headers"; + } + } + + // Token: 0x17000052 RID: 82 + public override string Name + { + // Token: 0x060001E4 RID: 484 RVA: 0x00011C6D File Offset: 0x0000FE6D + get + { + return Resources.EraseHeadersProtection_Name; + } + } + + // Token: 0x17000056 RID: 86 + public override ProtectionPreset Preset + { + // Token: 0x060001E8 RID: 488 RVA: 0x00011C89 File Offset: 0x0000FE89 + get + { + return ProtectionPreset.Normal; + } + } + + // Token: 0x04000174 RID: 372 + public const string _FullId = "Ki.EraseHeaders"; + + // Token: 0x04000173 RID: 371 + public const string _Id = "erase headers"; + + // Token: 0x02000075 RID: 117 + private class ErasePhase : ProtectionPhase + { + // Token: 0x060001EC RID: 492 RVA: 0x00011CA5 File Offset: 0x0000FEA5 + public ErasePhase(EraseHeadersProtection parent) : base(parent) + { + } + + // Token: 0x060001EF RID: 495 RVA: 0x00011CCC File Offset: 0x0000FECC + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + TypeDef rtType = context.Registry.GetService().GetRuntimeType("Confuser.Runtime.EraseHeaders"); + IMarkerService marker = context.Registry.GetService(); + INameService name = context.Registry.GetService(); + foreach (ModuleDef module in parameters.Targets.OfType()) + { + IEnumerable members = InjectHelper.Inject(rtType, module.GlobalType, module); + MethodDef cctor = module.GlobalType.FindStaticConstructor(); + + MethodDef init = (MethodDef)members.Single((IDnlibDef method) => method.Name == "Initialize"); + cctor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, init)); + + + + foreach (IDnlibDef member in members) + { + name.MarkHelper(member, marker, (Protection)base.Parent); + } + } + } + + // Token: 0x17000058 RID: 88 + public override string Name + { + // Token: 0x060001EE RID: 494 RVA: 0x00011CB2 File Offset: 0x0000FEB2 + get + { + return Resources.ErasePhase_Name; + } + } + + // Token: 0x17000057 RID: 87 + public override ProtectionTargets Targets + { + // Token: 0x060001ED RID: 493 RVA: 0x00011CAE File Offset: 0x0000FEAE + get + { + return ProtectionTargets.Modules; + } + } + } + } +} \ No newline at end of file diff --git a/Additions/EreaseHeader/Runtime/Ereaseheaders.cs b/Additions/EreaseHeader/Runtime/Ereaseheaders.cs new file mode 100644 index 000000000..7dc42f7fb --- /dev/null +++ b/Additions/EreaseHeader/Runtime/Ereaseheaders.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Confuser.Runtime { + + internal static class EraseHeaders { + [DllImport("kernel32.dll")] + public static extern IntPtr ZeroMemory(IntPtr addr, IntPtr size); + + [DllImport("kernel32.dll")] + public static extern IntPtr VirtualProtect(IntPtr lpAddress, IntPtr dwSize, IntPtr flNewProtect, ref IntPtr lpflOldProtect); + static unsafe void Initialize() { + + var sectiontabledwords = new List() { 0x8, 0xC, 0x10, 0x14, 0x18, 0x1C, 0x24 }; + var peheaderbytes = new List() { 0x1A, 0x1B }; + var peheaderwords = new List() { 0x4, 0x16, 0x18, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x5C, 0x5E }; + var process = System.Diagnostics.Process.GetCurrentProcess(); + var base_address = process.MainModule.BaseAddress; + var dwpeheader = Marshal.ReadInt32((IntPtr)(base_address.ToInt32() + 0x3C)); + var wnumberofsections = Marshal.ReadInt16((IntPtr)(base_address.ToInt32() + dwpeheader + 0x6)); + + for (int i = 0; i < peheaderwords.Count; i++) + { + EraseSection((IntPtr)(base_address.ToInt32() + dwpeheader + peheaderwords[i]), 1); + } + for (int i = 0; i < peheaderbytes.Count; i++) + { + EraseSection((IntPtr)(base_address.ToInt32() + dwpeheader + peheaderbytes[i]), 2); + } + + int x = 0; + int y = 0; + + while (x <= wnumberofsections) + { + if (y == 0) + { + EraseSection((IntPtr)((base_address.ToInt32() + dwpeheader + 0xFA + (0x28 * x)) + 0x20), 2); + } + + y++; + + if (y == sectiontabledwords.Count) + { + x++; + y = 0; + } + } + + } + public static void EraseSection(IntPtr address, int size) + { + IntPtr sz = (IntPtr)size; + IntPtr dwOld = default(IntPtr); + VirtualProtect(address, sz, (IntPtr)0x40, ref dwOld); + ZeroMemory(address, sz); + IntPtr temp = default(IntPtr); + VirtualProtect(address, sz, dwOld, ref temp); + } + } + } \ No newline at end of file diff --git a/Additions/FakeObfuscator/Function.txt b/Additions/FakeObfuscator/Function.txt new file mode 100644 index 000000000..c8f923aec --- /dev/null +++ b/Additions/FakeObfuscator/Function.txt @@ -0,0 +1 @@ +Confuses obfuscators like de4dot by adding types typical to other obfuscators. \ No newline at end of file diff --git a/Additions/FakeObfuscator/Protection/FakeObfuscatorAttributesPhase.cs b/Additions/FakeObfuscator/Protection/FakeObfuscatorAttributesPhase.cs new file mode 100644 index 000000000..16146564e --- /dev/null +++ b/Additions/FakeObfuscator/Protection/FakeObfuscatorAttributesPhase.cs @@ -0,0 +1,80 @@ +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using Confuser.Runtime.FakeObfuscator; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.FakeObuscator +{ + public class FakeObfuscatorAttributesPhase : ProtectionPhase + { + public override ProtectionTargets Targets => ProtectionTargets.Modules; + public override string Name => Resources.FakeObfuscatorAttributesPhase_Name; + + public FakeObfuscatorAttributesPhase(ConfuserComponent parent) : base(parent) { } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + var allAddedTypes = new List(); + var module = context.CurrentModule; + + TypeDefUser[] attributesToAdd = { + new TypeDefUser("SecureTeam.Attributes", "ObfuscatedByCliSecureAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("SecureTeam.Attributes", "ObfuscatedByAgileDotNetAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("BabelAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("Beds-Protector-v7.0", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("CryptoObfuscator", "ProtectedWithCryptoObfuscatorAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("DotfuscatorAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("ObfuscatedByGoliath", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("MaxtoCodeAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("NETSecure", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("SmartAssembly.Attributes", "PoweredByAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("NineRays.Obfuscator", "SoftwareWatermarkAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("NineRays.Obfuscator", "Evaluation", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("VMProtect", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("Xenocode.Client.Attributes.AssemblyAttributes", "ProcessedByXenocode", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("ZYXDNGuarder", module.CorLibTypes.GetTypeRef("System", "Attribute")), + new TypeDefUser("YanoAttribute", module.CorLibTypes.GetTypeRef("System", "Attribute")) + }; + + foreach (var m in parameters.Targets.Cast().WithProgress(context.Logger)) + { + //inject types + foreach (TypeDefUser idk in attributesToAdd.WithProgress(context.Logger)) + allAddedTypes.AddRange(InjectType(m, context.Logger, idk)); + + //mark types to NOT be renamed + foreach (IDnlibDef def in allAddedTypes) + { + marker.Mark(def, Parent); + name.MarkHelper(def, marker, Parent); + name.SetCanRename(def, false); + } + } + } + + private IEnumerable InjectType(ModuleDef m, Core.ILogger l, params TypeDefUser[] types) + { + List ret = new List(); + + foreach (TypeDefUser type in types) + { + m.Types.Add(type); + l.Debug(Resources.FakeObfuscatorAttributesPhase_InjectType_Debug + type); + + ret.AddRange(InjectHelper.Inject(type, type, m)); + } + + return ret; + } + } +} diff --git a/Additions/FakeObfuscator/Protection/FakeObfuscatorProtection.cs b/Additions/FakeObfuscator/Protection/FakeObfuscatorProtection.cs new file mode 100644 index 000000000..6066b5fb6 --- /dev/null +++ b/Additions/FakeObfuscator/Protection/FakeObfuscatorProtection.cs @@ -0,0 +1,26 @@ +using Confuser.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.FakeObuscator +{ + public class FakeObfuscatorProtection : Protection + { + public override string Name => Resources.FakeObfuscatorProtection_Name; + public override string Description => Resources.FakeObfuscatorProtection_Description; + public override string Id => "fake obfuscator"; + public override string FullId => "HoLLy.FakeObfuscator"; + public override ProtectionPreset Preset => ProtectionPreset.Normal; + + protected override void Initialize(ConfuserContext context) { } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPostStage(PipelineStage.EndModule, new FakeObfuscatorTypesPhase(this)); + pipeline.InsertPostStage(PipelineStage.EndModule, new FakeObfuscatorAttributesPhase(this)); + } + } +} diff --git a/Additions/FakeObfuscator/Protection/FakeObfuscatorTypesPhase.cs b/Additions/FakeObfuscator/Protection/FakeObfuscatorTypesPhase.cs new file mode 100644 index 000000000..794beb4fa --- /dev/null +++ b/Additions/FakeObfuscator/Protection/FakeObfuscatorTypesPhase.cs @@ -0,0 +1,75 @@ +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Renamer; +using Confuser.Runtime.FakeObfuscator; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.FakeObuscator +{ + public class FakeObfuscatorTypesPhase : ProtectionPhase + { + public override ProtectionTargets Targets => ProtectionTargets.Modules; + public override string Name => Resources.FakeObfuscatorTypesPhase_Name; + + public FakeObfuscatorTypesPhase(ConfuserComponent parent) : base(parent) { } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + var marker = context.Registry.GetService(); + var name = context.Registry.GetService(); + var runtime = context.Registry.GetService(); + var allAddedTypes = new List(); + + Type[][] typesToAdd = { + BabelDotNet.GetTypes(), //+110 + CodeFort.GetTypes(), //+100 + CodeWall.GetTypes(), //+100 + CryptoObfuscator.GetTypes(),//+120 + Dotfuscator.GetTypes(), //+100 + EazfuscatorDotNet.GetTypes(),//+100 + GoliathDotNet.GetTypes(), //+100 + Xenocode.GetTypes() //+100 + }; + + foreach (var m in parameters.Targets.Cast().WithProgress(context.Logger)) + { + //inject types + foreach (Type[] idk in typesToAdd.WithProgress(context.Logger)) + allAddedTypes.AddRange(InjectType(m, runtime, context.Logger, idk)); + + //mark types + foreach (IDnlibDef def in allAddedTypes) + { + marker.Mark(def, Parent); + name.SetCanRename(def, false); + } + } + } + + private static IEnumerable InjectType(ModuleDef m, IRuntimeService runtime, Core.ILogger l, params Type[] types) + { + List ret = new List(); + + foreach (TypeDef type in types.Select(n=> runtime.GetRuntimeType(n.FullName))) + { + if(type == null) continue; + var newType = new TypeDefUser(m.GlobalType.Namespace, type.Name, type.BaseType); + m.Types.Add(newType); + + l.Debug(Resources.FakeObfuscatorTypesPhase_InjectType_Debug + newType); + + ret.Add(newType); + ret.AddRange(InjectHelper.Inject(type, newType, m)); + } + + return ret; + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/BabelDotNet.cs b/Additions/FakeObfuscator/Runtime/BabelDotNet.cs new file mode 100644 index 000000000..c53e7108e --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/BabelDotNet.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections; +using System.IO; +using System.Reflection; +#pragma warning disable 169 + +namespace Confuser.Runtime.FakeObfuscator +{ + public class BabelDotNet + { + public static Type[] GetTypes() => new[] {typeof(BabelAssemblyResolver), typeof(BabelStringDecrypter) }; + + //no events + internal class BabelAssemblyResolver + { + //required fields + private object _o; + private int _i; + private Hashtable _h; + + //static, 1 exception handler + private static void Register() + { + try { + //ldftn OnAssemblyResolve + AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; + } catch (Exception) { } + } + + //has to be in same type as register, 1 exception handler + private static Assembly OnAssemblyResolve(object o, ResolveEventArgs e) + { + try { + return null; + } catch (Exception) { + return null; + } + } + + private static void Decrypt(Stream str) { } + } + + //no events, 2 or less nested types, 1 or less fields + //going for babel.net 3.0-3.5 + internal class BabelStringDecrypter + { + //static decrypter method + private static string Decrypt(int i) => ""; + + //no properties, no events + private class NestedType + { + //2 properties to detect as 3.0-3.5 + private Hashtable _o1; + private NestedType _o2; + + //requires a .ctor + public NestedType() { } + + //non-static decrypter method + private string Decrypt(int i) => ""; + } + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/CodeFort.cs b/Additions/FakeObfuscator/Runtime/CodeFort.cs new file mode 100644 index 000000000..68fb21344 --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/CodeFort.cs @@ -0,0 +1,17 @@ +using System; +using System.Globalization; + +namespace Confuser.Runtime.FakeObfuscator +{ + public class CodeFort + { + public static Type[] GetTypes() => new[] { typeof(CodeFortStringDecrypter) }; + + //may not have fields + internal static class CodeFortStringDecrypter + { + //static, has double 3992.0 + private static string Decrypt(string s) => 3992.0.ToString(CultureInfo.InvariantCulture); + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/CodeWall.cs b/Additions/FakeObfuscator/Runtime/CodeWall.cs new file mode 100644 index 000000000..3d44d41cb --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/CodeWall.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +#pragma warning disable 169 +#pragma warning disable 219 + +namespace Confuser.Runtime.FakeObfuscator +{ + public class CodeWall + { + public static Type[] GetTypes() => new[] { typeof(CodeWallStringDecrypter) }; + + //requires 2 methods: 1 decrypter and any other (eg. cctor) + internal static class CodeWallStringDecrypter + { + //required fields + private static object _o; + private static Dictionary _d = new Dictionary(); + + private static string Decrypt(int x, int y, int z) + { + //required locals + var l1 = default(int); + var l2 = default(byte[]); + var l3 = default(Assembly); + var l4 = default(Stream); + var l5 = default(Random); + var l6 = default(string); + var l7 = default(object); + + return l6; + } + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/CryptoObfuscator.cs b/Additions/FakeObfuscator/Runtime/CryptoObfuscator.cs new file mode 100644 index 000000000..5a1aaa4da --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/CryptoObfuscator.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +#pragma warning disable 169 +#pragma warning disable 219 + +namespace Confuser.Runtime.FakeObfuscator +{ + public class CryptoObfuscator + { + public static Type[] GetTypes() => new[] { + typeof(CryptoObfuscatorMethodDecrypter), + typeof(CryptoObfuscatorStringDecrypter), + typeof(CryptoObfuscatorConstantsDecrypter) + }; + + //1 nested type, 3 fields, has cctor + internal static class CryptoObfuscatorMethodDecrypter + { + //required fields + private static byte[] _b; + private static Dictionary _d = new Dictionary(); //creates .cctor + private static ModuleHandle _m; + + //has to be static + public static void Decrypt(int x, int y, int z) + { + var l1 = default(Delegate); + var l2 = default(ModuleHandle); + var l3 = default(DynamicILInfo); + var l4 = default(DynamicMethod); + var l5 = default(FieldInfo); + var l6 = default(FieldInfo[]); + var l7 = default(MethodBase); + var l8 = default(MethodBody); + var l9 = default(Type); + var l10 = default(Type[]); + } + + private class Nested { } + } + + //cannot be public, 1 static field (byte[]), 2 or 3 methods, no nested types + internal static class CryptoObfuscatorStringDecrypter + { + private static byte[] _b; + + private static string Decrypt(int i) => ""; + + private static void ExtraMethod() { } + } + + //7 methods, 1 or 2 fields, has a byte[] field + internal static class CryptoObfuscatorConstantsDecrypter + { + private static byte[] _b = new byte[0]; //creates .cctor + + //required methods + private static int RequiredMethod1(int a) => 0; + private static long RequiredMethod2(int a) => (long)0; + private static float RequiredMethod3(int a) => 0f; + private static double RequiredMethod4(int a) => 0.0; + private static void RequiredMethod5(Array arr, int a) { } + + //getting to 7 total methods + private static void Extra() { } + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/Dotfuscator.cs b/Additions/FakeObfuscator/Runtime/Dotfuscator.cs new file mode 100644 index 000000000..418e7aa51 --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/Dotfuscator.cs @@ -0,0 +1,25 @@ +using System; + +namespace Confuser.Runtime.FakeObfuscator +{ + public class Dotfuscator + { + public static Type[] GetTypes() => new[] { typeof(DotfuscatorStringDecrypter) }; + + internal class DotfuscatorStringDecrypter + { + //no exception handlers, static + private static string Decrypt(string s, int i) + { + //required method + string.Intern(s); + + //stloc + //ldci4 + char[] o = s.ToCharArray(); //ldarg0, callvirt tochararray + string s2 = 5.ToString(); //stloc x, ldci4 + return s2 + o; //prevent deobfuscator from adding a pop due to vars being unused + } + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/EazfuscatorDotNet.cs b/Additions/FakeObfuscator/Runtime/EazfuscatorDotNet.cs new file mode 100644 index 000000000..64032352d --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/EazfuscatorDotNet.cs @@ -0,0 +1,39 @@ +using System; +using System.Reflection; +#pragma warning disable 169 +#pragma warning disable 219 + +namespace Confuser.Runtime.FakeObfuscator +{ + public class EazfuscatorDotNet + { + public static Type[] GetTypes() => new[] {typeof(EazfuscatorStringDecrypter)}; + + internal class EazfuscatorStringDecrypter + { + //required fields + private byte[] _b; + private short _s; + + public static string Decrypter(int i) + { + //required locals + var l1 = default(bool); + var l2 = default(byte[]); + var l3 = default(char[]); + var l4 = default(short); + var l5 = default(int); + var l6 = default(Assembly); + var l7 = default(string); + + //required instruction + l6.GetManifestResourceStream(l7); + + return l7; + } + + //nested enum, for CheckType + public enum Enum { } + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/GoliathDotNet.cs b/Additions/FakeObfuscator/Runtime/GoliathDotNet.cs new file mode 100644 index 000000000..ed3b0d1a4 --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/GoliathDotNet.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +#pragma warning disable 219 + +namespace Confuser.Runtime.FakeObfuscator +{ + public class GoliathDotNet + { + public static Type[] GetTypes() => new[] {typeof(GoliathStrongNameChecker)}; + + //no fields, no events, no properties + internal class GoliathStrongNameChecker + { + //has throw instruction + public static void AntiTamper(Type t) + { + //required locals + var l1 = default(Assembly); + var l2 = default(Stack); + + //this gets boring after a while, you know + var party = new Exception(); + throw party; + } + + public byte[] RequiredMethod(Assembly s) => default(byte[]); + public string RequiredMethod(Stack s) => default(string); + public int RequiredMethod(int i, byte[] b) => default(int); + } + } +} diff --git a/Additions/FakeObfuscator/Runtime/Xenocode.cs b/Additions/FakeObfuscator/Runtime/Xenocode.cs new file mode 100644 index 000000000..63bf6ca2b --- /dev/null +++ b/Additions/FakeObfuscator/Runtime/Xenocode.cs @@ -0,0 +1,16 @@ +using System; + +namespace Confuser.Runtime.FakeObfuscator +{ + public class Xenocode + { + public static Type[] GetTypes() => new[] {typeof(XenocodeStringDecrypter)}; + + //no fields, 1, 2 or 3 methods, no properties, no events + internal class XenocodeStringDecrypter + { + //has to contain int 1789 + public string Decrypt(string x, int y) => 1789.ToString(); + } + } +} diff --git a/Additions/LICENSE b/Additions/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/Additions/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Additions/LocaltoFields/Function.txt b/Additions/LocaltoFields/Function.txt new file mode 100644 index 000000000..16bad43bf --- /dev/null +++ b/Additions/LocaltoFields/Function.txt @@ -0,0 +1 @@ +This protection marks the module with a attribute that discourage ILDasm from disassembling it. \ No newline at end of file diff --git a/Additions/LocaltoFields/Protection/LocaltoFieldProtection.cs b/Additions/LocaltoFields/Protection/LocaltoFieldProtection.cs new file mode 100644 index 000000000..fac4f93fd --- /dev/null +++ b/Additions/LocaltoFields/Protection/LocaltoFieldProtection.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Confuser.Core; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; +using dnlib.DotNet.Emit; + +namespace Confuser.Protections +{ + internal class LocaltoFieldProtection : Protection + { + public const string _Id = "local to field"; + public const string _FullId = "Ki.Local2Field"; + + public override string Name + { + get { return Resources.LocaltoFieldProtection_Name; } + } + + public override string Description + { + get { return Resources.LocaltoFieldProtection_Description; } + } + + public override string Id + { + get { return _Id; } + } + + public override string FullId + { + get { return _FullId; } + } + + public override ProtectionPreset Preset + { + get { return ProtectionPreset.Minimum; } + } + + protected override void Initialize(ConfuserContext context) + { + // + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new localtofieldphase(this)); + } + + class localtofieldphase : ProtectionPhase + { + public localtofieldphase(LocaltoFieldProtection parent) + : base(parent) { } + + public override ProtectionTargets Targets + { + get { return ProtectionTargets.Modules; } + } + + + + public override string Name + { + get { return Resources.localtofieldphase_Name; } + } + public void ProcessMethod(MethodDef method, ModuleDef modulee) + { + var instructions = method.Body.Instructions; + for (int i = 0; i < instructions.Count; i++) + { + if (instructions[i].Operand is Local local) + { + FieldDef def = null; + if (!convertedLocals.ContainsKey(local)) + { + def = new FieldDefUser("", new FieldSig(local.Type), FieldAttributes.Public | FieldAttributes.Static); + modulee.GlobalType.Fields.Add(def); + convertedLocals.Add(local, def); + } + else + def = convertedLocals[local]; + + + OpCode eq = null; + switch (instructions[i].OpCode.Code) + { + case Code.Ldloc: + case Code.Ldloc_S: + case Code.Ldloc_0: + case Code.Ldloc_1: + case Code.Ldloc_2: + case Code.Ldloc_3: + eq = OpCodes.Ldsfld; + break; + case Code.Ldloca: + case Code.Ldloca_S: + eq = OpCodes.Ldsflda; + break; + case Code.Stloc: + case Code.Stloc_0: + case Code.Stloc_1: + case Code.Stloc_2: + case Code.Stloc_3: + case Code.Stloc_S: + eq = OpCodes.Stsfld; + break; + } + instructions[i].OpCode = eq; + instructions[i].Operand = def; + + } + } + } + Dictionary convertedLocals = new Dictionary(); + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + foreach (ModuleDef module in parameters.Targets.OfType()) + { + foreach (var type in module.Types.Where(x => x != module.GlobalType)) + { + foreach (var method in type.Methods.Where(x => x.HasBody && x.Body.HasInstructions && !x.IsConstructor)) + { + convertedLocals = new Dictionary(); + ProcessMethod(method, module); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Additions/Mutate Constants/Function.txt b/Additions/Mutate Constants/Function.txt new file mode 100644 index 000000000..a8a1a9ad5 --- /dev/null +++ b/Additions/Mutate Constants/Function.txt @@ -0,0 +1 @@ +Mutate Contants with sizeofs. \ No newline at end of file diff --git a/Additions/Mutate Constants/Protections/MutateConstantsProtection.cs b/Additions/Mutate Constants/Protections/MutateConstantsProtection.cs new file mode 100644 index 000000000..b1e45e982 --- /dev/null +++ b/Additions/Mutate Constants/Protections/MutateConstantsProtection.cs @@ -0,0 +1,225 @@ +using System; +using System.Linq; +using Confuser.Core; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System.Collections.Generic; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections +{ + [BeforeProtection("Ki.ControlFlow")] + + internal class MutateConstantsProtection : Protection + { + public override string Name + { + get + { + return Resources.MutateConstantsProtection_Name; + } + } + + public override string Description + { + get + { + return Resources.MutateConstantsProtection_Description; + } + } + + public override string Id + { + get + { + return "Mutate Constants"; + } + } + + public override string FullId + { + get + { + return "Ki.MutateConstants"; + } + } + + public const string _Id = "Mutate Constants"; + + public const string _FullId = "Ki.MutateConstants"; + + public override ProtectionPreset Preset + { + get + { + return ProtectionPreset.Normal; + } + } + + protected override void Initialize(ConfuserContext context) + { + // Null + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new MutateConstantsPhase(this)); + } + + private class MutateConstantsPhase : ProtectionPhase + { + public MutateConstantsPhase(MutateConstantsProtection parent) : base(parent) + { + // Null + } + + public override ProtectionTargets Targets + { + get + { + return ProtectionTargets.Modules; + } + } + + public override string Name + { + get + { + return Resources.MutateConstantsPhase_Name; + } + } + + public CilBody body; + + public static Random rnd = new Random(); + + public static double RandomDouble(double min, double max) + { + return new Random().NextDouble() * (max - min) + min; + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + foreach (ModuleDef moduleDef in parameters.Targets.OfType()) + { + foreach (TypeDef typeDef in moduleDef.Types) + { + foreach (MethodDef methodDef in typeDef.Methods) + { + if (methodDef.HasBody && methodDef.Body.HasInstructions) + { + for (int i = 0; i < methodDef.Body.Instructions.Count; i++) + { + if (methodDef.Body.Instructions[i].IsLdcI4()) + { + // EmptyType + + int operand = methodDef.Body.Instructions[i].GetLdcI4Value(); + methodDef.Body.Instructions[i].Operand = operand - Type.EmptyTypes.Length; + methodDef.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + methodDef.Body.Instructions.Insert(i + 1, OpCodes.Ldsfld.ToInstruction(methodDef.Module.Import(typeof(Type).GetField("EmptyTypes")))); + methodDef.Body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Ldlen)); + methodDef.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Add)); + + body = methodDef.Body; + int ldcI4Value = body.Instructions[i].GetLdcI4Value(); + int num = rnd.Next(1, 4); + int num2 = ldcI4Value - num; + body.Instructions[i].Operand = num2; + Mutate(i, num, num2, moduleDef); + + // Double Parse + + int operand3 = methodDef.Body.Instructions[i].GetLdcI4Value(); + double n = RandomDouble(1.0, 1000.0); + string converter = Convert.ToString(n); + double nEw = double.Parse(converter); + int conta = operand3 - (int)nEw; + methodDef.Body.Instructions[i].Operand = conta; + methodDef.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + methodDef.Body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Ldstr, converter)); + methodDef.Body.Instructions.Insert(i + 2, OpCodes.Call.ToInstruction(methodDef.Module.Import(typeof(double).GetMethod("Parse", new Type[] { typeof(string) })))); + methodDef.Body.Instructions.Insert(i + 3, OpCodes.Conv_I4.ToInstruction()); + methodDef.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Add)); + + // Calc + + int op = methodDef.Body.Instructions[i].GetLdcI4Value(); + int newvalue = rnd.Next(-100, 10000); + switch (rnd.Next(1, 4)) + { + case 1: + methodDef.Body.Instructions[i].Operand = op - newvalue; + methodDef.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + methodDef.Body.Instructions.Insert(i + 2, OpCodes.Add.ToInstruction()); + i += 2; + break; + case 2: + methodDef.Body.Instructions[i].Operand = op + newvalue; + methodDef.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + methodDef.Body.Instructions.Insert(i + 2, OpCodes.Sub.ToInstruction()); + i += 2; + break; + case 3: + methodDef.Body.Instructions[i].Operand = op ^ newvalue; + methodDef.Body.Instructions.Insert(i + 1, OpCodes.Ldc_I4.ToInstruction(newvalue)); + methodDef.Body.Instructions.Insert(i + 2, OpCodes.Xor.ToInstruction()); + i += 2; + break; + case 4: + int operand2 = methodDef.Body.Instructions[i].GetLdcI4Value(); + methodDef.Body.Instructions[i].OpCode = OpCodes.Ldc_I4; + methodDef.Body.Instructions[i].Operand = operand2 - 1; + int valor = rnd.Next(100, 500); + int valor2 = rnd.Next(1000, 5000); + methodDef.Body.Instructions.Insert(i + 1, Instruction.CreateLdcI4(valor)); + methodDef.Body.Instructions.Insert(i + 2, Instruction.CreateLdcI4(valor2)); + methodDef.Body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Clt)); + methodDef.Body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Conv_I4)); + methodDef.Body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Add)); + i += 5; + break; + } + } + } + } + } + } + } + } + + private void Mutate(int i, int sub, int num2, ModuleDef module) + { + switch (sub) + { + case 1: + body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(byte)))); + body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Add)); + return; + case 2: + body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(byte)))); + body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(byte)))); + body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Add)); + body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Add)); + return; + case 3: + body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(int)))); + body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(byte)))); + body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Sub)); + body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Add)); + return; + case 4: + body.Instructions.Insert(i + 1, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(decimal)))); + body.Instructions.Insert(i + 2, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(GCCollectionMode)))); + body.Instructions.Insert(i + 3, Instruction.Create(OpCodes.Sub)); + body.Instructions.Insert(i + 4, Instruction.Create(OpCodes.Sizeof, module.Import(typeof(int)))); + body.Instructions.Insert(i + 5, Instruction.Create(OpCodes.Sub)); + body.Instructions.Insert(i + 6, Instruction.Create(OpCodes.Add)); + return; + default: + return; + } + } + } + } +} diff --git a/Additions/OpCodeProt/Function.txt b/Additions/OpCodeProt/Function.txt new file mode 100644 index 000000000..dd7fbf094 --- /dev/null +++ b/Additions/OpCodeProt/Function.txt @@ -0,0 +1 @@ +Protects OpCodes such as Ldlfd. \ No newline at end of file diff --git a/Additions/OpCodeProt/Protection/CallvirtPhase.cs b/Additions/OpCodeProt/Protection/CallvirtPhase.cs new file mode 100644 index 000000000..7ee890334 --- /dev/null +++ b/Additions/OpCodeProt/Protection/CallvirtPhase.cs @@ -0,0 +1,50 @@ +using Confuser.Core; +using Confuser.Core.Services; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System.Linq; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.OpCodeProt { + public class CallvirtPhase : ProtectionPhase { + public CallvirtPhase(OpCodeProtection parent) : base(parent) { } + + public override ProtectionTargets Targets => ProtectionTargets.Types; + + public override string Name => Resources.CallvirtPhase_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + var random = context.Registry.GetService().GetRandomGenerator(Parent.FullId + ".Callvirt"); + foreach (TypeDef type in parameters.Targets.OfType()) { + if (type.IsGlobalModuleType) continue; + foreach (MethodDef method in type.Methods) { + //if (method.InGlobalModuleType()) continue; + if (method.FullName.Contains("My.")) continue; + if (method.IsConstructor) continue; + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) { + if (method.Body.Instructions[i].OpCode == OpCodes.Callvirt) { + if (method.Body.Instructions[i].Operand.ToString().ToLower().Contains("int32")) { + if ((i - 1) > 0 && method.Body.Instructions[i - 1].IsLdloc()) { + Local new_local = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(new_local); + + method.Body.Instructions.Insert(i - 1, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i, OpCodes.Stloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 1, OpCodes.Ldloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 2, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i + 3, OpCodes.Ldarg_0.ToInstruction()); + method.Body.Instructions.Insert(i + 4, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 6, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 3, new Instruction(OpCodes.Beq_S, method.Body.Instructions[i + 4])); + method.Body.Instructions.Insert(i + 5, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 8])); + method.Body.Instructions.Insert(i + 8, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 9])); + } + } + } + } + } + } + } + } +} diff --git a/Additions/OpCodeProt/Protection/CtorCallProtection.cs b/Additions/OpCodeProt/Protection/CtorCallProtection.cs new file mode 100644 index 000000000..9e605ba94 --- /dev/null +++ b/Additions/OpCodeProt/Protection/CtorCallProtection.cs @@ -0,0 +1,50 @@ +using Confuser.Core; +using Confuser.Core.Services; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System.Linq; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.OpCodeProt { + public class CtorCallProtection : ProtectionPhase { + public CtorCallProtection(OpCodeProtection parent) : base(parent) { } + + public override ProtectionTargets Targets => ProtectionTargets.Types; + + public override string Name => Resources.CtorCallProtection_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + var random = context.Registry.GetService().GetRandomGenerator(Parent.FullId + ".CtorCall"); + foreach (TypeDef type in parameters.Targets.OfType()) { + if (type.IsGlobalModuleType) continue; + foreach (MethodDef method in type.Methods) { + //if (method.InGlobalModuleType()) continue; + if (method.FullName.Contains("My.")) continue; + if (method.IsConstructor) continue; + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) { + if (method.Body.Instructions[i].OpCode == OpCodes.Call) { + if (method.Body.Instructions[i].Operand.ToString().ToLower().Contains("void")) { + if ((i - 1) > 0 && method.Body.Instructions[i - 1].IsLdarg()) { + Local new_local = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(new_local); + + method.Body.Instructions.Insert(i - 1, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i, OpCodes.Stloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 1, OpCodes.Ldloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 2, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i + 3, OpCodes.Ldarg_0.ToInstruction()); + method.Body.Instructions.Insert(i + 4, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 6, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 3, new Instruction(OpCodes.Bne_Un_S, method.Body.Instructions[i + 4])); + method.Body.Instructions.Insert(i + 5, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 8])); + method.Body.Instructions.Insert(i + 8, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 9])); + } + } + } + } + } + } + } + } +} diff --git a/Additions/OpCodeProt/Protection/LdfldPhase.cs b/Additions/OpCodeProt/Protection/LdfldPhase.cs new file mode 100644 index 000000000..47eef206b --- /dev/null +++ b/Additions/OpCodeProt/Protection/LdfldPhase.cs @@ -0,0 +1,48 @@ +using Confuser.Core; +using Confuser.Core.Services; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System.Linq; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.OpCodeProt { + public class LdfldPhase : ProtectionPhase { + public LdfldPhase(OpCodeProtection parent) : base(parent) { } + + public override ProtectionTargets Targets => ProtectionTargets.Types; + + public override string Name => Resources.LdfldPhase_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + var random = context.Registry.GetService().GetRandomGenerator(Parent.FullId + ".Ldfld"); + foreach (TypeDef type in parameters.Targets.OfType()) { + if (type.IsGlobalModuleType) continue; + foreach (MethodDef method in type.Methods) { + //if (method.InGlobalModuleType()) continue; + if (method.FullName.Contains("My.")) continue; + if (method.IsConstructor) continue; + if (!method.HasBody) continue; + for (int i = 0; i < method.Body.Instructions.Count; i++) { + if (method.Body.Instructions[i].OpCode == OpCodes.Ldfld) { + if ((i - 1) > 0 && method.Body.Instructions[i - 1].IsLdarg()) { + Local new_local = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(new_local); + + method.Body.Instructions.Insert(i - 1, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i, OpCodes.Stloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 1, OpCodes.Ldloc_S.ToInstruction(new_local)); + method.Body.Instructions.Insert(i + 2, OpCodes.Ldc_I4.ToInstruction(random.NextInt32())); + method.Body.Instructions.Insert(i + 3, OpCodes.Ldarg_0.ToInstruction()); + method.Body.Instructions.Insert(i + 4, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 6, OpCodes.Nop.ToInstruction()); + method.Body.Instructions.Insert(i + 3, new Instruction(OpCodes.Beq_S, method.Body.Instructions[i + 4])); + method.Body.Instructions.Insert(i + 5, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 8])); + method.Body.Instructions.Insert(i + 8, new Instruction(OpCodes.Br_S, method.Body.Instructions[i + 9])); + } + } + } + } + } + } + } +} diff --git a/Additions/OpCodeProt/Protection/MultiplyPhase.cs b/Additions/OpCodeProt/Protection/MultiplyPhase.cs new file mode 100644 index 000000000..a33463ad9 --- /dev/null +++ b/Additions/OpCodeProt/Protection/MultiplyPhase.cs @@ -0,0 +1,72 @@ +using Confuser.Core; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections.OpCodeProt { + public class MultiplyPhase : ProtectionPhase { + public MultiplyPhase(OpCodeProtection parent) : base(parent) { } + + public override ProtectionTargets Targets => ProtectionTargets.Methods; + + public override string Name => Resources.MultiplyPhase_Name; + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { + foreach(MethodDef method in parameters.Targets.OfType()) { + if (method.FullName.Contains("My.")) continue; + if (method.IsConstructor) continue; + if (!method.HasBody) continue; + for (int index = 0; index < method.Body.Instructions.Count; index++) { + if (method.Body.Instructions[index].OpCode == OpCodes.Mul) { + if (method.Body.Instructions[index - 1].IsLdcI4() && method.Body.Instructions[index - 2].IsLdcI4()) { + var wl = method.Body.Instructions[index - 2].GetLdcI4Value(); + + var val = method.Body.Instructions[index - 1].GetLdcI4Value(); + if (val >= 3) { + Local lcl = new Local(method.Module.CorLibTypes.Int32); + method.Body.Variables.Add(lcl); + + method.Body.Instructions.Insert(0, new Instruction(OpCodes.Stloc, lcl)); + method.Body.Instructions.Insert(0, new Instruction(OpCodes.Ldc_I4, wl)); + index += 2; + + method.Body.Instructions[index - 2].OpCode = OpCodes.Ldloc; + method.Body.Instructions[index - 2].Operand = lcl; + + //now we have lcl * val + method.Body.Instructions[index - 1].OpCode = OpCodes.Nop; + method.Body.Instructions[index].OpCode = OpCodes.Nop; + + int count = 0; + int curval = val; + while (curval > 0) { + // check for set bit and left + // shift n, count times + if ((curval & 1) == 1) { + if (count != 0) { + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Ldloc, lcl)); + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Ldc_I4, count)); + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Shl)); + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Add)); + } + } + count++; + curval = curval >> 1; + } + if ((val & 1) == 0) { + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Ldloc, lcl)); + method.Body.Instructions.Insert(++index, new Instruction(OpCodes.Sub)); + } + } + } + } + } + } + } + } +} diff --git a/Additions/OpCodeProt/Protection/OpCodeProtection.cs b/Additions/OpCodeProt/Protection/OpCodeProtection.cs new file mode 100644 index 000000000..0bb09cbb6 --- /dev/null +++ b/Additions/OpCodeProt/Protection/OpCodeProtection.cs @@ -0,0 +1,34 @@ +using Confuser.Core; +using Confuser.Protections.OpCodeProt; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ConfuserEx_Additions.Properties; + +namespace Confuser.Protections { + [AfterProtection("Ki.ControlFlow")] + public class OpCodeProtection : Protection { + public override ProtectionPreset Preset => ProtectionPreset.Aggressive; + + public override string Name => Resources.OpCodeProtection_Name; + + public override string Description => Resources.OpCodeProtection_Description; + + public string Author => "Confuser"; + + public override string Id => "opcode prot"; + + public override string FullId => "Confuser.OpCode"; + + protected override void Initialize(ConfuserContext context) { } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new LdfldPhase(this)); + pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new CallvirtPhase(this)); + pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new CtorCallProtection(this)); + pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new MultiplyPhase(this)); + } + } +} diff --git a/Additions/Properties/Resources.Designer.cs b/Additions/Properties/Resources.Designer.cs new file mode 100644 index 000000000..8069750b8 --- /dev/null +++ b/Additions/Properties/Resources.Designer.cs @@ -0,0 +1,567 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace ConfuserEx_Additions.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConfuserEx_Additions.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 Anti De4Dot 的本地化字符串。 + /// + internal static string AntiDe4DotPhase_Name { + get { + return ResourceManager.GetString("AntiDe4DotPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Prevents usage of De4Dot. 的本地化字符串。 + /// + internal static string AntiDe4DotProtection_Description { + get { + return ResourceManager.GetString("AntiDe4DotProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Anti De4Dot Protection 的本地化字符串。 + /// + internal static string AntiDe4DotProtection_Name { + get { + return ResourceManager.GetString("AntiDe4DotProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Anti-dnspy injection 的本地化字符串。 + /// + internal static string AntiDnSpyPhase_Name { + get { + return ResourceManager.GetString("AntiDnSpyPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection prevents dnspy. 的本地化字符串。 + /// + internal static string AntiDnSpyProtection_Description { + get { + return ResourceManager.GetString("AntiDnSpyProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Anti DnSpy Protection 的本地化字符串。 + /// + internal static string AntiDnSpyProtection_Name { + get { + return ResourceManager.GetString("AntiDnSpyProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Anti Dump Injection 的本地化字符串。 + /// + internal static string AntiDumpPhase_Name { + get { + return ResourceManager.GetString("AntiDumpPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection prevents memory dumping. 的本地化字符串。 + /// + internal static string AntiDumpProtection_Description { + get { + return ResourceManager.GetString("AntiDumpProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Anti Dump Protection 的本地化字符串。 + /// + internal static string AntiDumpProtection_Name { + get { + return ResourceManager.GetString("AntiDumpProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Anti VM Injection 的本地化字符串。 + /// + internal static string AntiVMPhase_Name { + get { + return ResourceManager.GetString("AntiVMPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection prevents the assembly from being run on a VM. 的本地化字符串。 + /// + internal static string AntiVMProtection_Description { + get { + return ResourceManager.GetString("AntiVMProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Anti Virtual Machine Protection 的本地化字符串。 + /// + internal static string AntiVMProtection_Name { + get { + return ResourceManager.GetString("AntiVMProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 ProtectedBy attribute removal 的本地化字符串。 + /// + internal static string AntiWatermarkPhase_Name { + get { + return ResourceManager.GetString("AntiWatermarkPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Removes the ProtectedBy watermark to prevent Protector detection. 的本地化字符串。 + /// + internal static string AntiWatermarkProtection_Description { + get { + return ResourceManager.GetString("AntiWatermarkProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Anti Watermark 的本地化字符串。 + /// + internal static string AntiWatermarkProtection_Name { + get { + return ResourceManager.GetString("AntiWatermarkProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Callvirt Protection 的本地化字符串。 + /// + internal static string CallvirtPhase_Name { + get { + return ResourceManager.GetString("CallvirtPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection encodes and compresses constants in the code. 的本地化字符串。 + /// + internal static string ConstantProtection_Description { + get { + return ResourceManager.GetString("ConstantProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Constants Protection 的本地化字符串。 + /// + internal static string ConstantProtection_Name { + get { + return ResourceManager.GetString("ConstantProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Control flow mangling 的本地化字符串。 + /// + internal static string ControlFlowPhase_Name { + get { + return ResourceManager.GetString("ControlFlowPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Failed to calcuate maxstack. 的本地化字符串。 + /// + internal static string ControlFlowPhase_ProcessMethod_Failed { + get { + return ResourceManager.GetString("ControlFlowPhase_ProcessMethod_Failed", resourceCulture); + } + } + + /// + /// 查找类似 This protection mangles the code in the methods so that decompilers cannot decompile the methods. 的本地化字符串。 + /// + internal static string ControlFlowProtection_Description { + get { + return ResourceManager.GetString("ControlFlowProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Control Flow Protection 的本地化字符串。 + /// + internal static string ControlFlowProtection_Name { + get { + return ResourceManager.GetString("ControlFlowProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Ctor Call Protection 的本地化字符串。 + /// + internal static string CtorCallProtection_Name { + get { + return ResourceManager.GetString("CtorCallProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Constants encoding 的本地化字符串。 + /// + internal static string EncodePhase_Name { + get { + return ResourceManager.GetString("EncodePhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection flood the module.cctor. 的本地化字符串。 + /// + internal static string EraseHeadersProtection_Description { + get { + return ResourceManager.GetString("EraseHeadersProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 erase headers Protection 的本地化字符串。 + /// + internal static string EraseHeadersProtection_Name { + get { + return ResourceManager.GetString("EraseHeadersProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Erasing Headers 的本地化字符串。 + /// + internal static string ErasePhase_Name { + get { + return ResourceManager.GetString("ErasePhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Added attribute 的本地化字符串。 + /// + internal static string FakeObfuscatorAttributesPhase_InjectType_Debug { + get { + return ResourceManager.GetString("FakeObfuscatorAttributesPhase_InjectType_Debug", resourceCulture); + } + } + + /// + /// 查找类似 Fake obfuscator attribute addition 的本地化字符串。 + /// + internal static string FakeObfuscatorAttributesPhase_Name { + get { + return ResourceManager.GetString("FakeObfuscatorAttributesPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Confuses obfuscators like de4dot by adding types typical to other obfuscators. 的本地化字符串。 + /// + internal static string FakeObfuscatorProtection_Description { + get { + return ResourceManager.GetString("FakeObfuscatorProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Fake Obfuscator Protection 的本地化字符串。 + /// + internal static string FakeObfuscatorProtection_Name { + get { + return ResourceManager.GetString("FakeObfuscatorProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Added type 的本地化字符串。 + /// + internal static string FakeObfuscatorTypesPhase_InjectType_Debug { + get { + return ResourceManager.GetString("FakeObfuscatorTypesPhase_InjectType_Debug", resourceCulture); + } + } + + /// + /// 查找类似 Fake obfuscator type addition 的本地化字符串。 + /// + internal static string FakeObfuscatorTypesPhase_Name { + get { + return ResourceManager.GetString("FakeObfuscatorTypesPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Hash Phase 的本地化字符串。 + /// + internal static string HashPhase_Name { + get { + return ResourceManager.GetString("HashPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Hide Calls Injection 的本地化字符串。 + /// + internal static string HideCallsPhase_Name { + get { + return ResourceManager.GetString("HideCallsPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection crash .cctor. 的本地化字符串。 + /// + internal static string HideCallsProtection_Description { + get { + return ResourceManager.GetString("HideCallsProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Hide Calls Protection 的本地化字符串。 + /// + internal static string HideCallsProtection_Name { + get { + return ResourceManager.GetString("HideCallsProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Constant encryption helpers injection 的本地化字符串。 + /// + internal static string InjectPhase_Name { + get { + return ResourceManager.GetString("InjectPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection hashs the module to preventing file modifications. 的本地化字符串。 + /// + internal static string IntegrityChecker_Description { + get { + return ResourceManager.GetString("IntegrityChecker_Description", resourceCulture); + } + } + + /// + /// 查找类似 Integrity Protection 的本地化字符串。 + /// + internal static string IntegrityChecker_Name { + get { + return ResourceManager.GetString("IntegrityChecker_Name", resourceCulture); + } + } + + /// + /// 查找类似 MD5 Hash Check Injection 的本地化字符串。 + /// + internal static string IntegrityPhase_Name { + get { + return ResourceManager.GetString("IntegrityPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Encrypting method section... 的本地化字符串。 + /// + internal static string JITMode_OnWriterEvent_Encrypting_method_section { + get { + return ResourceManager.GetString("JITMode_OnWriterEvent_Encrypting_method_section", resourceCulture); + } + } + + /// + /// 查找类似 Extracting method bodies... 的本地化字符串。 + /// + internal static string JITMode_OnWriterEvent_Extracting_method_bodies { + get { + return ResourceManager.GetString("JITMode_OnWriterEvent_Extracting_method_bodies", resourceCulture); + } + } + + /// + /// 查找类似 Ldfld Protection 的本地化字符串。 + /// + internal static string LdfldPhase_Name { + get { + return ResourceManager.GetString("LdfldPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Local-to-field executing 的本地化字符串。 + /// + internal static string localtofieldphase_Name { + get { + return ResourceManager.GetString("localtofieldphase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection marks the module with a attribute that discourage ILDasm from disassembling it. 的本地化字符串。 + /// + internal static string LocaltoFieldProtection_Description { + get { + return ResourceManager.GetString("LocaltoFieldProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 local to field Protection 的本地化字符串。 + /// + internal static string LocaltoFieldProtection_Name { + get { + return ResourceManager.GetString("LocaltoFieldProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Multiply Protection 的本地化字符串。 + /// + internal static string MultiplyPhase_Name { + get { + return ResourceManager.GetString("MultiplyPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Mutating Constants 的本地化字符串。 + /// + internal static string MutateConstantsPhase_Name { + get { + return ResourceManager.GetString("MutateConstantsPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection mutate Contants with sizeofs. 的本地化字符串。 + /// + internal static string MutateConstantsProtection_Description { + get { + return ResourceManager.GetString("MutateConstantsProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 Mutate Constants 的本地化字符串。 + /// + internal static string MutateConstantsProtection_Name { + get { + return ResourceManager.GetString("MutateConstantsProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 Protects OpCodes such as Ldlfd. 的本地化字符串。 + /// + internal static string OpCodeProtection_Description { + get { + return ResourceManager.GetString("OpCodeProtection_Description", resourceCulture); + } + } + + /// + /// 查找类似 OpCode Protection 的本地化字符串。 + /// + internal static string OpCodeProtection_Name { + get { + return ResourceManager.GetString("OpCodeProtection_Name", resourceCulture); + } + } + + /// + /// 查找类似 This optimization remove unnecessary metadata. 的本地化字符串。 + /// + internal static string ReduceMetadataOptimization_Description { + get { + return ResourceManager.GetString("ReduceMetadataOptimization_Description", resourceCulture); + } + } + + /// + /// 查找类似 Reduce Metadata Confusion 的本地化字符串。 + /// + internal static string ReduceMetadataOptimization_Name { + get { + return ResourceManager.GetString("ReduceMetadataOptimization_Name", resourceCulture); + } + } + + /// + /// 查找类似 Reduce Metadata Confusion 的本地化字符串。 + /// + internal static string ReduceMetadataOptimizationPhase_Name { + get { + return ResourceManager.GetString("ReduceMetadataOptimizationPhase_Name", resourceCulture); + } + } + } +} diff --git a/Additions/Properties/Resources.resx b/Additions/Properties/Resources.resx new file mode 100644 index 000000000..40375163a --- /dev/null +++ b/Additions/Properties/Resources.resx @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Anti De4Dot Protection + + + Prevents usage of De4Dot. + + + Anti De4Dot + + + Anti DnSpy Protection + + + This protection prevents dnspy. + + + Anti-dnspy injection + + + Anti Dump Protection + + + This protection prevents memory dumping. + + + Anti Dump Injection + + + Anti Virtual Machine Protection + + + This protection prevents the assembly from being run on a VM. + + + Anti VM Injection + + + Anti Watermark + + + Removes the ProtectedBy watermark to prevent Protector detection. + + + ProtectedBy attribute removal + + + Constants Protection + + + This protection encodes and compresses constants in the code. + + + Constants encoding + + + Constant encryption helpers injection + + + Control flow mangling + + + Failed to calcuate maxstack. + + + Control Flow Protection + + + This protection mangles the code in the methods so that decompilers cannot decompile the methods. + + + This protection flood the module.cctor. + + + erase headers Protection + + + Erasing Headers + + + Fake obfuscator attribute addition + + + Added attribute + + + Fake Obfuscator Protection + + + Confuses obfuscators like de4dot by adding types typical to other obfuscators. + + + Fake obfuscator type addition + + + Added type + + + Hide Calls Protection + + + This protection crash .cctor. + + + Hide Calls Injection + + + Integrity Protection + + + This protection hashs the module to preventing file modifications. + + + Hash Phase + + + Extracting method bodies... + + + Encrypting method section... + + + local to field Protection + + + This protection marks the module with a attribute that discourage ILDasm from disassembling it. + + + Local-to-field executing + + + Mutate Constants + + + This protection mutate Contants with sizeofs. + + + Mutating Constants + + + Callvirt Protection + + + Ctor Call Protection + + + Ldfld Protection + + + Multiply Protection + + + OpCode Protection + + + Protects OpCodes such as Ldlfd. + + + Reduce Metadata Confusion + + + This optimization remove unnecessary metadata. + + + Reduce Metadata Confusion + + + MD5 Hash Check Injection + + \ No newline at end of file diff --git a/Additions/Properties/Resources.zh-Hans.resx b/Additions/Properties/Resources.zh-Hans.resx new file mode 100644 index 000000000..e5278065d --- /dev/null +++ b/Additions/Properties/Resources.zh-Hans.resx @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 防止De4Dot解密(插件) + + + 禁止使用De4Dot。 + + + 反De4Dot(插件) + + + 反DnSpy防护(插件) + + + 此保护可防止dnspy。 + + + DnSpy注入 + + + 内存转储保护(插件) + + + 此保护可防止内存转储。 + + + 防止内存转储注入 + + + 反虚拟机保护(插件) + + + 此保护可防止程序集在VM上运行。 + + + 反虚拟机注入 + + + 反水印(插件) + + + 删除ConfusedBy水印以防止检测到混淆器。 + + + 移除ConfusedBy水印标志 + + + 常量保护(插件) + + + 此保护对代码中的常数进行编码和压缩。 + + + 常量编码 + + + 常量加密注入 + + + 控制流处理 + + + 无法计算maxstack。 + + + 流程控制保护(插件) + + + 这种保护会破坏方法中的代码,以便反编译器无法反编译方法。 + + + 这种保护会清除module.cctor。 + + + 清除PE标头保护(插件) + + + 清除PE标头 + + + 伪造混淆器 + + + 新增特性 + + + 伪造混淆器保护(插件) + + + 通过添加其他混淆器的典型类型来迷惑反混淆器(如de4dot)。 + + + 伪造混淆器类型 + + + 新增类型 + + + 隐藏构造函数保护(插件) + + + 此保护崩溃.cctor。 + + + 隐藏构造函数注入 + + + 完整性保护(插件) + + + 这种保护会对模块进行哈希处理,以防止文件被修改。 + + + MD5哈希阶段 + + + 提取方法主体... + + + 加密方法部分... + + + 本地到现场保护(插件) + + + 此保护使用阻止ILDasm反汇编它的属性标记模块。 + + + Local-to-field 执行 + + + 变异常数(插件) + + + 此保护使用sizeofs突变了Contant。 + + + 变异常数 + + + Callvirt保护 + + + 构造函数保护(插件) + + + Ldfld保护 + + + 多重保护 + + + OpCode 保护(插件) + + + 保护OpCode操作码,例如Ldlfd。 + + + 减少元数据混淆(插件) + + + 此优化删除了不必要的元数据,例如枚举、事件定义等。 + + + 减少元数据混淆 + + + MD5哈希检查注入 + + diff --git a/Additions/Reduce Metadata Optimization/Function.txt b/Additions/Reduce Metadata Optimization/Function.txt new file mode 100644 index 000000000..9a1507cb0 --- /dev/null +++ b/Additions/Reduce Metadata Optimization/Function.txt @@ -0,0 +1 @@ +Reduces the size of assembly by removing unnecessary metadata such as parameter names, duplicate literal strings, etc. \ No newline at end of file diff --git a/Additions/Reduce Metadata Optimization/Protection/ReduceMetadataOptimization.cs b/Additions/Reduce Metadata Optimization/Protection/ReduceMetadataOptimization.cs new file mode 100644 index 000000000..d83e3422d --- /dev/null +++ b/Additions/Reduce Metadata Optimization/Protection/ReduceMetadataOptimization.cs @@ -0,0 +1,140 @@ +using Confuser.Core; +using ConfuserEx_Additions.Properties; +using dnlib.DotNet; + +namespace Confuser.Protections +{ + [BeforeProtection("Ki.ControlFlow")] + + internal class ReduceMetadataOptimization : Protection + { + public const string _Id = "Reduce MD"; + + public const string _FullId = "Ki.ReduceMetadata"; + + public override string Name + { + get + { + return Resources.ReduceMetadataOptimization_Name; + } + } + + public override string Description + { + get + { + return Resources.ReduceMetadataOptimization_Description; + } + } + + public override string Id + { + get + { + return _Id; + } + } + + public override string FullId + { + get + { + return _FullId; + } + } + + public override ProtectionPreset Preset + { + get + { + return ProtectionPreset.Maximum; + } + } + + protected override void Initialize(ConfuserContext context) + { + } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) + { + pipeline.InsertPreStage(PipelineStage.ProcessModule, new ReduceMetadataOptimizationPhase(this)); + } + + private class ReduceMetadataOptimizationPhase : ProtectionPhase + { + public ReduceMetadataOptimizationPhase(ReduceMetadataOptimization parent) : base(parent) + { + // Null + } + + public override ProtectionTargets Targets + { + get + { + return ProtectionTargets.Methods; + } + } + + public override string Name + { + get + { + return Resources.ReduceMetadataOptimizationPhase_Name; + } + } + + protected override void Execute(ConfuserContext context, ProtectionParameters parameters) + { + IMemberDef memberDef = parameters.Targets as IMemberDef; + + TypeDef typeDef; + + if ((typeDef = (memberDef as TypeDef)) != null && !this.IsTypePublic(typeDef)) + { + if (typeDef.IsEnum) + { + int num = 0; + while (typeDef.Fields.Count != 1) + { + if (typeDef.Fields[num].Name != "value__") + { + typeDef.Fields.RemoveAt(num); + } + else + { + num++; + } + } + return; + } + } + else if (memberDef is EventDef) + { + if (memberDef.DeclaringType != null) + { + memberDef.DeclaringType.Events.Remove(memberDef as EventDef); + return; + } + } + else if (memberDef is PropertyDef && memberDef.DeclaringType != null) + { + memberDef.DeclaringType.Properties.Remove(memberDef as PropertyDef); + } + } + + private bool IsTypePublic(TypeDef type) + { + while (type.IsPublic || type.IsNestedFamily || type.IsNestedFamilyAndAssembly || type.IsNestedFamilyOrAssembly || type.IsNestedPublic || type.IsPublic) + { + type = type.DeclaringType; + if (type == null) + { + return true; + } + } + return false; + } + } + } +} diff --git a/Confuser.CLI/Confuser.CLI.csproj b/Confuser.CLI/Confuser.CLI.csproj index 82743f158..c334f9720 100644 --- a/Confuser.CLI/Confuser.CLI.csproj +++ b/Confuser.CLI/Confuser.CLI.csproj @@ -4,7 +4,7 @@ Exe - net461 + net462 true ..\ConfuserEx.snk @@ -25,5 +25,11 @@ - + + + + + + + \ No newline at end of file diff --git a/Confuser.CLI/Program.cs b/Confuser.CLI/Program.cs index 2586fff31..a98a64d1e 100644 --- a/Confuser.CLI/Program.cs +++ b/Confuser.CLI/Program.cs @@ -61,7 +61,7 @@ static int Main(string[] args) { var xmlDoc = new XmlDocument(); xmlDoc.Load(files[0]); proj.Load(xmlDoc); - proj.BaseDirectory = Path.Combine(Path.GetDirectoryName(files[0]), proj.BaseDirectory); + proj.Load(xmlDoc, Path.GetDirectoryName(files[0])); } catch (Exception ex) { WriteLineWithColor(ConsoleColor.Red, "Failed to load project:"); diff --git a/Confuser.Core/Confuser.Core.csproj b/Confuser.Core/Confuser.Core.csproj index 0d7acf713..a8de94bf0 100644 --- a/Confuser.Core/Confuser.Core.csproj +++ b/Confuser.Core/Confuser.Core.csproj @@ -4,7 +4,7 @@ - net461;netstandard2.0 + net462;netstandard2.0 true ..\ConfuserEx.snk @@ -15,10 +15,11 @@ - + + @@ -27,6 +28,21 @@ + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + diff --git a/Confuser.Core/ConfuserEngine.cs b/Confuser.Core/ConfuserEngine.cs index 519f85851..2173ff6a8 100644 --- a/Confuser.Core/ConfuserEngine.cs +++ b/Confuser.Core/ConfuserEngine.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Confuser.Core.Project; +using Confuser.Core.Properties; using Confuser.Core.Services; using dnlib.DotNet; using dnlib.DotNet.Emit; @@ -104,19 +105,19 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) Marker marker = parameters.GetMarker(); // 2. Discover plugins - context.Logger.Debug("Discovering plugins..."); + context.Logger.Debug(Resources.ConfuserEngine_RunInternal_Discovering_plugins); IList prots; IList packers; IList components; parameters.GetPluginDiscovery().GetPlugins(context, out prots, out packers, out components); - context.Logger.InfoFormat("Discovered {0} protections, {1} packers.", prots.Count, packers.Count); + context.Logger.InfoFormat(Resources.ConfuserEngine_RunInternal_Discovered__protections, prots.Count, packers.Count); context.CheckCancellation(); // 3. Resolve dependency - context.Logger.Debug("Resolving component dependency..."); + context.Logger.Debug(Resources.ConfuserEngine_RunInternal_Resolving_component_dependency); try { var resolver = new DependencyResolver(prots); prots = resolver.SortDependency(); @@ -135,7 +136,7 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) context.CheckCancellation(); // 4. Load modules - context.Logger.Info("Loading input modules..."); + context.Logger.Info(Resources.ConfuserEngine_RunInternal_Loading_input_modules); marker.Initalize(prots, packers); MarkerResult markings = marker.MarkProject(context.Project, context); context.Modules = new ModuleSorter(markings.Modules).Sort().ToList().AsReadOnly(); @@ -150,13 +151,13 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) context.CheckCancellation(); // 5. Initialize components - context.Logger.Info("Initializing..."); + context.Logger.Info(Resources.ConfuserEngine_RunInternal_Initializing); foreach (ConfuserComponent comp in components) { try { comp.Initialize(context); } catch (Exception ex) { - context.Logger.ErrorException("Error occured during initialization of '" + comp.Name + "'.", ex); + context.Logger.ErrorException( string.Format(Resources.ConfuserEngine_RunInternal_Error_occured_during_initialization, comp.Name), ex); throw new ConfuserException(ex); } context.CheckCancellation(); @@ -165,7 +166,7 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) context.CheckCancellation(); // 6. Build pipeline - context.Logger.Debug("Building pipeline..."); + context.Logger.Debug(Resources.ConfuserEngine_RunInternal_Building_pipeline); var pipeline = new ProtectionPipeline(); context.Pipeline = pipeline; foreach (ConfuserComponent comp in components) { @@ -195,13 +196,13 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token) context.Logger.ErrorException("An IO error occurred, check if all input/output locations are readable/writable.", ex); } catch (OperationCanceledException) { - context.Logger.Error("Operation cancelled."); + context.Logger.Error(Resources.ConfuserEngine_RunInternal_Operation_cancelled); } catch (ConfuserException) { // Exception is already handled/logged, so just ignore and report failure } catch (Exception ex) { - context.Logger.ErrorException("Unknown error occurred.", ex); + context.Logger.ErrorException(Resources.ConfuserEngine_RunInternal_Unknown_error_occurred, ex); } finally { if (context.Resolver != null) @@ -256,30 +257,26 @@ static void RunPipeline(ProtectionPipeline pipeline, ConfuserContext context) { pipeline.ExecuteStage(PipelineStage.SaveModules, SaveModules, () => getAllDefs(), context); if (!context.PackerInitiated) - context.Logger.Info("Done."); + context.Logger.Info(Resources.ConfuserEngine_RunPipeline_Done); } static void Inspection(ConfuserContext context) { - context.Logger.Info("Resolving dependencies..."); + context.Logger.Info(Resources.ConfuserEngine_Inspection_Resolving_dependencies); foreach (var dependency in context.Modules - .SelectMany(module => module.GetAssemblyRefs().Select(asmRef => Tuple.Create(asmRef, module)))) { - try { - context.Resolver.ResolveThrow(dependency.Item1, dependency.Item2); - } - catch (AssemblyResolveException ex) { - context.Logger.ErrorException("Failed to resolve dependency of '" + dependency.Item2.Name + "'.", ex); - throw new ConfuserException(ex); - } + .SelectMany(module => module.GetAssemblyRefs().Select(asmRef => (asmRef, module)))) { + var assembly = context.Resolver.Resolve(dependency.asmRef, dependency.module); + if (assembly is null) + context.Logger.Warn(string.Format(Resources.ConfuserEngine_Inspection_Failed_to_resolve_dependency, dependency.module.Name, dependency.asmRef.Name)); } - context.Logger.Debug("Checking Strong Name..."); + context.Logger.Debug(Resources.ConfuserEngine_Inspection_Checking_Strong_Name); foreach (var module in context.Modules) { CheckStrongName(context, module); } var marker = context.Registry.GetService(); - context.Logger.Debug("Creating global .cctors..."); + context.Logger.Debug(Resources.ConfuserEngine_Inspection_Creating_global__cctors); foreach (ModuleDefMD module in context.Modules) { TypeDef modType = module.GlobalType; if (modType == null) { @@ -307,12 +304,12 @@ static void CheckStrongName(ConfuserContext context, ModuleDef module) { bool isKeyProvided = snKey != null || (snDelaySign && snPubKeyBytes != null); if (!isKeyProvided && moduleIsSignedOrDelayedSigned) - context.Logger.WarnFormat("[{0}] SN Key or SN public Key is not provided for a signed module, the output may not be working.", module.Name); + context.Logger.WarnFormat(Resources.ConfuserEngine_CheckStrongName1, module.Name); else if (isKeyProvided && !moduleIsSignedOrDelayedSigned) - context.Logger.WarnFormat("[{0}] SN Key or SN public Key is provided for an unsigned module, the output may not be working.", module.Name); + context.Logger.WarnFormat(Resources.ConfuserEngine_CheckStrongName2, module.Name); else if (snPubKeyBytes != null && moduleIsSignedOrDelayedSigned && !module.Assembly.PublicKey.Data.SequenceEqual(snPubKeyBytes)) - context.Logger.WarnFormat("[{0}] Provided SN public Key and signed module's public key do not match, the output may not be working.", + context.Logger.WarnFormat(Resources.ConfuserEngine_CheckStrongName3, module.Name); } @@ -329,16 +326,18 @@ static void CopyPEHeaders(PEHeadersOptions writerOptions, ModuleDefMD module) { } static void BeginModule(ConfuserContext context) { - context.Logger.InfoFormat("Processing module '{0}'...", context.CurrentModule.Name); + context.Logger.InfoFormat(Resources.ConfuserEngine_BeginModule_Processing_module, context.CurrentModule.Name); context.CurrentModuleWriterOptions = new ModuleWriterOptions(context.CurrentModule); + context.Logger.InfoFormat(Resources.ConfuserEngine_BeginModule_Processing_PEHeaders); CopyPEHeaders(context.CurrentModuleWriterOptions.PEHeadersOptions, context.CurrentModule); if (!context.CurrentModule.IsILOnly || context.CurrentModule.VTableFixups != null) context.RequestNative(true); - var snKey = context.Annotations.Get(context.CurrentModule, Marker.SNKey); - var snPubKey = context.Annotations.Get(context.CurrentModule, Marker.SNPubKey); + context.Logger.InfoFormat(Resources.ConfuserEngine_BeginModule_Processing_StrongName); + var snKey = context.Annotations.Get(context.CurrentModule, Marker.SNKey); + var snPubKey = context.Annotations.Get(context.CurrentModule, Marker.SNPubKey); var snSigKey = context.Annotations.Get(context.CurrentModule, Marker.SNSigKey); var snSigPubKey = context.Annotations.Get(context.CurrentModule, Marker.SNSigPubKey); @@ -348,14 +347,15 @@ static void BeginModule(ConfuserContext context) { if (snKey != null && snPubKey != null && snSigKey != null && snSigPubKey != null) context.CurrentModuleWriterOptions.InitializeEnhancedStrongNameSigning(context.CurrentModule, snSigKey, snSigPubKey, snKey, snPubKey); - else if (snSigPubKey != null && snSigKey != null) - context.CurrentModuleWriterOptions.InitializeEnhancedStrongNameSigning(context.CurrentModule, snSigKey, snSigPubKey); + else if (snSigPubKey != null && snSigKey != null) + context.CurrentModuleWriterOptions.InitializeEnhancedStrongNameSigning(context.CurrentModule, snSigKey, snSigPubKey); else context.CurrentModuleWriterOptions.InitializeStrongNameSigning(context.CurrentModule, snKey); if (snDelaySig) { context.CurrentModuleWriterOptions.StrongNamePublicKey = snPubKey; context.CurrentModuleWriterOptions.StrongNameKey = null; + context.Logger.InfoFormat(Resources.ConfuserEngine_BeginModule_Processing_DelayedStrongName, context.CurrentModule.Name); } foreach (TypeDef type in context.CurrentModule.GetTypes()) @@ -398,7 +398,7 @@ static void EndModule(ConfuserContext context) { } static void WriteModule(ConfuserContext context) { - context.Logger.InfoFormat("Writing module '{0}'...", context.CurrentModule.Name); + context.Logger.InfoFormat(Resources.ConfuserEngine_WriteModule_Writing_module, context.CurrentModule.Name); MemoryStream pdb = null, output = new MemoryStream(); @@ -420,7 +420,7 @@ static void WriteModule(ConfuserContext context) { } static void Debug(ConfuserContext context) { - context.Logger.Info("Finalizing..."); + context.Logger.Info(Resources.ConfuserEngine_Debug_Finalizing); for (int i = 0; i < context.OutputModules.Count; i++) { if (context.OutputSymbols[i] == null) continue; @@ -434,7 +434,7 @@ static void Debug(ConfuserContext context) { static void Pack(ConfuserContext context) { if (context.Packer != null) { - context.Logger.Info("Packing..."); + context.Logger.Info(Resources.ConfuserEngine_Pack_Packing); context.Packer.Pack(context, new ProtectionParameters(context.Packer, context.Modules.OfType().ToList())); } } @@ -446,7 +446,7 @@ static void SaveModules(ConfuserContext context) { string dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); - context.Logger.DebugFormat("Saving to '{0}'...", path); + context.Logger.DebugFormat(Resources.ConfuserEngine_SaveModules_Saving_to, path); File.WriteAllBytes(path, context.OutputModules[i]); } } @@ -457,13 +457,13 @@ static void SaveModules(ConfuserContext context) { /// The working context. static void PrintInfo(ConfuserContext context) { if (context.PackerInitiated) { - context.Logger.Info("Protecting packer stub..."); + context.Logger.Info(Resources.ConfuserEngine_PrintInfo_Protecting_packer_stub); } else { context.Logger.InfoFormat("{0} {1}", Version, Copyright); Type mono = Type.GetType("Mono.Runtime"); - context.Logger.InfoFormat("Running on {0}, {1}, {2} bits", + context.Logger.InfoFormat(Resources.ConfuserEngine_PrintInfo_Running_on, Environment.OSVersion, mono == null ? ".NET Framework v" + Environment.Version : @@ -527,15 +527,15 @@ static void PrintEnvironmentInfo(ConfuserContext context) { context.Logger.Error("---BEGIN DEBUG INFO---"); - context.Logger.Error("Installed Framework Versions:"); + context.Logger.Error(Resources.ConfuserEngine_PrintEnvironmentInfo_Installed_Framework_Versions); foreach (string ver in GetFrameworkVersions()) { context.Logger.ErrorFormat(" {0}", ver.Trim()); } context.Logger.Error(""); if (context.Resolver != null) { - context.Logger.Error("Cached assemblies:"); - foreach (AssemblyDef asm in context.InternalResolver.GetCachedAssemblies()) { + context.Logger.Error(Resources.ConfuserEngine_PrintEnvironmentInfo_Cached_assemblies); + foreach (var asm in context.InternalResolver.GetCachedAssemblies().Where(a => !(a is null))) { if (string.IsNullOrEmpty(asm.ManifestModule.Location)) context.Logger.ErrorFormat(" {0}", asm.FullName); else diff --git a/Confuser.Core/DnlibUtils.cs b/Confuser.Core/DnlibUtils.cs index 42d0ba439..7ebe43e33 100644 --- a/Confuser.Core/DnlibUtils.cs +++ b/Confuser.Core/DnlibUtils.cs @@ -208,16 +208,14 @@ public static bool IsDelegate(this TypeDef type) { /// The type. /// The full name of base type. /// true if the specified type is inherited from a base type; otherwise, false. - public static bool InheritsFromCorlib(this TypeDef type, string baseType) { - if (type.BaseType == null) - return false; - - TypeDef bas = type; - do { - bas = bas.BaseType.ResolveTypeDefThrow(); + public static bool InheritsFromCorLib(this TypeDef type, string baseType) { + var bas = type.GetBaseType(); + while (!(bas is null) && bas.DefinitionAssembly.IsCorLib()) { if (bas.ReflectionFullName == baseType) return true; - } while (bas.BaseType != null && bas.BaseType.DefinitionAssembly.IsCorLib()); + + bas = bas.GetBaseType(); + } return false; } @@ -228,15 +226,13 @@ public static bool InheritsFromCorlib(this TypeDef type, string baseType) { /// The full name of base type. /// true if the specified type is inherited from a base type; otherwise, false. public static bool InheritsFrom(this TypeDef type, string baseType) { - if (type.BaseType == null) - return false; - - TypeDef bas = type; - do { - bas = bas.BaseType.ResolveTypeDefThrow(); + var bas = type.GetBaseType(); + while (!(bas is null)) { if (bas.ReflectionFullName == baseType) return true; - } while (bas.BaseType != null); + + bas = bas.GetBaseType(); + } return false; } @@ -248,17 +244,14 @@ public static bool InheritsFrom(this TypeDef type, string baseType) { /// true if the specified type implements the interface; otherwise, false. public static bool Implements(this TypeDef type, string fullName) { do { - foreach (InterfaceImpl iface in type.Interfaces) { - if (iface.Interface.ReflectionFullName == fullName) - return true; + if (type.Interfaces.Any(iFace => iFace.Interface.ReflectionFullName == fullName)) { + return true; } - if (type.BaseType == null) - return false; - - type = type.BaseType.ResolveTypeDefThrow(); + type = type.GetBaseType() as TypeDef; } while (type != null); - throw new UnreachableException(); + + return false; } /// diff --git a/Confuser.Core/Marker.cs b/Confuser.Core/Marker.cs index 70e8a8529..5a18d8cda 100644 --- a/Confuser.Core/Marker.cs +++ b/Confuser.Core/Marker.cs @@ -6,6 +6,7 @@ using System.Security.Cryptography.X509Certificates; using Confuser.Core.Project; using Confuser.Core.Project.Patterns; +using Confuser.Core.Properties; using dnlib.DotNet; namespace Confuser.Core { @@ -167,7 +168,7 @@ protected internal virtual MarkerResult MarkProject(ConfuserProject proj, Confus } foreach (var module in modules) { - context.Logger.InfoFormat("Loading '{0}'...", module.Item1.Path); + context.Logger.InfoFormat(Resources.Marker_MarkProject_Loading, module.Item1.Path); Rules rules = ParseRules(proj, module.Item1, context); context.Annotations.Set(module.Item2, SNKey, LoadSNKey(context, module.Item1.SNKeyPath == null ? null : Path.Combine(proj.BaseDirectory, module.Item1.SNKeyPath), module.Item1.SNKeyPassword)); diff --git a/Confuser.Core/ObfAttrMarker.cs b/Confuser.Core/ObfAttrMarker.cs index 70212f9cf..676e0d284 100644 --- a/Confuser.Core/ObfAttrMarker.cs +++ b/Confuser.Core/ObfAttrMarker.cs @@ -7,6 +7,7 @@ using System.Text.RegularExpressions; using Confuser.Core.Project; using Confuser.Core.Project.Patterns; +using Confuser.Core.Properties; using dnlib.DotNet; namespace Confuser.Core { @@ -330,7 +331,7 @@ protected internal override MarkerResult MarkProject(ConfuserProject proj, Confu } } foreach (var module in modules) { - context.Logger.InfoFormat("Loading '{0}'...", module.Item1.Path); + context.Logger.InfoFormat(Resources.ObfAttrMarker_MarkProject_Loading, module.Item1.Path); Rules rules = ParseRules(proj, module.Item1, context); MarkModule(module.Item1, module.Item2, rules, module == modules[0]); diff --git a/Confuser.Core/PluginDiscovery.cs b/Confuser.Core/PluginDiscovery.cs index f95cdc8f3..a8062c815 100644 --- a/Confuser.Core/PluginDiscovery.cs +++ b/Confuser.Core/PluginDiscovery.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Reflection; +using Confuser.Core.Properties; +using dnlib.DotNet; namespace Confuser.Core { /// @@ -11,12 +13,29 @@ public class PluginDiscovery { /// /// The default plugin discovery service. /// - internal static readonly PluginDiscovery Instance = new PluginDiscovery(); + public static readonly PluginDiscovery Instance = new PluginDiscovery(); + /// + /// default plugins dir + /// + private static string basePlugInsDir; /// /// Initializes a new instance of the class. /// - protected PluginDiscovery() { } + protected PluginDiscovery() { + basePlugInsDir = Path.Combine(AppContext.BaseDirectory, "Plugins"); + if (!Directory.Exists(basePlugInsDir)) { + Directory.CreateDirectory(basePlugInsDir); + } + } + + /// + /// get default plugins dir + /// + /// + public string GetBasePlugInsDir() { + return basePlugInsDir; + } /// /// Retrieves the available protection plugins. @@ -64,7 +83,7 @@ protected static void AddPlugins( protections.Add((Protection)Activator.CreateInstance(i)); } catch (Exception ex) { - context.Logger.ErrorException("Failed to instantiate protection '" + i.Name + "'.", ex); + context.Logger.ErrorException(string.Format(Resources.PluginDiscovery_AddPlugins_Failed_to_instantiate_protection, i.Name), ex); } } else if (typeof(Packer).IsAssignableFrom(i)) { @@ -72,7 +91,7 @@ protected static void AddPlugins( packers.Add((Packer)Activator.CreateInstance(i)); } catch (Exception ex) { - context.Logger.ErrorException("Failed to instantiate packer '" + i.Name + "'.", ex); + context.Logger.ErrorException(string.Format(Resources.PluginDiscovery_AddPlugins_Failed_to_instantiate_packer, i.Name), ex); } } else if (typeof(ConfuserComponent).IsAssignableFrom(i)) { @@ -80,7 +99,7 @@ protected static void AddPlugins( components.Add((ConfuserComponent)Activator.CreateInstance(i)); } catch (Exception ex) { - context.Logger.ErrorException("Failed to instantiate component '" + i.Name + "'.", ex); + context.Logger.ErrorException(string.Format(Resources.PluginDiscovery_AddPlugins_Failed_to_instantiate_component, i.Name), ex); } } } @@ -103,7 +122,7 @@ protected virtual void GetPluginsInternal( AddPlugins(context, protections, packers, components, protAsm); } catch (Exception ex) { - context.Logger.WarnException("Failed to load built-in protections.", ex); + context.Logger.WarnException(Resources.PluginDiscovery_GetPluginsInternal_Failed_to_load_built_in_protections, ex); } try { @@ -111,7 +130,7 @@ protected virtual void GetPluginsInternal( AddPlugins(context, protections, packers, components, renameAsm); } catch (Exception ex) { - context.Logger.WarnException("Failed to load renamer.", ex); + context.Logger.WarnException(Resources.PluginDiscovery_GetPluginsInternal_Failed_to_load_renamer, ex); } try { @@ -119,19 +138,38 @@ protected virtual void GetPluginsInternal( AddPlugins(context, protections, packers, components, renameAsm); } catch (Exception ex) { - context.Logger.WarnException("Failed to load dynamic cipher library.", ex); + context.Logger.WarnException(Resources.PluginDiscovery_GetPluginsInternal_Failed_to_load_dynamic_cipher_library, ex); } - foreach (string pluginPath in context.Project.PluginPaths) { + #region load custom plugin + plugModule.Clear(); + var paths = new List(); + if (Directory.Exists(basePlugInsDir)) { + var dlls = Directory.GetFiles(basePlugInsDir, "*.dll"); + paths.AddRange(dlls); + } + paths.AddRange(context.Project.PluginPaths); + foreach (string pluginPath in paths) { string realPath = Path.Combine(context.BaseDirectory, pluginPath); try { Assembly plugin = Assembly.LoadFile(realPath); AddPlugins(context, protections, packers, components, plugin); + plugModule.Add(ModuleDefMD.Load(realPath, new ModuleCreationOptions() { TryToLoadPdbFromDisk = true })); } catch (Exception ex) { - context.Logger.WarnException("Failed to load plugin '" + pluginPath + "'.", ex); + context.Logger.WarnException(string.Format(Resources.PluginDiscovery_GetPluginsInternal_Failed_to_load_plugin, pluginPath), ex); } } + #endregion + } + + private List plugModule = new List(); + /// + /// 获取插件模块 + /// + /// + public List GetPluginModuleDef() { + return plugModule; } } } diff --git a/Confuser.Core/Project/ConfuserProject.cs b/Confuser.Core/Project/ConfuserProject.cs index d8dc25a54..5e2ea6c7d 100644 --- a/Confuser.Core/Project/ConfuserProject.cs +++ b/Confuser.Core/Project/ConfuserProject.cs @@ -1,704 +1,739 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml; -using System.Xml.Schema; -using dnlib.DotNet; - -namespace Confuser.Core.Project { - /// - /// A module description in a Confuser project. - /// - public class ProjectModule { - /// - /// Initializes a new instance of the class. - /// - public ProjectModule() { - Rules = new List(); - } - - /// - /// Gets the path to the module. - /// - public string Path { get; set; } - - /// - /// Indicates whether this module is external and should not be obfuscated. - /// - public bool IsExternal { get; set; } - - /// - /// Gets or sets the path to the strong name private key for signing. - /// - /// The path to the strong name private key, or null if not necessary. - /// This is also used as the identity key when doing strong name signing. - public string SNKeyPath { get; set; } - - /// - /// Gets or sets the password of the strong name private key. - /// - /// The password of the strong name private key, or null if not necessary. - /// This is the password for the key in +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using System.Xml.Schema; +using dnlib.DotNet; + +namespace Confuser.Core.Project { + /// + /// A module description in a Confuser project. + /// + public class ProjectModule { + /// + /// Initializes a new instance of the class. + /// + public ProjectModule() { + Rules = new List(); + } + + /// + /// Gets the path to the module. + /// + public string Path { get; set; } + + /// + /// Indicates whether this module is external and should not be obfuscated. + /// + public bool IsExternal { get; set; } + + /// + /// Gets or sets the path to the strong name private key for signing. + /// + /// The path to the strong name private key, or null if not necessary. + /// This is also used as the identity key when doing strong name signing. + public string SNKeyPath { get; set; } + + /// + /// Gets or sets the password of the strong name private key. + /// + /// The password of the strong name private key, or null if not necessary. + /// This is the password for the key in public string SNKeyPassword { get; set; } - /// - /// Gets or sets if the generated assembly should be delayed signed. - /// + /// + /// Gets or sets if the generated assembly should be delayed signed. + /// public bool SNDelaySig { get; set; } - /// - /// Gets or sets the path to the strong name public key for signing. - /// - /// The path to the strong name public key, or null if not necessary. - /// - /// This is only used in enhanced strong name signing and is the public part of the identity key. - /// The private part of the key - /// + /// + /// Gets or sets the path to the strong name public key for signing. + /// + /// The path to the strong name public key, or null if not necessary. + /// + /// This is only used in enhanced strong name signing and is the public part of the identity key. + /// The private part of the key + /// public string SNPubKeyPath { get; set; } - /// - /// Gets or sets the path to the strong name private key used for enhanced signing. - /// - /// The path to the strong name private key used for enhanced signing, or null if not necessary. - public string SNSigKeyPath { get; set; } - - /// - /// Gets or sets the password of the strong name private key. - /// - /// The password of the strong name private key, or null if not necessary. + /// + /// Gets or sets the path to the strong name private key used for enhanced signing. + /// + /// The path to the strong name private key used for enhanced signing, or null if not necessary. + public string SNSigKeyPath { get; set; } + + /// + /// Gets or sets the password of the strong name private key. + /// + /// The password of the strong name private key, or null if not necessary. public string SNSigKeyPassword { get; set; } - /// - /// Gets or sets the path to the strong name public key used for enhanced signing. - /// - /// The path to the strong name public key used for enhanced signing, or null if not necessary. + /// + /// Gets or sets the path to the strong name public key used for enhanced signing. + /// + /// The path to the strong name public key used for enhanced signing, or null if not necessary. public string SNPubSigKeyPath { get; set; } - /// - /// Gets a list of protection rules applies to the module. - /// - /// A list of protection rules. - public IList Rules { get; private set; } - - /// - /// Resolves the module from the path. - /// - /// - /// The base path for the relative module path, - /// or null if the module path is absolute or relative to current directory. - /// - /// The resolved module's context. - /// The resolved module. - public ModuleDefMD Resolve(string basePath, ModuleContext context = null) { - if (basePath == null) - return ModuleDefMD.Load(Path, context); - return ModuleDefMD.Load(System.IO.Path.Combine(basePath, Path), context); - } - - /// - /// Read the raw bytes of the module from the path. - /// - /// - /// The base path for the relative module path, - /// or null if the module path is absolute or relative to current directory. - /// - /// The loaded module. - public byte[] LoadRaw(string basePath) { - if (basePath == null) - return File.ReadAllBytes(Path); - return File.ReadAllBytes(System.IO.Path.Combine(basePath, Path)); - } - - /// - /// Saves the module description as XML element. - /// - /// The root XML document. - /// The serialized module description. - internal XmlElement Save(XmlDocument xmlDoc) { - XmlElement elem = xmlDoc.CreateElement("module", ConfuserProject.Namespace); - - XmlAttribute nameAttr = xmlDoc.CreateAttribute("path"); - nameAttr.Value = Path; - elem.Attributes.Append(nameAttr); - - if (IsExternal) { - XmlAttribute extAttr = xmlDoc.CreateAttribute("external"); - extAttr.Value = IsExternal ? "true" : "false"; - elem.Attributes.Append(extAttr); - } - if (SNKeyPath != null) { - XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snKey"); - snKeyAttr.Value = SNKeyPath; - elem.Attributes.Append(snKeyAttr); - } - if (SNKeyPassword != null) { - XmlAttribute snKeyPassAttr = xmlDoc.CreateAttribute("snKeyPass"); - snKeyPassAttr.Value = SNKeyPassword; - elem.Attributes.Append(snKeyPassAttr); + /// + /// Gets a list of protection rules applies to the module. + /// + /// A list of protection rules. + public IList Rules { get; private set; } + + /// + /// Resolves the module from the path. + /// + /// + /// The base path for the relative module path, + /// or null if the module path is absolute or relative to current directory. + /// + /// The resolved module's context. + /// The resolved module. + public ModuleDefMD Resolve(string basePath, ModuleContext context = null) { + if (basePath == null) + return ModuleDefMD.Load(Path, context); + return ModuleDefMD.Load(System.IO.Path.Combine(basePath, Path), context); + } + + /// + /// Read the raw bytes of the module from the path. + /// + /// + /// The base path for the relative module path, + /// or null if the module path is absolute or relative to current directory. + /// + /// The loaded module. + public byte[] LoadRaw(string basePath) { + if (basePath == null) + return File.ReadAllBytes(Path); + return File.ReadAllBytes(System.IO.Path.Combine(basePath, Path)); + } + + /// + /// Saves the module description as XML element. + /// + /// The root XML document. + /// The serialized module description. + internal XmlElement Save(XmlDocument xmlDoc) { + XmlElement elem = xmlDoc.CreateElement("module", ConfuserProject.Namespace); + + XmlAttribute nameAttr = xmlDoc.CreateAttribute("path"); + nameAttr.Value = Path; + elem.Attributes.Append(nameAttr); + + if (IsExternal) { + XmlAttribute extAttr = xmlDoc.CreateAttribute("external"); + extAttr.Value = IsExternal ? "true" : "false"; + elem.Attributes.Append(extAttr); + } + if (SNKeyPath != null) { + XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snKey"); + snKeyAttr.Value = SNKeyPath; + elem.Attributes.Append(snKeyAttr); + } + if (SNKeyPassword != null) { + XmlAttribute snKeyPassAttr = xmlDoc.CreateAttribute("snKeyPass"); + snKeyPassAttr.Value = SNKeyPassword; + elem.Attributes.Append(snKeyPassAttr); + } + if (SNDelaySig) { + XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snDelaySig"); + snKeyAttr.Value = SNDelaySig ? "true" : "false"; + elem.Attributes.Append(snKeyAttr); + } + if (SNPubKeyPath != null) { + XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snPubKey"); + snKeyAttr.Value = SNPubKeyPath; + elem.Attributes.Append(snKeyAttr); } - if (SNDelaySig) { - XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snDelaySig"); - snKeyAttr.Value = SNDelaySig ? "true" : "false"; - elem.Attributes.Append(snKeyAttr); + if (SNSigKeyPath != null) { + XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snSigKey"); + snKeyAttr.Value = SNSigKeyPath; + elem.Attributes.Append(snKeyAttr); } - if (SNPubKeyPath != null) { - XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snPubKey"); - snKeyAttr.Value = SNPubKeyPath; - elem.Attributes.Append(snKeyAttr); + if (SNSigKeyPassword != null) { + XmlAttribute snKeyPassAttr = xmlDoc.CreateAttribute("snSigKeyPass"); + snKeyPassAttr.Value = SNSigKeyPassword; + elem.Attributes.Append(snKeyPassAttr); } - if (SNSigKeyPath != null) { - XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snSigKey"); - snKeyAttr.Value = SNSigKeyPath; - elem.Attributes.Append(snKeyAttr); - } - if (SNSigKeyPassword != null) { - XmlAttribute snKeyPassAttr = xmlDoc.CreateAttribute("snSigKeyPass"); - snKeyPassAttr.Value = SNSigKeyPassword; - elem.Attributes.Append(snKeyPassAttr); + if (SNPubSigKeyPath != null) { + XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snPubSigKey"); + snKeyAttr.Value = SNPubSigKeyPath; + elem.Attributes.Append(snKeyAttr); } - if (SNPubSigKeyPath != null) { - XmlAttribute snKeyAttr = xmlDoc.CreateAttribute("snPubSigKey"); - snKeyAttr.Value = SNPubSigKeyPath; - elem.Attributes.Append(snKeyAttr); - } - - foreach (Rule i in Rules) - elem.AppendChild(i.Save(xmlDoc)); - - return elem; - } - - /// - /// Loads the module description from XML element. - /// - /// The serialized module description. - internal void Load(XmlElement elem) { - Path = elem.Attributes["path"].Value; - - if (elem.Attributes["external"] != null) - IsExternal = bool.Parse(elem.Attributes["external"].Value); - else - IsExternal = false; - - if (elem.Attributes["snKey"] != null) - SNKeyPath = elem.Attributes["snKey"].Value.NullIfEmpty(); - else - SNKeyPath = null; - - if (elem.Attributes["snKeyPass"] != null) - SNKeyPassword = elem.Attributes["snKeyPass"].Value.NullIfEmpty(); - else + + foreach (Rule i in Rules) + elem.AppendChild(i.Save(xmlDoc)); + + return elem; + } + + /// + /// Loads the module description from XML element. + /// + /// The serialized module description. + internal void Load(XmlElement elem) { + Path = elem.Attributes["path"].Value; + + if (elem.Attributes["external"] != null) + IsExternal = bool.Parse(elem.Attributes["external"].Value); + else + IsExternal = false; + + if (elem.Attributes["snKey"] != null) + SNKeyPath = elem.Attributes["snKey"].Value.NullIfEmpty(); + else + SNKeyPath = null; + + if (elem.Attributes["snKeyPass"] != null) + SNKeyPassword = elem.Attributes["snKeyPass"].Value.NullIfEmpty(); + else SNKeyPassword = null; bool delaySig = false; - if (elem.Attributes["snDelaySig"] != null) - bool.TryParse(elem.Attributes["snDelaySig"].Value, out delaySig); - + if (elem.Attributes["snDelaySig"] != null) + bool.TryParse(elem.Attributes["snDelaySig"].Value, out delaySig); + SNDelaySig = delaySig; - if (elem.Attributes["snPubKey"] != null) - SNPubKeyPath = elem.Attributes["snPubKey"].Value.NullIfEmpty(); - else + if (elem.Attributes["snPubKey"] != null) + SNPubKeyPath = elem.Attributes["snPubKey"].Value.NullIfEmpty(); + else SNPubKeyPath = null; - if (elem.Attributes["snSigKey"] != null) - SNSigKeyPath = elem.Attributes["snSigKey"].Value.NullIfEmpty(); - else - SNSigKeyPath = null; - - if (elem.Attributes["snSigKeyPass"] != null) - SNSigKeyPassword = elem.Attributes["snSigKeyPass"].Value.NullIfEmpty(); - else + if (elem.Attributes["snSigKey"] != null) + SNSigKeyPath = elem.Attributes["snSigKey"].Value.NullIfEmpty(); + else + SNSigKeyPath = null; + + if (elem.Attributes["snSigKeyPass"] != null) + SNSigKeyPassword = elem.Attributes["snSigKeyPass"].Value.NullIfEmpty(); + else SNSigKeyPassword = null; - if (elem.Attributes["snPubSigKey"] != null) - SNPubSigKeyPath = elem.Attributes["snPubSigKey"].Value.NullIfEmpty(); - else - SNPubSigKeyPath = null; - - Rules.Clear(); - foreach (XmlElement i in elem.ChildNodes.OfType()) { - var rule = new Rule(); - rule.Load(i); - Rules.Add(rule); - } - } - - /// - /// Returns a that represents this instance. - /// - /// A that represents this instance. - public override string ToString() { - return Path; - } - - /// - /// Clones this instance. - /// - /// A duplicated module. - public ProjectModule Clone() { - var ret = new ProjectModule(); - ret.Path = Path; - ret.IsExternal = IsExternal; + if (elem.Attributes["snPubSigKey"] != null) + SNPubSigKeyPath = elem.Attributes["snPubSigKey"].Value.NullIfEmpty(); + else + SNPubSigKeyPath = null; + + Rules.Clear(); + foreach (XmlElement i in elem.ChildNodes.OfType()) { + var rule = new Rule(); + rule.Load(i); + Rules.Add(rule); + } + } + + /// + /// Returns a that represents this instance. + /// + /// A that represents this instance. + public override string ToString() { + return Path; + } + + /// + /// Clones this instance. + /// + /// A duplicated module. + public ProjectModule Clone() { + var ret = new ProjectModule(); + ret.Path = Path; + ret.IsExternal = IsExternal; ret.SNKeyPath = SNKeyPath; ret.SNPubKeyPath = SNPubKeyPath; ret.SNDelaySig = SNDelaySig; ret.SNPubSigKeyPath = SNPubSigKeyPath; - ret.SNSigKeyPath = SNSigKeyPath; - ret.SNKeyPassword = SNKeyPassword; - ret.SNSigKeyPassword = SNSigKeyPassword; - foreach (var r in Rules) - ret.Rules.Add(r.Clone()); - return ret; - } - } - - /// - /// Indicates add or remove the protection from the active protections - /// - public enum SettingItemAction { - /// - /// Add the protection to the active protections - /// - Add, - - /// - /// Remove the protection from the active protections - /// - Remove - } - - /// - /// A setting within a rule. - /// - /// or - public class SettingItem : Dictionary { - /// - /// Initialize this setting item instance - /// - /// The protection id - /// The action to take - public SettingItem(string id = null, SettingItemAction action = SettingItemAction.Add) { - Id = id; - Action = action; - } - - /// - /// The identifier of component - /// - /// The identifier of component. - /// - public string Id { get; set; } - - /// - /// Gets or sets the action of component. - /// - /// The action of component. - public SettingItemAction Action { get; set; } - - /// - /// Saves the setting description as XML element. - /// - /// The root XML document. - /// The setting module description. - internal XmlElement Save(XmlDocument xmlDoc) { - XmlElement elem = xmlDoc.CreateElement(typeof(T) == typeof(Packer) ? "packer" : "protection", ConfuserProject.Namespace); - - XmlAttribute idAttr = xmlDoc.CreateAttribute("id"); - idAttr.Value = Id; - elem.Attributes.Append(idAttr); - - if (Action != SettingItemAction.Add) { - XmlAttribute pAttr = xmlDoc.CreateAttribute("action"); - pAttr.Value = Action.ToString().ToLower(); - elem.Attributes.Append(pAttr); - } - - foreach (var i in this) { - XmlElement arg = xmlDoc.CreateElement("argument", ConfuserProject.Namespace); - - XmlAttribute nameAttr = xmlDoc.CreateAttribute("name"); - nameAttr.Value = i.Key; - arg.Attributes.Append(nameAttr); - XmlAttribute valAttr = xmlDoc.CreateAttribute("value"); - valAttr.Value = i.Value; - arg.Attributes.Append(valAttr); - - elem.AppendChild(arg); - } - - return elem; - } - - /// - /// Loads the setting description from XML element. - /// - /// The serialized setting description. - internal void Load(XmlElement elem) { - Id = elem.Attributes["id"].Value; - - if (elem.Attributes["action"] != null) - Action = (SettingItemAction)Enum.Parse(typeof(SettingItemAction), elem.Attributes["action"].Value, true); - else - Action = SettingItemAction.Add; - - Clear(); - foreach (XmlElement i in elem.ChildNodes.OfType()) - Add(i.Attributes["name"].Value, i.Attributes["value"].Value); - } - - /// - /// Clones this instance. - /// - /// A duplicated setting item. - public SettingItem Clone() { - var item = new SettingItem(Id, Action); - foreach (var entry in this) - item.Add(entry.Key, entry.Value); - return item; - } - } - - - /// - /// A rule that control how s are applied to module - /// - public class Rule : List> { - /// - /// Initialize this rule instance - /// - /// The pattern - /// The preset - /// Inherits protection - public Rule(string pattern = "true", ProtectionPreset preset = ProtectionPreset.None, bool inherit = false) { - Pattern = pattern; - Preset = preset; - Inherit = inherit; - } - - /// - /// Gets or sets the pattern that determine the target components of the rule. - /// - /// The pattern expression. - public string Pattern { get; set; } - - /// - /// Gets or sets the protection preset this rule uses. - /// - /// The protection preset. - public ProtectionPreset Preset { get; set; } - - /// - /// Gets or sets a value indicating whether this inherits settings from earlier rules. - /// - /// true if it inherits settings; otherwise, false. - public bool Inherit { get; set; } - - /// - /// Saves the rule description as XML element. - /// - /// The root XML document. - /// The serialized rule description. - internal XmlElement Save(XmlDocument xmlDoc) { - XmlElement elem = xmlDoc.CreateElement("rule", ConfuserProject.Namespace); - - XmlAttribute ruleAttr = xmlDoc.CreateAttribute("pattern"); - ruleAttr.Value = Pattern; - elem.Attributes.Append(ruleAttr); - - if (Preset != ProtectionPreset.None) { - XmlAttribute pAttr = xmlDoc.CreateAttribute("preset"); - pAttr.Value = Preset.ToString().ToLower(); - elem.Attributes.Append(pAttr); - } - - if (Inherit != true) { - XmlAttribute attr = xmlDoc.CreateAttribute("inherit"); - attr.Value = Inherit.ToString().ToLower(); - elem.Attributes.Append(attr); - } - - foreach (var i in this) - elem.AppendChild(i.Save(xmlDoc)); - - return elem; - } - - /// - /// Loads the rule description from XML element. - /// - /// The serialized module description. - internal void Load(XmlElement elem) { - Pattern = elem.Attributes["pattern"].Value; - - if (elem.Attributes["preset"] != null) - Preset = (ProtectionPreset)Enum.Parse(typeof(ProtectionPreset), elem.Attributes["preset"].Value, true); - else - Preset = ProtectionPreset.None; - - if (elem.Attributes["inherit"] != null) - Inherit = bool.Parse(elem.Attributes["inherit"].Value); - else - Inherit = true; - - Clear(); - foreach (XmlElement i in elem.ChildNodes.OfType()) { - var x = new SettingItem(); - x.Load(i); - Add(x); - } - } - - - /// - /// Clones this instance. - /// - /// A duplicated rule. - public Rule Clone() { - var ret = new Rule(); - ret.Preset = Preset; - ret.Pattern = Pattern; - ret.Inherit = Inherit; - foreach (var i in this) { - var item = new SettingItem(); - item.Id = i.Id; - item.Action = i.Action; - foreach (string j in i.Keys) - item.Add(j, i[j]); - ret.Add(item); - } - return ret; - } - } - - /// - /// The exception that is thrown when there exists schema errors in the project XML. - /// - public class ProjectValidationException : Exception { - /// - /// Initializes a new instance of the class. - /// - /// The list of schema exceptions. - internal ProjectValidationException(List exceptions) - : base(exceptions[0].Message) { - Errors = exceptions; - } - - /// - /// Gets the schema exceptions. - /// - /// A list of schema exceptions. - public IList Errors { get; private set; } - } - - /// - /// Represent a project of Confuser. - /// - public class ConfuserProject : List { - /// - /// The namespace of Confuser project schema - /// - public const string Namespace = "http://confuser.codeplex.com"; - - /// - /// The schema of project XML. - /// - public static readonly XmlSchema Schema = XmlSchema.Read(typeof(ConfuserProject).Assembly.GetManifestResourceStream("Confuser.Core.Project.ConfuserPrj.xsd"), null); - - /// - /// Initializes a new instance of the class. - /// - public ConfuserProject() { - ProbePaths = new List(); - PluginPaths = new List(); - Rules = new List(); - } - - /// - /// Gets or sets the seed of pseudo-random generator used in process of protection. - /// - /// The random seed. - public string Seed { get; set; } - - /// - /// Gets or sets a value indicating whether debug symbols are generated. - /// - /// true if debug symbols are generated; otherwise, false. - public bool Debug { get; set; } - - /// - /// Gets or sets the output directory. - /// - /// The output directory. - public string OutputDirectory { get; set; } - - /// - /// Gets or sets the base directory of the project. - /// - /// The base directory. - public string BaseDirectory { get; set; } - - /// - /// Gets a list of protection rules that applies globally. - /// - /// A list of protection rules. - public IList Rules { get; private set; } - - /// - /// Gets or sets the packer used to pack up the output. - /// - /// The packer. - public SettingItem Packer { get; set; } - - /// - /// Gets a list of paths that used to resolve assemblies. - /// - /// The list of paths. - public IList ProbePaths { get; private set; } - - /// - /// Gets a list of paths to plugin. - /// - /// The list of plugins. - public IList PluginPaths { get; private set; } - - /// - /// Saves the project as XML document. - /// - /// The serialized project XML. - public XmlDocument Save() { - var xmlDoc = new XmlDocument(); - xmlDoc.Schemas.Add(Schema); - - XmlElement elem = xmlDoc.CreateElement("project", Namespace); - - XmlAttribute outputAttr = xmlDoc.CreateAttribute("outputDir"); - outputAttr.Value = OutputDirectory; - elem.Attributes.Append(outputAttr); - - XmlAttribute baseAttr = xmlDoc.CreateAttribute("baseDir"); - baseAttr.Value = BaseDirectory; - elem.Attributes.Append(baseAttr); - - if (Seed != null) { - XmlAttribute seedAttr = xmlDoc.CreateAttribute("seed"); - seedAttr.Value = Seed; - elem.Attributes.Append(seedAttr); - } - - if (Debug) { - XmlAttribute debugAttr = xmlDoc.CreateAttribute("debug"); - debugAttr.Value = Debug.ToString().ToLower(); - elem.Attributes.Append(debugAttr); - } - - foreach (Rule i in Rules) - elem.AppendChild(i.Save(xmlDoc)); - - if (Packer != null) - elem.AppendChild(Packer.Save(xmlDoc)); - - foreach (ProjectModule i in this) - elem.AppendChild(i.Save(xmlDoc)); - - foreach (string i in ProbePaths) { - XmlElement path = xmlDoc.CreateElement("probePath", Namespace); - path.InnerText = i; - elem.AppendChild(path); - } - - foreach (string i in PluginPaths) { - XmlElement path = xmlDoc.CreateElement("plugin", Namespace); - path.InnerText = i; - elem.AppendChild(path); - } - - xmlDoc.AppendChild(elem); - return xmlDoc; - } - - /// - /// Loads the project from specified XML document. - /// - /// The XML document storing the project. - /// - /// The project XML contains schema errors. - /// - public void Load(XmlDocument doc) { - doc.Schemas.Add(Schema); - var exceptions = new List(); - doc.Validate((sender, e) => { - if (e.Severity != XmlSeverityType.Error) return; - exceptions.Add(e.Exception); - }); - if (exceptions.Count > 0) { - throw new ProjectValidationException(exceptions); - } - - XmlElement docElem = doc.DocumentElement; - - OutputDirectory = docElem.Attributes["outputDir"].Value; - BaseDirectory = docElem.Attributes["baseDir"].Value; - - if (docElem.Attributes["seed"] != null) - Seed = docElem.Attributes["seed"].Value.NullIfEmpty(); - else - Seed = null; - - if (docElem.Attributes["debug"] != null) - Debug = bool.Parse(docElem.Attributes["debug"].Value); - else - Debug = false; - - Packer = null; - Clear(); - ProbePaths.Clear(); - PluginPaths.Clear(); - Rules.Clear(); - foreach (XmlElement i in docElem.ChildNodes.OfType()) { - if (i.Name == "rule") { - var rule = new Rule(); - rule.Load(i); - Rules.Add(rule); - } - else if (i.Name == "packer") { - Packer = new SettingItem(); - Packer.Load(i); - } - else if (i.Name == "probePath") { - ProbePaths.Add(i.InnerText); - } - else if (i.Name == "plugin") { - PluginPaths.Add(i.InnerText); - } - else { - var asm = new ProjectModule(); - asm.Load(i); - Add(asm); - } - } - } - - /// - /// Clones this instance. - /// - /// A duplicated project. - public ConfuserProject Clone() { - var ret = new ConfuserProject(); - ret.Seed = Seed; - ret.Debug = Debug; - ret.OutputDirectory = OutputDirectory; - ret.BaseDirectory = BaseDirectory; - ret.Packer = Packer == null ? null : Packer.Clone(); - ret.ProbePaths = new List(ProbePaths); - ret.PluginPaths = new List(PluginPaths); - foreach (var module in this) - ret.Add(module.Clone()); - foreach (var r in Rules) - ret.Rules.Add(r); - return ret; - } - } -} + ret.SNSigKeyPath = SNSigKeyPath; + ret.SNKeyPassword = SNKeyPassword; + ret.SNSigKeyPassword = SNSigKeyPassword; + foreach (var r in Rules) + ret.Rules.Add(r.Clone()); + return ret; + } + } + + /// + /// Indicates add or remove the protection from the active protections + /// + public enum SettingItemAction { + /// + /// Add the protection to the active protections + /// + Add, + + /// + /// Remove the protection from the active protections + /// + Remove + } + + /// + /// A setting within a rule. + /// + /// or + public class SettingItem : Dictionary { + /// + /// Initialize this setting item instance + /// + /// The protection id + /// The action to take + public SettingItem(string id = null, SettingItemAction action = SettingItemAction.Add) { + Id = id; + Action = action; + } + + /// + /// The identifier of component + /// + /// The identifier of component. + /// + public string Id { get; set; } + + /// + /// Gets or sets the action of component. + /// + /// The action of component. + public SettingItemAction Action { get; set; } + + /// + /// Saves the setting description as XML element. + /// + /// The root XML document. + /// The setting module description. + internal XmlElement Save(XmlDocument xmlDoc) { + XmlElement elem = xmlDoc.CreateElement(typeof(T) == typeof(Packer) ? "packer" : "protection", ConfuserProject.Namespace); + + XmlAttribute idAttr = xmlDoc.CreateAttribute("id"); + idAttr.Value = Id; + elem.Attributes.Append(idAttr); + + if (Action != SettingItemAction.Add) { + XmlAttribute pAttr = xmlDoc.CreateAttribute("action"); + pAttr.Value = Action.ToString().ToLower(); + elem.Attributes.Append(pAttr); + } + + foreach (var i in this) { + XmlElement arg = xmlDoc.CreateElement("argument", ConfuserProject.Namespace); + + XmlAttribute nameAttr = xmlDoc.CreateAttribute("name"); + nameAttr.Value = i.Key; + arg.Attributes.Append(nameAttr); + XmlAttribute valAttr = xmlDoc.CreateAttribute("value"); + valAttr.Value = i.Value; + arg.Attributes.Append(valAttr); + + elem.AppendChild(arg); + } + + return elem; + } + + /// + /// Loads the setting description from XML element. + /// + /// The serialized setting description. + internal void Load(XmlElement elem) { + Id = elem.Attributes["id"].Value; + + if (elem.Attributes["action"] != null) + Action = (SettingItemAction)Enum.Parse(typeof(SettingItemAction), elem.Attributes["action"].Value, true); + else + Action = SettingItemAction.Add; + + Clear(); + foreach (XmlElement i in elem.ChildNodes.OfType()) + Add(i.Attributes["name"].Value, i.Attributes["value"].Value); + } + + /// + /// Clones this instance. + /// + /// A duplicated setting item. + public SettingItem Clone() { + var item = new SettingItem(Id, Action); + foreach (var entry in this) + item.Add(entry.Key, entry.Value); + return item; + } + } + + + /// + /// A rule that control how s are applied to module + /// + public class Rule : List> { + /// + /// Initialize this rule instance + /// + /// The pattern + /// The preset + /// Inherits protection + public Rule(string pattern = "true", ProtectionPreset preset = ProtectionPreset.None, bool inherit = false) { + Pattern = pattern; + Preset = preset; + Inherit = inherit; + } + + /// + /// Gets or sets the pattern that determine the target components of the rule. + /// + /// The pattern expression. + public string Pattern { get; set; } + + /// + /// Gets or sets the protection preset this rule uses. + /// + /// The protection preset. + public ProtectionPreset Preset { get; set; } + + /// + /// Gets or sets a value indicating whether this inherits settings from earlier rules. + /// + /// true if it inherits settings; otherwise, false. + public bool Inherit { get; set; } + + /// + /// Saves the rule description as XML element. + /// + /// The root XML document. + /// The serialized rule description. + internal XmlElement Save(XmlDocument xmlDoc) { + XmlElement elem = xmlDoc.CreateElement("rule", ConfuserProject.Namespace); + + XmlAttribute ruleAttr = xmlDoc.CreateAttribute("pattern"); + ruleAttr.Value = Pattern; + elem.Attributes.Append(ruleAttr); + + if (Preset != ProtectionPreset.None) { + XmlAttribute pAttr = xmlDoc.CreateAttribute("preset"); + pAttr.Value = Preset.ToString().ToLower(); + elem.Attributes.Append(pAttr); + } + + if (Inherit != true) { + XmlAttribute attr = xmlDoc.CreateAttribute("inherit"); + attr.Value = Inherit.ToString().ToLower(); + elem.Attributes.Append(attr); + } + + foreach (var i in this) + elem.AppendChild(i.Save(xmlDoc)); + + return elem; + } + + /// + /// Loads the rule description from XML element. + /// + /// The serialized module description. + internal void Load(XmlElement elem) { + Pattern = elem.Attributes["pattern"].Value; + + if (elem.Attributes["preset"] != null) + Preset = (ProtectionPreset)Enum.Parse(typeof(ProtectionPreset), elem.Attributes["preset"].Value, true); + else + Preset = ProtectionPreset.None; + + if (elem.Attributes["inherit"] != null) + Inherit = bool.Parse(elem.Attributes["inherit"].Value); + else + Inherit = true; + + Clear(); + foreach (XmlElement i in elem.ChildNodes.OfType()) { + var x = new SettingItem(); + x.Load(i); + Add(x); + } + } + + + /// + /// Clones this instance. + /// + /// A duplicated rule. + public Rule Clone() { + var ret = new Rule(); + ret.Preset = Preset; + ret.Pattern = Pattern; + ret.Inherit = Inherit; + foreach (var i in this) { + var item = new SettingItem(); + item.Id = i.Id; + item.Action = i.Action; + foreach (string j in i.Keys) + item.Add(j, i[j]); + ret.Add(item); + } + return ret; + } + } + + /// + /// The exception that is thrown when there exists schema errors in the project XML. + /// + public class ProjectValidationException : Exception { + /// + /// Initializes a new instance of the class. + /// + /// The list of schema exceptions. + internal ProjectValidationException(List exceptions) + : base(exceptions[0].Message) { + Errors = exceptions; + } + + /// + /// Gets the schema exceptions. + /// + /// A list of schema exceptions. + public IList Errors { get; private set; } + } + + /// + /// Represent a project of Confuser. + /// + public class ConfuserProject : List { + /// + /// The namespace of Confuser project schema + /// + public const string Namespace = "http://confuser.codeplex.com"; + + /// + /// The schema of project XML. + /// + public static readonly XmlSchema Schema = XmlSchema.Read(typeof(ConfuserProject).Assembly.GetManifestResourceStream("Confuser.Core.Project.ConfuserPrj.xsd"), null); + + /// + /// Initializes a new instance of the class. + /// + public ConfuserProject() { + ProbePaths = new List(); + PluginPaths = new List(); + Rules = new List(); + } + + /// + /// Gets or sets the seed of pseudo-random generator used in process of protection. + /// + /// The random seed. + public string Seed { get; set; } + + /// + /// Gets or sets a value indicating whether debug symbols are generated. + /// + /// true if debug symbols are generated; otherwise, false. + public bool Debug { get; set; } + + /// + /// Gets or sets the output directory. + /// + /// The output directory. + public string OutputDirectory { get; set; } + + /// + /// Gets or sets the base directory of the project. + /// + /// The base directory. + public string BaseDirectory { get; set; } + + /// + /// Gets a list of protection rules that applies globally. + /// + /// A list of protection rules. + public IList Rules { get; private set; } + + /// + /// Gets or sets the packer used to pack up the output. + /// + /// The packer. + public SettingItem Packer { get; set; } + + /// + /// Gets a list of paths that used to resolve assemblies. + /// + /// The list of paths. + public IList ProbePaths { get; private set; } + + /// + /// Gets a list of paths to plugin. + /// + /// The list of plugins. + public IList PluginPaths { get; private set; } + + /// + /// Saves the project as XML document. + /// + /// The serialized project XML. + public XmlDocument Save() { + var xmlDoc = new XmlDocument(); + xmlDoc.Schemas.Add(Schema); + + XmlElement elem = xmlDoc.CreateElement("project", Namespace); + + XmlAttribute outputAttr = xmlDoc.CreateAttribute("outputDir"); + outputAttr.Value = OutputDirectory; + elem.Attributes.Append(outputAttr); + + XmlAttribute baseAttr = xmlDoc.CreateAttribute("baseDir"); + baseAttr.Value = BaseDirectory; + elem.Attributes.Append(baseAttr); + + if (Seed != null) { + XmlAttribute seedAttr = xmlDoc.CreateAttribute("seed"); + seedAttr.Value = Seed; + elem.Attributes.Append(seedAttr); + } + + if (Debug) { + XmlAttribute debugAttr = xmlDoc.CreateAttribute("debug"); + debugAttr.Value = Debug.ToString().ToLower(); + elem.Attributes.Append(debugAttr); + } + + foreach (Rule i in Rules) + elem.AppendChild(i.Save(xmlDoc)); + + if (Packer != null) + elem.AppendChild(Packer.Save(xmlDoc)); + + foreach (ProjectModule i in this) + elem.AppendChild(i.Save(xmlDoc)); + + foreach (string i in ProbePaths) { + XmlElement path = xmlDoc.CreateElement("probePath", Namespace); + path.InnerText = i; + elem.AppendChild(path); + } + + foreach (string i in PluginPaths) { + XmlElement path = xmlDoc.CreateElement("plugin", Namespace); + path.InnerText = i; + elem.AppendChild(path); + } + + xmlDoc.AppendChild(elem); + return xmlDoc; + } + + /// + /// Loads the project from specified XML document. + /// + /// The XML document storing the project. + /// + /// The project XML contains schema errors. + /// + public void Load(XmlDocument doc, string baseDirRoot = null) { + doc.Schemas.Add(Schema); + var exceptions = new List(); + doc.Validate((sender, e) => { + if (e.Severity != XmlSeverityType.Error) return; + exceptions.Add(e.Exception); + }); + if (exceptions.Count > 0) { + throw new ProjectValidationException(exceptions); + } + + XmlElement docElem = doc.DocumentElement; + + OutputDirectory = docElem.Attributes["outputDir"].Value; + BaseDirectory = docElem.Attributes["baseDir"].Value; + if (!string.IsNullOrEmpty(baseDirRoot)) { + BaseDirectory = Path.Combine(baseDirRoot, BaseDirectory); + } + + if (docElem.Attributes["seed"] != null) + Seed = docElem.Attributes["seed"].Value.NullIfEmpty(); + else + Seed = null; + + if (docElem.Attributes["debug"] != null) + Debug = bool.Parse(docElem.Attributes["debug"].Value); + else + Debug = false; + + Packer = null; + Clear(); + ProbePaths.Clear(); + PluginPaths.Clear(); + Rules.Clear(); + foreach (XmlElement i in docElem.ChildNodes.OfType()) { + if (i.Name == "rule") { + var rule = new Rule(); + rule.Load(i); + Rules.Add(rule); + } + else if (i.Name == "packer") { + Packer = new SettingItem(); + Packer.Load(i); + } + else if (i.Name == "probePath") { + ProbePaths.Add(i.InnerText); + } + else if (i.Name == "plugin") { + PluginPaths.Add(i.InnerText); + } + else { + AddModule(i); + } + } + } + + internal void AddModule(XmlElement elem) { + if (IsWildcard(elem.Attributes["path"].Value)) { + BatchLoadModules(elem); + } + else { + var asm = new ProjectModule(); + asm.Load(elem); + Add(asm); + } + } + + internal bool IsWildcard(string path) { + return !string.IsNullOrEmpty(path) && path.Contains(@"*"); + } + + internal bool BatchLoadModules(XmlElement elem) { + string wildCardPath = elem.Attributes["path"].Value; + string[] files = Directory.GetFiles(BaseDirectory, wildCardPath, SearchOption.TopDirectoryOnly); + if (files.Length <= 0) { + return false; + } + + var asmPrototype = new ProjectModule(); + asmPrototype.Load(elem); + + foreach (string fileName in files) { + var moduleEntry = asmPrototype.Clone(); + moduleEntry.Path = fileName; + Add(moduleEntry); + } + + return true; + } + + /// + /// Clones this instance. + /// + /// A duplicated project. + public ConfuserProject Clone() { + var ret = new ConfuserProject(); + ret.Seed = Seed; + ret.Debug = Debug; + ret.OutputDirectory = OutputDirectory; + ret.BaseDirectory = BaseDirectory; + ret.Packer = Packer == null ? null : Packer.Clone(); + ret.ProbePaths = new List(ProbePaths); + ret.PluginPaths = new List(PluginPaths); + foreach (var module in this) + ret.Add(module.Clone()); + foreach (var r in Rules) + ret.Rules.Add(r); + return ret; + } + } +} diff --git a/Confuser.Core/Properties/Resources.Designer.cs b/Confuser.Core/Properties/Resources.Designer.cs new file mode 100644 index 000000000..efe92f92b --- /dev/null +++ b/Confuser.Core/Properties/Resources.Designer.cs @@ -0,0 +1,450 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Confuser.Core.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Confuser.Core.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 Module {0} has been delayed the strong name. 的本地化字符串。 + /// + internal static string ConfuserEngine_BeginModule_Processing_DelayedStrongName { + get { + return ResourceManager.GetString("ConfuserEngine_BeginModule_Processing_DelayedStrongName", resourceCulture); + } + } + + /// + /// 查找类似 Processing module '{0}'... 的本地化字符串。 + /// + internal static string ConfuserEngine_BeginModule_Processing_module { + get { + return ResourceManager.GetString("ConfuserEngine_BeginModule_Processing_module", resourceCulture); + } + } + + /// + /// 查找类似 Write PE header... 的本地化字符串。 + /// + internal static string ConfuserEngine_BeginModule_Processing_PEHeaders { + get { + return ResourceManager.GetString("ConfuserEngine_BeginModule_Processing_PEHeaders", resourceCulture); + } + } + + /// + /// 查找类似 Processing strong name... 的本地化字符串。 + /// + internal static string ConfuserEngine_BeginModule_Processing_StrongName { + get { + return ResourceManager.GetString("ConfuserEngine_BeginModule_Processing_StrongName", resourceCulture); + } + } + + /// + /// 查找类似 [{0}] SN Key or SN public Key is not provided for a signed module, the output may not be working. 的本地化字符串。 + /// + internal static string ConfuserEngine_CheckStrongName1 { + get { + return ResourceManager.GetString("ConfuserEngine_CheckStrongName1", resourceCulture); + } + } + + /// + /// 查找类似 [{0}] SN Key or SN public Key is provided for an unsigned module, the output may not be working. 的本地化字符串。 + /// + internal static string ConfuserEngine_CheckStrongName2 { + get { + return ResourceManager.GetString("ConfuserEngine_CheckStrongName2", resourceCulture); + } + } + + /// + /// 查找类似 [{0}] Provided SN public Key and signed module's public key do not match, the output may not be working. 的本地化字符串。 + /// + internal static string ConfuserEngine_CheckStrongName3 { + get { + return ResourceManager.GetString("ConfuserEngine_CheckStrongName3", resourceCulture); + } + } + + /// + /// 查找类似 Finalizing... 的本地化字符串。 + /// + internal static string ConfuserEngine_Debug_Finalizing { + get { + return ResourceManager.GetString("ConfuserEngine_Debug_Finalizing", resourceCulture); + } + } + + /// + /// 查找类似 Checking Strong Name... 的本地化字符串。 + /// + internal static string ConfuserEngine_Inspection_Checking_Strong_Name { + get { + return ResourceManager.GetString("ConfuserEngine_Inspection_Checking_Strong_Name", resourceCulture); + } + } + + /// + /// 查找类似 Creating global .cctors... 的本地化字符串。 + /// + internal static string ConfuserEngine_Inspection_Creating_global__cctors { + get { + return ResourceManager.GetString("ConfuserEngine_Inspection_Creating_global__cctors", resourceCulture); + } + } + + /// + /// 查找类似 Failed to resolve dependency assembly '{1}' in module '{0}' 的本地化字符串。 + /// + internal static string ConfuserEngine_Inspection_Failed_to_resolve_dependency { + get { + return ResourceManager.GetString("ConfuserEngine_Inspection_Failed_to_resolve_dependency", resourceCulture); + } + } + + /// + /// 查找类似 Resolving dependencies... 的本地化字符串。 + /// + internal static string ConfuserEngine_Inspection_Resolving_dependencies { + get { + return ResourceManager.GetString("ConfuserEngine_Inspection_Resolving_dependencies", resourceCulture); + } + } + + /// + /// 查找类似 Packing... 的本地化字符串。 + /// + internal static string ConfuserEngine_Pack_Packing { + get { + return ResourceManager.GetString("ConfuserEngine_Pack_Packing", resourceCulture); + } + } + + /// + /// 查找类似 Cached assemblies: 的本地化字符串。 + /// + internal static string ConfuserEngine_PrintEnvironmentInfo_Cached_assemblies { + get { + return ResourceManager.GetString("ConfuserEngine_PrintEnvironmentInfo_Cached_assemblies", resourceCulture); + } + } + + /// + /// 查找类似 Installed Framework Versions: 的本地化字符串。 + /// + internal static string ConfuserEngine_PrintEnvironmentInfo_Installed_Framework_Versions { + get { + return ResourceManager.GetString("ConfuserEngine_PrintEnvironmentInfo_Installed_Framework_Versions", resourceCulture); + } + } + + /// + /// 查找类似 Protecting packer stub... 的本地化字符串。 + /// + internal static string ConfuserEngine_PrintInfo_Protecting_packer_stub { + get { + return ResourceManager.GetString("ConfuserEngine_PrintInfo_Protecting_packer_stub", resourceCulture); + } + } + + /// + /// 查找类似 Running on {0}, {1}, {2} bits 的本地化字符串。 + /// + internal static string ConfuserEngine_PrintInfo_Running_on { + get { + return ResourceManager.GetString("ConfuserEngine_PrintInfo_Running_on", resourceCulture); + } + } + + /// + /// 查找类似 Building pipeline... 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Building_pipeline { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Building_pipeline", resourceCulture); + } + } + + /// + /// 查找类似 Discovered {0} protections, {1} packers. 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Discovered__protections { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Discovered__protections", resourceCulture); + } + } + + /// + /// 查找类似 Discovering plugins... 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Discovering_plugins { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Discovering_plugins", resourceCulture); + } + } + + /// + /// 查找类似 Error occured during initialization of '{0}'. 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Error_occured_during_initialization { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Error_occured_during_initialization", resourceCulture); + } + } + + /// + /// 查找类似 Initializing... 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Initializing { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Initializing", resourceCulture); + } + } + + /// + /// 查找类似 Loading input modules... 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Loading_input_modules { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Loading_input_modules", resourceCulture); + } + } + + /// + /// 查找类似 Operation cancelled. 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Operation_cancelled { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Operation_cancelled", resourceCulture); + } + } + + /// + /// 查找类似 Resolving component dependency... 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Resolving_component_dependency { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Resolving_component_dependency", resourceCulture); + } + } + + /// + /// 查找类似 Unknown error occurred. 的本地化字符串。 + /// + internal static string ConfuserEngine_RunInternal_Unknown_error_occurred { + get { + return ResourceManager.GetString("ConfuserEngine_RunInternal_Unknown_error_occurred", resourceCulture); + } + } + + /// + /// 查找类似 Done. 的本地化字符串。 + /// + internal static string ConfuserEngine_RunPipeline_Done { + get { + return ResourceManager.GetString("ConfuserEngine_RunPipeline_Done", resourceCulture); + } + } + + /// + /// 查找类似 Saving to '{0}'... 的本地化字符串。 + /// + internal static string ConfuserEngine_SaveModules_Saving_to { + get { + return ResourceManager.GetString("ConfuserEngine_SaveModules_Saving_to", resourceCulture); + } + } + + /// + /// 查找类似 Writing module '{0}'... 的本地化字符串。 + /// + internal static string ConfuserEngine_WriteModule_Writing_module { + get { + return ResourceManager.GetString("ConfuserEngine_WriteModule_Writing_module", resourceCulture); + } + } + + /// + /// 查找类似 Loading '{0}'... 的本地化字符串。 + /// + internal static string Marker_MarkProject_Loading { + get { + return ResourceManager.GetString("Marker_MarkProject_Loading", resourceCulture); + } + } + + /// + /// 查找类似 Loading '{0}'... 的本地化字符串。 + /// + internal static string ObfAttrMarker_MarkProject_Loading { + get { + return ResourceManager.GetString("ObfAttrMarker_MarkProject_Loading", resourceCulture); + } + } + + /// + /// 查找类似 Failed to instantiate component '{0}'. 的本地化字符串。 + /// + internal static string PluginDiscovery_AddPlugins_Failed_to_instantiate_component { + get { + return ResourceManager.GetString("PluginDiscovery_AddPlugins_Failed_to_instantiate_component", resourceCulture); + } + } + + /// + /// 查找类似 Failed to instantiate packer '{0}'. 的本地化字符串。 + /// + internal static string PluginDiscovery_AddPlugins_Failed_to_instantiate_packer { + get { + return ResourceManager.GetString("PluginDiscovery_AddPlugins_Failed_to_instantiate_packer", resourceCulture); + } + } + + /// + /// 查找类似 Failed to instantiate protection '{0}'. 的本地化字符串。 + /// + internal static string PluginDiscovery_AddPlugins_Failed_to_instantiate_protection { + get { + return ResourceManager.GetString("PluginDiscovery_AddPlugins_Failed_to_instantiate_protection", resourceCulture); + } + } + + /// + /// 查找类似 Failed to load built-in protections. 的本地化字符串。 + /// + internal static string PluginDiscovery_GetPluginsInternal_Failed_to_load_built_in_protections { + get { + return ResourceManager.GetString("PluginDiscovery_GetPluginsInternal_Failed_to_load_built_in_protections", resourceCulture); + } + } + + /// + /// 查找类似 Failed to load dynamic cipher library. 的本地化字符串。 + /// + internal static string PluginDiscovery_GetPluginsInternal_Failed_to_load_dynamic_cipher_library { + get { + return ResourceManager.GetString("PluginDiscovery_GetPluginsInternal_Failed_to_load_dynamic_cipher_library", resourceCulture); + } + } + + /// + /// 查找类似 Failed to load plugin '{0}'. 的本地化字符串。 + /// + internal static string PluginDiscovery_GetPluginsInternal_Failed_to_load_plugin { + get { + return ResourceManager.GetString("PluginDiscovery_GetPluginsInternal_Failed_to_load_plugin", resourceCulture); + } + } + + /// + /// 查找类似 Failed to load renamer. 的本地化字符串。 + /// + internal static string PluginDiscovery_GetPluginsInternal_Failed_to_load_renamer { + get { + return ResourceManager.GetString("PluginDiscovery_GetPluginsInternal_Failed_to_load_renamer", resourceCulture); + } + } + + /// + /// 查找类似 Executing '{0}' phase... 的本地化字符串。 + /// + internal static string ProtectionPipeline_ExecuteStage_Executing { + get { + return ResourceManager.GetString("ProtectionPipeline_ExecuteStage_Executing", resourceCulture); + } + } + + /// + /// 查找类似 Watermarking... 的本地化字符串。 + /// + internal static string WatermarkingPhase_Execute_Watermarking { + get { + return ResourceManager.GetString("WatermarkingPhase_Execute_Watermarking", resourceCulture); + } + } + + /// + /// 查找类似 Apply watermark 的本地化字符串。 + /// + internal static string WatermarkingPhase_Name { + get { + return ResourceManager.GetString("WatermarkingPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This applies a watermark to the assembly, showing that ConfuserEx protected the assembly. So people try to reverse the obfuscation know to just give up. 的本地化字符串。 + /// + internal static string WatermarkingProtectionDescription { + get { + return ResourceManager.GetString("WatermarkingProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Watermarking 的本地化字符串。 + /// + internal static string WatermarkingProtectionName { + get { + return ResourceManager.GetString("WatermarkingProtectionName", resourceCulture); + } + } + } +} diff --git a/Confuser.Core/Properties/Resources.resx b/Confuser.Core/Properties/Resources.resx new file mode 100644 index 000000000..ca7668545 --- /dev/null +++ b/Confuser.Core/Properties/Resources.resx @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Watermarking + + + This applies a watermark to the assembly, showing that ConfuserEx protected the assembly. So people try to reverse the obfuscation know to just give up. + + + Apply watermark + + + Executing '{0}' phase... + + + Initializing... + + + Discovering plugins... + + + Discovered {0} protections, {1} packers. + + + Resolving component dependency... + + + Loading input modules... + + + Error occured during initialization of '{0}'. + + + Building pipeline... + + + Operation cancelled. + + + Unknown error occurred. + + + Done. + + + Resolving dependencies... + + + Failed to resolve dependency assembly '{1}' in module '{0}' + + + Checking Strong Name... + + + Creating global .cctors... + + + Processing module '{0}'... + + + Writing module '{0}'... + + + Finalizing... + + + Packing... + + + Saving to '{0}'... + + + Protecting packer stub... + + + Cached assemblies: + + + Watermarking... + + + [{0}] SN Key or SN public Key is not provided for a signed module, the output may not be working. + + + [{0}] SN Key or SN public Key is provided for an unsigned module, the output may not be working. + + + [{0}] Provided SN public Key and signed module's public key do not match, the output may not be working. + + + Loading '{0}'... + + + Loading '{0}'... + + + Running on {0}, {1}, {2} bits + + + Installed Framework Versions: + + + Failed to load plugin '{0}'. + + + Failed to instantiate protection '{0}'. + + + Failed to instantiate packer '{0}'. + + + Failed to instantiate component '{0}'. + + + Failed to load built-in protections. + + + Failed to load renamer. + + + Failed to load dynamic cipher library. + + + Processing strong name... + + + Module {0} has been delayed the strong name. + + + Write PE header... + + diff --git a/Confuser.Core/Properties/Resources.zh-Hans.resx b/Confuser.Core/Properties/Resources.zh-Hans.resx new file mode 100644 index 000000000..f1c6fa836 --- /dev/null +++ b/Confuser.Core/Properties/Resources.zh-Hans.resx @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 这将水印应用于程序集,表明ConfuserEx保护了程序集。 + + + 水印 + + + 正在执行“ {0}” 阶段... + + + 应用水印 + + + 发现插件... + + + 发现{0}个保护模块, {1}个压缩打包模块. + + + 解析组件依赖... + + + 加载输入模块... + + + 正在初始化... + + + 操作取消。 + + + 出现未知错误。 + + + 完成。 + + + 解析依赖项... + + + 检查强名称... + + + 创建全局.cctors... + + + 处理模块 '{0}'... + + + 写入模块 "{0}"... + + + 打包中... + + + 缓存程序集: + + + 保存到 "{0}"... + + + 正在完成... + + + 初始化“{0}”时出错。 + + + 正在生成管道... + + + 保护打包器子程序... + + + 无法解析模块“{0}”的依赖程序集“{1}” + + + 生成水印中... + + + [{0}] SN 密钥或 SN 公钥未为签名模块提供,输出模块可能无法正常运行。 + + + [{0}] SN 密钥或 SN 公钥为未签名的模块提供,输出模块可能无法正常运行。 + + + [{0}] 如果 SN 公钥和签名模块的公钥不匹配,输出模块可能无法正常运行。 + + + 加载中 “{0}” ... + + + 加载中 “{0}” ... + + + 运行在 {0}, {1}, {2}位 + + + 已安装.NET框架版本: + + + 无法加载插件 "{0}"! + + + 无法加载动态密码库! + + + 实例化保护模块“{0}”失败! + + + 实例化压缩打包模块“{0}”失败! + + + 实例化组件“{0}”失败! + + + 无法加载内置保护模块! + + + 无法加载重命名模块! + + + 正在处理强签名... + + + 模块“{0}”已延迟强签名 + + + 写PE标头... + + diff --git a/Confuser.Core/ProtectionPipeline.cs b/Confuser.Core/ProtectionPipeline.cs index 406ed3ebc..5c566c4bb 100644 --- a/Confuser.Core/ProtectionPipeline.cs +++ b/Confuser.Core/ProtectionPipeline.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Confuser.Core.Properties; using dnlib.DotNet; namespace Confuser.Core { @@ -127,15 +128,21 @@ public T FindPhase() where T : ProtectionPhase { internal void ExecuteStage(PipelineStage stage, Action func, Func> targets, ConfuserContext context) { foreach (ProtectionPhase pre in preStage[stage]) { context.CheckCancellation(); - context.Logger.DebugFormat("Executing '{0}' phase...", pre.Name); - pre.Execute(context, new ProtectionParameters(pre.Parent, Filter(context, targets(), pre))); + var specifiedTargets = Filter(context, targets(), pre); + if (specifiedTargets.Count > 0) { + context.Logger.DebugFormat(Resources.ProtectionPipeline_ExecuteStage_Executing, pre.Name); + pre.Execute(context, new ProtectionParameters(pre.Parent, specifiedTargets)); + } } context.CheckCancellation(); func(context); context.CheckCancellation(); foreach (ProtectionPhase post in postStage[stage]) { - context.Logger.DebugFormat("Executing '{0}' phase...", post.Name); - post.Execute(context, new ProtectionParameters(post.Parent, Filter(context, targets(), post))); + var specifiedTargets = Filter(context, targets(), post); + if (specifiedTargets.Count > 0) { + context.Logger.DebugFormat(Resources.ProtectionPipeline_ExecuteStage_Executing, post.Name); + post.Execute(context, new ProtectionParameters(post.Parent, specifiedTargets)); + } context.CheckCancellation(); } } @@ -177,4 +184,4 @@ static IList Filter(ConfuserContext context, IList targets }).ToList(); } } -} \ No newline at end of file +} diff --git a/Confuser.Core/ProtectionPreset.cs b/Confuser.Core/ProtectionPreset.cs index 9a686ba2c..6217a6377 100644 --- a/Confuser.Core/ProtectionPreset.cs +++ b/Confuser.Core/ProtectionPreset.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Confuser.Core { /// @@ -20,4 +21,8 @@ public enum ProtectionPreset { /// The protection provides strongest security with possible incompatibility. Maximum = 4 } -} \ No newline at end of file + + //public class Preset { + // public List<> + //} +} diff --git a/Confuser.Core/Services/RuntimeService.cs b/Confuser.Core/Services/RuntimeService.cs index 4d4edae4a..d4ec47110 100644 --- a/Confuser.Core/Services/RuntimeService.cs +++ b/Confuser.Core/Services/RuntimeService.cs @@ -12,7 +12,17 @@ public TypeDef GetRuntimeType(string fullName) { if (rtModule == null) { LoadConfuserRuntimeModule(); } - return rtModule.Find(fullName, true); + var typeDef = rtModule.Find(fullName, true); + if (typeDef == null) { + var moduleDefs = PluginDiscovery.Instance.GetPluginModuleDef(); + foreach (var moduleDef in moduleDefs) { + typeDef = moduleDef.Find(fullName, true); + if (typeDef != null) { + return typeDef; + } + } + } + return typeDef; } private void LoadConfuserRuntimeModule() { diff --git a/Confuser.Core/WatermarkingProtection.cs b/Confuser.Core/WatermarkingProtection.cs index 5330bdcb9..76530d7ce 100644 --- a/Confuser.Core/WatermarkingProtection.cs +++ b/Confuser.Core/WatermarkingProtection.cs @@ -1,4 +1,5 @@ using System.Linq; +using Confuser.Core.Properties; using Confuser.Core.Services; using dnlib.DotNet; using dnlib.DotNet.Emit; @@ -9,11 +10,11 @@ public sealed class WatermarkingProtection : Protection { public const string _FullId = "Cx.Watermark"; /// - public override string Name => "Watermarking"; + public override string Name => Resources.WatermarkingProtectionName; /// public override string Description => - "This applies a watermark to the assembly, showing that ConfuserEx protected the assembly. So people try to reverse the obfuscation know to just give up."; + Resources.WatermarkingProtectionDescription; /// public override string Id => _Id; @@ -39,13 +40,13 @@ public WatermarkingPhase(ConfuserComponent parent) : base(parent) { } public override ProtectionTargets Targets => ProtectionTargets.Modules; /// - public override string Name => "Apply watermark"; + public override string Name => Resources.WatermarkingPhase_Name; /// protected internal override void Execute(ConfuserContext context, ProtectionParameters parameters) { var marker = context.Registry.GetService(); - context.Logger.Debug("Watermarking..."); + context.Logger.Debug(Resources.WatermarkingPhase_Execute_Watermarking); foreach (var module in parameters.Targets.OfType()) { var attrRef = module.CorLibTypes.GetTypeRef("System", "Attribute"); var attrType = module.FindNormal("ConfusedByAttribute"); diff --git a/Confuser.DynCipher/Confuser.DynCipher.csproj b/Confuser.DynCipher/Confuser.DynCipher.csproj index 669658e52..a88293b7f 100644 --- a/Confuser.DynCipher/Confuser.DynCipher.csproj +++ b/Confuser.DynCipher/Confuser.DynCipher.csproj @@ -4,7 +4,7 @@ - net461;netstandard2.0 + net462;netstandard2.0 true ..\ConfuserEx.snk diff --git a/Confuser.MSBuild.Tasks/Confuser.MSBuild.Tasks.csproj b/Confuser.MSBuild.Tasks/Confuser.MSBuild.Tasks.csproj index 06999b4d3..d791c73e8 100644 --- a/Confuser.MSBuild.Tasks/Confuser.MSBuild.Tasks.csproj +++ b/Confuser.MSBuild.Tasks/Confuser.MSBuild.Tasks.csproj @@ -4,7 +4,7 @@ - net461;netstandard2.0 + net462;netstandard2.0 true ..\ConfuserEx.snk @@ -25,14 +25,14 @@ - + - + @@ -48,10 +48,10 @@ - + - - + + diff --git a/Confuser.Protections/AntiDebugProtection.cs b/Confuser.Protections/AntiDebugProtection.cs index d1252eef7..b8d221097 100644 --- a/Confuser.Protections/AntiDebugProtection.cs +++ b/Confuser.Protections/AntiDebugProtection.cs @@ -15,11 +15,11 @@ internal class AntiDebugProtection : Protection { public const string _FullId = "Ki.AntiDebug"; public override string Name { - get { return "Anti Debug Protection"; } + get { return Properties.Resources.AntiDebugProtectionName; } } public override string Description { - get { return "This protection prevents the assembly from being debugged or profiled."; } + get { return Properties.Resources.AntiDebugProtectionDescription; } } public override string Id { @@ -51,7 +51,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Anti-debug injection"; } + get { return Properties.Resources.AntiDebugProtectionAntiDebugPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { diff --git a/Confuser.Protections/AntiDumpProtection.cs b/Confuser.Protections/AntiDumpProtection.cs index 77b02700d..f9568e188 100644 --- a/Confuser.Protections/AntiDumpProtection.cs +++ b/Confuser.Protections/AntiDumpProtection.cs @@ -15,11 +15,11 @@ internal class AntiDumpProtection : Protection { public const string _FullId = "Ki.AntiDump"; public override string Name { - get { return "Anti Dump Protection"; } + get { return Properties.Resources.AntiDumpProtectionName; } } public override string Description { - get { return "This protection prevents the assembly from being dumped from memory."; } + get { return Properties.Resources.AntiDumpProtectionDescription; } } public override string Id { @@ -51,7 +51,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Anti-dump injection"; } + get { return Properties.Resources.AntiDumpPhase_Name; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -73,4 +73,4 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa } } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/AntiILDasmProtection.cs b/Confuser.Protections/AntiILDasmProtection.cs index 43241c96e..857c92e23 100644 --- a/Confuser.Protections/AntiILDasmProtection.cs +++ b/Confuser.Protections/AntiILDasmProtection.cs @@ -9,11 +9,11 @@ internal class AntiILDasmProtection : Protection { public const string _FullId = "Ki.AntiILDasm"; public override string Name { - get { return "Anti IL Dasm Protection"; } + get { return Properties.Resources.AntiILDasmProtectionName; } } public override string Description { - get { return "This protection marks the module with a attribute that discourage ILDasm from disassembling it."; } + get { return Properties.Resources.AntiILDasmProtectionDescription; } } public override string Id { @@ -45,7 +45,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Anti-ILDasm marking"; } + get { return Properties.Resources.AntiILDasmPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -59,4 +59,4 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa } } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/AntiTamper/AntiTamperProtection.cs b/Confuser.Protections/AntiTamper/AntiTamperProtection.cs index a528f845c..5ea9b5f8a 100644 --- a/Confuser.Protections/AntiTamper/AntiTamperProtection.cs +++ b/Confuser.Protections/AntiTamper/AntiTamperProtection.cs @@ -18,11 +18,11 @@ internal class AntiTamperProtection : Protection, IAntiTamperService { static readonly object HandlerKey = new object(); public override string Name { - get { return "Anti Tamper Protection"; } + get { return Properties.Resources.AntiTamperProtectionName; } } public override string Description { - get { return "This protection ensures the integrity of application."; } + get { return Properties.Resources.AntiTamperProtectionDescription; } } public override string Id { @@ -79,7 +79,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Anti-tamper helpers injection"; } + get { return Properties.Resources.AntiTamperProtectionInjectPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -115,7 +115,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Anti-tamper metadata preparation"; } + get { return Properties.Resources.MDPhase_Name; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { diff --git a/Confuser.Protections/AntiTamper/JITBody.cs b/Confuser.Protections/AntiTamper/JITBody.cs index ae306d349..0d14e841e 100644 --- a/Confuser.Protections/AntiTamper/JITBody.cs +++ b/Confuser.Protections/AntiTamper/JITBody.cs @@ -47,6 +47,8 @@ public uint GetVirtualSize() { return GetFileLength(); } + public uint CalculateAlignment() => 0; + public void WriteTo(DataWriter writer) { writer.WriteUInt32((uint)(Body.Length >> 2)); writer.WriteBytes(Body); @@ -224,6 +226,8 @@ public uint GetVirtualSize() { return GetFileLength(); } + public uint CalculateAlignment() => 0; + public void WriteTo(DataWriter writer) { uint length = GetFileLength() - 4; // minus length field writer.WriteUInt32((uint)bodies.Count); @@ -252,4 +256,4 @@ public void PopulateSection(PESection section) { } } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/Compress/Compressor.cs b/Confuser.Protections/Compress/Compressor.cs index 33c0ea6b7..c8384e83f 100644 --- a/Confuser.Protections/Compress/Compressor.cs +++ b/Confuser.Protections/Compress/Compressor.cs @@ -1,355 +1,355 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Security.Cryptography; -using System.Text; -using Confuser.Core; -using Confuser.Core.Helpers; -using Confuser.Core.Services; -using Confuser.Protections.Compress; -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using dnlib.DotNet.MD; -using dnlib.DotNet.Writer; -using dnlib.PE; -using FileAttributes = dnlib.DotNet.FileAttributes; -using SR = System.Reflection; - -namespace Confuser.Protections { - internal class Compressor : Packer { - public const string _Id = "compressor"; - public const string _FullId = "Ki.Compressor"; - public const string _ServiceId = "Ki.Compressor"; - public static readonly object ContextKey = new object(); - - public override string Name { - get { return "Compressing Packer"; } - } - - public override string Description { - get { return "This packer reduces the size of output."; } - } - - public override string Id { - get { return _Id; } - } - - public override string FullId { - get { return _FullId; } - } - - protected override void Initialize(ConfuserContext context) { } - - protected override void PopulatePipeline(ProtectionPipeline pipeline) { - pipeline.InsertPreStage(PipelineStage.WriteModule, new ExtractPhase(this)); - } - - protected override void Pack(ConfuserContext context, ProtectionParameters parameters) { - var ctx = context.Annotations.Get(context, ContextKey); - if (ctx == null) { - context.Logger.Error("No executable module!"); - throw new ConfuserException(null); - } - - ModuleDefMD originModule = context.Modules[ctx.ModuleIndex]; - ctx.OriginModuleDef = originModule; - - var stubModule = new ModuleDefUser(ctx.ModuleName, originModule.Mvid, originModule.CorLibTypes.AssemblyRef); - if (ctx.CompatMode) { - var assembly = new AssemblyDefUser(originModule.Assembly); - assembly.Name += ".cr"; - assembly.Modules.Add(stubModule); - } - else { - ctx.Assembly.Modules.Insert(0, stubModule); - ImportAssemblyTypeReferences(originModule, stubModule); - } - stubModule.Characteristics = originModule.Characteristics; - stubModule.Cor20HeaderFlags = originModule.Cor20HeaderFlags; - stubModule.Cor20HeaderRuntimeVersion = originModule.Cor20HeaderRuntimeVersion; - stubModule.DllCharacteristics = originModule.DllCharacteristics; - stubModule.EncBaseId = originModule.EncBaseId; - stubModule.EncId = originModule.EncId; - stubModule.Generation = originModule.Generation; - stubModule.Kind = ctx.Kind; - stubModule.Machine = originModule.Machine; - stubModule.RuntimeVersion = originModule.RuntimeVersion; - stubModule.TablesHeaderVersion = originModule.TablesHeaderVersion; - stubModule.Win32Resources = originModule.Win32Resources; - - InjectStub(context, ctx, parameters, stubModule); - +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Text; +using Confuser.Core; +using Confuser.Core.Helpers; +using Confuser.Core.Services; +using Confuser.Protections.Compress; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using dnlib.DotNet.MD; +using dnlib.DotNet.Writer; +using dnlib.PE; +using FileAttributes = dnlib.DotNet.FileAttributes; +using SR = System.Reflection; + +namespace Confuser.Protections { + internal class Compressor : Packer { + public const string _Id = "compressor"; + public const string _FullId = "Ki.Compressor"; + public const string _ServiceId = "Ki.Compressor"; + public static readonly object ContextKey = new object(); + + public override string Name { + get { return Properties.Resources.CompressorName; } + } + + public override string Description { + get { return Properties.Resources.CompressorDescription; } + } + + public override string Id { + get { return _Id; } + } + + public override string FullId { + get { return _FullId; } + } + + protected override void Initialize(ConfuserContext context) { } + + protected override void PopulatePipeline(ProtectionPipeline pipeline) { + pipeline.InsertPreStage(PipelineStage.WriteModule, new ExtractPhase(this)); + } + + protected override void Pack(ConfuserContext context, ProtectionParameters parameters) { + var ctx = context.Annotations.Get(context, ContextKey); + if (ctx == null) { + context.Logger.Error(Properties.Resources.Compressor_Pack_No_executable_module); + throw new ConfuserException(null); + } + + ModuleDefMD originModule = context.Modules[ctx.ModuleIndex]; + ctx.OriginModuleDef = originModule; + + var stubModule = new ModuleDefUser(ctx.ModuleName, originModule.Mvid, originModule.CorLibTypes.AssemblyRef); + if (ctx.CompatMode) { + var assembly = new AssemblyDefUser(originModule.Assembly); + assembly.Name += ".cr"; + assembly.Modules.Add(stubModule); + } + else { + ctx.Assembly.Modules.Insert(0, stubModule); + ImportAssemblyTypeReferences(originModule, stubModule); + } + stubModule.Characteristics = originModule.Characteristics; + stubModule.Cor20HeaderFlags = originModule.Cor20HeaderFlags; + stubModule.Cor20HeaderRuntimeVersion = originModule.Cor20HeaderRuntimeVersion; + stubModule.DllCharacteristics = originModule.DllCharacteristics; + stubModule.EncBaseId = originModule.EncBaseId; + stubModule.EncId = originModule.EncId; + stubModule.Generation = originModule.Generation; + stubModule.Kind = ctx.Kind; + stubModule.Machine = originModule.Machine; + stubModule.RuntimeVersion = originModule.RuntimeVersion; + stubModule.TablesHeaderVersion = originModule.TablesHeaderVersion; + stubModule.Win32Resources = originModule.Win32Resources; + + InjectStub(context, ctx, parameters, stubModule); + var snKey = context.Annotations.Get(originModule, Marker.SNKey); - var snPubKey = context.Annotations.Get(originModule, Marker.SNPubKey); - var snDelaySig = context.Annotations.Get(originModule, Marker.SNDelaySig, false); + var snPubKey = context.Annotations.Get(originModule, Marker.SNPubKey); + var snDelaySig = context.Annotations.Get(originModule, Marker.SNDelaySig, false); var snSigKey = context.Annotations.Get(originModule, Marker.SNSigKey); - var snPubSigKey = context.Annotations.Get(originModule, Marker.SNSigPubKey); - - using (var ms = new MemoryStream()) { - var options = new ModuleWriterOptions(stubModule) { - StrongNameKey = snKey, - StrongNamePublicKey = snPubKey, - DelaySign = snDelaySig - }; - var injector = new KeyInjector(ctx); - options.WriterEvent += injector.WriterEvent; - - stubModule.Write(ms, options); - context.CheckCancellation(); - ProtectStub(context, context.OutputPaths[ctx.ModuleIndex], ms.ToArray(), snKey, snPubKey, snSigKey, snPubKey, snDelaySig, new StubProtection(ctx, originModule)); - } - } - - static string GetId(byte[] module) { - var md = MetadataFactory.CreateMetadata(new PEImage(module)); - var assembly = new AssemblyNameInfo(); - if (md.TablesStream.TryReadAssemblyRow(1, out var assemblyRow)) { - assembly.Name = md.StringsStream.ReadNoNull(assemblyRow.Name); - assembly.Culture = md.StringsStream.ReadNoNull(assemblyRow.Locale); - assembly.PublicKeyOrToken = new PublicKey(md.BlobStream.Read(assemblyRow.PublicKey)); - assembly.HashAlgId = (AssemblyHashAlgorithm)assemblyRow.HashAlgId; - assembly.Version = new Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber); - assembly.Attributes = (AssemblyAttributes)assemblyRow.Flags; - } - return GetId(assembly); - } - - static string GetId(IAssembly assembly) { - return new SR.AssemblyName(assembly.FullName).FullName.ToUpperInvariant(); - } - - void PackModules(ConfuserContext context, CompressorContext compCtx, ModuleDef stubModule, ICompressionService comp, RandomGenerator random) { - int maxLen = 0; - var modules = new Dictionary(); - for (int i = 0; i < context.OutputModules.Count; i++) { - if (i == compCtx.ModuleIndex) - continue; - - string id = GetId(context.Modules[i].Assembly); - modules.Add(id, context.OutputModules[i]); - - int strLen = Encoding.UTF8.GetByteCount(id); - if (strLen > maxLen) - maxLen = strLen; - } - foreach (var extModule in context.ExternalModules) { - var name = GetId(extModule).ToUpperInvariant(); - modules.Add(name, extModule); - - int strLen = Encoding.UTF8.GetByteCount(name); - if (strLen > maxLen) - maxLen = strLen; - } - - byte[] key = random.NextBytes(4 + maxLen); - key[0] = (byte)(compCtx.EntryPointToken >> 0); - key[1] = (byte)(compCtx.EntryPointToken >> 8); - key[2] = (byte)(compCtx.EntryPointToken >> 16); - key[3] = (byte)(compCtx.EntryPointToken >> 24); - for (int i = 4; i < key.Length; i++) // no zero bytes - key[i] |= 1; - compCtx.KeySig = key; - - int moduleIndex = 0; - foreach (var entry in modules) { - byte[] name = Encoding.UTF8.GetBytes(entry.Key); - for (int i = 0; i < name.Length; i++) - name[i] *= key[i + 4]; - - uint state = 0x6fff61; - foreach (byte chr in name) - state = state * 0x5e3f1f + chr; - byte[] encrypted = compCtx.Encrypt(comp, entry.Value, state, progress => { - progress = (progress + moduleIndex) / modules.Count; - context.Logger.Progress((int)(progress * 10000), 10000); - }); - context.CheckCancellation(); - - var resource = new EmbeddedResource(Convert.ToBase64String(name), encrypted, ManifestResourceAttributes.Private); - stubModule.Resources.Add(resource); - moduleIndex++; - } - context.Logger.EndProgress(); - } - - void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { - var dataType = new TypeDefUser("", "DataType", stubModule.CorLibTypes.GetTypeRef("System", "ValueType")); - dataType.Layout = TypeAttributes.ExplicitLayout; - dataType.Visibility = TypeAttributes.NestedPrivate; - dataType.IsSealed = true; - dataType.ClassLayout = new ClassLayoutUser(1, (uint)data.Length); - stubModule.GlobalType.NestedTypes.Add(dataType); - - var dataField = new FieldDefUser("DataField", new FieldSig(dataType.ToTypeSig())) { - IsStatic = true, - HasFieldRVA = true, - InitialValue = data, - Access = FieldAttributes.CompilerControlled - }; - stubModule.GlobalType.Fields.Add(dataField); - - MutationHelper.ReplacePlaceholder(method, arg => { - var repl = new List(); - repl.AddRange(arg); - repl.Add(Instruction.Create(OpCodes.Dup)); - repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField)); - repl.Add(Instruction.Create(OpCodes.Call, stubModule.Import( - typeof(RuntimeHelpers).GetMethod("InitializeArray")))); - return repl.ToArray(); - }); - } - - void InjectStub(ConfuserContext context, CompressorContext compCtx, ProtectionParameters parameters, ModuleDef stubModule) { - var rt = context.Registry.GetService(); - RandomGenerator random = context.Registry.GetService().GetRandomGenerator(Id); - var comp = context.Registry.GetService(); - - var rtType = rt.GetRuntimeType(compCtx.CompatMode ? "Confuser.Runtime.CompressorCompat" : "Confuser.Runtime.Compressor"); - IEnumerable defs = InjectHelper.Inject(rtType, stubModule.GlobalType, stubModule); - - switch (parameters.GetParameter(context, context.CurrentModule, "key", Mode.Normal)) { - case Mode.Normal: - compCtx.Deriver = new NormalDeriver(); - break; - case Mode.Dynamic: - compCtx.Deriver = new DynamicDeriver(); - break; - default: - throw new UnreachableException(); - } - compCtx.Deriver.Init(context, random); - - context.Logger.Debug("Encrypting modules..."); - - // Main - MethodDef entryPoint = defs.OfType().Single(method => method.Name == "Main"); - stubModule.EntryPoint = entryPoint; - - if (compCtx.EntryPoint.HasAttribute("System.STAThreadAttribute")) { - var attrType = stubModule.CorLibTypes.GetTypeRef("System", "STAThreadAttribute"); - var ctorSig = MethodSig.CreateInstance(stubModule.CorLibTypes.Void); - entryPoint.CustomAttributes.Add(new CustomAttribute( - new MemberRefUser(stubModule, ".ctor", ctorSig, attrType))); - } - else if (compCtx.EntryPoint.HasAttribute("System.MTAThreadAttribute")) { - var attrType = stubModule.CorLibTypes.GetTypeRef("System", "MTAThreadAttribute"); - var ctorSig = MethodSig.CreateInstance(stubModule.CorLibTypes.Void); - entryPoint.CustomAttributes.Add(new CustomAttribute( - new MemberRefUser(stubModule, ".ctor", ctorSig, attrType))); - } - - uint seed = random.NextUInt32(); - compCtx.OriginModule = context.OutputModules[compCtx.ModuleIndex]; - - byte[] encryptedModule = compCtx.Encrypt(comp, compCtx.OriginModule, seed, - progress => context.Logger.Progress((int)(progress * 10000), 10000)); - context.Logger.EndProgress(); - context.CheckCancellation(); - - compCtx.EncryptedModule = encryptedModule; - - MutationHelper.InjectKeys(entryPoint, - new[] { 0, 1 }, - new[] { encryptedModule.Length >> 2, (int)seed }); - InjectData(stubModule, entryPoint, encryptedModule); - - // Decrypt - MethodDef decrypter = defs.OfType().Single(method => method.Name == "Decrypt"); - decrypter.Body.SimplifyMacros(decrypter.Parameters); - List instrs = decrypter.Body.Instructions.ToList(); - for (int i = 0; i < instrs.Count; i++) { - Instruction instr = instrs[i]; - if (instr.OpCode == OpCodes.Call) { - var method = (IMethod)instr.Operand; - if (method.DeclaringType.Name == "Mutation" && - method.Name == "Crypt") { - Instruction ldDst = instrs[i - 2]; - Instruction ldSrc = instrs[i - 1]; - Debug.Assert(ldDst.OpCode == OpCodes.Ldloc && ldSrc.OpCode == OpCodes.Ldloc); - instrs.RemoveAt(i); - instrs.RemoveAt(i - 1); - instrs.RemoveAt(i - 2); - instrs.InsertRange(i - 2, compCtx.Deriver.EmitDerivation(decrypter, context, (Local)ldDst.Operand, (Local)ldSrc.Operand)); - } - else if (method.DeclaringType.Name == "Lzma" && - method.Name == "Decompress") { - MethodDef decomp = comp.GetRuntimeDecompressor(stubModule, member => { }); - instr.Operand = decomp; - } - } - } - decrypter.Body.Instructions.Clear(); - foreach (Instruction instr in instrs) - decrypter.Body.Instructions.Add(instr); - - // Pack modules - PackModules(context, compCtx, stubModule, comp, random); - } - - void ImportAssemblyTypeReferences(ModuleDef originModule, ModuleDef stubModule) { - var assembly = stubModule.Assembly; - foreach (var ca in assembly.CustomAttributes) { - if (ca.AttributeType.Scope == originModule) - ca.Constructor = (ICustomAttributeType)stubModule.Import(ca.Constructor); - } - foreach (var ca in assembly.DeclSecurities.SelectMany(declSec => declSec.CustomAttributes)) { - if (ca.AttributeType.Scope == originModule) - ca.Constructor = (ICustomAttributeType)stubModule.Import(ca.Constructor); - } - } - - class KeyInjector { - readonly CompressorContext ctx; - - public KeyInjector(CompressorContext ctx) { - this.ctx = ctx; - } - - public void WriterEvent(object sender, ModuleWriterEventArgs args) { - OnWriterEvent(args.Writer, args.Event); - } - - private void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { - if (evt == ModuleWriterEvent.MDBeginCreateTables) { - // Add key signature - uint sigBlob = writer.Metadata.BlobHeap.Add(ctx.KeySig); - uint sigRid = writer.Metadata.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(sigBlob)); - Debug.Assert(sigRid == 1); - uint sigToken = 0x11000000 | sigRid; - ctx.KeyToken = sigToken; - MutationHelper.InjectKey(writer.Module.EntryPoint, 2, (int)sigToken); - } - else if (evt == ModuleWriterEvent.MDBeginAddResources && !ctx.CompatMode) { - // Compute hash - byte[] hash = SHA1.Create().ComputeHash(ctx.OriginModule); - uint hashBlob = writer.Metadata.BlobHeap.Add(hash); - - MDTable fileTbl = writer.Metadata.TablesHeap.FileTable; - uint fileRid = fileTbl.Add(new RawFileRow( - (uint)FileAttributes.ContainsMetadata, - writer.Metadata.StringsHeap.Add("koi"), - hashBlob)); - uint impl = CodedToken.Implementation.Encode(new MDToken(Table.File, fileRid)); - - // Add resources - MDTable resTbl = writer.Metadata.TablesHeap.ManifestResourceTable; - foreach (var resource in ctx.ManifestResources) - resTbl.Add(new RawManifestResourceRow(resource.Offset, resource.Flags, writer.Metadata.StringsHeap.Add(resource.Value), impl)); - - // Add exported types - var exTbl = writer.Metadata.TablesHeap.ExportedTypeTable; - foreach (var type in ctx.OriginModuleDef.GetTypes()) { - if (!type.IsVisibleOutside()) - continue; - exTbl.Add(new RawExportedTypeRow((uint)type.Attributes, 0, - writer.Metadata.StringsHeap.Add(type.Name), - writer.Metadata.StringsHeap.Add(type.Namespace), impl)); - } - } - } - } - } -} + var snPubSigKey = context.Annotations.Get(originModule, Marker.SNSigPubKey); + + using (var ms = new MemoryStream()) { + var options = new ModuleWriterOptions(stubModule) { + StrongNameKey = snKey, + StrongNamePublicKey = snPubKey, + DelaySign = snDelaySig + }; + var injector = new KeyInjector(ctx); + options.WriterEvent += injector.WriterEvent; + + stubModule.Write(ms, options); + context.CheckCancellation(); + ProtectStub(context, context.OutputPaths[ctx.ModuleIndex], ms.ToArray(), snKey, snPubKey, snSigKey, snPubKey, snDelaySig, new StubProtection(ctx, originModule)); + } + } + + static string GetId(byte[] module) { + var md = MetadataFactory.CreateMetadata(new PEImage(module)); + var assembly = new AssemblyNameInfo(); + if (md.TablesStream.TryReadAssemblyRow(1, out var assemblyRow)) { + assembly.Name = md.StringsStream.ReadNoNull(assemblyRow.Name); + assembly.Culture = md.StringsStream.ReadNoNull(assemblyRow.Locale); + assembly.PublicKeyOrToken = new PublicKey(md.BlobStream.Read(assemblyRow.PublicKey)); + assembly.HashAlgId = (AssemblyHashAlgorithm)assemblyRow.HashAlgId; + assembly.Version = new Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber); + assembly.Attributes = (AssemblyAttributes)assemblyRow.Flags; + } + return GetId(assembly); + } + + static string GetId(IAssembly assembly) { + return new SR.AssemblyName(assembly.FullName).FullName.ToUpperInvariant(); + } + + void PackModules(ConfuserContext context, CompressorContext compCtx, ModuleDef stubModule, ICompressionService comp, RandomGenerator random) { + int maxLen = 0; + var modules = new Dictionary(); + for (int i = 0; i < context.OutputModules.Count; i++) { + if (i == compCtx.ModuleIndex) + continue; + + string id = GetId(context.Modules[i].Assembly); + modules.Add(id, context.OutputModules[i]); + + int strLen = Encoding.UTF8.GetByteCount(id); + if (strLen > maxLen) + maxLen = strLen; + } + foreach (var extModule in context.ExternalModules) { + var name = GetId(extModule).ToUpperInvariant(); + modules.Add(name, extModule); + + int strLen = Encoding.UTF8.GetByteCount(name); + if (strLen > maxLen) + maxLen = strLen; + } + + byte[] key = random.NextBytes(4 + maxLen); + key[0] = (byte)(compCtx.EntryPointToken >> 0); + key[1] = (byte)(compCtx.EntryPointToken >> 8); + key[2] = (byte)(compCtx.EntryPointToken >> 16); + key[3] = (byte)(compCtx.EntryPointToken >> 24); + for (int i = 4; i < key.Length; i++) // no zero bytes + key[i] |= 1; + compCtx.KeySig = key; + + int moduleIndex = 0; + foreach (var entry in modules) { + byte[] name = Encoding.UTF8.GetBytes(entry.Key); + for (int i = 0; i < name.Length; i++) + name[i] *= key[i + 4]; + + uint state = 0x6fff61; + foreach (byte chr in name) + state = state * 0x5e3f1f + chr; + byte[] encrypted = compCtx.Encrypt(comp, entry.Value, state, progress => { + progress = (progress + moduleIndex) / modules.Count; + context.Logger.Progress((int)(progress * 10000), 10000); + }); + context.CheckCancellation(); + + var resource = new EmbeddedResource(Convert.ToBase64String(name), encrypted, ManifestResourceAttributes.Private); + stubModule.Resources.Add(resource); + moduleIndex++; + } + context.Logger.EndProgress(); + } + + void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { + var dataType = new TypeDefUser("", "DataType", stubModule.CorLibTypes.GetTypeRef("System", "ValueType")); + dataType.Layout = TypeAttributes.ExplicitLayout; + dataType.Visibility = TypeAttributes.NestedPrivate; + dataType.IsSealed = true; + dataType.ClassLayout = new ClassLayoutUser(1, (uint)data.Length); + stubModule.GlobalType.NestedTypes.Add(dataType); + + var dataField = new FieldDefUser("DataField", new FieldSig(dataType.ToTypeSig())) { + IsStatic = true, + HasFieldRVA = true, + InitialValue = data, + Access = FieldAttributes.CompilerControlled + }; + stubModule.GlobalType.Fields.Add(dataField); + + MutationHelper.ReplacePlaceholder(method, arg => { + var repl = new List(); + repl.AddRange(arg); + repl.Add(Instruction.Create(OpCodes.Dup)); + repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField)); + repl.Add(Instruction.Create(OpCodes.Call, stubModule.Import( + typeof(RuntimeHelpers).GetMethod("InitializeArray")))); + return repl.ToArray(); + }); + } + + void InjectStub(ConfuserContext context, CompressorContext compCtx, ProtectionParameters parameters, ModuleDef stubModule) { + var rt = context.Registry.GetService(); + RandomGenerator random = context.Registry.GetService().GetRandomGenerator(Id); + var comp = context.Registry.GetService(); + + var rtType = rt.GetRuntimeType(compCtx.CompatMode ? "Confuser.Runtime.CompressorCompat" : "Confuser.Runtime.Compressor"); + IEnumerable defs = InjectHelper.Inject(rtType, stubModule.GlobalType, stubModule); + + switch (parameters.GetParameter(context, context.CurrentModule, "key", Mode.Normal)) { + case Mode.Normal: + compCtx.Deriver = new NormalDeriver(); + break; + case Mode.Dynamic: + compCtx.Deriver = new DynamicDeriver(); + break; + default: + throw new UnreachableException(); + } + compCtx.Deriver.Init(context, random); + + context.Logger.Debug(Properties.Resources.Compressor_InjectStub_Encrypting_modules); + + // Main + MethodDef entryPoint = defs.OfType().Single(method => method.Name == "Main"); + stubModule.EntryPoint = entryPoint; + + if (compCtx.EntryPoint.HasAttribute("System.STAThreadAttribute")) { + var attrType = stubModule.CorLibTypes.GetTypeRef("System", "STAThreadAttribute"); + var ctorSig = MethodSig.CreateInstance(stubModule.CorLibTypes.Void); + entryPoint.CustomAttributes.Add(new CustomAttribute( + new MemberRefUser(stubModule, ".ctor", ctorSig, attrType))); + } + else if (compCtx.EntryPoint.HasAttribute("System.MTAThreadAttribute")) { + var attrType = stubModule.CorLibTypes.GetTypeRef("System", "MTAThreadAttribute"); + var ctorSig = MethodSig.CreateInstance(stubModule.CorLibTypes.Void); + entryPoint.CustomAttributes.Add(new CustomAttribute( + new MemberRefUser(stubModule, ".ctor", ctorSig, attrType))); + } + + uint seed = random.NextUInt32(); + compCtx.OriginModule = context.OutputModules[compCtx.ModuleIndex]; + + byte[] encryptedModule = compCtx.Encrypt(comp, compCtx.OriginModule, seed, + progress => context.Logger.Progress((int)(progress * 10000), 10000)); + context.Logger.EndProgress(); + context.CheckCancellation(); + + compCtx.EncryptedModule = encryptedModule; + + MutationHelper.InjectKeys(entryPoint, + new[] { 0, 1 }, + new[] { encryptedModule.Length >> 2, (int)seed }); + InjectData(stubModule, entryPoint, encryptedModule); + + // Decrypt + MethodDef decrypter = defs.OfType().Single(method => method.Name == "Decrypt"); + decrypter.Body.SimplifyMacros(decrypter.Parameters); + List instrs = decrypter.Body.Instructions.ToList(); + for (int i = 0; i < instrs.Count; i++) { + Instruction instr = instrs[i]; + if (instr.OpCode == OpCodes.Call) { + var method = (IMethod)instr.Operand; + if (method.DeclaringType.Name == "Mutation" && + method.Name == "Crypt") { + Instruction ldDst = instrs[i - 2]; + Instruction ldSrc = instrs[i - 1]; + Debug.Assert(ldDst.OpCode == OpCodes.Ldloc && ldSrc.OpCode == OpCodes.Ldloc); + instrs.RemoveAt(i); + instrs.RemoveAt(i - 1); + instrs.RemoveAt(i - 2); + instrs.InsertRange(i - 2, compCtx.Deriver.EmitDerivation(decrypter, context, (Local)ldDst.Operand, (Local)ldSrc.Operand)); + } + else if (method.DeclaringType.Name == "Lzma" && + method.Name == "Decompress") { + MethodDef decomp = comp.GetRuntimeDecompressor(stubModule, member => { }); + instr.Operand = decomp; + } + } + } + decrypter.Body.Instructions.Clear(); + foreach (Instruction instr in instrs) + decrypter.Body.Instructions.Add(instr); + + // Pack modules + PackModules(context, compCtx, stubModule, comp, random); + } + + void ImportAssemblyTypeReferences(ModuleDef originModule, ModuleDef stubModule) { + var assembly = stubModule.Assembly; + foreach (var ca in assembly.CustomAttributes) { + if (ca.AttributeType.Scope == originModule) + ca.Constructor = (ICustomAttributeType)stubModule.Import(ca.Constructor); + } + foreach (var ca in assembly.DeclSecurities.SelectMany(declSec => declSec.CustomAttributes)) { + if (ca.AttributeType.Scope == originModule) + ca.Constructor = (ICustomAttributeType)stubModule.Import(ca.Constructor); + } + } + + class KeyInjector { + readonly CompressorContext ctx; + + public KeyInjector(CompressorContext ctx) { + this.ctx = ctx; + } + + public void WriterEvent(object sender, ModuleWriterEventArgs args) { + OnWriterEvent(args.Writer, args.Event); + } + + private void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) { + if (evt == ModuleWriterEvent.MDBeginCreateTables) { + // Add key signature + uint sigBlob = writer.Metadata.BlobHeap.Add(ctx.KeySig); + uint sigRid = writer.Metadata.TablesHeap.StandAloneSigTable.Add(new RawStandAloneSigRow(sigBlob)); + Debug.Assert(sigRid == 1); + uint sigToken = 0x11000000 | sigRid; + ctx.KeyToken = sigToken; + MutationHelper.InjectKey(writer.Module.EntryPoint, 2, (int)sigToken); + } + else if (evt == ModuleWriterEvent.MDBeginAddResources && !ctx.CompatMode) { + // Compute hash + byte[] hash = SHA1.Create().ComputeHash(ctx.OriginModule); + uint hashBlob = writer.Metadata.BlobHeap.Add(hash); + + MDTable fileTbl = writer.Metadata.TablesHeap.FileTable; + uint fileRid = fileTbl.Add(new RawFileRow( + (uint)FileAttributes.ContainsMetadata, + writer.Metadata.StringsHeap.Add("koi"), + hashBlob)); + uint impl = CodedToken.Implementation.Encode(new MDToken(Table.File, fileRid)); + + // Add resources + MDTable resTbl = writer.Metadata.TablesHeap.ManifestResourceTable; + foreach (var resource in ctx.ManifestResources) + resTbl.Add(new RawManifestResourceRow(resource.Offset, resource.Flags, writer.Metadata.StringsHeap.Add(resource.Value), impl)); + + // Add exported types + var exTbl = writer.Metadata.TablesHeap.ExportedTypeTable; + foreach (var type in ctx.OriginModuleDef.GetTypes()) { + if (!type.IsVisibleOutside()) + continue; + exTbl.Add(new RawExportedTypeRow((uint)type.Attributes, 0, + writer.Metadata.StringsHeap.Add(type.Name), + writer.Metadata.StringsHeap.Add(type.Namespace), impl)); + } + } + } + } + } +} diff --git a/Confuser.Protections/Compress/ExtractPhase.cs b/Confuser.Protections/Compress/ExtractPhase.cs index 24fd835b0..b70b70226 100644 --- a/Confuser.Protections/Compress/ExtractPhase.cs +++ b/Confuser.Protections/Compress/ExtractPhase.cs @@ -17,7 +17,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Packer info extraction"; } + get { return Properties.Resources.ExtractPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { diff --git a/Confuser.Protections/Compress/StubProtection.cs b/Confuser.Protections/Compress/StubProtection.cs index 784e9482a..e2904536a 100644 --- a/Confuser.Protections/Compress/StubProtection.cs +++ b/Confuser.Protections/Compress/StubProtection.cs @@ -18,11 +18,11 @@ internal StubProtection(CompressorContext ctx, ModuleDef originModule) { } public override string Name { - get { return "Compressor Stub Protection"; } + get { return Properties.Resources.StubProtectionName; } } public override string Description { - get { return "Do some extra works on the protected stub."; } + get { return Properties.Resources.StubProtectionDescription; } } public override string Id { @@ -60,7 +60,7 @@ public override bool ProcessAll { } public override string Name { - get { return "Module injection"; } + get { return Properties.Resources.StubProtectionInjPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -80,7 +80,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Packer info encoding"; } + get { return Properties.Resources.StubProtectionSigPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -114,4 +114,4 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa } } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/Confuser.Protections.csproj b/Confuser.Protections/Confuser.Protections.csproj index 8584200be..df8b58814 100644 --- a/Confuser.Protections/Confuser.Protections.csproj +++ b/Confuser.Protections/Confuser.Protections.csproj @@ -4,7 +4,7 @@ - net461;netstandard2.0 + net462;netstandard2.0 true ..\ConfuserEx.snk @@ -21,7 +21,22 @@ - + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + diff --git a/Confuser.Protections/Constants/ConstantProtection.cs b/Confuser.Protections/Constants/ConstantProtection.cs index bfa304746..e9a714c4b 100644 --- a/Confuser.Protections/Constants/ConstantProtection.cs +++ b/Confuser.Protections/Constants/ConstantProtection.cs @@ -16,11 +16,11 @@ internal class ConstantProtection : Protection, IConstantService { internal static readonly object ContextKey = new object(); public override string Name { - get { return "Constants Protection"; } + get { return Properties.Resources.ConstantProtectionName; } } public override string Description { - get { return "This protection encodes and compresses constants in the code."; } + get { return Properties.Resources.ConstantProtectionDescription; } } public override string Id { @@ -48,4 +48,4 @@ protected override void PopulatePipeline(ProtectionPipeline pipeline) { pipeline.InsertPostStage(PipelineStage.ProcessModule, new EncodePhase(this)); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/Constants/EncodePhase.cs b/Confuser.Protections/Constants/EncodePhase.cs index 4eba9118e..d0256d8e9 100644 --- a/Confuser.Protections/Constants/EncodePhase.cs +++ b/Confuser.Protections/Constants/EncodePhase.cs @@ -21,7 +21,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Constants encoding"; } + get { return Properties.Resources.EncodePhaseConstantsName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { diff --git a/Confuser.Protections/Constants/InjectPhase.cs b/Confuser.Protections/Constants/InjectPhase.cs index c8d0c3318..1273d7a90 100644 --- a/Confuser.Protections/Constants/InjectPhase.cs +++ b/Confuser.Protections/Constants/InjectPhase.cs @@ -21,7 +21,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Constant encryption helpers injection"; } + get { return Properties.Resources.InjectPhaseConstantName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -175,4 +175,4 @@ void MutateInitializer(CEContext moduleCtx, MethodDef decomp) { moduleCtx.InitMethod.Body.Instructions.Add(instr); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/ControlFlow/ControlFlowPhase.cs b/Confuser.Protections/ControlFlow/ControlFlowPhase.cs index 3f1b15e28..7b840f626 100644 --- a/Confuser.Protections/ControlFlow/ControlFlowPhase.cs +++ b/Confuser.Protections/ControlFlow/ControlFlowPhase.cs @@ -23,7 +23,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Control flow mangling"; } + get { return Properties.Resources.ControlFlowPhaseName; } } CFContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RandomGenerator random, bool disableOpti) { diff --git a/Confuser.Protections/ControlFlow/ControlFlowProtection.cs b/Confuser.Protections/ControlFlow/ControlFlowProtection.cs index 8a58222a1..1e9d1209e 100644 --- a/Confuser.Protections/ControlFlow/ControlFlowProtection.cs +++ b/Confuser.Protections/ControlFlow/ControlFlowProtection.cs @@ -14,11 +14,11 @@ internal class ControlFlowProtection : Protection, IControlFlowService { public const string _ServiceId = "Ki.ControlFlow"; public override string Name { - get { return "Control Flow Protection"; } + get { return Properties.Resources.ControlFlowProtectionName; } } public override string Description { - get { return "This protection mangles the code in the methods so that decompilers cannot decompile the methods."; } + get { return Properties.Resources.ControlFlowProtectionDescription; } } public override string Id { @@ -45,4 +45,4 @@ protected override void PopulatePipeline(ProtectionPipeline pipeline) { pipeline.InsertPreStage(PipelineStage.OptimizeMethods, new ControlFlowPhase(this)); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/HardeningPhase.cs b/Confuser.Protections/HardeningPhase.cs index 88de86bff..459c52924 100644 --- a/Confuser.Protections/HardeningPhase.cs +++ b/Confuser.Protections/HardeningPhase.cs @@ -17,7 +17,7 @@ public HardeningPhase(HardeningProtection parent) : base(parent) { } public override ProtectionTargets Targets => ProtectionTargets.Modules; /// - public override string Name => "Hardening Phase"; + public override string Name => Properties.Resources.HardeningPhaseName; /// public override bool ProcessAll => false; diff --git a/Confuser.Protections/HardeningProtection.cs b/Confuser.Protections/HardeningProtection.cs index 8e4cbfe18..42b8edd9f 100644 --- a/Confuser.Protections/HardeningProtection.cs +++ b/Confuser.Protections/HardeningProtection.cs @@ -5,10 +5,10 @@ namespace Confuser.Protections { [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Instantiated by reflection.")] internal sealed class HardeningProtection : Protection { /// - public override string Name => "Protection Hardening"; + public override string Name => Properties.Resources.HardeningProtectionName; /// - public override string Description => "This component improves the protection code, making it harder to circumvent it."; + public override string Description => Properties.Resources.HardeningProtectionDescription; /// public override string Id => "harden"; diff --git a/Confuser.Protections/InvalidMetadataProtection.cs b/Confuser.Protections/InvalidMetadataProtection.cs index d2093a290..a5e3ef4da 100644 --- a/Confuser.Protections/InvalidMetadataProtection.cs +++ b/Confuser.Protections/InvalidMetadataProtection.cs @@ -13,11 +13,11 @@ internal class InvalidMetadataProtection : Protection { public const string _FullId = "Ki.InvalidMD"; public override string Name { - get { return "Invalid Metadata Protection"; } + get { return Properties.Resources.InvalidMetadataProtectionName; } } public override string Description { - get { return "This protection adds invalid metadata to modules to prevent disassembler/decompiler from opening them."; } + get { return Properties.Resources.InvalidMetadataProtectionDescription; } } public override string Id { @@ -51,7 +51,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Invalid metadata addition"; } + get { return Properties.Resources.InvalidMetadataProtectionInvalidMDPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { diff --git a/Confuser.Protections/Properties/Resources.Designer.cs b/Confuser.Protections/Properties/Resources.Designer.cs new file mode 100644 index 000000000..5ed9f05ca --- /dev/null +++ b/Confuser.Protections/Properties/Resources.Designer.cs @@ -0,0 +1,477 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Confuser.Protections.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Confuser.Protections.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找类似 Type scanner 的本地化字符串。 + /// + internal static string AnalyzePhaseName { + get { + return ResourceManager.GetString("AnalyzePhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Anti-debug injection 的本地化字符串。 + /// + internal static string AntiDebugProtectionAntiDebugPhaseName { + get { + return ResourceManager.GetString("AntiDebugProtectionAntiDebugPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This protection prevents the assembly from being debugged or profiled. 的本地化字符串。 + /// + internal static string AntiDebugProtectionDescription { + get { + return ResourceManager.GetString("AntiDebugProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Anti Debug Protection 的本地化字符串。 + /// + internal static string AntiDebugProtectionName { + get { + return ResourceManager.GetString("AntiDebugProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Anti-dump injection 的本地化字符串。 + /// + internal static string AntiDumpPhase_Name { + get { + return ResourceManager.GetString("AntiDumpPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 This protection prevents the assembly from being dumped from memory. 的本地化字符串。 + /// + internal static string AntiDumpProtectionDescription { + get { + return ResourceManager.GetString("AntiDumpProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Hardening Phase 的本地化字符串。 + /// + internal static string AntiDumpProtectionName { + get { + return ResourceManager.GetString("AntiDumpProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Anti-ILDasm marking 的本地化字符串。 + /// + internal static string AntiILDasmPhaseName { + get { + return ResourceManager.GetString("AntiILDasmPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This protection marks the module with a attribute that discourage ILDasm from disassembling it. 的本地化字符串。 + /// + internal static string AntiILDasmProtectionDescription { + get { + return ResourceManager.GetString("AntiILDasmProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Anti IL Dasm Protection 的本地化字符串。 + /// + internal static string AntiILDasmProtectionName { + get { + return ResourceManager.GetString("AntiILDasmProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 This protection ensures the integrity of application. 的本地化字符串。 + /// + internal static string AntiTamperProtectionDescription { + get { + return ResourceManager.GetString("AntiTamperProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Anti-tamper helpers injection 的本地化字符串。 + /// + internal static string AntiTamperProtectionInjectPhaseName { + get { + return ResourceManager.GetString("AntiTamperProtectionInjectPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Anti Tamper Protection 的本地化字符串。 + /// + internal static string AntiTamperProtectionName { + get { + return ResourceManager.GetString("AntiTamperProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Encrypting modules... 的本地化字符串。 + /// + internal static string Compressor_InjectStub_Encrypting_modules { + get { + return ResourceManager.GetString("Compressor_InjectStub_Encrypting_modules", resourceCulture); + } + } + + /// + /// 查找类似 No executable module! 的本地化字符串。 + /// + internal static string Compressor_Pack_No_executable_module { + get { + return ResourceManager.GetString("Compressor_Pack_No_executable_module", resourceCulture); + } + } + + /// + /// 查找类似 This packer reduces the size of output. 的本地化字符串。 + /// + internal static string CompressorDescription { + get { + return ResourceManager.GetString("CompressorDescription", resourceCulture); + } + } + + /// + /// 查找类似 Compressing Packer 的本地化字符串。 + /// + internal static string CompressorName { + get { + return ResourceManager.GetString("CompressorName", resourceCulture); + } + } + + /// + /// 查找类似 This protection encodes and compresses constants in the code. 的本地化字符串。 + /// + internal static string ConstantProtectionDescription { + get { + return ResourceManager.GetString("ConstantProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Constants Protection 的本地化字符串。 + /// + internal static string ConstantProtectionName { + get { + return ResourceManager.GetString("ConstantProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Control flow mangling 的本地化字符串。 + /// + internal static string ControlFlowPhaseName { + get { + return ResourceManager.GetString("ControlFlowPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This protection mangles the code in the methods so that decompilers cannot decompile the methods. 的本地化字符串。 + /// + internal static string ControlFlowProtectionDescription { + get { + return ResourceManager.GetString("ControlFlowProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Control Flow Protection 的本地化字符串。 + /// + internal static string ControlFlowProtectionName { + get { + return ResourceManager.GetString("ControlFlowProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Constants encoding 的本地化字符串。 + /// + internal static string EncodePhaseConstantsName { + get { + return ResourceManager.GetString("EncodePhaseConstantsName", resourceCulture); + } + } + + /// + /// 查找类似 Packer info extraction 的本地化字符串。 + /// + internal static string ExtractPhaseName { + get { + return ResourceManager.GetString("ExtractPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Hardening Phase 的本地化字符串。 + /// + internal static string HardeningPhaseName { + get { + return ResourceManager.GetString("HardeningPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This component improves the protection code, making it harder to circumvent it. 的本地化字符串。 + /// + internal static string HardeningProtectionDescription { + get { + return ResourceManager.GetString("HardeningProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Protection Hardening 的本地化字符串。 + /// + internal static string HardeningProtectionName { + get { + return ResourceManager.GetString("HardeningProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Constant encryption helpers injection 的本地化字符串。 + /// + internal static string InjectPhaseConstantName { + get { + return ResourceManager.GetString("InjectPhaseConstantName", resourceCulture); + } + } + + /// + /// 查找类似 Resource encryption helpers injection 的本地化字符串。 + /// + internal static string InjectPhaseName { + get { + return ResourceManager.GetString("InjectPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This protection adds invalid metadata to modules to prevent disassembler/decompiler from opening them. 的本地化字符串。 + /// + internal static string InvalidMetadataProtectionDescription { + get { + return ResourceManager.GetString("InvalidMetadataProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Invalid metadata addition 的本地化字符串。 + /// + internal static string InvalidMetadataProtectionInvalidMDPhaseName { + get { + return ResourceManager.GetString("InvalidMetadataProtectionInvalidMDPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Invalid Metadata Protection 的本地化字符串。 + /// + internal static string InvalidMetadataProtectionName { + get { + return ResourceManager.GetString("InvalidMetadataProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Encrypting resources... 的本地化字符串。 + /// + internal static string MDPhase_EncryptingResourcesText { + get { + return ResourceManager.GetString("MDPhase_EncryptingResourcesText", resourceCulture); + } + } + + /// + /// 查找类似 Anti-tamper metadata preparation 的本地化字符串。 + /// + internal static string MDPhase_Name { + get { + return ResourceManager.GetString("MDPhase_Name", resourceCulture); + } + } + + /// + /// 查找类似 Encoding reference proxies 的本地化字符串。 + /// + internal static string ReferenceProxyPhaseName { + get { + return ResourceManager.GetString("ReferenceProxyPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 This protection encodes and hides references to type/method/fields. 的本地化字符串。 + /// + internal static string ReferenceProxyProtectionDescription { + get { + return ResourceManager.GetString("ReferenceProxyProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Reference Proxy Protection 的本地化字符串。 + /// + internal static string ReferenceProxyProtectionName { + get { + return ResourceManager.GetString("ReferenceProxyProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 This protection encodes and compresses the embedded resources. 的本地化字符串。 + /// + internal static string ResourceProtectionDescription { + get { + return ResourceManager.GetString("ResourceProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Resources Protection 的本地化字符串。 + /// + internal static string ResourceProtectionName { + get { + return ResourceManager.GetString("ResourceProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Type scrambler 的本地化字符串。 + /// + internal static string ScramblePhaseName { + get { + return ResourceManager.GetString("ScramblePhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Do some extra works on the protected stub. 的本地化字符串。 + /// + internal static string StubProtectionDescription { + get { + return ResourceManager.GetString("StubProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Module injection 的本地化字符串。 + /// + internal static string StubProtectionInjPhaseName { + get { + return ResourceManager.GetString("StubProtectionInjPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Compressor Stub Protection 的本地化字符串。 + /// + internal static string StubProtectionName { + get { + return ResourceManager.GetString("StubProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Packer info encoding 的本地化字符串。 + /// + internal static string StubProtectionSigPhaseName { + get { + return ResourceManager.GetString("StubProtectionSigPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Replaces types with generics 的本地化字符串。 + /// + internal static string TypeScrambleProtectionDescription { + get { + return ResourceManager.GetString("TypeScrambleProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Type Scrambler 的本地化字符串。 + /// + internal static string TypeScrambleProtectionName { + get { + return ResourceManager.GetString("TypeScrambleProtectionName", resourceCulture); + } + } + } +} diff --git a/Confuser.Protections/Properties/Resources.resx b/Confuser.Protections/Properties/Resources.resx new file mode 100644 index 000000000..8cf60975c --- /dev/null +++ b/Confuser.Protections/Properties/Resources.resx @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Invalid Metadata Protection + + + This protection adds invalid metadata to modules to prevent disassembler/decompiler from opening them. + + + Invalid metadata addition + + + Protection Hardening + + + This protection marks the module with a attribute that discourage ILDasm from disassembling it. + + + Hardening Phase + + + Hardening Phase + + + Anti-ILDasm marking + + + This component improves the protection code, making it harder to circumvent it. + + + This protection prevents the assembly from being dumped from memory. + + + Anti Debug Protection + + + This protection prevents the assembly from being debugged or profiled. + + + Anti-debug injection + + + Anti Tamper Protection + + + This protection ensures the integrity of application. + + + Anti-tamper helpers injection + + + Compressor Stub Protection + + + Do some extra works on the protected stub. + + + Module injection + + + Packer info encoding + + + Constants Protection + + + This protection encodes and compresses constants in the code. + + + Control Flow Protection + + + This protection mangles the code in the methods so that decompilers cannot decompile the methods. + + + Reference Proxy Protection + + + This protection encodes and hides references to type/method/fields. + + + Resources Protection + + + This protection encodes and compresses the embedded resources. + + + Type Scrambler + + + Replaces types with generics + + + Type scrambler + + + Type scanner + + + Encrypting resources... + + + Resource encryption helpers injection + + + Encoding reference proxies + + + Control flow mangling + + + Constant encryption helpers injection + + + Constants encoding + + + Packer info extraction + + + Anti IL Dasm Protection + + + Anti-dump injection + + + Anti-tamper metadata preparation + + + Compressing Packer + + + This packer reduces the size of output. + + + No executable module! + + + Encrypting modules... + + diff --git a/Confuser.Protections/Properties/Resources.zh-Hans.resx b/Confuser.Protections/Properties/Resources.zh-Hans.resx new file mode 100644 index 000000000..c8c9ea3a7 --- /dev/null +++ b/Confuser.Protections/Properties/Resources.zh-Hans.resx @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 无效的元数据保护 + + + 此保护将无效的元数据添加到模块中,以防止反汇编程序/反编译器打开它们。 + + + 添加无效的元数据 + + + 将模块标记一个属性,以阻止ILDASM对其进行反编译。 + + + 内存转储保护 + + + 强化阶段 + + + 反ILDasm标记 + + + 保护加强 + + + 该组件改进了保护代码,使其难以规避。 + + + 此保护可防止程序集从内存中转储。 + + + 反调试保护 + + + 此保护可防止对程序集进行调试或分析。 + + + 反调试注入 + + + 正在加密资源... + + + 防篡改保护 + + + 确保应用程序的完整性,防止窜改程序集。 + + + 防篡改保护注入 + + + 压缩打包程序保护 + + + 在受保护的存根上做一些额外的工作。 + + + 模块注入 + + + 打包程序信息编码 + + + 常量保护 + + + 在代码中编码和压缩常量。 + + + 流程控制保护 + + + 这种保护会破坏方法中的代码,以便反编译器无法反编译方法。 + + + 引用代理保护 + + + 对类型/方法/字段进行编码并隐藏引用。 + + + 资源保护 + + + 此保护可对嵌入式资源进行编码和压缩。 + + + 类型干扰器 + + + 使用泛型替换方法参数传入的类型 + + + 类型干扰器 + + + 类型扫描 + + + 资源加密注入 + + + 编码引用代理 + + + 控制流处理 + + + 常量加密注入 + + + 常量编码 + + + 打包信息提取 + + + IL Dasm 反编译保护 + + + 防篡改元数据 + + + 反内存转储注入 + + + 此压缩包可以减小输出文件大小。 + + + 压缩打包 + + + 没有可执行模块! + + + 加密模块中... + + diff --git a/Confuser.Protections/ReferenceProxy/MildMode.cs b/Confuser.Protections/ReferenceProxy/MildMode.cs index fcc50f435..e5c625455 100644 --- a/Confuser.Protections/ReferenceProxy/MildMode.cs +++ b/Confuser.Protections/ReferenceProxy/MildMode.cs @@ -13,8 +13,12 @@ public override void ProcessCall(RPContext ctx, int instrIndex) { Instruction invoke = ctx.Body.Instructions[instrIndex]; var target = (IMethod)invoke.Operand; + // Value type proxy is not supported in mild mode. - if (target.DeclaringType.ResolveTypeDefThrow().IsValueType) + var typeDef = target.DeclaringType.ResolveTypeDef(); + if (typeDef == null) + return; + if (typeDef.IsValueType) return; // Skipping visibility is not supported in mild mode. if (!target.ResolveThrow().IsPublic && !target.ResolveThrow().IsAssembly) @@ -72,4 +76,4 @@ public override void ProcessCall(RPContext ctx, int instrIndex) { public override void Finalize(RPContext ctx) { } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/ReferenceProxy/ReferenceProxyPhase.cs b/Confuser.Protections/ReferenceProxy/ReferenceProxyPhase.cs index f9f8c64b0..33a06fb04 100644 --- a/Confuser.Protections/ReferenceProxy/ReferenceProxyPhase.cs +++ b/Confuser.Protections/ReferenceProxy/ReferenceProxyPhase.cs @@ -19,7 +19,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Encoding reference proxies"; } + get { return Properties.Resources.ReferenceProxyPhaseName; } } RPContext ParseParameters(MethodDef method, ConfuserContext context, ProtectionParameters parameters, RPStore store) { @@ -147,7 +147,8 @@ void ProcessMethod(RPContext ctx) { if (operand.MethodSig.ParamsAfterSentinel != null && operand.MethodSig.ParamsAfterSentinel.Count > 0) continue; - TypeDef declType = operand.DeclaringType.ResolveTypeDefThrow(); + var declType = operand.DeclaringType.ResolveTypeDef(); + if (declType is null) continue; // No delegates if (declType.IsDelegate()) continue; diff --git a/Confuser.Protections/ReferenceProxy/ReferenceProxyProtection.cs b/Confuser.Protections/ReferenceProxy/ReferenceProxyProtection.cs index 7a5ecc57b..bb8e58abe 100644 --- a/Confuser.Protections/ReferenceProxy/ReferenceProxyProtection.cs +++ b/Confuser.Protections/ReferenceProxy/ReferenceProxyProtection.cs @@ -21,11 +21,11 @@ internal class ReferenceProxyProtection : Protection, IReferenceProxyService { internal static object Targeted = new object(); public override string Name { - get { return "Reference Proxy Protection"; } + get { return Properties.Resources.ReferenceProxyProtectionName; } } public override string Description { - get { return "This protection encodes and hides references to type/method/fields."; } + get { return Properties.Resources.ReferenceProxyProtectionDescription; } } public override string Id { @@ -60,4 +60,4 @@ protected override void PopulatePipeline(ProtectionPipeline pipeline) { pipeline.InsertPreStage(PipelineStage.ProcessModule, new ReferenceProxyPhase(this)); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/ReferenceProxy/StrongMode.cs b/Confuser.Protections/ReferenceProxy/StrongMode.cs index 766c777cc..04cd47765 100644 --- a/Confuser.Protections/ReferenceProxy/StrongMode.cs +++ b/Confuser.Protections/ReferenceProxy/StrongMode.cs @@ -64,7 +64,9 @@ internal class StrongMode : RPMode { public override void ProcessCall(RPContext ctx, int instrIndex) { Instruction invoke = ctx.Body.Instructions[instrIndex]; - TypeDef declType = ((IMethod)invoke.Operand).DeclaringType.ResolveTypeDefThrow(); + TypeDef declType = ((IMethod)invoke.Operand).DeclaringType.ResolveTypeDef(); + if (declType == null) + return; if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules. return; if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too. @@ -88,7 +90,9 @@ void ProcessBridge(RPContext ctx, int instrIndex) { Instruction instr = ctx.Body.Instructions[instrIndex]; var target = (IMethod)instr.Operand; - TypeDef declType = target.DeclaringType.ResolveTypeDefThrow(); + var declType = target.DeclaringType.ResolveTypeDef(); + if (declType == null) + return; if (!declType.Module.IsILOnly) // Reflection doesn't like mixed mode modules. return; if (declType.IsGlobalModuleType) // Reflection doesn't like global methods too. diff --git a/Confuser.Protections/Resources/InjectPhase.cs b/Confuser.Protections/Resources/InjectPhase.cs index 540591750..0657033f5 100644 --- a/Confuser.Protections/Resources/InjectPhase.cs +++ b/Confuser.Protections/Resources/InjectPhase.cs @@ -21,7 +21,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Resource encryption helpers injection"; } + get { return Properties.Resources.InjectPhaseName; } } protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { @@ -143,4 +143,4 @@ void MutateInitializer(REContext moduleCtx, MethodDef decomp) { moduleCtx.Context.Registry.GetService().ExcludeMethod(moduleCtx.Context, moduleCtx.InitMethod); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/Resources/MDPhase.cs b/Confuser.Protections/Resources/MDPhase.cs index 13f6b8b73..0ca21370c 100644 --- a/Confuser.Protections/Resources/MDPhase.cs +++ b/Confuser.Protections/Resources/MDPhase.cs @@ -28,7 +28,7 @@ void OnWriterEvent(object sender, ModuleWriterEventArgs e) { var writer = (ModuleWriterBase)sender; if (e.Event == ModuleWriterEvent.MDBeginAddResources) { ctx.Context.CheckCancellation(); - ctx.Context.Logger.Debug("Encrypting resources..."); + ctx.Context.Logger.Debug(Properties.Resources.MDPhase_EncryptingResourcesText); bool hasPacker = ctx.Context.Packer != null; List resources = ctx.Module.Resources.OfType().ToList(); diff --git a/Confuser.Protections/Resources/ResourceProtection.cs b/Confuser.Protections/Resources/ResourceProtection.cs index a572bf079..a4eecfc1f 100644 --- a/Confuser.Protections/Resources/ResourceProtection.cs +++ b/Confuser.Protections/Resources/ResourceProtection.cs @@ -10,11 +10,11 @@ internal class ResourceProtection : Protection { public const string _ServiceId = "Ki.Resources"; public override string Name { - get { return "Resources Protection"; } + get { return Properties.Resources.ResourceProtectionName; } } public override string Description { - get { return "This protection encodes and compresses the embedded resources."; } + get { return Properties.Resources.ResourceProtectionDescription; } } public override string Id { @@ -35,4 +35,4 @@ protected override void PopulatePipeline(ProtectionPipeline pipeline) { pipeline.InsertPreStage(PipelineStage.ProcessModule, new InjectPhase(this)); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/TypeScrambler/AnalyzePhase.cs b/Confuser.Protections/TypeScrambler/AnalyzePhase.cs index a24328485..be2671bbd 100644 --- a/Confuser.Protections/TypeScrambler/AnalyzePhase.cs +++ b/Confuser.Protections/TypeScrambler/AnalyzePhase.cs @@ -10,7 +10,7 @@ public AnalyzePhase(TypeScrambleProtection parent) : base(parent) {} public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods; - public override string Name => "Type scanner"; + public override string Name => Properties.Resources.AnalyzePhaseName; protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/Confuser.Protections/TypeScrambler/ScramblePhase.cs b/Confuser.Protections/TypeScrambler/ScramblePhase.cs index 6fc86bfd0..efcd9b4f7 100644 --- a/Confuser.Protections/TypeScrambler/ScramblePhase.cs +++ b/Confuser.Protections/TypeScrambler/ScramblePhase.cs @@ -10,7 +10,7 @@ public ScramblePhase(TypeScrambleProtection parent) : base(parent) { } public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods; - public override string Name => "Type scrambler"; + public override string Name => Properties.Resources.ScramblePhaseName; protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { if (context == null) throw new ArgumentNullException(nameof(context)); diff --git a/Confuser.Protections/TypeScrambler/TypeScrambleProtection.cs b/Confuser.Protections/TypeScrambler/TypeScrambleProtection.cs index c0d761ce9..18354be7c 100644 --- a/Confuser.Protections/TypeScrambler/TypeScrambleProtection.cs +++ b/Confuser.Protections/TypeScrambler/TypeScrambleProtection.cs @@ -5,9 +5,9 @@ namespace Confuser.Protections.TypeScrambler { class TypeScrambleProtection : Protection { public override ProtectionPreset Preset => ProtectionPreset.None; - public override string Name => "Type Scrambler"; + public override string Name => Properties.Resources.TypeScrambleProtectionName; - public override string Description => "Replaces types with generics"; + public override string Description => Properties.Resources.TypeScrambleProtectionDescription; public override string Id => "typescramble"; diff --git a/Confuser.Renamer/AnalyzePhase.cs b/Confuser.Renamer/AnalyzePhase.cs index 875a681ad..33ccb0cb2 100644 --- a/Confuser.Renamer/AnalyzePhase.cs +++ b/Confuser.Renamer/AnalyzePhase.cs @@ -5,6 +5,7 @@ using Confuser.Core; using Confuser.Core.Services; using Confuser.Renamer.Analyzers; +using Confuser.Renamer.Properties; using dnlib.DotNet; namespace Confuser.Renamer { @@ -22,7 +23,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Name analysis"; } + get { return Resources.AnalyzePhase_Name_Name_analysis; } } void ParseParameters(IDnlibDef def, ConfuserContext context, NameService service, ProtectionParameters parameters) { @@ -33,8 +34,7 @@ void ParseParameters(IDnlibDef def, ConfuserContext context, NameService service protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { var service = (NameService)context.Registry.GetService(); - - context.Logger.Debug("Building VTables & identifier list..."); + context.Logger.Debug(Resources.AnalyzePhase_Execute_Building_VTables); foreach (ModuleDef moduleDef in parameters.Targets.OfType()) moduleDef.EnableTypeDefFindCache = true; @@ -56,7 +56,7 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa context.CheckCancellation(); } - context.Logger.Debug("Analyzing..."); + context.Logger.Debug(Resources.AnalyzePhaseAnalyzingText); RegisterRenamers(context, service); IList renamers = service.Renamers; foreach (IDnlibDef def in parameters.Targets.WithProgress(context.Logger)) { @@ -106,35 +106,35 @@ void RegisterRenamers(ConfuserContext context, NameService service) { if (wpf) { var wpfAnalyzer = new WPFAnalyzer(); - context.Logger.Debug("WPF found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_WPF_found); service.Renamers.Add(wpfAnalyzer); if (caliburn) { - context.Logger.Debug("Caliburn.Micro found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_Caliburn_Micro_found); service.Renamers.Add(new CaliburnAnalyzer(wpfAnalyzer)); } } if (winforms) { var winformsAnalyzer = new WinFormsAnalyzer(); - context.Logger.Debug("WinForms found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_WinForms_found); service.Renamers.Add(winformsAnalyzer); } if (json) { var jsonAnalyzer = new JsonAnalyzer(); - context.Logger.Debug("Newtonsoft.Json found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_Newtonsoft_Json_found); service.Renamers.Add(jsonAnalyzer); } if (visualBasic) { var vbAnalyzer = new VisualBasicRuntimeAnalyzer(); - context.Logger.Debug("Visual Basic Embedded Runtime found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_Visual_Basic_Embedded_Runtime_found); service.Renamers.Add(vbAnalyzer); } if (vsComposition) { var analyzer = new VsCompositionAnalyzer(); - context.Logger.Debug("Visual Studio Composition found, enabling compatibility."); + context.Logger.Debug(Resources.AnalyzePhase_RegisterRenamers_Visual_Studio_Composition_found); service.Renamers.Add(analyzer); } } @@ -199,7 +199,7 @@ void Analyze(NameService service, ConfuserContext context, ProtectionParameters if (parameters.GetParameter(context, type, "forceRen", false)) return; - if (type.InheritsFromCorlib("System.Attribute")) { + if (type.InheritsFromCorLib("System.Attribute")) { service.ReduceRenameMode(type, RenameMode.Reflection); } diff --git a/Confuser.Renamer/Analyzers/InterReferenceAnalyzer.cs b/Confuser.Renamer/Analyzers/InterReferenceAnalyzer.cs index 9ea0ea8b6..ab364892f 100644 --- a/Confuser.Renamer/Analyzers/InterReferenceAnalyzer.cs +++ b/Confuser.Renamer/Analyzers/InterReferenceAnalyzer.cs @@ -35,7 +35,9 @@ public void Analyze(ConfuserContext context, INameService service, ProtectionPar for (uint i = 1; i <= len; i++) { TypeRef typeRef = module.ResolveTypeRef(i); - TypeDef typeDef = typeRef.ResolveTypeDefThrow(); + TypeDef typeDef = typeRef.ResolveTypeDef(); + if (typeDef is null) continue; + if (typeDef.Module != module && context.Modules.Contains((ModuleDefMD)typeDef.Module)) { service.AddReference(typeDef, new TypeRefReference(typeRef, typeDef)); } @@ -51,7 +53,9 @@ void ProcessMemberRef(ConfuserContext context, INameService service, ModuleDefMD if (memberRef.DeclaringType.TryGetArraySig() != null) return; - TypeDef declType = memberRef.DeclaringType.ResolveTypeDefThrow(); + TypeDef declType = memberRef.DeclaringType.ResolveTypeDef(); + if (declType is null) return; + if (declType.Module != module && context.Modules.Contains((ModuleDefMD)declType.Module)) { var memberDef = (IMemberDef)declType.ResolveThrow(memberRef); service.AddReference(memberDef, new MemberRefReference(memberRef, memberDef)); diff --git a/Confuser.Renamer/Analyzers/LdtokenEnumAnalyzer.cs b/Confuser.Renamer/Analyzers/LdtokenEnumAnalyzer.cs index e652d5a3f..cba4ad230 100644 --- a/Confuser.Renamer/Analyzers/LdtokenEnumAnalyzer.cs +++ b/Confuser.Renamer/Analyzers/LdtokenEnumAnalyzer.cs @@ -38,9 +38,9 @@ public void Analyze(ConfuserContext context, INameService service, ProtectionPar } else if (instr.Operand is ITypeDefOrRef) { if (!(instr.Operand is TypeSpec)) { - TypeDef type = ((ITypeDefOrRef)instr.Operand).ResolveTypeDefThrow(); - if (context.Modules.Contains((ModuleDefMD)type.Module) && - HandleTypeOf(context, service, method, i)) { + var type = ((ITypeDefOrRef)instr.Operand).ResolveTypeDef(); + if (!(type is null) && context.Modules.Contains((ModuleDefMD)type.Module) && + HandleTypeOf(context, service, method, i)) { var t = type; do { DisableRename(service, t, false); @@ -112,7 +112,7 @@ void HandleEnum(ConfuserContext context, INameService service, MethodDef method, if (targetTypeRef == null) return; - TypeDef targetTypeDef = targetTypeRef.ResolveTypeDefThrow(); + var targetTypeDef = targetTypeRef.ResolveTypeDef(); if (targetTypeDef != null && targetTypeDef.IsEnum && context.Modules.Contains((ModuleDefMD)targetTypeDef.Module)) DisableRename(service, targetTypeDef); } @@ -183,4 +183,4 @@ void DisableRename(INameService service, TypeDef typeDef, bool memberOnly = true DisableRename(service, nested, false); } } -} \ No newline at end of file +} diff --git a/Confuser.Renamer/Analyzers/TypeBlobAnalyzer.cs b/Confuser.Renamer/Analyzers/TypeBlobAnalyzer.cs index 15a3e94f1..4328f38c5 100644 --- a/Confuser.Renamer/Analyzers/TypeBlobAnalyzer.cs +++ b/Confuser.Renamer/Analyzers/TypeBlobAnalyzer.cs @@ -68,8 +68,8 @@ public static void Analyze(INameService service, ICollection module foreach (CANamedArgument arg in attr.Properties) AnalyzeCAArgument(modules, service, arg.Argument); - TypeDef attrType = attr.AttributeType.ResolveTypeDefThrow(); - if (!modules.Contains((ModuleDefMD)attrType.Module)) + TypeDef attrType = attr.AttributeType.ResolveTypeDef(); + if (attrType is null || !modules.Contains((ModuleDefMD)attrType.Module)) continue; foreach (var arg in attr.NamedArguments) { @@ -159,8 +159,8 @@ private static void AnalyzeMemberRef(ICollection modules, INameServ if (sig is GenericInstSig) { var inst = (GenericInstSig)sig; Debug.Assert(!(inst.GenericType.TypeDefOrRef is TypeSpec)); - TypeDef openType = inst.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - if (!modules.Contains((ModuleDefMD)openType.Module) || + TypeDef openType = inst.GenericType.TypeDefOrRef.ResolveTypeDef(); + if (openType is null || !modules.Contains((ModuleDefMD)openType.Module) || memberRef.IsArrayAccessors()) return; diff --git a/Confuser.Renamer/Confuser.Renamer.csproj b/Confuser.Renamer/Confuser.Renamer.csproj index f053a7a77..da0a0b511 100644 --- a/Confuser.Renamer/Confuser.Renamer.csproj +++ b/Confuser.Renamer/Confuser.Renamer.csproj @@ -4,7 +4,7 @@ - net461;netstandard2.0 + net462;netstandard2.0 true ..\ConfuserEx.snk @@ -15,11 +15,11 @@ - + - + diff --git a/Confuser.Renamer/NameProtection.cs b/Confuser.Renamer/NameProtection.cs index ee27226a6..e4a41757b 100644 --- a/Confuser.Renamer/NameProtection.cs +++ b/Confuser.Renamer/NameProtection.cs @@ -1,6 +1,7 @@ using System; using System.IO; using Confuser.Core; +using Confuser.Renamer.Properties; namespace Confuser.Renamer { internal class NameProtection : Protection { @@ -9,11 +10,11 @@ internal class NameProtection : Protection { public const string _ServiceId = "Ki.Rename"; public override string Name { - get { return "Name Protection"; } + get { return Resources.NameProtectionName; } } public override string Description { - get { return "This protection obfuscate the symbols' name so the decompiled source code can neither be compiled nor read."; } + get { return Resources.NameProtectionDescription; } } public override string Id { @@ -48,7 +49,7 @@ public override ProtectionTargets Targets { } public override string Name { - get { return "Export symbol map"; } + get { return Resources.NameProtectionExportMapPhaseName; } } public override bool ProcessAll { diff --git a/Confuser.Renamer/NameService.cs b/Confuser.Renamer/NameService.cs index aafebadda..ac60618b7 100644 --- a/Confuser.Renamer/NameService.cs +++ b/Confuser.Renamer/NameService.cs @@ -214,7 +214,7 @@ public string ObfuscateName(IDnlibDef dnlibDef, RenameMode mode) { public string ObfuscateName(string format, string name, RenameMode mode, bool preserveGenericParams = false) { int genericParamsCount = 0; - if (preserveGenericParams) { + if (preserveGenericParams && !string.IsNullOrEmpty(name)) { name = ParseGenericName(name, out genericParamsCount); } diff --git a/Confuser.Renamer/Properties/Resources.Designer.cs b/Confuser.Renamer/Properties/Resources.Designer.cs index f64c1f574..f82e5cf8d 100644 --- a/Confuser.Renamer/Properties/Resources.Designer.cs +++ b/Confuser.Renamer/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace Confuser.Renamer.Properties { /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// 一个强类型的资源类,用于查找本地化的字符串等。 /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -33,7 +33,7 @@ internal Resources() { } /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// 返回此类使用的缓存的 ResourceManager 实例。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal Resources() { } /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,8 +61,89 @@ internal Resources() { } /// - /// Sucht eine lokalisierte Zeichenfolge, die The syntax is of the path is invalid. - ///{0}<ERROR>{1} ähnelt. + /// 查找类似 Building VTables & identifier list... 的本地化字符串。 + /// + internal static string AnalyzePhase_Execute_Building_VTables { + get { + return ResourceManager.GetString("AnalyzePhase_Execute_Building_VTables", resourceCulture); + } + } + + /// + /// 查找类似 Name analysis 的本地化字符串。 + /// + internal static string AnalyzePhase_Name_Name_analysis { + get { + return ResourceManager.GetString("AnalyzePhase_Name_Name_analysis", resourceCulture); + } + } + + /// + /// 查找类似 Caliburn.Micro found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_Caliburn_Micro_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_Caliburn_Micro_found", resourceCulture); + } + } + + /// + /// 查找类似 Newtonsoft.Json found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_Newtonsoft_Json_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_Newtonsoft_Json_found", resourceCulture); + } + } + + /// + /// 查找类似 Visual Basic Embedded Runtime found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_Visual_Basic_Embedded_Runtime_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_Visual_Basic_Embedded_Runtime_found", resourceCulture); + } + } + + /// + /// 查找类似 Visual Studio Composition found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_Visual_Studio_Composition_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_Visual_Studio_Composition_found", resourceCulture); + } + } + + /// + /// 查找类似 WinForms found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_WinForms_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_WinForms_found", resourceCulture); + } + } + + /// + /// 查找类似 WPF found, enabling compatibility. 的本地化字符串。 + /// + internal static string AnalyzePhase_RegisterRenamers_WPF_found { + get { + return ResourceManager.GetString("AnalyzePhase_RegisterRenamers_WPF_found", resourceCulture); + } + } + + /// + /// 查找类似 Analyzing... 的本地化字符串。 + /// + internal static string AnalyzePhaseAnalyzingText { + get { + return ResourceManager.GetString("AnalyzePhaseAnalyzingText", resourceCulture); + } + } + + /// + /// 查找类似 The syntax is of the path is invalid. + ///{0}<ERROR>{1} 的本地化字符串。 /// internal static string InvalidPathSyntax { get { @@ -71,6 +152,7 @@ internal static string InvalidPathSyntax { } /// + /// Sucht eine lokalisierte Zeichenfolge, die Tracing arguments for {0} call in {1} failed. What ever member is referenced here by reflection won't be properly handled by the name obfuscation. ähnelt. /// Sucht eine lokalisierte Zeichenfolge, die Invalid format string provided for the namespace format. Got: {0} ähnelt. /// internal static string NameService_ObfuscateName_InvalidFormat { @@ -81,6 +163,34 @@ internal static string NameService_ObfuscateName_InvalidFormat { /// /// Sucht eine lokalisierte Zeichenfolge, die Tracing arguments for {0} call in {1} failed. What ever member is referenced here by reflection won't be properly handled by the name obfuscation. ähnelt. + /// 查找类似 This protection obfuscate the symbols' name so the decompiled source code can neither be compiled nor read. 的本地化字符串。 + /// + internal static string NameProtectionDescription { + get { + return ResourceManager.GetString("NameProtectionDescription", resourceCulture); + } + } + + /// + /// 查找类似 Export symbol map 的本地化字符串。 + /// + internal static string NameProtectionExportMapPhaseName { + get { + return ResourceManager.GetString("NameProtectionExportMapPhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Name Protection 的本地化字符串。 + /// + internal static string NameProtectionName { + get { + return ResourceManager.GetString("NameProtectionName", resourceCulture); + } + } + + /// + /// 查找类似 Tracing arguments for {0} call in {1} failed. What ever member is referenced here by reflection won't be properly handled by the name obfuscation. 的本地化字符串。 /// internal static string ReflectionAnalyzer_Analyze_TracingArgumentsFailed { get { @@ -89,7 +199,25 @@ internal static string ReflectionAnalyzer_Analyze_TracingArgumentsFailed { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Could not find backing code for resource type '{0}', protections may not apply to that type. ähnelt. + /// 查找类似 Renaming 的本地化字符串。 + /// + internal static string RenamePhaseName { + get { + return ResourceManager.GetString("RenamePhaseName", resourceCulture); + } + } + + /// + /// 查找类似 Renaming... 的本地化字符串。 + /// + internal static string RenamePhaseRenamingText { + get { + return ResourceManager.GetString("RenamePhaseRenamingText", resourceCulture); + } + } + + /// + /// 查找类似 Could not find backing code for resource type '{0}', protections may not apply to that type. 的本地化字符串。 /// internal static string ResourceAnalyzer_Analyze_CouldNotFindResourceType { get { @@ -98,8 +226,8 @@ internal static string ResourceAnalyzer_Analyze_CouldNotFindResourceType { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Unmatched brackets. - ///{0} ähnelt. + /// 查找类似 Unmatched brackets. + ///{0} 的本地化字符串。 /// internal static string UnmatchedBracket { get { @@ -108,8 +236,8 @@ internal static string UnmatchedBracket { } /// - /// Sucht eine lokalisierte Zeichenfolge, die Unmatched parenthesis. - ///{0} ähnelt. + /// 查找类似 Unmatched parenthesis. + ///{0} 的本地化字符串。 /// internal static string UnmatchedParen { get { diff --git a/Confuser.Renamer/Properties/Resources.resx b/Confuser.Renamer/Properties/Resources.resx index 6691474d1..59701a095 100644 --- a/Confuser.Renamer/Properties/Resources.resx +++ b/Confuser.Renamer/Properties/Resources.resx @@ -139,4 +139,46 @@ Invalid format string provided for the namespace format. Got: {0} Exception message + + Name analysis + + + Analyzing... + + + This protection obfuscate the symbols' name so the decompiled source code can neither be compiled nor read. + + + Name Protection + + + Export symbol map + + + Renaming + + + Renaming... + + + Building VTables & identifier list... + + + WPF found, enabling compatibility. + + + Caliburn.Micro found, enabling compatibility. + + + WinForms found, enabling compatibility. + + + Newtonsoft.Json found, enabling compatibility. + + + Visual Basic Embedded Runtime found, enabling compatibility. + + + Visual Studio Composition found, enabling compatibility. + \ No newline at end of file diff --git a/Confuser.Renamer/Properties/Resources.zh-Hans.resx b/Confuser.Renamer/Properties/Resources.zh-Hans.resx new file mode 100644 index 000000000..24a0e5d23 --- /dev/null +++ b/Confuser.Renamer/Properties/Resources.zh-Hans.resx @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 该路径的语法是无效的。 +{0} <错误> {1} + + + 不匹配的括号。 +{0} + + + 括号不匹配。 +{0} + + + 找不到资源类型“ {0}”的后备代码,保护可能不适用于该类型。 + + + 在{1}中跟踪{0}调用的参数失败。此处通过反射引用的成员将无法通过混淆名称来正确处理。 + + + 名称分析 + + + 分析中… + + + 、移除命名空间,并混淆所有类、方法、字段、枚举等名称,包括有声明public的访问修饰符,全部会混淆。 + + + 名称保护 + + + 导出符号图 + + + 重命名 + + + 正在重命名... + + + 正在生成VTables标识符列表... + + + 找到Caliburn.Micro,正在启用兼容性。 + + + 找到Newtonsoft.Json,正在启用兼容性。 + + + 找到Visual Basic Embedded Runtime,正在启用兼容性。 + + + 找到Visual Studio Composition,正在启用兼容性。 + + + 找到WinForms,正在启用兼容性。 + + + 找到WPF,正在启用兼容性。 + + diff --git a/Confuser.Renamer/RenamePhase.cs b/Confuser.Renamer/RenamePhase.cs index cb8edd666..1355e32ce 100644 --- a/Confuser.Renamer/RenamePhase.cs +++ b/Confuser.Renamer/RenamePhase.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Text; using Confuser.Core; +using Confuser.Renamer.Properties; using dnlib.DotNet; using dnlib.DotNet.Pdb; @@ -12,12 +13,12 @@ public RenamePhase(NameProtection parent) public override ProtectionTargets Targets => ProtectionTargets.AllDefinitions; - public override string Name => "Renaming"; + public override string Name => Resources.RenamePhaseName; protected override void Execute(ConfuserContext context, ProtectionParameters parameters) { var service = (NameService)context.Registry.GetService(); - context.Logger.Debug("Renaming..."); + context.Logger.Debug(Resources.RenamePhaseRenamingText); foreach (var renamer in service.Renamers) { foreach (var def in parameters.Targets) renamer.PreRename(context, service, parameters, def); diff --git a/Confuser.Renamer/VTable.cs b/Confuser.Renamer/VTable.cs index a1fe8f215..3a3e4796f 100644 --- a/Confuser.Renamer/VTable.cs +++ b/Confuser.Renamer/VTable.cs @@ -202,7 +202,8 @@ public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { foreach (var impl in method.Value.Overrides) { Debug.Assert(impl.MethodBody == method.Value); - MethodDef targetMethod = impl.MethodDeclaration.ResolveThrow(); + var targetMethod = impl.MethodDeclaration.ResolveMethodDef(); + if (targetMethod is null) continue; if (targetMethod.DeclaringType.IsInterface) { var iface = impl.MethodDeclaration.DeclaringType.ToTypeSig(); CheckKeyExist(storage, vTbl.InterfaceSlots, iface, "MethodImpl Iface"); @@ -227,7 +228,7 @@ public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { }); } else { - var targetSlot = vTbl.AllSlots.SingleOrDefault(slot => slot.MethodDef == targetMethod); + var targetSlot = vTbl.AllSlots.Single(slot => MethodEqualityComparer.CompareDeclaringTypes.Equals(slot.MethodDef, targetMethod)); if (targetSlot == null) { throw new Exception($"method [{method}] not found."); } @@ -348,35 +349,40 @@ public VTable this[TypeDef type] { } VTable GetOrConstruct(TypeDef type) { - VTable ret; - if (!storage.TryGetValue(type, out ret)) + if (type is null) return null; + if (!storage.TryGetValue(type, out var ret)) ret = storage[type] = VTable.ConstructVTable(type, this); return ret; } public VTable GetVTable(ITypeDefOrRef type) { - if (type == null) - return null; - if (type is TypeDef) - return GetOrConstruct((TypeDef)type); - if (type is TypeRef) - return GetOrConstruct(((TypeRef)type).ResolveThrow()); - if (type is TypeSpec) { - TypeSig sig = ((TypeSpec)type).TypeSig; - if (sig is TypeDefOrRefSig) { - TypeDef typeDef = ((TypeDefOrRefSig)sig).TypeDefOrRef.ResolveTypeDefThrow(); + switch (type) { + case null: + return null; + case TypeDef typeDef: return GetOrConstruct(typeDef); - } - if (sig is GenericInstSig) { - var genInst = (GenericInstSig)sig; - TypeDef openType = genInst.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - VTable vTable = GetOrConstruct(openType); + case TypeRef typeRef: + return GetOrConstruct(typeRef.Resolve()); + case TypeSpec typeSpec: { + var sig = typeSpec.TypeSig; + switch (sig) { + case TypeDefOrRefSig defOrRefSig: { + var sigTypeDef = defOrRefSig.TypeDefOrRef.ResolveTypeDef(); + return GetOrConstruct(sigTypeDef); + } + case GenericInstSig genInst: { + var openType = genInst.GenericType.TypeDefOrRef.ResolveTypeDef(); + var vTable = GetOrConstruct(openType); - return ResolveGenericArgument(openType, genInst, vTable); + return vTable is null ? null : ResolveGenericArgument(openType, genInst, vTable); + } + default: + throw new NotSupportedException("Unexpected type: " + type); + } } - throw new NotSupportedException("Unexpected type: " + type); + default: + throw new UnreachableException(); } - throw new UnreachableException(); } static VTableSlot ResolveSlot(TypeDef openType, VTableSlot slot, IList genArgs) { diff --git a/Confuser.Runtime/Confuser.Runtime.csproj b/Confuser.Runtime/Confuser.Runtime.csproj index ce22f3c40..b4bce2576 100644 --- a/Confuser.Runtime/Confuser.Runtime.csproj +++ b/Confuser.Runtime/Confuser.Runtime.csproj @@ -16,7 +16,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Confuser2.sln b/Confuser2.sln index cbacdd964..520b36aa3 100644 --- a/Confuser2.sln +++ b/Confuser2.sln @@ -151,6 +151,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "470_ImplementationInBaseCla EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "470_ImplementationInBaseClass.Test", "Tests\470_ImplementationInBaseClass.Test\470_ImplementationInBaseClass.Test.csproj", "{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}" EndProject + +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfuserEx.Additions", "Additions\ConfuserEx.Additions.csproj", "{18E3F483-9013-4A60-A280-028FC6BF3829}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -965,6 +968,18 @@ Global {F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x64.Build.0 = Release|Any CPU {F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x86.ActiveCfg = Release|Any CPU {F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x86.Build.0 = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|x64.ActiveCfg = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|x64.Build.0 = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|x86.ActiveCfg = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Debug|x86.Build.0 = Debug|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|Any CPU.Build.0 = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|x64.ActiveCfg = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|x64.Build.0 = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|x86.ActiveCfg = Release|Any CPU + {18E3F483-9013-4A60-A280-028FC6BF3829}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ConfuserEx.Common.targets b/ConfuserEx.Common.targets index f6083488a..de103fe19 100644 --- a/ConfuserEx.Common.targets +++ b/ConfuserEx.Common.targets @@ -1,8 +1,8 @@ - - + + diff --git a/ConfuserEx/CompComboBox.xaml b/ConfuserEx/CompComboBox.xaml index b316505fe..8b60df16f 100644 --- a/ConfuserEx/CompComboBox.xaml +++ b/ConfuserEx/CompComboBox.xaml @@ -5,8 +5,20 @@ xmlns:core="clr-namespace:Confuser.Core;assembly=Confuser.Core"> + + + + + + + + + + + + - \ No newline at end of file + diff --git a/ConfuserEx/ComponentDiscovery.cs b/ConfuserEx/ComponentDiscovery.cs index 3a8988579..0d9ae8b34 100644 --- a/ConfuserEx/ComponentDiscovery.cs +++ b/ConfuserEx/ComponentDiscovery.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using Confuser.Core; @@ -10,8 +11,17 @@ static void CrossDomainLoadComponents() { // Initialize the version resolver callback ConfuserEngine.Version.ToString(); - Assembly assembly = Assembly.LoadFile(ctx.PluginPath); - foreach (var module in assembly.GetLoadedModules()) + var paths = new List(); + paths.Add(ctx.PluginPath); + var pluginDir = PluginDiscovery.Instance.GetBasePlugInsDir(); + if (Directory.Exists(pluginDir)) { + var dlls = Directory.GetFiles(pluginDir, "*.dll"); + paths.AddRange(dlls); + } + + foreach (string path in paths) { + Assembly assembly = Assembly.LoadFile(path); + foreach (var module in assembly.GetLoadedModules()) foreach (var i in module.GetTypes()) { if (i.IsAbstract || !PluginDiscovery.HasAccessibleDefConstructor(i)) continue; @@ -25,6 +35,7 @@ static void CrossDomainLoadComponents() { ctx.AddPacker(Info.FromComponent(packer, ctx.PluginPath)); } } + } } public static void LoadComponents(IList protections, IList packers, string pluginPath) { @@ -123,4 +134,4 @@ protected override void PopulatePipeline(ProtectionPipeline pipeline) { } } } -} \ No newline at end of file +} diff --git a/ConfuserEx/ConfuserEx.csproj b/ConfuserEx/ConfuserEx.csproj index f9f103e7a..8e3835a36 100644 --- a/ConfuserEx/ConfuserEx.csproj +++ b/ConfuserEx/ConfuserEx.csproj @@ -4,7 +4,7 @@ WinExe - net461 + net462 true true ..\ConfuserEx.snk @@ -18,7 +18,7 @@ - + @@ -35,4 +35,15 @@ - + + + + + + + + + + + + \ No newline at end of file diff --git a/ConfuserEx/MainWindow.xaml b/ConfuserEx/MainWindow.xaml index 204d5b451..8544df22f 100644 --- a/ConfuserEx/MainWindow.xaml +++ b/ConfuserEx/MainWindow.xaml @@ -2,6 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ConfuserEx" + xmlns:properties="clr-namespace:ConfuserEx.Properties" Title="{Binding Title}" Width="800" Height="600" Style="{StaticResource DarkWindow}"> @@ -13,32 +14,32 @@