Skip to content

Commit 11e088c

Browse files
authored
Merge b3df4ce into 0b7d281
2 parents 0b7d281 + b3df4ce commit 11e088c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1496
-2
lines changed

Confuser.Core/DnlibUtils.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,35 @@ public static bool IsStatic(this EventDef evt) {
430430
return evt.AllMethods().Any(method => method.IsStatic);
431431
}
432432

433+
public static bool IsInterfaceImplementation(this MethodDef method) {
434+
if (method == null) throw new ArgumentNullException(nameof(method));
435+
436+
return IsImplicitImplementedInterfaceMember(method) || IsExplicitlyImplementedInterfaceMember(method);
437+
}
438+
439+
/// <summary>
440+
/// Determines whether the specified method is an implicitly implemented interface member.
441+
/// </summary>
442+
/// <param name="method">The method.</param>
443+
/// <returns>
444+
/// <see langword="true" /> if the specified method is an implicitly implemented interface member;
445+
/// otherwise, <see langword="false" />.
446+
/// </returns>
447+
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null" />.</exception>
448+
/// <exception cref="TypeResolveException">Failed to resolve required interface types.</exception>
449+
public static bool IsImplicitImplementedInterfaceMember(this MethodDef method) {
450+
if (method == null) throw new ArgumentNullException(nameof(method));
451+
452+
if (method.IsPublic && method.IsNewSlot) {
453+
foreach (var iFace in method.DeclaringType.Interfaces) {
454+
var iFaceDef = iFace.Interface.ResolveTypeDefThrow();
455+
if (iFaceDef.FindMethod(method.Name, (MethodSig)method.Signature) != null)
456+
return true;
457+
}
458+
}
459+
return false;
460+
}
461+
433462
/// <summary>
434463
/// Determines whether the specified method is an explicitly implemented interface member.
435464
/// </summary>
@@ -516,6 +545,18 @@ public static bool IsArrayAccessors(this IMethod method) {
516545
return false;
517546
}
518547

548+
public static bool IsEntryPoint(this MethodDef methodDef) {
549+
if (methodDef == null) throw new ArgumentNullException(nameof(methodDef));
550+
551+
return methodDef == methodDef.Module.EntryPoint;
552+
}
553+
554+
public static bool IsEntryPoint(this TypeDef typeDef) {
555+
if (typeDef == null) throw new ArgumentNullException(nameof(typeDef));
556+
557+
return typeDef == typeDef.Module.EntryPoint?.DeclaringType;
558+
}
559+
519560
/// <summary>
520561
/// Merges a specified call instruction into the body.
521562
/// </summary>

