From f1ccb1e31a3b0926346c2472a362297e8101d5e9 Mon Sep 17 00:00:00 2001 From: Martin Karing Date: Sun, 28 Jun 2020 15:55:59 +0200 Subject: [PATCH] Obfuscating assemblies with missing dependencies ConfuserEx is now able to obfuscate assemblies without all the dependencies. It makes some worst case assumptions for missing dependencies. --- Confuser.Core/Confuser.Core.csproj | 1 + Confuser.Core/ConfuserEngine.cs | 34 ++++++------ Confuser.Core/DnlibUtils.cs | 39 ++++++-------- .../Analyzers/InterReferenceAnalyzer.cs | 8 ++- .../Analyzers/LdtokenEnumAnalyzer.cs | 12 ++--- .../Analyzers/TypeBlobAnalyzer.cs | 8 +-- Confuser.Renamer/VTable.cs | 53 +++++++++++-------- 7 files changed, 78 insertions(+), 77 deletions(-) diff --git a/Confuser.Core/Confuser.Core.csproj b/Confuser.Core/Confuser.Core.csproj index 7fc5d29a3..c4a78767c 100644 --- a/Confuser.Core/Confuser.Core.csproj +++ b/Confuser.Core/Confuser.Core.csproj @@ -19,6 +19,7 @@ + diff --git a/Confuser.Core/ConfuserEngine.cs b/Confuser.Core/ConfuserEngine.cs index 07542b6ac..eb1a7b0f7 100644 --- a/Confuser.Core/ConfuserEngine.cs +++ b/Confuser.Core/ConfuserEngine.cs @@ -262,14 +262,10 @@ static void RunPipeline(ProtectionPipeline pipeline, ConfuserContext context) { static void Inspection(ConfuserContext context) { context.Logger.Info("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("Failed to resolve dependency '" + dependency.asmRef.FullName + "'."); } context.Logger.Debug("Checking Strong Name..."); @@ -311,7 +307,7 @@ static void CheckStrongName(ConfuserContext context, ModuleDef module) { 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); else if (snPubKeyBytes != null && moduleIsSignedOrDelayedSigned && - !module.Assembly.PublicKey.Data.SequenceEqual(snPubKeyBytes)) + !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.", module.Name); } @@ -338,23 +334,23 @@ static void BeginModule(ConfuserContext context) { if (!context.CurrentModule.IsILOnly || context.CurrentModule.VTableFixups != null) context.RequestNative(); - 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 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); - var snDelaySig = context.Annotations.Get(context.CurrentModule, Marker.SNDelaySig, false); - + var snDelaySig = context.Annotations.Get(context.CurrentModule, Marker.SNDelaySig, false); + context.CurrentModuleWriterOptions.DelaySign = snDelaySig; 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 + else if (snSigPubKey != null && snSigKey != null) + context.CurrentModuleWriterOptions.InitializeEnhancedStrongNameSigning(context.CurrentModule, snSigKey, snSigPubKey); + else context.CurrentModuleWriterOptions.InitializeStrongNameSigning(context.CurrentModule, snKey); - if (snDelaySig) { + if (snDelaySig) { context.CurrentModuleWriterOptions.StrongNamePublicKey = snPubKey; context.CurrentModuleWriterOptions.StrongNameKey = null; } @@ -528,7 +524,7 @@ static void PrintEnvironmentInfo(ConfuserContext context) { if (context.Resolver != null) { context.Logger.Error("Cached assemblies:"); - foreach (AssemblyDef asm in context.InternalResolver.GetCachedAssemblies()) { + 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.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..54345700c 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); @@ -108,11 +108,11 @@ void HandleEnum(ConfuserContext context, INameService service, MethodDef method, else return; - ITypeDefOrRef targetTypeRef = targetType.ToBasicTypeDefOrRef(); + var targetTypeRef = targetType.ToBasicTypeDefOrRef(); 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/VTable.cs b/Confuser.Renamer/VTable.cs index b71dc3d16..a808e2e37 100644 --- a/Confuser.Renamer/VTable.cs +++ b/Confuser.Renamer/VTable.cs @@ -214,7 +214,9 @@ 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"); @@ -239,7 +241,7 @@ public static VTable ConstructVTable(TypeDef typeDef, VTableStorage storage) { }); } else { - var targetSlot = vTbl.AllSlots.Single(slot => slot.MethodDef == targetMethod); + var targetSlot = vTbl.AllSlots.Single(slot => MethodEqualityComparer.CompareDeclaringTypes.Equals(slot.MethodDef, targetMethod)); CheckKeyExist(storage, vTbl.SlotsMap, targetSlot.Signature, "MethodImpl Normal Sig"); targetSlot = vTbl.SlotsMap[targetSlot.Signature]; // Use the most derived slot // Maybe implemented by above processes --- this process should take priority @@ -357,35 +359,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); + 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 vTable is null ? null : ResolveGenericArgument(openType, genInst, vTable); + } + default: + throw new NotSupportedException("Unexpected type: " + type); + } } - if (sig is GenericInstSig) { - var genInst = (GenericInstSig)sig; - TypeDef openType = genInst.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - VTable vTable = GetOrConstruct(openType); - - return ResolveGenericArgument(openType, genInst, vTable); - } - throw new NotSupportedException("Unexpected type: " + type); + default: + throw new UnreachableException(); } - throw new UnreachableException(); } static VTableSlot ResolveSlot(TypeDef openType, VTableSlot slot, IList genArgs) {