Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic support for netcore #190

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
[submodule "dnlib"]
path = dnlib
url=../dnlib.git
5 changes: 1 addition & 4 deletions Confuser.Core/Confuser.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
<ItemGroup Label="Nuget Dependencies">
<PackageReference Include="Microsoft.Win32.Registry" Version="4.*" />
<PackageReference Include="System.Threading" Version="4.*" />
</ItemGroup>

<ItemGroup Label="Project Dependencies">
<ProjectReference Include="..\dnlib\src\dnlib.csproj" />
<PackageReference Include="dnlib" Version="3.3.2" />
</ItemGroup>


Expand Down
5 changes: 4 additions & 1 deletion Confuser.Core/ConfuserEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ static void RunInternal(ConfuserParameters parameters, CancellationToken token)
var asmResolver = new AssemblyResolver();
asmResolver.EnableTypeDefCache = true;
asmResolver.DefaultModuleContext = new ModuleContext(asmResolver);
asmResolver.EnableFrameworkRedirect = false;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this line without any conditions will break resolving the assemblies when mixing .NET 2.0, .NET 3.5 and .NET 4 assemblies in the same project. Means if you have a .NET 3.5 assembly as the dependency of a .NET 4 assembly, the referenced assemblies will not resolve properly, because the mscorlib version changes. This works during runtime, because the .NET rumtime redirects mscorlib 3.5 to mscorlib 4.0. The line you added, disables this functionality for dnlib.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will test this and reference netfx dll in netcore later, still not sure what will happen in this case. Is there any actual issue for the case can be tested?
The option is needed for netcore, otherwise something like System.Runtime 4.2.2 will be changed to 4.0.0 by FrameworkRedirect.ApplyFrameworkRedirect(), and then it will perfer the one in GAC as extra match instead of netcore.
Since FindExactMatch is still false, it can match mscorlib 4.0 if 3.5 is not found.And what will happen if resolve 3.5 for 3.5 and 4.0 for 4.0 side by side, if reference assembly don't needed to be confused, since they should be api compatable to executed.

context.Resolver = asmResolver;
context.BaseDirectory = Path.Combine(Environment.CurrentDirectory, context.Project.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar);
context.OutputDirectory = Path.Combine(context.Project.BaseDirectory, context.Project.OutputDirectory.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar);
foreach (string probePath in context.Project.ProbePaths)
asmResolver.PostSearchPaths.Insert(0, Path.Combine(context.BaseDirectory, probePath));
asmResolver.PreSearchPaths.Add(Path.Combine(context.BaseDirectory, probePath));

context.CheckCancellation();