Confuser.Protections/AntiDebugProtection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,4 @@ enum AntiMode {
135135
}
136136
}
137137
}
138-
}
138+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Diagnostics;
3+
using Confuser.Core;
4+
using Confuser.Protections.TypeScrambler.Scrambler;
5+
using dnlib.DotNet;
6+
7+
namespace Confuser.Protections.TypeScrambler {
8+
internal sealed class AnalyzePhase : ProtectionPhase {
9+
public AnalyzePhase(TypeScrambleProtection parent) : base(parent) {}
10+
11+
public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods;
12+
13+
public override string Name => "Type scanner";
14+
15+
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
16+
if (context == null) throw new ArgumentNullException(nameof(context));
17+
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
18+
19+
var typeService = context.Registry.GetService<TypeService>();
20+
Debug.Assert(typeService != null, $"{nameof(typeService)} != null");
21+
22+
foreach (var target in parameters.Targets.WithProgress(context.Logger)) {
23+
switch (target) {
24+
case TypeDef typeDef:
25+
typeService.AddScannedItem(new ScannedType(typeDef));
26+
break;
27+
case MethodDef methodDef:
28+
var scramblePublic = parameters.GetParameter(context, methodDef, "scramblePublic", false);
29+
typeService.AddScannedItem(new ScannedMethod(typeService, methodDef, scramblePublic));
30+
break;
31+
}
32+
context.CheckCancellation();
33+
}
34+
}
35+
}
36+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Diagnostics;
3+
using Confuser.Core;
4+
using Confuser.Protections.TypeScrambler.Scrambler;
5+
using dnlib.DotNet;
6+
7+
namespace Confuser.Protections.TypeScrambler {
8+
internal sealed class ScramblePhase : ProtectionPhase {
9+
public ScramblePhase(TypeScrambleProtection parent) : base(parent) { }
10+
11+
public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods;
12+
13+
public override string Name => "Type scrambler";
14+
15+
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
16+
if (context == null) throw new ArgumentNullException(nameof(context));
17+
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
18+
19+
// First check if the type scrambler did anything that needs rewriting.
20+
// If that is not the case, we can skip this whole thing.
21+
var service = context.Registry.GetService<TypeService>();
22+
Debug.Assert(service != null, $"{nameof(service)} != null");
23+
if (!service.ScrambledAnything) return;
24+
25+
var rewriter = new TypeRewriter(context);
26+
rewriter.ApplyGenerics();
27+
28+
// In this stage the references to the scrambled types need to be fixed. This needs to be done for all
29+
// methods in the assembly, because all methods may contain references to the scrambled types and methods.
30+
foreach (var def in context.CurrentModule.FindDefinitions().WithProgress(context.Logger)) {
31+
switch (def) {
32+
case MethodDef md:
33+
md.ReturnType = rewriter.UpdateSignature(md.ReturnType);
34+
if (md.HasBody) {
35+
rewriter.ProcessBody(md);
36+
}
37+
break;
38+
case TypeDef td:
39+
foreach (var field in td.Fields) {
40+
field.FieldType = rewriter.UpdateSignature(field.FieldType);
41+
}
42+
break;
43+
}
44+
45+
context.CheckCancellation();
46+
}
47+
}
48+
}
49+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using dnlib.DotNet.Emit;
3+
4+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
5+
internal abstract class ContextAnalyzer {
6+
internal abstract Type TargetType();
7+
8+
internal abstract void ProcessOperand(ScannedMethod method, Instruction instruction, object operand);
9+
}
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using dnlib.DotNet.Emit;
6+
7+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
8+
internal sealed class ContextAnalyzerFactory : IEnumerable<ContextAnalyzer> {
9+
private IDictionary<Type, ContextAnalyzer> Analyzers { get; } = new Dictionary<Type, ContextAnalyzer>();
10+
private ScannedMethod TargetMethod { get; }
11+
internal ContextAnalyzerFactory(ScannedMethod method) {
12+
Debug.Assert(method != null, $"{nameof(method)} != null");
13+
14+
TargetMethod = method;
15+
}
16+
17+
internal void Add(ContextAnalyzer a) {
18+
Analyzers.Add(a.TargetType(), a);
19+
}
20+
21+
internal void Analyze(Instruction inst) {
22+
Debug.Assert(inst != null, $"{nameof(inst)} != null");
23+
Debug.Assert(inst.Operand != null, $"{nameof(inst)}.Operand != null");
24+
25+
var operand = inst.Operand;
26+
27+
var currentRefType = operand.GetType();
28+
while (currentRefType != typeof(object)) {
29+
if (Analyzers.TryGetValue(currentRefType, out var analyzer)) {
30+
analyzer.ProcessOperand(TargetMethod, inst, operand);
31+
break;
32+
}
33+
currentRefType = currentRefType.BaseType;
34+
}
35+
}
36+
37+
public IEnumerator<ContextAnalyzer> GetEnumerator() => Analyzers.Values.GetEnumerator();
38+
39+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
40+
}
41+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
using dnlib.DotNet.Emit;
3+
4+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
5+
internal abstract class ContextAnalyzer<T> : ContextAnalyzer {
6+
internal override Type TargetType() => typeof(T);
7+
internal abstract void Process(ScannedMethod method, Instruction instruction, T operand);
8+
internal override void ProcessOperand(ScannedMethod method, Instruction instruction, object operand) =>
9+
Process(method, instruction, (T)operand);
10+
}
11+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Diagnostics;
2+
using dnlib.DotNet;
3+
using dnlib.DotNet.Emit;
4+
5+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
6+
internal sealed class MemberRefAnalyzer : ContextAnalyzer<MemberRef> {
7+
internal override void Process(ScannedMethod method, Instruction instruction, MemberRef operand) {
8+
Debug.Assert(method != null, $"{nameof(method)} != null");
9+
Debug.Assert(instruction != null, $"{nameof(instruction)} != null");
10+
Debug.Assert(operand != null, $"{nameof(operand)} != null");
11+
12+
// Scrambling member references only works for constructors without parameters currently.
13+
if (instruction.OpCode != OpCodes.Newobj) return;
14+
if (operand.MethodSig.Params.Count > 0) return;
15+
16+
TypeSig sig = null;
17+
if (operand.Class is TypeRef typeRef)
18+
sig = typeRef.ToTypeSig();
19+
20+
if (operand.Class is TypeSpec typeSpec)
21+
sig = typeSpec.ToTypeSig();
22+
23+
if (sig != null)
24+
method.RegisterGeneric(sig);
25+
}
26+
}
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Diagnostics;
2+
using dnlib.DotNet;
3+
using dnlib.DotNet.Emit;
4+
5+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
6+
internal sealed class MethodDefAnalyzer : ContextAnalyzer<MethodDef> {
7+
private TypeService Service { get; }
8+
9+
internal MethodDefAnalyzer(TypeService service) {
10+
Debug.Assert(service != null, $"{nameof(service)} != null");
11+
12+
Service = service;
13+
}
14+
internal override void Process(ScannedMethod method, Instruction instruction, MethodDef operand) {
15+
Debug.Assert(method != null, $"{nameof(method)} != null");
16+
Debug.Assert(instruction != null, $"{nameof(instruction)} != null");
17+
Debug.Assert(operand != null, $"{nameof(operand)} != null");
18+
19+
var sc = Service.GetItem(operand);
20+
if (sc?.IsScambled == true)
21+
foreach (var regTypes in sc.TrueTypes)
22+
method.RegisterGeneric(regTypes);
23+
}
24+
}
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Diagnostics;
2+
using dnlib.DotNet;
3+
using dnlib.DotNet.Emit;
4+
5+
namespace Confuser.Protections.TypeScrambler.Scrambler.Analyzers {
6+
internal sealed class MethodSpecAnalyzer : ContextAnalyzer<MethodSpec> {
7+
internal override void Process(ScannedMethod method, Instruction instruction, MethodSpec operand) {
8+
Debug.Assert(method != null, $"{nameof(method)} != null");
9+
Debug.Assert(instruction != null, $"{nameof(instruction)} != null");
10+
Debug.Assert(operand != null, $"{nameof(operand)} != null");
11+
12+
foreach (var t in operand.GenericInstMethodSig.GenericArguments)
13+
method.RegisterGeneric(t);
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)