Skip to content

Commit 3ad3663

Browse files
mcpolo99kamcip
andauthored
fix(core): support .NET Standard library obfuscation (#31)
* 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. * 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. * 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. * 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. --------- Co-authored-by: KC Ip <kamchuen.ip@hidglobal.com>
1 parent 8cae43e commit 3ad3663

6 files changed

Lines changed: 78 additions & 9 deletions

File tree

Confuser.Core/ConfuserAssemblyResolver.cs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,50 @@ public AssemblyDef Resolve(IAssembly assembly, ModuleDef sourceModule) {
3333
if (assembly is AssemblyDef assemblyDef)
3434
return assemblyDef;
3535

36-
var resolvedAssemblyDef = InternalExactResolver.Resolve(assembly, sourceModule);
37-
return resolvedAssemblyDef ?? InternalFuzzyResolver.Resolve(assembly, sourceModule);
36+
var resolvedAssemblyDef =
37+
InternalExactResolver.Resolve(assembly, sourceModule) ??
38+
InternalFuzzyResolver.Resolve(assembly, sourceModule);
39+
40+
// Remove AssemblyAttributes.PA_NoPlatform
41+
if (null != resolvedAssemblyDef &&
42+
(AssemblyAttributes.PA_Mask & resolvedAssemblyDef.Attributes) == AssemblyAttributes.PA_NoPlatform) {
43+
resolvedAssemblyDef.Attributes =
44+
resolvedAssemblyDef.Attributes & ~AssemblyAttributes.PA_FullMask;
45+
}
46+
47+
if (resolvedAssemblyDef?.Name == "netstandard" && 0 < resolvedAssemblyDef.ManifestModule.ExportedTypes.Count) {
48+
// Move types from AssemblyRef to here
49+
var module = resolvedAssemblyDef.ManifestModule;
50+
var newTypes = new List<TypeDef>();
51+
var allAssemblyRefs = new List<AssemblyDef>();
52+
53+
module.ExportedTypes.Clear();
54+
55+
foreach (var assemblyRef in module.GetAssemblyRefs()) {
56+
var subAss =
57+
InternalExactResolver.Resolve(assemblyRef, module) ??
58+
InternalFuzzyResolver.Resolve(assemblyRef, module);
59+
allAssemblyRefs.Add(subAss);
60+
foreach (var subModule in subAss?.Modules) {
61+
foreach (var defType in subModule.Types) {
62+
newTypes.Add(defType);
63+
}
64+
subModule.Types.Clear();
65+
foreach (var defType in newTypes) {
66+
module.Types.Add(defType);
67+
}
68+
newTypes.Clear();
69+
}
70+
}
71+
72+
// Remove them because their types has been removed.
73+
foreach (var subAss in allAssemblyRefs) {
74+
InternalExactResolver.Remove(subAss);
75+
InternalFuzzyResolver.Remove(subAss);
76+
}
77+
}
78+
79+
return resolvedAssemblyDef;
3880
}
3981

4082
public void Clear() {

Confuser.Core/Helpers/InjectHelper.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,16 @@ public override ITypeDefOrRef Map(ITypeDefOrRef source) {
292292
// check if the assembly reference needs to be fixed.
293293
if (source is TypeRef sourceRef) {
294294
var targetAssemblyRef = TargetModule.GetAssemblyRef(sourceRef.DefinitionAssembly.Name);
295-
if (!(targetAssemblyRef is null) && !string.Equals(targetAssemblyRef.FullName, source.DefinitionAssembly.FullName, StringComparison.Ordinal)) {
295+
if (targetAssemblyRef is null) {
296+
// Handle assemblies referenced by netstandard
297+
var corLibAssemblyRef = TargetModule.CorLibTypes.AssemblyRef;
298+
var corLibAssembly = TargetModule.Context.AssemblyResolver.Resolve(corLibAssemblyRef, TargetModule);
299+
if (null != corLibAssembly?.ManifestModule.GetAssemblyRef(sourceRef.DefinitionAssembly.Name)) {
300+
var fixedTypeRef = new TypeRefUser(sourceRef.Module, sourceRef.Namespace, sourceRef.Name, corLibAssemblyRef);
301+
return Importer.Import(fixedTypeRef);
302+
}
303+
}
304+
else if (!string.Equals(targetAssemblyRef.FullName, source.DefinitionAssembly.FullName, StringComparison.Ordinal)) {
296305
// We got a matching assembly by the simple name, but not by the full name.
297306
// This means the injected code uses a different assembly version than the target assembly.
298307
// We'll fix the assembly reference, to avoid breaking anything.

Confuser.Protections/Compress/Compressor.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ void PackModules(ConfuserContext context, CompressorContext compCtx, ModuleDef s
175175
context.Logger.EndProgress();
176176
}
177177

178-
void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) {
178+
void InjectData(ConfuserContext context, ModuleDef stubModule, MethodDef method, byte[] data) {
179179
var dataType = new TypeDefUser("", "DataType", stubModule.CorLibTypes.GetTypeRef("System", "ValueType"));
180180
dataType.Layout = TypeAttributes.ExplicitLayout;
181181
dataType.Visibility = TypeAttributes.NestedPrivate;
@@ -197,7 +197,7 @@ void InjectData(ModuleDef stubModule, MethodDef method, byte[] data) {
197197
repl.Add(Instruction.Create(OpCodes.Dup));
198198
repl.Add(Instruction.Create(OpCodes.Ldtoken, dataField));
199199
repl.Add(Instruction.Create(OpCodes.Call, stubModule.Import(
200-
typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
200+
context, typeof(RuntimeHelpers), "InitializeArray")));
201201
return repl.ToArray();
202202
});
203203
}
@@ -254,7 +254,7 @@ void InjectStub(ConfuserContext context, CompressorContext compCtx, ProtectionPa
254254
MutationHelper.InjectKeys(entryPoint,
255255
new[] { 0, 1 },
256256
new[] { encryptedModule.Length >> 2, (int)seed });
257-
InjectData(stubModule, entryPoint, encryptedModule);
257+
InjectData(context, stubModule, entryPoint, encryptedModule);
258258

259259
// Decrypt
260260
MethodDef decrypter = defs.OfType<MethodDef>().Single(method => method.Name == "Decrypt");

Confuser.Protections/Constants/EncodePhase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ protected override void Execute(ConfuserContext context, ProtectionParameters pa
122122
repl.Add(Instruction.Create(OpCodes.Dup));
123123
repl.Add(Instruction.Create(OpCodes.Ldtoken, moduleCtx.DataField));
124124
repl.Add(Instruction.Create(OpCodes.Call, moduleCtx.Module.Import(
125-
typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
125+
context, typeof(RuntimeHelpers), "InitializeArray")));
126126
return repl.ToArray();
127127
});
128128
}

Confuser.Protections/Resources/InjectPhase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ void MutateInitializer(REContext moduleCtx, MethodDef decomp) {
137137
repl.Add(Instruction.Create(OpCodes.Dup));
138138
repl.Add(Instruction.Create(OpCodes.Ldtoken, moduleCtx.DataField));
139139
repl.Add(Instruction.Create(OpCodes.Call, moduleCtx.Module.Import(
140-
typeof(RuntimeHelpers).GetMethod("InitializeArray"))));
140+
moduleCtx.Context, typeof(RuntimeHelpers), "InitializeArray")));
141141
return repl.ToArray();
142142
});
143143
moduleCtx.Context.Registry.GetService<IConstantService>().ExcludeMethod(moduleCtx.Context, moduleCtx.InitMethod);
144144
}
145145
}
146-
}
146+
}

Confuser.Protections/Utils.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Runtime.CompilerServices;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Confuser.Core;
8+
using dnlib.DotNet;
9+
10+
namespace Confuser.Protections {
11+
internal static class Utils {
12+
public static IMethod Import(this ModuleDef module, ConfuserContext context, Type classType, string method) {
13+
var corLib = context.Resolver.Resolve(context.CurrentModule?.CorLibTypes.AssemblyRef, context.CurrentModule);
14+
var typeInfo = corLib?.ManifestModule.Find(classType.FullName, true);
15+
return (typeInfo == null) ? module.Import(classType.GetMethod(method)) : module.Import(typeInfo.FindMethod(method));
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)