Expand Down Expand Up @@ -384,6 +385,8 @@ static void EndModule(ConfuserContext context) {
if (!Path.IsPathRooted(output))
output = Path.Combine(Environment.CurrentDirectory, output);
output = Utils.GetRelativePath(output, context.BaseDirectory);
if (Path.IsPathRooted(output))
output = Path.GetFileName(output);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is added? Why is the oath completely stripped in case the path is rooted? If the path is still rooted at this point, it only means that the output path has no relative relation to the location of the project. That is perfectly valid.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mkaring
All usesite of context.OutputPaths[i] look like Path.Combine(context.OutputDirectory, context.OutputPaths[i]) or Path.Combine(tmpDir, context.OutputPaths[i]), if context.OutputPaths[i] is an fullpath, it will get the same path as input, and makes the input file will be overwrite by output data.

}
else {
output = context.CurrentModule.Name;
Expand Down
118 changes: 87 additions & 31 deletions Confuser.Core/Helpers/InjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ static FieldDefUser Clone(FieldDef origin) {
/// <returns>The new TypeDef.</returns>
static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx) {
TypeDef ret;
IDnlibDef existing;
if (!ctx.Map.TryGetValue(typeDef, out existing)) {
if (!ctx.MemberMap.TryGetValue(typeDef, out var existing)) {
ret = Clone(typeDef);
ctx.Map[typeDef] = ret;
ctx.MemberMap[typeDef] = ret;
}
else
ret = (TypeDef)existing;
Expand All @@ -71,10 +70,10 @@ static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx) {
ret.NestedTypes.Add(PopulateContext(nestedType, ctx));

foreach (MethodDef method in typeDef.Methods)
ret.Methods.Add((MethodDef)(ctx.Map[method] = Clone(method)));
ret.Methods.Add((MethodDef)(ctx.MemberMap[method] = Clone(method)));

foreach (FieldDef field in typeDef.Fields)
ret.Fields.Add((FieldDef)(ctx.Map[field] = Clone(field)));
ret.Fields.Add((FieldDef)(ctx.MemberMap[field] = Clone(field)));

return ret;
}
Expand All @@ -85,12 +84,12 @@ static TypeDef PopulateContext(TypeDef typeDef, InjectContext ctx) {
/// <param name="typeDef">The origin TypeDef.</param>
/// <param name="ctx">The injection context.</param>
static void CopyTypeDef(TypeDef typeDef, InjectContext ctx) {
var newTypeDef = (TypeDef)ctx.Map[typeDef];
var newTypeDef = (TypeDef)ctx.MemberMap[typeDef];

newTypeDef.BaseType = (ITypeDefOrRef)ctx.Importer.Import(typeDef.BaseType);
newTypeDef.BaseType = ctx.Importer.Import(typeDef.BaseType);

foreach (InterfaceImpl iface in typeDef.Interfaces)
newTypeDef.Interfaces.Add(new InterfaceImplUser((ITypeDefOrRef)ctx.Importer.Import(iface.Interface)));
newTypeDef.Interfaces.Add(new InterfaceImplUser(ctx.Importer.Import(iface.Interface)));
}

/// <summary>
Expand All @@ -99,7 +98,7 @@ static void CopyTypeDef(TypeDef typeDef, InjectContext ctx) {
/// <param name="methodDef">The origin MethodDef.</param>
/// <param name="ctx">The injection context.</param>
static void CopyMethodDef(MethodDef methodDef, InjectContext ctx) {
var newMethodDef = (MethodDef)ctx.Map[methodDef];
var newMethodDef = (MethodDef)ctx.MemberMap[methodDef];

newMethodDef.Signature = ctx.Importer.Import(methodDef.Signature);
newMethodDef.Parameters.UpdateParameterTypes();
Expand Down Expand Up @@ -151,7 +150,7 @@ static void CopyMethodDef(MethodDef methodDef, InjectContext ctx) {

foreach (ExceptionHandler eh in methodDef.Body.ExceptionHandlers)
newMethodDef.Body.ExceptionHandlers.Add(new ExceptionHandler(eh.HandlerType) {
CatchType = eh.CatchType == null ? null : (ITypeDefOrRef)ctx.Importer.Import(eh.CatchType),
CatchType = eh.CatchType == null ? null : ctx.Importer.Import(eh.CatchType),
TryStart = (Instruction)bodyMap[eh.TryStart],
TryEnd = (Instruction)bodyMap[eh.TryEnd],
HandlerStart = (Instruction)bodyMap[eh.HandlerStart],
Expand All @@ -169,7 +168,7 @@ static void CopyMethodDef(MethodDef methodDef, InjectContext ctx) {
/// <param name="fieldDef">The origin FieldDef.</param>
/// <param name="ctx">The injection context.</param>
static void CopyFieldDef(FieldDef fieldDef, InjectContext ctx) {
var newFieldDef = (FieldDef)ctx.Map[fieldDef];
var newFieldDef = (FieldDef)ctx.MemberMap[fieldDef];

newFieldDef.Signature = ctx.Importer.Import(fieldDef.Signature);
}
Expand Down Expand Up @@ -204,7 +203,7 @@ public static TypeDef Inject(TypeDef typeDef, ModuleDef target) {
var ctx = new InjectContext(typeDef.Module, target);
PopulateContext(typeDef, ctx);
Copy(typeDef, ctx, true);
return (TypeDef)ctx.Map[typeDef];
return (TypeDef)ctx.MemberMap[typeDef];
}

/// <summary>
Expand All @@ -215,9 +214,9 @@ public static TypeDef Inject(TypeDef typeDef, ModuleDef target) {
/// <returns>The injected MethodDef.</returns>
public static MethodDef Inject(MethodDef methodDef, ModuleDef target) {
var ctx = new InjectContext(methodDef.Module, target);
ctx.Map[methodDef] = Clone(methodDef);
ctx.MemberMap[methodDef] = Clone(methodDef);
CopyMethodDef(methodDef, ctx);
return (MethodDef)ctx.Map[methodDef];
return (MethodDef)ctx.MemberMap[methodDef];
}

/// <summary>
Expand All @@ -229,20 +228,20 @@ public static MethodDef Inject(MethodDef methodDef, ModuleDef target) {
/// <returns>Injected members.</returns>
public static IEnumerable<IDnlibDef> Inject(TypeDef typeDef, TypeDef newType, ModuleDef target) {
var ctx = new InjectContext(typeDef.Module, target);
ctx.Map[typeDef] = newType;
ctx.MemberMap[typeDef] = newType;
PopulateContext(typeDef, ctx);
Copy(typeDef, ctx, false);
return ctx.Map.Values.Except(new[] { newType });
return ctx.MemberMap.Values.Except(new[] { newType }).OfType<IDnlibDef>();
}

/// <summary>
/// Context of the injection process.
/// </summary>
class InjectContext : ImportResolver {
class InjectContext : ImportMapper {
/// <summary>
/// The mapping of origin definitions to injected definitions.
/// </summary>
public readonly Dictionary<IDnlibDef, IDnlibDef> Map = new Dictionary<IDnlibDef, IDnlibDef>();
public readonly Dictionary<IMemberRef, IMemberRef> MemberMap = new Dictionary<IMemberRef, IMemberRef>();

/// <summary>
/// The module which source type originated from.
Expand All @@ -267,8 +266,7 @@ class InjectContext : ImportResolver {
public InjectContext(ModuleDef module, ModuleDef target) {
OriginModule = module;
TargetModule = target;
importer = new Importer(target, ImporterOptions.TryToUseTypeDefs);
importer.Resolver = this;
importer = new Importer(target, ImporterOptions.TryToUseTypeDefs, new GenericParamContext(), this);
}

/// <summary>
Expand All @@ -280,23 +278,81 @@ public Importer Importer {
}

/// <inheritdoc />
public override TypeDef Resolve(TypeDef typeDef) {
if (Map.ContainsKey(typeDef))
return (TypeDef)Map[typeDef];
return null;
}
public override ITypeDefOrRef Map(ITypeDefOrRef source) {
if (MemberMap.TryGetValue(source, out var result))
return (ITypeDefOrRef)result;

//HACK: for netcore
//System.Enviroment and System.AppDomain is in System.Runtime.Extensions/mscorlib/netstandard
//System.Runtime.InteropServices.Marshal is in System.Runtime.InteropServices/mscorlib/netstandard
if (source.IsTypeRef && OriginModule.CorLibTypes.AssemblyRef != TargetModule.CorLibTypes.AssemblyRef &&
source.DefinitionAssembly == OriginModule.CorLibTypes.AssemblyRef) {
var sourceRef = (TypeRef)source;
TypeRef typeRef = TryResolveType(sourceRef, TargetModule.CorLibTypes.AssemblyRef, false);
if (typeRef == null) {
if (source.DefinitionAssembly.Name != "mscorlib")
typeRef = TryResolveType(sourceRef, new AssemblyRefUser(source.DefinitionAssembly), false);

typeRef = typeRef ?? TryResolveType(sourceRef, new AssemblyRefUser("netstandard"), true) ??
TryResolveType(sourceRef, new AssemblyRefUser("mscorlib"), true) ??
TryResolveType(sourceRef, new AssemblyRefUser("System.Private.CoreLib"), false);
}
if (typeRef != null) {
TargetModule.UpdateRowId(typeRef.ResolutionScope);
TargetModule.UpdateRowId(typeRef);
MemberMap[source] = typeRef;
return typeRef;
}
}

return null;
}

TypeRef TryResolveType(TypeRef sourceRef, AssemblyRef scope, bool checkExport) {
var typeRef = Import2(sourceRef, scope);

if (checkExport) {
var scopeDef = TargetModule.Context.AssemblyResolver.Resolve(typeRef.DefinitionAssembly, TargetModule);
if (scopeDef != null) {
var sigComparer = new SigComparer(SigComparerOptions.DontCompareTypeScope);
var exportType = scopeDef.Modules.SelectMany(m => m.ExportedTypes).Where(et => sigComparer.Equals(et, typeRef)).FirstOrDefault();
if (exportType != null && exportType.Implementation.Name != "System.Private.CoreLib" && exportType.Resolve() != null) {
return exportType.ToTypeRef();
}
}
}

if (typeRef.Resolve() != null)
return typeRef;

return null;
}

TypeRef Import2(TypeRef type, IResolutionScope scope) {
if (type is null)
return null;
TypeRef result;

var declaringType = type.DeclaringType;
if (!(declaringType is null))
result = new TypeRefUser(TargetModule, type.Namespace, type.Name, Import2(declaringType, scope));
else
result = new TypeRefUser(TargetModule, type.Namespace, type.Name, scope);

return result;
}

/// <inheritdoc />
public override MethodDef Resolve(MethodDef methodDef) {
if (Map.ContainsKey(methodDef))
return (MethodDef)Map[methodDef];
public override IMethod Map(MethodDef source) {
if (MemberMap.TryGetValue(source, out var result))
return (MethodDef)result;
return null;
}

/// <inheritdoc />
public override FieldDef Resolve(FieldDef fieldDef) {
if (Map.ContainsKey(fieldDef))
return (FieldDef)Map[fieldDef];
public override IField Map(FieldDef source) {
if (MemberMap.ContainsKey(source))
return (FieldDef)MemberMap[source];
return null;
}
}
Expand Down
4 changes: 2 additions & 2 deletions Confuser.Protections/Compress/Compressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ void ImportAssemblyTypeReferences(ModuleDef originModule, ModuleDef stubModule)
}
}

class KeyInjector : IModuleWriterListener {
class KeyInjector {
readonly CompressorContext ctx;

public KeyInjector(CompressorContext ctx) {
Expand All @@ -312,7 +312,7 @@ public void WriterEvent(object sender, ModuleWriterEventArgs args) {
OnWriterEvent(args.Writer, args.Event);
}

public void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
private void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
if (evt == ModuleWriterEvent.MDBeginCreateTables) {
// Add key signature
uint sigBlob = writer.Metadata.BlobHeap.Add(ctx.KeySig);
Expand Down
6 changes: 2 additions & 4 deletions Confuser.Renamer/GenericArgumentResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Confuser.Renamer {
/// <summary>
/// Resolves generic arguments
/// </summary>
public struct GenericArgumentResolver {
public ref struct GenericArgumentResolver {
GenericArguments genericArguments;
RecursionCounter recursionCounter;

Expand Down Expand Up @@ -53,8 +53,6 @@ public static MethodSig Resolve(MethodSig methodSig, IList<TypeSig> typeGenArgs)
}

bool ReplaceGenericArg(ref TypeSig typeSig) {
if (genericArguments == null)
return false;
TypeSig newTypeSig = genericArguments.Resolve(typeSig);
if (newTypeSig != typeSig) {
typeSig = newTypeSig;
Expand Down Expand Up @@ -156,4 +154,4 @@ TypeSig ResolveGenericArgs(TypeSig typeSig) {
return result;
}
}
}
}
Loading