Skip to content

Commit 1b51383

Browse files
authored
Merge d8432f0 into 0b7d281
2 parents 0b7d281 + d8432f0 commit 1b51383

40 files changed

+1519
-3
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: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Diagnostics;
3+
using Confuser.Core;
4+
using Confuser.Protections.TypeScramble.Scrambler;
5+
using dnlib.DotNet;
6+
7+
namespace Confuser.Protections.TypeScramble {
8+
internal sealed class AnalyzePhase : ProtectionPhase {
9+
10+
public AnalyzePhase(TypeScrambleProtection parent) : base(parent) {}
11+
12+
public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods;
13+
14+
public override string Name => "Type scanner";
15+
16+
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
17+
if (context == null) throw new ArgumentNullException(nameof(context));
18+
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
19+
20+
var typeService = context.Registry.GetService<TypeService>();
21+
Debug.Assert(typeService != null, $"{nameof(typeService)} != null");
22+
23+
foreach (var target in parameters.Targets.WithProgress(context.Logger)) {
24+
switch (target) {
25+
case TypeDef typeDef:
26+
typeService.AddScannedItem(new ScannedType(typeDef));
27+
break;
28+
case MethodDef methodDef:
29+
var scramblePublic = parameters.GetParameter(context, methodDef, "scramblePublic", false);
30+
typeService.AddScannedItem(new ScannedMethod(typeService, methodDef, scramblePublic));
31+
break;
32+
33+
}
34+
context.CheckCancellation();
35+
}
36+
}
37+
}
38+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Diagnostics;
3+
using Confuser.Core;
4+
using Confuser.Protections.TypeScramble.Scrambler;
5+
using dnlib.DotNet;
6+
7+
namespace Confuser.Protections.TypeScramble {
8+
internal sealed class ScramblePhase : ProtectionPhase {
9+
10+
public ScramblePhase(TypeScrambleProtection parent) : base(parent) { }
11+
12+
public override ProtectionTargets Targets => ProtectionTargets.Types | ProtectionTargets.Methods;
13+
14+
public override string Name => "Type scrambler";
15+
16+
protected override void Execute(ConfuserContext context, ProtectionParameters parameters) {
17+
if (context == null) throw new ArgumentNullException(nameof(context));
18+
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
19+
20+
// First check if the type scrambler did anything that needs rewriting.
21+
// If that is not the case, we can skip this whole thing.
22+
var service = context.Registry.GetService<TypeService>();
23+
Debug.Assert(service != null, $"{nameof(service)} != null");
24+
if (!service.ScrambledAnything) return;
25+
26+
var rewriter = new TypeRewriter(context);
27+
rewriter.ApplyGenerics();
28+
29+
// In this stage the references to the scrambled types need to be fixed. This needs to be done for all
30+
// methods in the assembly, because all methods may contain references to the scrambled types and methods.
31+
foreach (var def in context.CurrentModule.FindDefinitions().WithProgress(context.Logger)) {
32+
switch (def) {
33+
case MethodDef md:
34+
md.ReturnType = rewriter.UpdateSignature(md.ReturnType);
35+
if (md.HasBody) {
36+
rewriter.ProcessBody(md);
37+
}
38+
break;
39+
case TypeDef td:
40+
foreach (var field in td.Fields) {
41+
field.FieldType = rewriter.UpdateSignature(field.FieldType);
42+
}
43+
break;
44+
}
45+
46+
context.CheckCancellation();
47+
}
48+
}
49+
}
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using dnlib.DotNet.Emit;
3+
4+
namespace Confuser.Protections.TypeScramble.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+
11+
12+
internal abstract class ContextAnalyzer<T> : ContextAnalyzer {
13+
internal override Type TargetType() => typeof(T);
14+
internal abstract void Process(ScannedMethod method, Instruction instruction, T operand);
15+
internal override void ProcessOperand(ScannedMethod method, Instruction instruction, object operand) =>
16+
Process(method, instruction, (T)operand);
17+
18+
}
19+
}
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.TypeScramble.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: 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.TypeScramble.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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Diagnostics;
2+
using dnlib.DotNet;
3+
using dnlib.DotNet.Emit;
4+
5+
namespace Confuser.Protections.TypeScramble.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+
}
26+
}
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.TypeScramble.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+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Diagnostics;
2+
using dnlib.DotNet;
3+
using dnlib.DotNet.Emit;
4+
5+
namespace Confuser.Protections.TypeScramble.Scrambler.Analyzers {
6+
internal sealed class TypeRefAnalyzer : ContextAnalyzer<TypeRef> {
7+
internal override void Process(ScannedMethod method, Instruction instruction, TypeRef 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+
method.RegisterGeneric(operand.ToTypeSig());
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)