From 5c61e231330204f23ecfc6765a01924fd922cfe2 Mon Sep 17 00:00:00 2001 From: KC Ip Date: Fri, 7 Jun 2024 12:37:39 +0800 Subject: [PATCH 1/4] Add types in referencing assembly to netstandard DLL. Types defined in AssemblyRefs of netstandard (e.g. mscorlib) will be moved to netstandard. Therefore, subsequence ModuleDef.Find will return AssemblyRef to netstandard. As a result, the confused module will only reference to netstandard. --- Confuser.Core/ConfuserAssemblyResolver.cs | 39 +++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/Confuser.Core/ConfuserAssemblyResolver.cs b/Confuser.Core/ConfuserAssemblyResolver.cs index 05ef4731f..7992fd995 100644 --- a/Confuser.Core/ConfuserAssemblyResolver.cs +++ b/Confuser.Core/ConfuserAssemblyResolver.cs @@ -33,8 +33,43 @@ public AssemblyDef Resolve(IAssembly assembly, ModuleDef sourceModule) { if (assembly is AssemblyDef assemblyDef) return assemblyDef; - var resolvedAssemblyDef = InternalExactResolver.Resolve(assembly, sourceModule); - return resolvedAssemblyDef ?? InternalFuzzyResolver.Resolve(assembly, sourceModule); + var resolvedAssemblyDef = + InternalExactResolver.Resolve(assembly, sourceModule) ?? + InternalFuzzyResolver.Resolve(assembly, sourceModule); + + if (resolvedAssemblyDef?.Name == "netstandard" && 0 < resolvedAssemblyDef.ManifestModule.ExportedTypes.Count) { + // Move types from AssemblyRef to here + var module = resolvedAssemblyDef.ManifestModule; + var newTypes = new List(); + var allAssemblyRefs = new List(); + + module.ExportedTypes.Clear(); + + foreach (var assemblyRef in module.GetAssemblyRefs()) { + var subAss = + InternalExactResolver.Resolve(assemblyRef, module) ?? + InternalFuzzyResolver.Resolve(assemblyRef, module); + allAssemblyRefs.Add(subAss); + foreach (var subModule in subAss?.Modules) { + foreach (var defType in subModule.Types) { + newTypes.Add(defType); + } + subModule.Types.Clear(); + foreach (var defType in newTypes) { + module.Types.Add(defType); + } + newTypes.Clear(); + } + } + + // Remove them because their types has been removed. + foreach (var subAss in allAssemblyRefs) { + InternalExactResolver.Remove(subAss); + InternalFuzzyResolver.Remove(subAss); + } + } + + return resolvedAssemblyDef; } public void Clear() { From 1f2c98a3d22f5d22ad2c437c087be5c235107cb5 Mon Sep 17 00:00:00 2001 From: KC Ip Date: Fri, 7 Jun 2024 12:45:31 +0800 Subject: [PATCH 2/4] Remove AssemblyAttributes.PA_NoPlatform from assembly. Net standard project may refer to NuGet package (e.g. System.ComponentModel.Composition) in order to use the Framework libraries. However, DLL in NuGet may have this attribute set but the actual Framework DLL does not. As a result, dnlib treats them as different assemblies and confused DLL will reference to two identical assemblies. --- Confuser.Core/ConfuserAssemblyResolver.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Confuser.Core/ConfuserAssemblyResolver.cs b/Confuser.Core/ConfuserAssemblyResolver.cs index 7992fd995..22346b13e 100644 --- a/Confuser.Core/ConfuserAssemblyResolver.cs +++ b/Confuser.Core/ConfuserAssemblyResolver.cs @@ -37,6 +37,13 @@ public AssemblyDef Resolve(IAssembly assembly, ModuleDef sourceModule) { InternalExactResolver.Resolve(assembly, sourceModule) ?? InternalFuzzyResolver.Resolve(assembly, sourceModule); + // Remove AssemblyAttributes.PA_NoPlatform + if (null != resolvedAssemblyDef && + (AssemblyAttributes.PA_Mask & resolvedAssemblyDef.Attributes) == AssemblyAttributes.PA_NoPlatform) { + resolvedAssemblyDef.Attributes = + resolvedAssemblyDef.Attributes & ~AssemblyAttributes.PA_FullMask; + } + if (resolvedAssemblyDef?.Name == "netstandard" && 0 < resolvedAssemblyDef.ManifestModule.ExportedTypes.Count) { // Move types from AssemblyRef to here var module = resolvedAssemblyDef.ManifestModule; From 74c18bce04640b66ebc4123b9f403a96ada50d2a Mon Sep 17 00:00:00 2001 From: KC Ip Date: Fri, 7 Jun 2024 12:53:13 +0800 Subject: [PATCH 3/4] Fix assembly reference to assemblies that hidden by netstandard assembly. TargetModule.GetAssemblyRef returns null if type is defined in assembly hidden by netstandard. This change searches assemblies hidden by netstandard and returns the fixed type reference. --- Confuser.Core/Helpers/InjectHelper.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Confuser.Core/Helpers/InjectHelper.cs b/Confuser.Core/Helpers/InjectHelper.cs index 6aaf566a0..6cb066c23 100644 --- a/Confuser.Core/Helpers/InjectHelper.cs +++ b/Confuser.Core/Helpers/InjectHelper.cs @@ -292,7 +292,16 @@ public override ITypeDefOrRef Map(ITypeDefOrRef source) { // check if the assembly reference needs to be fixed. if (source is TypeRef sourceRef) { var targetAssemblyRef = TargetModule.GetAssemblyRef(sourceRef.DefinitionAssembly.Name); - if (!(targetAssemblyRef is null) && !string.Equals(targetAssemblyRef.FullName, source.DefinitionAssembly.FullName, StringComparison.Ordinal)) { + if (targetAssemblyRef is null) { + // Handle assemblies referenced by netstandard + var corLibAssemblyRef = TargetModule.CorLibTypes.AssemblyRef; + var corLibAssembly = TargetModule.Context.AssemblyResolver.Resolve(corLibAssemblyRef, TargetModule); + if (null != corLibAssembly?.ManifestModule.GetAssemblyRef(sourceRef.DefinitionAssembly.Name)) { + var fixedTypeRef = new TypeRefUser(sourceRef.Module, sourceRef.Namespace, sourceRef.Name, corLibAssemblyRef); + return Importer.Import(fixedTypeRef); + } + } + else if (!string.Equals(targetAssemblyRef.FullName, source.DefinitionAssembly.FullName, StringComparison.Ordinal)) { // We got a matching assembly by the simple name, but not by the full name. // This means the injected code uses a different assembly version than the target assembly. // We'll fix the assembly reference, to avoid breaking anything. From 758ddd6bf1606e31a0258b5c5de293c39864fb05 Mon Sep 17 00:00:00 2001 From: KC Ip Date: Fri, 7 Jun 2024 13:02:29 +0800 Subject: [PATCH 4/4] Returns the method from CorLib of module to be confused instead from runtime. MSBuild may runs on .net framework and runtime help will reference to mscorlib instead of netstandard. This change try resolve it from CorLib before from runtime type. --- Confuser.Protections/Compress/Compressor.cs | 6 +++--- Confuser.Protections/Constants/EncodePhase.cs | 2 +- Confuser.Protections/Resources/InjectPhase.cs | 4 ++-- Confuser.Protections/Utils.cs | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 Confuser.Protections/Utils.cs diff --git a/Confuser.Protections/Compress/Compressor.cs b/Confuser.Protections/Compress/Compressor.cs index 33c0ea6b7..abbbd13c6 100644 --- a/Confuser.Protections/Compress/Compressor.cs +++ b/Confuser.Protections/Compress/Compressor.cs @@ -175,7 +175,7 @@ void PackModules(ConfuserContext context, CompressorContext compCtx, ModuleDef s context.Logger.EndProgress(); } - void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { + void InjectData(ConfuserContext context, ModuleDef stubModule, MethodDef method, byte[] data) { var dataType = new TypeDefUser("", "DataType", stubModule.CorLibTypes.GetTypeRef("System", "ValueType")); dataType.Layout = TypeAttributes.ExplicitLayout; dataType.Visibility = TypeAttributes.NestedPrivate; @@ -197,7 +197,7 @@ void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) { 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")))); + context, typeof(RuntimeHelpers), "InitializeArray"))); return repl.ToArray(); }); } @@ -254,7 +254,7 @@ void InjectStub(ConfuserContext context, CompressorContext compCtx, ProtectionPa MutationHelper.InjectKeys(entryPoint, new[] { 0, 1 }, new[] { encryptedModule.Length >> 2, (int)seed }); - InjectData(stubModule, entryPoint, encryptedModule); + InjectData(context, stubModule, entryPoint, encryptedModule); // Decrypt MethodDef decrypter = defs.OfType().Single(method => method.Name == "Decrypt"); diff --git a/Confuser.Protections/Constants/EncodePhase.cs b/Confuser.Protections/Constants/EncodePhase.cs index 4eba9118e..ade681d17 100644 --- a/Confuser.Protections/Constants/EncodePhase.cs +++ b/Confuser.Protections/Constants/EncodePhase.cs @@ -122,7 +122,7 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa 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")))); + context, typeof(RuntimeHelpers), "InitializeArray"))); return repl.ToArray(); }); } diff --git a/Confuser.Protections/Resources/InjectPhase.cs b/Confuser.Protections/Resources/InjectPhase.cs index 540591750..27c58ab03 100644 --- a/Confuser.Protections/Resources/InjectPhase.cs +++ b/Confuser.Protections/Resources/InjectPhase.cs @@ -137,10 +137,10 @@ void MutateInitializer(REContext moduleCtx, MethodDef decomp) { 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")))); + moduleCtx.Context, typeof(RuntimeHelpers), "InitializeArray"))); return repl.ToArray(); }); moduleCtx.Context.Registry.GetService().ExcludeMethod(moduleCtx.Context, moduleCtx.InitMethod); } } -} \ No newline at end of file +} diff --git a/Confuser.Protections/Utils.cs b/Confuser.Protections/Utils.cs new file mode 100644 index 000000000..e46f701c1 --- /dev/null +++ b/Confuser.Protections/Utils.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Confuser.Core; +using dnlib.DotNet; + +namespace Confuser.Protections { + internal static class Utils { + public static IMethod Import(this ModuleDef module, ConfuserContext context, Type classType, string method) { + var corLib = context.Resolver.Resolve(context.CurrentModule?.CorLibTypes.AssemblyRef, context.CurrentModule); + var typeInfo = corLib?.ManifestModule.Find(classType.FullName, true); + return (typeInfo == null) ? module.Import(classType.GetMethod(method)) : module.Import(typeInfo.FindMethod(method)); + } + } +}